libaribcaption.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /*
  2. * ARIB STD-B24 caption decoder using the libaribcaption library
  3. * Copyright (c) 2022 TADANO Tokumei
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avcodec.h"
  22. #include "codec_internal.h"
  23. #include "internal.h"
  24. #include "libavcodec/ass.h"
  25. #include "libavutil/avstring.h"
  26. #include "libavutil/avutil.h"
  27. #include "libavutil/mem.h"
  28. #include "libavutil/thread.h"
  29. #include "libavutil/log.h"
  30. #include "libavutil/opt.h"
  31. #include <aribcaption/aribcaption.h>
  32. #if !defined(DEFAULT_FONT_ASS)
  33. # define DEFAULT_FONT_ASS "sans-serif"
  34. #endif
  35. #define ARIBC_BPRINT_SIZE_INIT 64
  36. #define ARIBC_BPRINT_SIZE_MAX (8 * 1024)
  37. #define ARIBC_ALPHA_MAX_NUM 4
  38. #define ARIBC_ALPHA_DEFAULT_FRONT 0xFF
  39. #define ARIBC_ALPHA_DEFAULT_BACK 0x80
  40. #define ARIBCC_COLOR_RGB(c) ((c) & 0xFFFFFF)
  41. #define ARIBCC_COLOR_DIFF_RGB(c1,c2) (((c1) ^ (c2)) & 0x00FFFFFF)
  42. #define ARIBCC_COLOR_DIFF_A(c1,c2) (((c1) ^ (c2)) & 0xFF000000)
  43. #define CLUT_RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
  44. #define CLUT_A(c) (((c) >> 24) & 0xFF)
  45. #define CLUT_R(c) (((c) >> 16) & 0xFF)
  46. #define CLUT_G(c) (((c) >> 8) & 0xFF)
  47. #define CLUT_B(c) ( (c) & 0xFF)
  48. #define ARIBCC_COLOR_TO_CLUT_RGBA(c,a) (((ARIBCC_COLOR_A(c) ? ARIBCC_COLOR_A(c) : (a)) << 24) | \
  49. (ARIBCC_COLOR_R(c) << 16) | \
  50. (ARIBCC_COLOR_G(c) << 8) | \
  51. (ARIBCC_COLOR_B(c)))
  52. typedef struct ARIBCaptionContext {
  53. AVClass *class;
  54. AVCodecContext *avctx;
  55. const AVPacket *avpkt;
  56. AVSubtitle *sub;
  57. aribcc_context_t *context;
  58. aribcc_decoder_t *decoder;
  59. aribcc_renderer_t *renderer;
  60. int subtitle_type;
  61. int encoding_scheme;
  62. int ass_single_rect;
  63. char *font;
  64. int force_stroke_text;
  65. int ignore_background;
  66. int ignore_ruby;
  67. float stroke_width;
  68. int replace_drcs;
  69. int replace_msz_ascii;
  70. int replace_msz_japanese;
  71. int replace_msz_glyph;
  72. int64_t pts;
  73. AVRational time_base;
  74. int canvas_width;
  75. int canvas_height;
  76. int plane_width;
  77. int plane_height;
  78. int frame_width;
  79. int frame_height;
  80. int bitmap_plane_width;
  81. int bitmap_plane_height;
  82. int font_size;
  83. int charstyle;
  84. int border_style;
  85. int readorder;
  86. aribcc_caption_t caption;
  87. aribcc_render_result_t render_result;
  88. uint32_t *clut;
  89. int clut_idx;
  90. int clut_overflow;
  91. uint8_t clut_alpha[ARIBC_ALPHA_MAX_NUM];
  92. } ARIBCaptionContext;
  93. static void hex_dump_debug(void *ctx, const char *buf, int buf_size)
  94. {
  95. int i;
  96. for (i = 0; i < buf_size; i++) {
  97. ff_dlog(ctx, "%02hhx ", buf[i]);
  98. if (i % 16 == 15)
  99. ff_dlog(ctx, "\n");
  100. }
  101. if (i % 16)
  102. ff_dlog(ctx, "\n");
  103. }
  104. static void logcat_callback(aribcc_loglevel_t level, const char* message, void* userdata)
  105. {
  106. ARIBCaptionContext *ctx = userdata;
  107. int lvl;
  108. if (ctx->decoder != NULL) {
  109. switch (level) {
  110. case ARIBCC_LOGLEVEL_ERROR:
  111. lvl = AV_LOG_ERROR;
  112. break;
  113. case ARIBCC_LOGLEVEL_WARNING:
  114. lvl = AV_LOG_WARNING;
  115. break;
  116. default:
  117. lvl = AV_LOG_INFO;
  118. }
  119. av_log(ctx, lvl, "%s\n", message);
  120. }
  121. }
  122. static void estimate_video_frame_size(ARIBCaptionContext *ctx)
  123. {
  124. if (ctx->avctx->width > 0 && ctx->avctx->height > 0) {
  125. /* input video size specified by -canvas_size option */
  126. ctx->bitmap_plane_width = ctx->avctx->width;
  127. ctx->bitmap_plane_height = ctx->avctx->height;
  128. } else if (ctx->plane_width == 960) {
  129. /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] 4.3.1 */
  130. /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] Appendix-4 */
  131. ctx->bitmap_plane_width = 1440;
  132. ctx->bitmap_plane_height = 1080;
  133. } else {
  134. ctx->bitmap_plane_width = ctx->plane_width;
  135. ctx->bitmap_plane_height = ctx->plane_height;
  136. }
  137. /* Expand either width or height */
  138. if (ctx->bitmap_plane_height * ctx->plane_width > ctx->bitmap_plane_width * ctx->plane_height) {
  139. ctx->frame_height = ctx->bitmap_plane_height;
  140. ctx->frame_width = ctx->frame_height * ctx->plane_width / ctx->plane_height;
  141. } else {
  142. ctx->frame_width = ctx->bitmap_plane_width;
  143. ctx->frame_height = ctx->frame_width * ctx->plane_height / ctx->plane_width;
  144. }
  145. }
  146. static void clut_set_alpha(ARIBCaptionContext *ctx, uint8_t a)
  147. {
  148. int i;
  149. for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) {
  150. if (ctx->clut_alpha[i] == 0) {
  151. ctx->clut_alpha[i] = a;
  152. return;
  153. }
  154. if (ctx->clut_alpha[i] == a)
  155. return;
  156. }
  157. return;
  158. }
  159. static uint8_t clut_find_nearlest_alpha(ARIBCaptionContext *ctx, uint8_t a)
  160. {
  161. int i, j, d;
  162. if (a == 0)
  163. return a;
  164. d = 256;
  165. j = 0;
  166. for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) {
  167. if (ctx->clut_alpha[i] == a)
  168. return a;
  169. if (ctx->clut_alpha[i] == 0)
  170. break;
  171. if (abs((int)a - (int)ctx->clut_alpha[i]) < d) {
  172. d = abs((int)a - (int)ctx->clut_alpha[i]);
  173. j = i;
  174. }
  175. }
  176. return ctx->clut_alpha[j];
  177. }
  178. static int clut_find(ARIBCaptionContext *ctx, uint32_t rgba)
  179. {
  180. int i;
  181. for (i = 0; i < ctx->clut_idx; i++) {
  182. if (ctx->clut[i] == rgba)
  183. return i;
  184. }
  185. return -1;
  186. }
  187. static inline int clut_color_distance(uint32_t rgba1, uint32_t rgba2)
  188. {
  189. return abs((int)CLUT_R(rgba1) - (int)CLUT_R(rgba2)) +
  190. abs((int)CLUT_G(rgba1) - (int)CLUT_G(rgba2)) +
  191. abs((int)CLUT_B(rgba1) - (int)CLUT_B(rgba2));
  192. }
  193. static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, int a)
  194. {
  195. int c, i, d, d_min;
  196. uint32_t rgba;
  197. a = clut_find_nearlest_alpha(ctx, a);
  198. if (a == 0)
  199. return 0; /* transparent */
  200. rgba = CLUT_RGBA(r,g,b,a);
  201. d_min = 256 * 3;
  202. c = 0;
  203. for (i = 0; i < ctx->clut_idx; i++) {
  204. if (ctx->clut[i] == rgba)
  205. return i;
  206. if (CLUT_A(ctx->clut[i]) != a)
  207. continue;
  208. d = clut_color_distance(ctx->clut[i], rgba);
  209. if (d < d_min) {
  210. d_min = d;
  211. c = i;
  212. }
  213. }
  214. if (d_min > 3) {
  215. if (ctx->clut_idx >= AVPALETTE_COUNT)
  216. ctx->clut_overflow++;
  217. else {
  218. c = ctx->clut_idx;
  219. ctx->clut[ctx->clut_idx++] = rgba;
  220. }
  221. }
  222. return c;
  223. }
  224. /* initialize CLUT with each character colors */
  225. static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region)
  226. {
  227. aribcc_color_t text_color, back_color, stroke_color;
  228. uint32_t rgba;
  229. ctx->clut[0] = CLUT_RGBA(0,0,0,0); /* transparent */
  230. ctx->clut_alpha[0] = 0xFF;
  231. ctx->clut_idx = 1;
  232. ctx->clut_overflow = 0;
  233. text_color = region->chars[0].text_color;
  234. back_color = region->chars[0].back_color;
  235. stroke_color = region->chars[0].stroke_color;
  236. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(text_color, ARIBC_ALPHA_DEFAULT_FRONT);
  237. ctx->clut[ctx->clut_idx++] = rgba;
  238. clut_set_alpha(ctx, CLUT_A(rgba));
  239. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(back_color, ARIBC_ALPHA_DEFAULT_BACK);
  240. ctx->clut[ctx->clut_idx++] = rgba;
  241. clut_set_alpha(ctx, CLUT_A(rgba));
  242. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(stroke_color, ARIBC_ALPHA_DEFAULT_FRONT);
  243. if (clut_find(ctx, rgba) < 0) {
  244. ctx->clut[ctx->clut_idx++] = rgba;
  245. clut_set_alpha(ctx, CLUT_A(rgba));
  246. }
  247. for (int i = 1; i < region->char_count; i++) {
  248. if (region->chars[i].text_color != text_color) {
  249. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].text_color,
  250. ARIBC_ALPHA_DEFAULT_FRONT);
  251. if (clut_find(ctx, rgba) < 0) {
  252. ctx->clut[ctx->clut_idx++] = rgba;
  253. clut_set_alpha(ctx, CLUT_A(rgba));
  254. }
  255. }
  256. if (region->chars[i].back_color != back_color) {
  257. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].back_color,
  258. ARIBC_ALPHA_DEFAULT_BACK);
  259. if (clut_find(ctx, rgba) < 0) {
  260. ctx->clut[ctx->clut_idx++] = rgba;
  261. clut_set_alpha(ctx, CLUT_A(rgba));
  262. }
  263. }
  264. if (region->chars[i].stroke_color != stroke_color) {
  265. rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].stroke_color,
  266. ARIBC_ALPHA_DEFAULT_FRONT);
  267. if (clut_find(ctx, rgba) < 0) {
  268. if (ctx->clut_idx < AVPALETTE_COUNT)
  269. ctx->clut[ctx->clut_idx++] = rgba;
  270. clut_set_alpha(ctx, CLUT_A(rgba));
  271. }
  272. }
  273. }
  274. }
  275. /**
  276. * aribcaption_trans_{bitmap|ass|text}_subtitle()
  277. *
  278. * Transfer decoded subtitle to AVSubtitle with corresponding subtitle type.
  279. *
  280. * @param ctx pointer to the ARIBCaptionContext
  281. * @return > 0 number of rectangles to be displayed
  282. * = 0 no subtitle
  283. * < 0 error code
  284. */
  285. static int aribcaption_trans_bitmap_subtitle(ARIBCaptionContext *ctx)
  286. {
  287. int ret = 0;
  288. AVSubtitle *sub = ctx->sub;
  289. int status, rect_idx;
  290. int old_width = ctx->frame_width;
  291. int old_height = ctx->frame_height;
  292. if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0) {
  293. ctx->plane_width = ctx->caption.plane_width;
  294. ctx->plane_height = ctx->caption.plane_height;
  295. }
  296. estimate_video_frame_size(ctx);
  297. if (ctx->frame_width != old_width || ctx->frame_height != old_height) {
  298. ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n",
  299. ctx->avctx->width, ctx->avctx->height,
  300. ctx->plane_width, ctx->plane_height,
  301. ctx->bitmap_plane_width, ctx->bitmap_plane_height,
  302. ctx->frame_width, ctx->frame_height);
  303. if (!aribcc_renderer_set_frame_size(ctx->renderer,
  304. ctx->frame_width, ctx->frame_height)) {
  305. av_log(ctx, AV_LOG_ERROR,
  306. "aribcc_renderer_set_frame_size() returned with error.\n");
  307. return AVERROR_EXTERNAL;
  308. }
  309. }
  310. status = aribcc_renderer_append_caption(ctx->renderer, &ctx->caption);
  311. if (!status) {
  312. av_log(ctx, AV_LOG_ERROR,
  313. "aribcc_renderer_append_caption() returned with error.\n");
  314. return AVERROR_EXTERNAL;
  315. }
  316. status = aribcc_renderer_render(ctx->renderer, ctx->pts, &ctx->render_result);
  317. switch (status) {
  318. case ARIBCC_RENDER_STATUS_GOT_IMAGE:
  319. break;
  320. case ARIBCC_RENDER_STATUS_GOT_IMAGE_UNCHANGED:
  321. aribcc_render_result_cleanup(&ctx->render_result);
  322. ff_dlog(ctx, "got image unchanged\n");
  323. return 0;
  324. case ARIBCC_RENDER_STATUS_NO_IMAGE:
  325. ff_dlog(ctx, "no image\n");
  326. return 0;
  327. case ARIBCC_RENDER_STATUS_ERROR:
  328. av_log(ctx, AV_LOG_ERROR,
  329. "aribcc_renderer_render() returned with error.\n");
  330. return AVERROR_EXTERNAL;
  331. default:
  332. aribcc_render_result_cleanup(&ctx->render_result);
  333. av_log(ctx, AV_LOG_ERROR,
  334. "aribcc_renderer_render() returned unknown status: %d\n", status);
  335. return AVERROR_EXTERNAL;
  336. }
  337. if (!ctx->render_result.image_count || ctx->render_result.images == NULL) {
  338. aribcc_render_result_cleanup(&ctx->render_result);
  339. ff_dlog(ctx, "no image (%d)\n", ctx->render_result.image_count);
  340. return 0;
  341. }
  342. sub->format = 0; /* graphic */
  343. sub->rects = av_calloc(ctx->render_result.image_count, sizeof(*sub->rects));
  344. if (!sub->rects) {
  345. ret = AVERROR(ENOMEM);
  346. goto fail;
  347. }
  348. for (int i = 0; i < ctx->render_result.image_count; i++) {
  349. sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
  350. if (!sub->rects[i]) {
  351. ret = AVERROR(ENOMEM);
  352. goto fail;
  353. }
  354. }
  355. for (rect_idx = 0; rect_idx < ctx->caption.region_count; rect_idx++) {
  356. AVSubtitleRect *rect = sub->rects[rect_idx];
  357. aribcc_image_t *image = &ctx->render_result.images[rect_idx];
  358. int w, h, shrink_height, dst_idx;
  359. clut_init(ctx, &ctx->caption.regions[rect_idx]);
  360. rect->w = image->width * ctx->bitmap_plane_width / ctx->frame_width;
  361. rect->h = image->height * ctx->bitmap_plane_height / ctx->frame_height;
  362. rect->data[0] = av_mallocz(rect->w * rect->h);
  363. if (!rect->data[0]) {
  364. ret = AVERROR(ENOMEM);
  365. goto fail;
  366. }
  367. if ((image->height != rect->h && image->width != rect->w) ||
  368. image->stride < image->width * 4 ||
  369. image->stride * image->height > image->bitmap_size) {
  370. av_log(ctx, AV_LOG_ERROR, "Bug: unexpected rendered image: %d(%d)x%d -> %dx%d\n",
  371. image->width, image->stride / 4, image->height, rect->w, rect->h);
  372. ret = AVERROR_EXTERNAL;
  373. goto fail;
  374. }
  375. shrink_height = image->height != rect->h;
  376. dst_idx = 0;
  377. for (h = 0; h < rect->h; h++) {
  378. for (w = 0; w < rect->w; w++) {
  379. /* Bi-linear interpolation */
  380. int n, m, idx0, idx1, r, g, b, a;
  381. if (shrink_height) {
  382. int div_a, y0, y1;
  383. div_a = h * ctx->frame_height;
  384. n = ctx->bitmap_plane_height;
  385. y0 = div_a / n;
  386. y1 = FFMIN(y0 + 1, image->height - 1);
  387. m = div_a - n * y0;
  388. idx0 = image->stride * y0 + w * 4;
  389. idx1 = image->stride * y1 + w * 4;
  390. } else {
  391. int div_a, x0, x1;
  392. div_a = w * ctx->frame_width;
  393. n = ctx->bitmap_plane_width;
  394. x0 = div_a / n;
  395. x1 = FFMIN(x0 + 1, image->width - 1);
  396. m = div_a - n * x0;
  397. idx0 = image->stride * h + x0 * 4;
  398. idx1 = image->stride * h + x1 * 4;
  399. }
  400. r = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
  401. g = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
  402. b = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
  403. a = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
  404. rect->data[0][dst_idx++] = clut_pick_or_set(ctx, r, g, b, a);
  405. }
  406. }
  407. rect->data[1] = av_memdup(ctx->clut, AVPALETTE_SIZE);
  408. if (!rect->data[1]) {
  409. ret = AVERROR(ENOMEM);
  410. goto fail;
  411. }
  412. if (ctx->avctx->profile == AV_PROFILE_ARIB_PROFILE_C) {
  413. /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */
  414. /* No position information is provided for profile C */
  415. rect->x = (ctx->frame_width - rect->w) / 2;
  416. rect->y = ctx->frame_height - rect->h * (ctx->caption.region_count - rect_idx);
  417. } else {
  418. rect->x = image->dst_x * ctx->bitmap_plane_width / ctx->frame_width;
  419. rect->y = image->dst_y * ctx->bitmap_plane_height / ctx->frame_height;
  420. }
  421. rect->type = SUBTITLE_BITMAP;
  422. rect->linesize[0] = rect->w;
  423. rect->nb_colors = 256;
  424. ff_dlog(ctx, "BITMAP subtitle%s (%d,%d) %dx%d -> (%d,%d) %dx%d [%d]: %d colors\n",
  425. (ctx->caption.regions[rect_idx].is_ruby) ? " (ruby)" : "",
  426. image->dst_x, image->dst_y, image->width, image->height,
  427. rect->x, rect->y, rect->w, rect->h,
  428. rect_idx, ctx->clut_idx);
  429. if (ctx->clut_overflow)
  430. av_log(ctx, AV_LOG_WARNING, "CLUT overflow (%d).\n", ctx->clut_overflow);
  431. }
  432. sub->num_rects = rect_idx;
  433. return rect_idx;
  434. fail:
  435. if (sub->rects) {
  436. for (int i = 0; i < ctx->caption.region_count; i++) {
  437. if (sub->rects[i]) {
  438. av_freep(&sub->rects[i]->data[0]);
  439. av_freep(&sub->rects[i]->data[1]);
  440. av_freep(&sub->rects[i]);
  441. }
  442. }
  443. av_freep(&sub->rects);
  444. }
  445. sub->num_rects = 0;
  446. return ret;
  447. }
  448. static int set_ass_header(ARIBCaptionContext *ctx)
  449. {
  450. AVCodecContext *avctx = ctx->avctx;
  451. int outline, shadow;
  452. const char *font_name;
  453. const char *fonts = ctx->font;
  454. if (ctx->border_style == 4) {
  455. outline = 0;
  456. shadow = 4;
  457. } else {
  458. outline = 1;
  459. shadow = 0;
  460. }
  461. if (ctx->force_stroke_text)
  462. outline = (int)(ctx->stroke_width * 4.0 / 3.0);
  463. if (fonts && *fonts)
  464. font_name = av_get_token(&fonts, ",");
  465. else
  466. font_name = av_strdup(DEFAULT_FONT_ASS);
  467. if (!font_name)
  468. return AVERROR(ENOMEM);
  469. av_freep(&avctx->subtitle_header);
  470. avctx->subtitle_header = av_asprintf(
  471. "[Script Info]\n"
  472. "ScriptType: v4.00+\n"
  473. "PlayResX: %d\n"
  474. "PlayResY: %d\n"
  475. "WrapStyle: 2\n" /* 2: no word wrapping */
  476. "\n"
  477. "[V4+ Styles]\n"
  478. "Format: Name, "
  479. "Fontname, Fontsize, "
  480. "PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
  481. "Bold, Italic, Underline, StrikeOut, "
  482. "ScaleX, ScaleY, "
  483. "Spacing, Angle, "
  484. "BorderStyle, Outline, Shadow, "
  485. "Alignment, MarginL, MarginR, MarginV, "
  486. "Encoding\n"
  487. "Style: "
  488. "Default," /* Name */
  489. "%s,%d," /* Font{name,size} */
  490. "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */
  491. "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */
  492. "100,100," /* Scale{X,Y} */
  493. "0,0," /* Spacing, Angle */
  494. "%d,%d,%d," /* BorderStyle, Outline, Shadow */
  495. "%d,10,10,10," /* Alignment, Margin[LRV] */
  496. "0\n" /* Encoding */
  497. "\n"
  498. "[Events]\n"
  499. "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n",
  500. ctx->plane_width, ctx->plane_height,
  501. font_name, ctx->font_size,
  502. ASS_DEFAULT_COLOR, ASS_DEFAULT_COLOR,
  503. ASS_DEFAULT_BACK_COLOR, ASS_DEFAULT_BACK_COLOR,
  504. -ASS_DEFAULT_BOLD, -ASS_DEFAULT_ITALIC, -ASS_DEFAULT_UNDERLINE,
  505. ctx->border_style, outline, shadow, ASS_DEFAULT_ALIGNMENT);
  506. av_freep(&font_name);
  507. if (!avctx->subtitle_header)
  508. return AVERROR(ENOMEM);
  509. avctx->subtitle_header_size = strlen(avctx->subtitle_header);
  510. return 0;
  511. }
  512. static void set_ass_color(AVBPrint *buf, int color_num,
  513. aribcc_color_t new_color, aribcc_color_t old_color)
  514. {
  515. if (ARIBCC_COLOR_DIFF_RGB(new_color, old_color))
  516. av_bprintf(buf, "{\\%dc&H%06x&}", color_num,
  517. ARIBCC_COLOR_RGB(new_color));
  518. if (ARIBCC_COLOR_DIFF_A(new_color, old_color))
  519. av_bprintf(buf, "{\\%da&H%02x&}", color_num,
  520. 0xFF - ARIBCC_COLOR_A(new_color));
  521. }
  522. static int aribcaption_trans_ass_subtitle(ARIBCaptionContext *ctx)
  523. {
  524. AVSubtitle *sub = ctx->sub;
  525. AVBPrint buf;
  526. bool single_rect = ctx->ass_single_rect;
  527. int ret = 0, rect_idx;
  528. if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0 &&
  529. (ctx->caption.plane_width != ctx->plane_width ||
  530. ctx->caption.plane_height != ctx->plane_height)) {
  531. ctx->plane_width = ctx->caption.plane_width;
  532. ctx->plane_height = ctx->caption.plane_height;
  533. if ((ret = set_ass_header(ctx)) < 0)
  534. return ret;
  535. }
  536. /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */
  537. /* No position information is provided for profile C */
  538. if (ctx->avctx->profile == AV_PROFILE_ARIB_PROFILE_C)
  539. single_rect = true;
  540. sub->format = 1; /* text */
  541. if (ctx->caption.region_count == 0) {
  542. /* clear previous caption for indefinite duration */
  543. ff_ass_add_rect(sub, "", ctx->readorder++, 0, NULL, NULL);
  544. return 1;
  545. }
  546. av_bprint_init(&buf, ARIBC_BPRINT_SIZE_INIT, ARIBC_BPRINT_SIZE_MAX);
  547. if (single_rect && ctx->avctx->profile != AV_PROFILE_ARIB_PROFILE_C) {
  548. int x, y, rx, ry;
  549. x = ctx->plane_width;
  550. y = ctx->plane_height;
  551. for (int i = 0; i < ctx->caption.region_count; i++) {
  552. rx = ctx->caption.regions[i].x;
  553. ry = ctx->caption.regions[i].y;
  554. if (rx < x)
  555. x = rx;
  556. if (ry < y)
  557. y = ry;
  558. }
  559. av_bprintf(&buf, "{\\an7}");
  560. if (y < 0)
  561. y += ctx->plane_height;
  562. if (x > 0 || y > 0)
  563. av_bprintf(&buf, "{\\pos(%d,%d)}", x, y);
  564. }
  565. rect_idx = 0;
  566. for (int i = 0; i < ctx->caption.region_count; i++) {
  567. aribcc_caption_region_t *region = &ctx->caption.regions[i];
  568. aribcc_color_t text_color = ARIBCC_MAKE_RGBA(0xFF, 0xFF, 0xFF,
  569. ARIBC_ALPHA_DEFAULT_FRONT);
  570. aribcc_color_t stroke_color = ARIBCC_MAKE_RGBA(0, 0, 0,
  571. ARIBC_ALPHA_DEFAULT_FRONT);
  572. aribcc_color_t back_color = ARIBCC_MAKE_RGBA(0, 0, 0,
  573. ARIBC_ALPHA_DEFAULT_BACK);
  574. aribcc_charstyle_t charstyle = ctx->charstyle;
  575. int char_width = ctx->font_size;
  576. int char_height = ctx->font_size;
  577. int char_horizontal_spacing = 0;
  578. if (region->is_ruby && ctx->ignore_ruby)
  579. continue;
  580. if (!single_rect) {
  581. int x = region->x;
  582. int y = region->y;
  583. if (x < 0)
  584. x += ctx->plane_width;
  585. if (y < 0)
  586. y += ctx->plane_height;
  587. av_bprint_clear(&buf);
  588. av_bprintf(&buf, "{\\an7}");
  589. if (x > 0 || y > 0)
  590. av_bprintf(&buf, "{\\pos(%d,%d)}", x, y);
  591. }
  592. if (region->is_ruby)
  593. av_bprintf(&buf, "{\\fs%d}", char_height / 2);
  594. for (int j = 0; j < region->char_count; j++) {
  595. aribcc_caption_char_t *ch = &region->chars[j];
  596. if (ctx->avctx->profile != AV_PROFILE_ARIB_PROFILE_C) {
  597. if (ch->char_horizontal_spacing != char_horizontal_spacing) {
  598. av_bprintf(&buf, "{\\fsp%d}", (region->is_ruby) ?
  599. ch->char_horizontal_spacing / 2 :
  600. ch->char_horizontal_spacing);
  601. char_horizontal_spacing = ch->char_horizontal_spacing;
  602. }
  603. if (ch->char_width != char_width) {
  604. av_bprintf(&buf, "{\\fscx%"PRId64"}",
  605. av_rescale(ch->char_width, 100, ctx->font_size));
  606. char_width = ch->char_width;
  607. }
  608. if (ch->char_height != char_height) {
  609. av_bprintf(&buf, "{\\fscy%"PRId64"}",
  610. av_rescale(ch->char_height, 100, ctx->font_size));
  611. char_height = ch->char_height;
  612. }
  613. }
  614. if (ch->style != charstyle) {
  615. aribcc_charstyle_t diff = ch->style ^ charstyle;
  616. if (diff & ARIBCC_CHARSTYLE_STROKE) {
  617. if (charstyle & ARIBCC_CHARSTYLE_STROKE) {
  618. if (ctx->force_stroke_text)
  619. av_bprintf(&buf, "{\\bord%d}",
  620. (int)(ctx->stroke_width * 4.0 / 3.0));
  621. else
  622. av_bprintf(&buf, "{\\bord0}");
  623. } else
  624. av_bprintf(&buf, "{\\bord3}");
  625. }
  626. if (diff & ARIBCC_CHARSTYLE_BOLD) {
  627. if (charstyle & ARIBCC_CHARSTYLE_BOLD)
  628. av_bprintf(&buf, "{\\b0}");
  629. else
  630. av_bprintf(&buf, "{\\b1}");
  631. }
  632. if (diff & ARIBCC_CHARSTYLE_ITALIC) {
  633. if (charstyle & ARIBCC_CHARSTYLE_ITALIC)
  634. av_bprintf(&buf, "{\\i0}");
  635. else
  636. av_bprintf(&buf, "{\\i1}");
  637. }
  638. if (diff & ARIBCC_CHARSTYLE_UNDERLINE) {
  639. if (charstyle & ARIBCC_CHARSTYLE_UNDERLINE)
  640. av_bprintf(&buf, "{\\u0}");
  641. else
  642. av_bprintf(&buf, "{\\u1}");
  643. }
  644. charstyle = ch->style;
  645. }
  646. if (ch->text_color != text_color) {
  647. set_ass_color(&buf, 1, ch->text_color, text_color);
  648. text_color = ch->text_color;
  649. }
  650. if (ch->stroke_color != stroke_color) {
  651. set_ass_color(&buf, 3, ch->stroke_color, stroke_color);
  652. stroke_color = ch->stroke_color;
  653. }
  654. if (ch->back_color != back_color) {
  655. if (ctx->border_style == 4)
  656. set_ass_color(&buf, 4, ch->back_color, back_color);
  657. else
  658. set_ass_color(&buf, 3, ch->back_color, back_color);
  659. back_color = ch->back_color;
  660. }
  661. if (region->chars[j].type == ARIBCC_CHARTYPE_DRCS)
  662. av_bprintf(&buf, "\xe3\x80\x93"); /* Geta Mark */
  663. else
  664. ff_ass_bprint_text_event(&buf, ch->u8str, strlen(ch->u8str), "", 0);
  665. }
  666. if (single_rect) {
  667. if (i + 1 < ctx->caption.region_count)
  668. av_bprintf(&buf, "{\\r}\\N");
  669. ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]\n",
  670. (region->is_ruby) ? " (ruby)" : "",
  671. region->x, region->y, region->width, region->height,
  672. rect_idx);
  673. } else {
  674. if (!av_bprint_is_complete(&buf)) {
  675. ret = AVERROR(ENOMEM);
  676. goto fail;
  677. }
  678. ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]: %s\n",
  679. (region->is_ruby) ? " (ruby)" : "",
  680. region->x, region->y, region->width, region->height,
  681. rect_idx, buf.str);
  682. ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL);
  683. if (ret != 0)
  684. goto fail;
  685. rect_idx++;
  686. }
  687. }
  688. if (single_rect) {
  689. if (!av_bprint_is_complete(&buf)) {
  690. ret = AVERROR(ENOMEM);
  691. goto fail;
  692. }
  693. ff_dlog(ctx, "ASS subtitle: %s\n", buf.str);
  694. ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL);
  695. if (ret != 0)
  696. goto fail;
  697. rect_idx++;
  698. }
  699. av_bprint_finalize(&buf, NULL);
  700. return rect_idx;
  701. fail:
  702. if (sub->rects) {
  703. for (int i = 0; i < ctx->caption.region_count; i++) {
  704. if (sub->rects[i]) {
  705. av_freep(&sub->rects[i]->ass);
  706. av_freep(&sub->rects[i]);
  707. }
  708. }
  709. av_freep(&sub->rects);
  710. }
  711. sub->num_rects = 0;
  712. av_bprint_finalize(&buf, NULL);
  713. return ret;
  714. }
  715. static int aribcaption_trans_text_subtitle(ARIBCaptionContext *ctx)
  716. {
  717. AVSubtitle *sub = ctx->sub;
  718. AVSubtitleRect *rect;
  719. int ret = 0;
  720. const char *text;
  721. sub->rects = av_calloc(ctx->caption.region_count, sizeof(*sub->rects));
  722. if (!sub->rects) {
  723. ret = AVERROR(ENOMEM);
  724. goto fail;
  725. }
  726. sub->num_rects = 1;
  727. sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
  728. if (!sub->rects[0]) {
  729. ret = AVERROR(ENOMEM);
  730. goto fail;
  731. }
  732. rect = sub->rects[0];
  733. if (ctx->caption.region_count == 0)
  734. text = ""; /* clear previous caption */
  735. else {
  736. text = ctx->caption.text;
  737. ff_dlog(ctx, "TEXT subtitle: %s\n", text);
  738. }
  739. rect->text = av_strdup(text);
  740. if (!rect->text) {
  741. ret = AVERROR(ENOMEM);
  742. goto fail;
  743. }
  744. sub->format = 1; /* text */
  745. rect->type = SUBTITLE_TEXT;
  746. return 1;
  747. fail:
  748. if (sub->rects) {
  749. rect = sub->rects[0];
  750. if (rect) {
  751. av_freep(&rect->text);
  752. av_freep(&rect);
  753. }
  754. av_freep(&sub->rects);
  755. }
  756. sub->num_rects = 0;
  757. return ret;
  758. }
  759. static int aribcaption_decode(AVCodecContext *avctx, AVSubtitle *sub,
  760. int *got_sub_ptr, const AVPacket *avpkt)
  761. {
  762. ARIBCaptionContext *ctx = avctx->priv_data;
  763. int status;
  764. ff_dlog(ctx, "ARIB caption packet pts=%"PRIx64":\n", avpkt->pts);
  765. if (sub->num_rects) {
  766. avpriv_request_sample(ctx, "Different Version of Segment asked Twice");
  767. return AVERROR_PATCHWELCOME;
  768. }
  769. hex_dump_debug(ctx, avpkt->data, avpkt->size);
  770. ctx->sub = sub;
  771. ctx->avpkt = avpkt;
  772. ctx->time_base = avctx->pkt_timebase;
  773. if (ctx->time_base.num <= 0 || ctx->time_base.den <= 0) {
  774. av_log(ctx, AV_LOG_VERBOSE, "No timebase set. assuming 90kHz.\n");
  775. ctx->time_base = av_make_q(1, 90000);
  776. }
  777. if (avpkt->pts == AV_NOPTS_VALUE)
  778. ctx->pts = ARIBCC_PTS_NOPTS;
  779. else
  780. ctx->pts = av_rescale_q(avpkt->pts, ctx->time_base, (AVRational){1, 1000});
  781. status = aribcc_decoder_decode(ctx->decoder, avpkt->data, avpkt->size,
  782. ctx->pts, &ctx->caption);
  783. if (status == ARIBCC_DECODE_STATUS_ERROR) {
  784. av_log(ctx, AV_LOG_ERROR,
  785. "aribcc_decoder_decode() returned with error.\n");
  786. return AVERROR(EAGAIN);
  787. }
  788. if (status == ARIBCC_DECODE_STATUS_NO_CAPTION) {
  789. ff_dlog(ctx, "No caption.\n");
  790. return avpkt->size;
  791. } else {
  792. ff_dlog(ctx, "type=%02x, flags=%x, lang=%03x\n",
  793. ctx->caption.type, ctx->caption.flags, ctx->caption.iso6392_language_code);
  794. ff_dlog(ctx, "region count = %d, start=%d.%d, duration=%d.%d\n",
  795. ctx->caption.region_count,
  796. (int)(ctx->caption.pts / 1000), (int)(ctx->caption.pts % 1000),
  797. (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ?
  798. -1 : ctx->caption.wait_duration / 1000),
  799. (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ?
  800. 0 : ctx->caption.wait_duration % 1000));
  801. }
  802. switch ((enum AVSubtitleType) ctx->subtitle_type) {
  803. case SUBTITLE_TEXT:
  804. status = aribcaption_trans_text_subtitle(ctx);
  805. break;
  806. case SUBTITLE_ASS:
  807. status = aribcaption_trans_ass_subtitle(ctx);
  808. break;
  809. case SUBTITLE_BITMAP:
  810. status = aribcaption_trans_bitmap_subtitle(ctx);
  811. break;
  812. case SUBTITLE_NONE:
  813. default:
  814. status = 0;
  815. }
  816. if (status < 0) {
  817. av_log(ctx, AV_LOG_ERROR, "Failed to set Subtitle: %s\n",
  818. av_err2str(status));
  819. aribcc_caption_cleanup(&ctx->caption);
  820. return status;
  821. }
  822. if (status > 0) {
  823. *got_sub_ptr = 1;
  824. if (ctx->avpkt->pts != AV_NOPTS_VALUE)
  825. sub->pts = av_rescale_q(ctx->avpkt->pts,
  826. ctx->time_base, AV_TIME_BASE_Q);
  827. if (ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE)
  828. sub->end_display_time = UINT32_MAX;
  829. else
  830. sub->end_display_time = (uint32_t)ctx->caption.wait_duration;
  831. }
  832. aribcc_caption_cleanup(&ctx->caption);
  833. return avpkt->size;
  834. }
  835. static void aribcaption_flush(AVCodecContext *avctx)
  836. {
  837. ARIBCaptionContext *ctx = avctx->priv_data;
  838. if (ctx->decoder)
  839. aribcc_decoder_flush(ctx->decoder);
  840. if (ctx->renderer)
  841. aribcc_renderer_flush(ctx->renderer);
  842. if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
  843. ctx->readorder = 0;
  844. }
  845. static av_cold int aribcaption_close(AVCodecContext *avctx)
  846. {
  847. ARIBCaptionContext *ctx = avctx->priv_data;
  848. av_freep(&ctx->clut);
  849. if (ctx->renderer)
  850. aribcc_renderer_free(ctx->renderer);
  851. if (ctx->decoder)
  852. aribcc_decoder_free(ctx->decoder);
  853. if (ctx->context)
  854. aribcc_context_free(ctx->context);
  855. return 0;
  856. }
  857. static av_cold int aribcaption_init(AVCodecContext *avctx)
  858. {
  859. ARIBCaptionContext *ctx = avctx->priv_data;
  860. aribcc_profile_t profile;
  861. int ret = 0;
  862. ctx->avctx = avctx;
  863. switch (avctx->profile) {
  864. case AV_PROFILE_ARIB_PROFILE_A:
  865. profile = ARIBCC_PROFILE_A;
  866. /* assume 960x540 at initial state */
  867. ctx->plane_width = 960;
  868. ctx->plane_height = 540;
  869. ctx->font_size = 36;
  870. break;
  871. case AV_PROFILE_ARIB_PROFILE_C:
  872. profile = ARIBCC_PROFILE_C;
  873. ctx->plane_width = 320;
  874. ctx->plane_height = 180;
  875. ctx->font_size = 16;
  876. break;
  877. default:
  878. av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set.\n");
  879. return AVERROR(EINVAL);
  880. }
  881. /* determine BorderStyle of ASS header */
  882. if (ctx->ignore_background)
  883. ctx->border_style = 1;
  884. else
  885. ctx->border_style = 4;
  886. ctx->charstyle = ARIBCC_CHARSTYLE_DEFAULT;
  887. if (ctx->force_stroke_text || ctx->ignore_background)
  888. ctx->charstyle |= ARIBCC_CHARSTYLE_STROKE;
  889. if (!(ctx->context = aribcc_context_alloc())) {
  890. av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption context.\n");
  891. return AVERROR_EXTERNAL;
  892. }
  893. aribcc_context_set_logcat_callback(ctx->context, logcat_callback, avctx);
  894. if (!(ctx->decoder = aribcc_decoder_alloc(ctx->context))) {
  895. av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption decoder.\n");
  896. return AVERROR_EXTERNAL;
  897. }
  898. if (!aribcc_decoder_initialize(ctx->decoder,
  899. (enum aribcc_encoding_scheme_t) ctx->encoding_scheme,
  900. ARIBCC_CAPTIONTYPE_CAPTION,
  901. profile,
  902. ARIBCC_LANGUAGEID_FIRST)) {
  903. av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption decoder.\n");
  904. return AVERROR_EXTERNAL;
  905. }
  906. aribcc_decoder_set_replace_msz_fullwidth_ascii(ctx->decoder,
  907. ctx->replace_msz_ascii);
  908. aribcc_decoder_set_replace_msz_fullwidth_japanese(ctx->decoder,
  909. ctx->replace_msz_japanese);
  910. /* Similar behavior as ffmpeg tool to set canvas size */
  911. if (ctx->canvas_width > 0 && ctx->canvas_height > 0 &&
  912. (ctx->avctx->width == 0 || ctx->avctx->height == 0)) {
  913. ctx->avctx->width = ctx->canvas_width;
  914. ctx->avctx->height = ctx->canvas_height;
  915. }
  916. switch ((enum AVSubtitleType) ctx->subtitle_type) {
  917. case SUBTITLE_ASS:
  918. ret = set_ass_header(ctx);
  919. if (ret != 0) {
  920. av_log(avctx, AV_LOG_ERROR, "Failed to set ASS header: %s\n",
  921. av_err2str(ret));
  922. return ret;
  923. }
  924. break;
  925. case SUBTITLE_BITMAP:
  926. if(!(ctx->renderer = aribcc_renderer_alloc(ctx->context))) {
  927. av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption renderer.\n");
  928. return AVERROR_EXTERNAL;
  929. }
  930. if(!aribcc_renderer_initialize(ctx->renderer,
  931. ARIBCC_CAPTIONTYPE_CAPTION,
  932. ARIBCC_FONTPROVIDER_TYPE_AUTO,
  933. ARIBCC_TEXTRENDERER_TYPE_AUTO)) {
  934. av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption renderer.\n");
  935. return AVERROR_EXTERNAL;
  936. }
  937. estimate_video_frame_size(ctx);
  938. ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n",
  939. ctx->avctx->width, ctx->avctx->height,
  940. ctx->plane_width, ctx->plane_height,
  941. ctx->bitmap_plane_width, ctx->bitmap_plane_height,
  942. ctx->frame_width, ctx->frame_height);
  943. if (!aribcc_renderer_set_frame_size(ctx->renderer,
  944. ctx->frame_width, ctx->frame_height)) {
  945. av_log(ctx, AV_LOG_ERROR,
  946. "aribcc_renderer_set_frame_size() returned with error.\n");
  947. return AVERROR_EXTERNAL;
  948. }
  949. if (!(ctx->clut = av_mallocz(AVPALETTE_SIZE)))
  950. return AVERROR(ENOMEM);
  951. aribcc_renderer_set_storage_policy(ctx->renderer, ARIBCC_CAPTION_STORAGE_POLICY_MINIMUM, 0);
  952. aribcc_renderer_set_replace_drcs(ctx->renderer, ctx->replace_drcs);
  953. aribcc_renderer_set_force_stroke_text(ctx->renderer, ctx->force_stroke_text);
  954. aribcc_renderer_set_force_no_background(ctx->renderer, ctx->ignore_background);
  955. aribcc_renderer_set_force_no_ruby(ctx->renderer, ctx->ignore_ruby);
  956. aribcc_renderer_set_stroke_width(ctx->renderer, ctx->stroke_width);
  957. aribcc_renderer_set_replace_msz_halfwidth_glyph(ctx->renderer,
  958. ctx->replace_msz_glyph);
  959. if (ctx->font) {
  960. int is_nomem = 0;
  961. size_t count = 0;
  962. const char **font_families = NULL;
  963. const char *fonts = ctx->font;
  964. while (*fonts) {
  965. const char **ff = av_realloc_array(font_families, count + 1, sizeof(*font_families));
  966. if (!ff) {
  967. is_nomem = 1;
  968. break;
  969. } else {
  970. font_families = ff;
  971. ff[count++] = av_get_token(&fonts, ",");
  972. if (!ff[count - 1]) {
  973. is_nomem = 1;
  974. break;
  975. } else if (*fonts)
  976. fonts++;
  977. }
  978. }
  979. if (!is_nomem && count)
  980. aribcc_renderer_set_default_font_family(ctx->renderer, font_families, count, true);
  981. while (count)
  982. av_freep(&font_families[--count]);
  983. av_freep(&font_families);
  984. if (is_nomem)
  985. return AVERROR(ENOMEM);
  986. }
  987. break;
  988. case SUBTITLE_TEXT:
  989. case SUBTITLE_NONE:
  990. default:
  991. /* do nothing */ ;
  992. }
  993. ctx->readorder = 0;
  994. return 0;
  995. }
  996. #if !defined(ASS_SINGLE_RECT)
  997. # define ASS_SINGLE_RECT 0
  998. #endif
  999. #define OFFSET(x) offsetof(ARIBCaptionContext, x)
  1000. #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
  1001. static const AVOption options[] = {
  1002. { "sub_type", "subtitle rendering type",
  1003. OFFSET(subtitle_type), AV_OPT_TYPE_INT,
  1004. { .i64 = SUBTITLE_ASS }, SUBTITLE_NONE, SUBTITLE_ASS, SD, .unit = "type" },
  1005. { "none", "do nothing", 0, AV_OPT_TYPE_CONST,
  1006. { .i64 = SUBTITLE_NONE }, .flags = SD, .unit = "type" },
  1007. { "bitmap", "bitmap rendering", 0, AV_OPT_TYPE_CONST,
  1008. { .i64 = SUBTITLE_BITMAP }, .flags = SD, .unit = "type" },
  1009. { "text", "plain text", 0, AV_OPT_TYPE_CONST,
  1010. { .i64 = SUBTITLE_TEXT }, .flags = SD, .unit = "type" },
  1011. { "ass", "formatted text", 0, AV_OPT_TYPE_CONST,
  1012. { .i64 = SUBTITLE_ASS }, .flags = SD, .unit = "type" },
  1013. { "caption_encoding", "encoding scheme of subtitle text",
  1014. OFFSET(encoding_scheme), AV_OPT_TYPE_INT, { .i64 = ARIBCC_ENCODING_SCHEME_AUTO },
  1015. ARIBCC_ENCODING_SCHEME_AUTO, ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN, SD, .unit = "encoding" },
  1016. { "auto", "automatically detect encoding scheme", 0, AV_OPT_TYPE_CONST,
  1017. { .i64 = ARIBCC_ENCODING_SCHEME_AUTO }, .flags = SD, .unit = "encoding" },
  1018. { "jis", "8bit-char JIS encoding (Japanese ISDB captions)", 0, AV_OPT_TYPE_CONST,
  1019. { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_JIS }, .flags = SD, .unit = "encoding" },
  1020. { "utf8", "UTF-8 encoding (Philippines ISDB-T captions)", 0, AV_OPT_TYPE_CONST,
  1021. { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_UTF8 }, .flags = SD, .unit = "encoding" },
  1022. { "latin", "latin characters (SBTVD / ISDB-Tb captions used in South America)", 0, AV_OPT_TYPE_CONST,
  1023. { .i64 = ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN }, .flags = SD, .unit = "encoding" },
  1024. { "ass_single_rect", "workaround of ASS subtitle for players which can't handle multi-rectangle [ass]",
  1025. OFFSET(ass_single_rect), AV_OPT_TYPE_BOOL, { .i64 = ASS_SINGLE_RECT }, 0, 1, SD },
  1026. { "font", "comma-separated font family [ass, bitmap]",
  1027. OFFSET(font), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
  1028. { "force_outline_text", "always render characters with outline [(ass), bitmap]",
  1029. OFFSET(force_stroke_text), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
  1030. { "ignore_background", "ignore rendering caption background [(ass), bitmap]",
  1031. OFFSET(ignore_background), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
  1032. { "ignore_ruby", "ignore ruby-like characters [ass, bitmap]",
  1033. OFFSET(ignore_ruby), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
  1034. { "outline_width", "outline width of text [(ass), bitmap]",
  1035. OFFSET(stroke_width), AV_OPT_TYPE_FLOAT, { .dbl = 1.5 }, 0.0, 3.0, SD },
  1036. { "replace_drcs", "replace known DRCS [bitmap]",
  1037. OFFSET(replace_drcs), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
  1038. { "replace_msz_ascii", "replace MSZ fullwidth alphanumerics with halfwidth alphanumerics [ass, bitmap]",
  1039. OFFSET(replace_msz_ascii), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
  1040. { "replace_msz_japanese", "replace MSZ fullwidth Japanese with halfwidth [ass, bitmap]",
  1041. OFFSET(replace_msz_japanese), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
  1042. { "replace_msz_glyph", "replace MSZ characters with halfwidth glyphs [bitmap]",
  1043. OFFSET(replace_msz_glyph), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
  1044. {"canvas_size", "set input video size (WxH or abbreviation) [bitmap]",
  1045. OFFSET(canvas_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, INT_MAX, SD },
  1046. { NULL }
  1047. };
  1048. static const AVClass aribcaption_class = {
  1049. .class_name = "aribcaption decoder",
  1050. .item_name = av_default_item_name,
  1051. .option = options,
  1052. .version = LIBAVUTIL_VERSION_INT,
  1053. };
  1054. const FFCodec ff_libaribcaption_decoder = {
  1055. .p.name = "libaribcaption",
  1056. .p.long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption decoder"),
  1057. .p.type = AVMEDIA_TYPE_SUBTITLE,
  1058. .p.id = AV_CODEC_ID_ARIB_CAPTION,
  1059. .priv_data_size = sizeof(ARIBCaptionContext),
  1060. .init = aribcaption_init,
  1061. .close = aribcaption_close,
  1062. FF_CODEC_DECODE_SUB_CB(aribcaption_decode),
  1063. .flush = aribcaption_flush,
  1064. .p.priv_class = &aribcaption_class,
  1065. .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
  1066. };