FFmpeg
libaribcaption.c
Go to the documentation of this file.
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 
22 #include "avcodec.h"
23 #include "codec_internal.h"
24 #include "internal.h"
25 #include "libavcodec/ass.h"
26 #include "libavutil/avstring.h"
27 #include "libavutil/avutil.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/thread.h"
30 #include "libavutil/log.h"
31 #include "libavutil/opt.h"
32 
33 #include <aribcaption/aribcaption.h>
34 
35 #if !defined(DEFAULT_FONT_ASS)
36 # define DEFAULT_FONT_ASS "sans-serif"
37 #endif
38 
39 #define ARIBC_BPRINT_SIZE_INIT 64
40 #define ARIBC_BPRINT_SIZE_MAX (8 * 1024)
41 #define ARIBC_ALPHA_MAX_NUM 4
42 #define ARIBC_ALPHA_DEFAULT_FRONT 0xFF
43 #define ARIBC_ALPHA_DEFAULT_BACK 0x80
44 
45 #define ARIBCC_COLOR_RGB(c) ((c) & 0xFFFFFF)
46 #define ARIBCC_COLOR_DIFF_RGB(c1,c2) (((c1) ^ (c2)) & 0x00FFFFFF)
47 #define ARIBCC_COLOR_DIFF_A(c1,c2) (((c1) ^ (c2)) & 0xFF000000)
48 
49 #define CLUT_RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
50 #define CLUT_A(c) (((c) >> 24) & 0xFF)
51 #define CLUT_R(c) (((c) >> 16) & 0xFF)
52 #define CLUT_G(c) (((c) >> 8) & 0xFF)
53 #define CLUT_B(c) ( (c) & 0xFF)
54 
55 #define ARIBCC_COLOR_TO_CLUT_RGBA(c,a) (((ARIBCC_COLOR_A(c) ? ARIBCC_COLOR_A(c) : (a)) << 24) | \
56  (ARIBCC_COLOR_R(c) << 16) | \
57  (ARIBCC_COLOR_G(c) << 8) | \
58  (ARIBCC_COLOR_B(c)))
59 
60 typedef struct ARIBCaptionContext {
61  AVClass *class;
63  const AVPacket *avpkt;
65 
66  aribcc_context_t *context;
67  aribcc_decoder_t *decoder;
68  aribcc_renderer_t *renderer;
69 
73  char *font;
77  float stroke_width;
82 
83  int64_t pts;
93  int font_size;
94  int charstyle;
96  int readorder;
97 
98  aribcc_caption_t caption;
99  aribcc_render_result_t render_result;
100  uint32_t *clut;
101  int clut_idx;
105 
106 static void hex_dump_debug(void *ctx, const char *buf, int buf_size)
107 {
108  int i;
109 
110  for (i = 0; i < buf_size; i++) {
111  ff_dlog(ctx, "%02hhx ", buf[i]);
112  if (i % 16 == 15)
113  ff_dlog(ctx, "\n");
114  }
115  if (i % 16)
116  ff_dlog(ctx, "\n");
117 }
118 
119 static void logcat_callback(aribcc_loglevel_t level, const char* message, void* userdata)
120 {
121  ARIBCaptionContext *ctx = userdata;
122  int lvl;
123 
124  if (ctx->decoder != NULL) {
125  switch (level) {
126  case ARIBCC_LOGLEVEL_ERROR:
127  lvl = AV_LOG_ERROR;
128  break;
129  case ARIBCC_LOGLEVEL_WARNING:
130  lvl = AV_LOG_WARNING;
131  break;
132  default:
133  lvl = AV_LOG_INFO;
134  }
135 
136  av_log(ctx, lvl, "%s\n", message);
137  }
138 }
139 
141 {
142  if (ctx->avctx->width > 0 && ctx->avctx->height > 0) {
143  /* input video size specified by -canvas_size option */
144  ctx->bitmap_plane_width = ctx->avctx->width;
145  ctx->bitmap_plane_height = ctx->avctx->height;
146  } else if (ctx->plane_width == 960) {
147  /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] 4.3.1 */
148  /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] Appendix-4 */
149  ctx->bitmap_plane_width = 1440;
150  ctx->bitmap_plane_height = 1080;
151  } else {
152  ctx->bitmap_plane_width = ctx->plane_width;
153  ctx->bitmap_plane_height = ctx->plane_height;
154  }
155  /* Expand either width or height */
156  if (ctx->bitmap_plane_height * ctx->plane_width > ctx->bitmap_plane_width * ctx->plane_height) {
157  ctx->frame_height = ctx->bitmap_plane_height;
158  ctx->frame_width = ctx->frame_height * ctx->plane_width / ctx->plane_height;
159  } else {
160  ctx->frame_width = ctx->bitmap_plane_width;
161  ctx->frame_height = ctx->frame_width * ctx->plane_height / ctx->plane_width;
162  }
163 }
164 
165 static void clut_set_alpha(ARIBCaptionContext *ctx, uint8_t a)
166 {
167  int i;
168 
169  for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) {
170  if (ctx->clut_alpha[i] == 0) {
171  ctx->clut_alpha[i] = a;
172  return;
173  }
174  if (ctx->clut_alpha[i] == a)
175  return;
176  }
177  return;
178 }
179 
181 {
182  int i, j, d;
183 
184  if (a == 0)
185  return a;
186  d = 256;
187  j = 0;
188  for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) {
189  if (ctx->clut_alpha[i] == a)
190  return a;
191  if (ctx->clut_alpha[i] == 0)
192  break;
193  if (abs((int)a - (int)ctx->clut_alpha[i]) < d) {
194  d = abs((int)a - (int)ctx->clut_alpha[i]);
195  j = i;
196  }
197  }
198  return ctx->clut_alpha[j];
199 }
200 
201 static int clut_find(ARIBCaptionContext *ctx, uint32_t rgba)
202 {
203  int i;
204 
205  for (i = 0; i < ctx->clut_idx; i++) {
206  if (ctx->clut[i] == rgba)
207  return i;
208  }
209  return -1;
210 }
211 
212 static inline int clut_color_distance(uint32_t rgba1, uint32_t rgba2)
213 {
214  return abs((int)CLUT_R(rgba1) - (int)CLUT_R(rgba2)) +
215  abs((int)CLUT_G(rgba1) - (int)CLUT_G(rgba2)) +
216  abs((int)CLUT_B(rgba1) - (int)CLUT_B(rgba2));
217 }
218 
219 static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, int a)
220 {
221  int c, i, d, d_min;
222  uint32_t rgba;
223 
225  if (a == 0)
226  return 0; /* transparent */
227  rgba = CLUT_RGBA(r,g,b,a);
228 
229  d_min = 256 * 3;
230  c = 0;
231  for (i = 0; i < ctx->clut_idx; i++) {
232  if (ctx->clut[i] == rgba)
233  return i;
234  if (CLUT_A(ctx->clut[i]) != a)
235  continue;
236  d = clut_color_distance(ctx->clut[i], rgba);
237  if (d < d_min) {
238  d_min = d;
239  c = i;
240  }
241  }
242  if (d_min > 3) {
243  if (ctx->clut_idx >= AVPALETTE_COUNT)
244  ctx->clut_overflow++;
245  else {
246  c = ctx->clut_idx;
247  ctx->clut[ctx->clut_idx++] = rgba;
248  }
249  }
250  return c;
251 }
252 
253 /* initialiaze CLUT with each character colors */
254 static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region)
255 {
256  aribcc_color_t text_color, back_color, stroke_color;
257  uint32_t rgba;
258 
259  ctx->clut[0] = CLUT_RGBA(0,0,0,0); /* transparent */
260  ctx->clut_alpha[0] = 0xFF;
261  ctx->clut_idx = 1;
262  ctx->clut_overflow = 0;
263  text_color = region->chars[0].text_color;
264  back_color = region->chars[0].back_color;
265  stroke_color = region->chars[0].stroke_color;
267  ctx->clut[ctx->clut_idx++] = rgba;
268  clut_set_alpha(ctx, CLUT_A(rgba));
270  ctx->clut[ctx->clut_idx++] = rgba;
271  clut_set_alpha(ctx, CLUT_A(rgba));
273  if (clut_find(ctx, rgba) < 0) {
274  ctx->clut[ctx->clut_idx++] = rgba;
275  clut_set_alpha(ctx, CLUT_A(rgba));
276  }
277 
278  for (int i = 1; i < region->char_count; i++) {
279  if (region->chars[i].text_color != text_color) {
280  rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].text_color,
282  if (clut_find(ctx, rgba) < 0) {
283  ctx->clut[ctx->clut_idx++] = rgba;
284  clut_set_alpha(ctx, CLUT_A(rgba));
285  }
286  }
287  if (region->chars[i].back_color != back_color) {
288  rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].back_color,
290  if (clut_find(ctx, rgba) < 0) {
291  ctx->clut[ctx->clut_idx++] = rgba;
292  clut_set_alpha(ctx, CLUT_A(rgba));
293  }
294  }
295  if (region->chars[i].stroke_color != stroke_color) {
296  rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].stroke_color,
298  if (clut_find(ctx, rgba) < 0) {
299  if (ctx->clut_idx < AVPALETTE_COUNT)
300  ctx->clut[ctx->clut_idx++] = rgba;
301  clut_set_alpha(ctx, CLUT_A(rgba));
302  }
303  }
304  }
305 }
306 
307 /**
308  * aribcaption_trans_{bitmap|ass|text}_subtitle()
309  *
310  * Transfer decoded subtitle to AVSubtitle with corresponding subtitle type.
311  *
312  * @param ctx pointer to the ARIBCaptionContext
313  * @return > 0 number of rectangles to be displayed
314  * = 0 no subtitle
315  * < 0 error code
316  */
318 {
319  int ret = 0;
320  AVSubtitle *sub = ctx->sub;
321  int status, rect_idx;
322  int old_width = ctx->frame_width;
323  int old_height = ctx->frame_height;
324 
325  if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0) {
326  ctx->plane_width = ctx->caption.plane_width;
327  ctx->plane_height = ctx->caption.plane_height;
328  }
330  if (ctx->frame_width != old_width || ctx->frame_height != old_height) {
331  ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n",
332  ctx->avctx->width, ctx->avctx->height,
333  ctx->plane_width, ctx->plane_height,
334  ctx->bitmap_plane_width, ctx->bitmap_plane_height,
335  ctx->frame_width, ctx->frame_height);
336  if (!aribcc_renderer_set_frame_size(ctx->renderer,
337  ctx->frame_width, ctx->frame_height)) {
339  "aribcc_renderer_set_frame_size() returned with error.\n");
340  return AVERROR_EXTERNAL;
341  }
342  }
343 
344  status = aribcc_renderer_append_caption(ctx->renderer, &ctx->caption);
345  if (!status) {
347  "aribcc_renderer_append_caption() returned with error.\n");
348  return AVERROR_EXTERNAL;
349  }
350 
351  status = aribcc_renderer_render(ctx->renderer, ctx->pts, &ctx->render_result);
352  switch (status) {
353  case ARIBCC_RENDER_STATUS_GOT_IMAGE:
354  break;
355 
356  case ARIBCC_RENDER_STATUS_GOT_IMAGE_UNCHANGED:
357  aribcc_render_result_cleanup(&ctx->render_result);
358  ff_dlog(ctx, "got image unchanged\n");
359  return 0;
360 
361  case ARIBCC_RENDER_STATUS_NO_IMAGE:
362  ff_dlog(ctx, "no image\n");
363  return 0;
364 
365  case ARIBCC_RENDER_STATUS_ERROR:
367  "aribcc_renderer_render() returned with error.\n");
368  return AVERROR_EXTERNAL;
369 
370  default:
371  aribcc_render_result_cleanup(&ctx->render_result);
373  "aribcc_renderer_render() returned unknown status: %d\n", status);
374  return AVERROR_EXTERNAL;
375  }
376 
377  if (!ctx->render_result.image_count || ctx->render_result.images == NULL) {
378  aribcc_render_result_cleanup(&ctx->render_result);
379  ff_dlog(ctx, "no image (%d)\n", ctx->render_result.image_count);
380  return 0;
381  }
382 
383  sub->format = 0; /* graphic */
384  sub->rects = av_calloc(ctx->render_result.image_count, sizeof(*sub->rects));
385  if (!sub->rects) {
386  ret = AVERROR(ENOMEM);
387  goto fail;
388  }
389  for (int i = 0; i < ctx->render_result.image_count; i++) {
390  sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
391  if (!sub->rects[i]) {
392  ret = AVERROR(ENOMEM);
393  goto fail;
394  }
395  }
396 
397  for (rect_idx = 0; rect_idx < ctx->caption.region_count; rect_idx++) {
398  AVSubtitleRect *rect = sub->rects[rect_idx];
399  aribcc_image_t *image = &ctx->render_result.images[rect_idx];
400  int w, h, shrink_height, dst_idx;
401 
402  clut_init(ctx, &ctx->caption.regions[rect_idx]);
403 
404  rect->w = image->width * ctx->bitmap_plane_width / ctx->frame_width;
405  rect->h = image->height * ctx->bitmap_plane_height / ctx->frame_height;
406  rect->data[0] = av_mallocz(rect->w * rect->h);
407  if (!rect->data[0]) {
408  ret = AVERROR(ENOMEM);
409  goto fail;
410  }
411  if ((image->height != rect->h && image->width != rect->w) ||
412  image->stride < image->width * 4 ||
413  image->stride * image->height > image->bitmap_size) {
414  av_log(ctx, AV_LOG_ERROR, "Bug: unexpected rendered image: %d(%d)x%d -> %dx%d\n",
415  image->width, image->stride / 4, image->height, rect->w, rect->h);
417  goto fail;
418  }
419 
420  shrink_height = image->height != rect->h;
421  dst_idx = 0;
422  for (h = 0; h < rect->h; h++) {
423  for (w = 0; w < rect->w; w++) {
424  /* Bi-linear interpolation */
425  int n, m, idx0, idx1, r, g, b, a;
426  if (shrink_height) {
427  int div_a, y0, y1;
428  div_a = h * ctx->frame_height;
429  n = ctx->bitmap_plane_height;
430  y0 = div_a / n;
431  y1 = FFMIN(y0 + 1, image->height - 1);
432  m = div_a - n * y0;
433  idx0 = image->stride * y0 + w * 4;
434  idx1 = image->stride * y1 + w * 4;
435  } else {
436  int div_a, x0, x1;
437  div_a = w * ctx->frame_width;
438  n = ctx->bitmap_plane_width;
439  x0 = div_a / n;
440  x1 = FFMIN(x0 + 1, image->width - 1);
441  m = div_a - n * x0;
442  idx0 = image->stride * h + x0 * 4;
443  idx1 = image->stride * h + x1 * 4;
444  }
445  r = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
446  g = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
447  b = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
448  a = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n;
449  rect->data[0][dst_idx++] = clut_pick_or_set(ctx, r, g, b, a);
450  }
451  }
452  rect->data[1] = av_memdup(ctx->clut, AVPALETTE_SIZE);
453  if (!rect->data[1]) {
454  ret = AVERROR(ENOMEM);
455  goto fail;
456  }
457 
458  if (ctx->avctx->profile == AV_PROFILE_ARIB_PROFILE_C) {
459  /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */
460  /* No position information is provided for profile C */
461  rect->x = (ctx->frame_width - rect->w) / 2;
462  rect->y = ctx->frame_height - rect->h * (ctx->caption.region_count - rect_idx);
463  } else {
464  rect->x = image->dst_x * ctx->bitmap_plane_width / ctx->frame_width;
465  rect->y = image->dst_y * ctx->bitmap_plane_height / ctx->frame_height;
466  }
467  rect->type = SUBTITLE_BITMAP;
468  rect->linesize[0] = rect->w;
469  rect->nb_colors = 256;
470 
471  ff_dlog(ctx, "BITMAP subtitle%s (%d,%d) %dx%d -> (%d,%d) %dx%d [%d]: %d colors\n",
472  (ctx->caption.regions[rect_idx].is_ruby) ? " (ruby)" : "",
473  image->dst_x, image->dst_y, image->width, image->height,
474  rect->x, rect->y, rect->w, rect->h,
475  rect_idx, ctx->clut_idx);
476  if (ctx->clut_overflow)
477  av_log(ctx, AV_LOG_WARNING, "CLUT overflow (%d).\n", ctx->clut_overflow);
478  }
479  sub->num_rects = rect_idx;
480 
481  return rect_idx;
482 
483 fail:
484  if (sub->rects) {
485  for (int i = 0; i < ctx->caption.region_count; i++) {
486  if (sub->rects[i]) {
487  av_freep(&sub->rects[i]->data[0]);
488  av_freep(&sub->rects[i]->data[1]);
489  av_freep(&sub->rects[i]);
490  }
491  }
492  av_freep(&sub->rects);
493  }
494  sub->num_rects = 0;
495 
496  return ret;
497 }
498 
500 {
501  AVCodecContext *avctx = ctx->avctx;
502  int outline, shadow;
503  const char *font_name;
504  const char *fonts = ctx->font;
505 
506  if (ctx->border_style == 4) {
507  outline = 0;
508  shadow = 4;
509  } else {
510  outline = 1;
511  shadow = 0;
512  }
513  if (ctx->force_stroke_text)
514  outline = (int)(ctx->stroke_width * 4.0 / 3.0);
515 
516  if (fonts && *fonts)
517  font_name = av_get_token(&fonts, ",");
518  else
519  font_name = av_strdup(DEFAULT_FONT_ASS);
520  if (!font_name)
521  return AVERROR(ENOMEM);
522 
523  av_freep(&avctx->subtitle_header);
524  avctx->subtitle_header = av_asprintf(
525  "[Script Info]\r\n"
526  "ScriptType: v4.00+\r\n"
527  "PlayResX: %d\r\n"
528  "PlayResY: %d\r\n"
529  "WrapStyle: 2\r\n" /* 2: no word wrapping */
530  "\r\n"
531 
532  "[V4+ Styles]\r\n"
533  "Format: Name, "
534  "Fontname, Fontsize, "
535  "PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
536  "Bold, Italic, Underline, StrikeOut, "
537  "ScaleX, ScaleY, "
538  "Spacing, Angle, "
539  "BorderStyle, Outline, Shadow, "
540  "Alignment, MarginL, MarginR, MarginV, "
541  "Encoding\r\n"
542 
543  "Style: "
544  "Default," /* Name */
545  "%s,%d," /* Font{name,size} */
546  "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */
547  "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */
548  "100,100," /* Scale{X,Y} */
549  "0,0," /* Spacing, Angle */
550  "%d,%d,%d," /* BorderStyle, Outline, Shadow */
551  "%d,10,10,10," /* Alignment, Margin[LRV] */
552  "0\r\n" /* Encoding */
553  "\r\n"
554 
555  "[Events]\r\n"
556  "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n",
557  ctx->plane_width, ctx->plane_height,
558  font_name, ctx->font_size,
562  ctx->border_style, outline, shadow, ASS_DEFAULT_ALIGNMENT);
563 
564  av_freep(&font_name);
565  if (!avctx->subtitle_header)
566  return AVERROR(ENOMEM);
567  avctx->subtitle_header_size = strlen(avctx->subtitle_header);
568  return 0;
569 }
570 
571 static void set_ass_color(AVBPrint *buf, int color_num,
572  aribcc_color_t new_color, aribcc_color_t old_color)
573 {
574  if (ARIBCC_COLOR_DIFF_RGB(new_color, old_color))
575  av_bprintf(buf, "{\\%dc&H%06x&}", color_num,
576  ARIBCC_COLOR_RGB(new_color));
577  if (ARIBCC_COLOR_DIFF_A(new_color, old_color))
578  av_bprintf(buf, "{\\%da&H%02x&}", color_num,
579  0xFF - ARIBCC_COLOR_A(new_color));
580 }
581 
583 {
584  AVSubtitle *sub = ctx->sub;
585  AVBPrint buf;
586  bool single_rect = ctx->ass_single_rect;
587  int ret = 0, rect_idx;
588 
589  if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0 &&
590  (ctx->caption.plane_width != ctx->plane_width ||
591  ctx->caption.plane_height != ctx->plane_height)) {
592  ctx->plane_width = ctx->caption.plane_width;
593  ctx->plane_height = ctx->caption.plane_height;
594  if ((ret = set_ass_header(ctx)) < 0)
595  return ret;
596  }
597 
598  /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */
599  /* No position information is provided for profile C */
600  if (ctx->avctx->profile == AV_PROFILE_ARIB_PROFILE_C)
601  single_rect = true;
602 
603  sub->format = 1; /* text */
604  if (ctx->caption.region_count == 0) {
605  /* clear previous caption for indefinite duration */
606  ff_ass_add_rect(sub, "", ctx->readorder++, 0, NULL, NULL);
607  return 1;
608  }
609 
611 
612  if (single_rect && ctx->avctx->profile != AV_PROFILE_ARIB_PROFILE_C) {
613  int x, y, rx, ry;
614  x = ctx->plane_width;
615  y = ctx->plane_height;
616  for (int i = 0; i < ctx->caption.region_count; i++) {
617  rx = ctx->caption.regions[i].x;
618  ry = ctx->caption.regions[i].y;
619  if (rx < x)
620  x = rx;
621  if (ry < y)
622  y = ry;
623  }
624  av_bprintf(&buf, "{\\an7}");
625  if (y < 0)
626  y += ctx->plane_height;
627  if (x > 0 || y > 0)
628  av_bprintf(&buf, "{\\pos(%d,%d)}", x, y);
629  }
630 
631  rect_idx = 0;
632  for (int i = 0; i < ctx->caption.region_count; i++) {
633  aribcc_caption_region_t *region = &ctx->caption.regions[i];
634  aribcc_color_t text_color = ARIBCC_MAKE_RGBA(0xFF, 0xFF, 0xFF,
636  aribcc_color_t stroke_color = ARIBCC_MAKE_RGBA(0, 0, 0,
638  aribcc_color_t back_color = ARIBCC_MAKE_RGBA(0, 0, 0,
640  aribcc_charstyle_t charstyle = ctx->charstyle;
641  int char_width = ctx->font_size;
642  int char_height = ctx->font_size;
643  int char_horizontal_spacing = 0;
644 
645  if (region->is_ruby && ctx->ignore_ruby)
646  continue;
647 
648  if (!single_rect) {
649  int x = region->x;
650  int y = region->y;
651  if (x < 0)
652  x += ctx->plane_width;
653  if (y < 0)
654  y += ctx->plane_height;
655  av_bprint_clear(&buf);
656  av_bprintf(&buf, "{\\an7}");
657  if (x > 0 || y > 0)
658  av_bprintf(&buf, "{\\pos(%d,%d)}", x, y);
659  }
660  if (region->is_ruby)
661  av_bprintf(&buf, "{\\fs%d}", char_height / 2);
662 
663  for (int j = 0; j < region->char_count; j++) {
664  aribcc_caption_char_t *ch = &region->chars[j];
665 
666  if (ctx->avctx->profile != AV_PROFILE_ARIB_PROFILE_C) {
667  if (ch->char_horizontal_spacing != char_horizontal_spacing) {
668  av_bprintf(&buf, "{\\fsp%d}", (region->is_ruby) ?
669  ch->char_horizontal_spacing / 2 :
670  ch->char_horizontal_spacing);
671  char_horizontal_spacing = ch->char_horizontal_spacing;
672  }
673  if (ch->char_width != char_width) {
674  av_bprintf(&buf, "{\\fscx%"PRId64"}",
675  av_rescale(ch->char_width, 100, ctx->font_size));
676  char_width = ch->char_width;
677  }
678  if (ch->char_height != char_height) {
679  av_bprintf(&buf, "{\\fscy%"PRId64"}",
680  av_rescale(ch->char_height, 100, ctx->font_size));
681  char_height = ch->char_height;
682  }
683  }
684  if (ch->style != charstyle) {
685  aribcc_charstyle_t diff = ch->style ^ charstyle;
686  if (diff & ARIBCC_CHARSTYLE_STROKE) {
687  if (charstyle & ARIBCC_CHARSTYLE_STROKE) {
688  if (ctx->force_stroke_text)
689  av_bprintf(&buf, "{\\bord%d}",
690  (int)(ctx->stroke_width * 4.0 / 3.0));
691  else
692  av_bprintf(&buf, "{\\bord0}");
693  } else
694  av_bprintf(&buf, "{\\bord3}");
695  }
696  if (diff & ARIBCC_CHARSTYLE_BOLD) {
697  if (charstyle & ARIBCC_CHARSTYLE_BOLD)
698  av_bprintf(&buf, "{\\b0}");
699  else
700  av_bprintf(&buf, "{\\b1}");
701  }
702  if (diff & ARIBCC_CHARSTYLE_ITALIC) {
703  if (charstyle & ARIBCC_CHARSTYLE_ITALIC)
704  av_bprintf(&buf, "{\\i0}");
705  else
706  av_bprintf(&buf, "{\\i1}");
707  }
708  if (diff & ARIBCC_CHARSTYLE_UNDERLINE) {
709  if (charstyle & ARIBCC_CHARSTYLE_UNDERLINE)
710  av_bprintf(&buf, "{\\u0}");
711  else
712  av_bprintf(&buf, "{\\u1}");
713  }
714  charstyle = ch->style;
715  }
716  if (ch->text_color != text_color) {
717  set_ass_color(&buf, 1, ch->text_color, text_color);
718  text_color = ch->text_color;
719  }
720  if (ch->stroke_color != stroke_color) {
721  set_ass_color(&buf, 3, ch->stroke_color, stroke_color);
722  stroke_color = ch->stroke_color;
723  }
724  if (ch->back_color != back_color) {
725  if (ctx->border_style == 4)
726  set_ass_color(&buf, 4, ch->back_color, back_color);
727  else
728  set_ass_color(&buf, 3, ch->back_color, back_color);
729  back_color = ch->back_color;
730  }
731  if (region->chars[j].type == ARIBCC_CHARTYPE_DRCS)
732  av_bprintf(&buf, "\xe3\x80\x93"); /* Geta Mark */
733  else
734  ff_ass_bprint_text_event(&buf, ch->u8str, strlen(ch->u8str), "", 0);
735  }
736 
737  if (single_rect) {
738  if (i + 1 < ctx->caption.region_count)
739  av_bprintf(&buf, "{\\r}\\N");
740  ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]\n",
741  (region->is_ruby) ? " (ruby)" : "",
742  region->x, region->y, region->width, region->height,
743  rect_idx);
744  } else {
745  if (!av_bprint_is_complete(&buf)) {
746  ret = AVERROR(ENOMEM);
747  goto fail;
748  }
749  ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]: %s\n",
750  (region->is_ruby) ? " (ruby)" : "",
751  region->x, region->y, region->width, region->height,
752  rect_idx, buf.str);
753 
754  ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL);
755  if (ret != 0)
756  goto fail;
757  rect_idx++;
758  }
759  }
760  if (single_rect) {
761  if (!av_bprint_is_complete(&buf)) {
762  ret = AVERROR(ENOMEM);
763  goto fail;
764  }
765  ff_dlog(ctx, "ASS subtitle: %s\n", buf.str);
766 
767  ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL);
768  if (ret != 0)
769  goto fail;
770  rect_idx++;
771  }
772 
773  av_bprint_finalize(&buf, NULL);
774  return rect_idx;
775 
776 fail:
777  if (sub->rects) {
778  for (int i = 0; i < ctx->caption.region_count; i++) {
779  if (sub->rects[i]) {
780  av_freep(&sub->rects[i]->ass);
781  av_freep(&sub->rects[i]);
782  }
783  }
784  av_freep(&sub->rects);
785  }
786  sub->num_rects = 0;
787  av_bprint_finalize(&buf, NULL);
788 
789  return ret;
790 }
791 
793 {
794  AVSubtitle *sub = ctx->sub;
796  int ret = 0;
797  const char *text;
798 
799  sub->rects = av_calloc(ctx->caption.region_count, sizeof(*sub->rects));
800  if (!sub->rects) {
801  ret = AVERROR(ENOMEM);
802  goto fail;
803  }
804  sub->num_rects = 1;
805 
806  sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
807  if (!sub->rects[0]) {
808  ret = AVERROR(ENOMEM);
809  goto fail;
810  }
811  rect = sub->rects[0];
812 
813  if (ctx->caption.region_count == 0)
814  text = ""; /* clear previous caption */
815  else {
816  text = ctx->caption.text;
817  ff_dlog(ctx, "TEXT subtitle: %s\n", text);
818  }
819  rect->text = av_strdup(text);
820  if (!rect->text) {
821  ret = AVERROR(ENOMEM);
822  goto fail;
823  }
824 
825  sub->format = 1; /* text */
826  rect->type = SUBTITLE_TEXT;
827 
828  return 1;
829 
830 fail:
831  if (sub->rects) {
832  rect = sub->rects[0];
833  if (rect) {
834  av_freep(&rect->text);
835  av_freep(&rect);
836  }
837  av_freep(&sub->rects);
838  }
839  sub->num_rects = 0;
840 
841  return ret;
842 }
843 
845  int *got_sub_ptr, const AVPacket *avpkt)
846 {
847  ARIBCaptionContext *ctx = avctx->priv_data;
848  int status;
849 
850  ff_dlog(ctx, "ARIB caption packet pts=%"PRIx64":\n", avpkt->pts);
851  if (sub->num_rects) {
852  avpriv_request_sample(ctx, "Different Version of Segment asked Twice");
853  return AVERROR_PATCHWELCOME;
854  }
855  hex_dump_debug(ctx, avpkt->data, avpkt->size);
856 
857  ctx->sub = sub;
858  ctx->avpkt = avpkt;
859  ctx->time_base = avctx->pkt_timebase;
860  if (ctx->time_base.num <= 0 || ctx->time_base.den <= 0) {
861  av_log(ctx, AV_LOG_VERBOSE, "No timebase set. assuming 90kHz.\n");
862  ctx->time_base = av_make_q(1, 90000);
863  }
864  if (avpkt->pts == AV_NOPTS_VALUE)
865  ctx->pts = ARIBCC_PTS_NOPTS;
866  else
867  ctx->pts = av_rescale_q(avpkt->pts, ctx->time_base, (AVRational){1, 1000});
868 
869  status = aribcc_decoder_decode(ctx->decoder, avpkt->data, avpkt->size,
870  ctx->pts, &ctx->caption);
871  if (status == ARIBCC_DECODE_STATUS_ERROR) {
873  "aribcc_decoder_decode() returned with error.\n");
874  return AVERROR(EAGAIN);
875  }
876  if (status == ARIBCC_DECODE_STATUS_NO_CAPTION) {
877  ff_dlog(ctx, "No caption.\n");
878  return avpkt->size;
879  } else {
880  ff_dlog(ctx, "type=%02x, flags=%x, lang=%03x\n",
881  ctx->caption.type, ctx->caption.flags, ctx->caption.iso6392_language_code);
882  ff_dlog(ctx, "region count = %d, start=%d.%d, duration=%d.%d\n",
883  ctx->caption.region_count,
884  (int)(ctx->caption.pts / 1000), (int)(ctx->caption.pts % 1000),
885  (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ?
886  -1 : ctx->caption.wait_duration / 1000),
887  (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ?
888  0 : ctx->caption.wait_duration % 1000));
889  }
890 
891  switch ((enum AVSubtitleType) ctx->subtitle_type) {
892  case SUBTITLE_TEXT:
894  break;
895 
896  case SUBTITLE_ASS:
898  break;
899 
900  case SUBTITLE_BITMAP:
902  break;
903 
904  case SUBTITLE_NONE:
905  default:
906  status = 0;
907  }
908 
909  if (status < 0) {
910  av_log(ctx, AV_LOG_ERROR, "Failed to set Subtitle: %s\n",
911  av_err2str(status));
912  aribcc_caption_cleanup(&ctx->caption);
913  return status;
914  }
915  if (status > 0) {
916  *got_sub_ptr = 1;
917  if (ctx->avpkt->pts != AV_NOPTS_VALUE)
918  sub->pts = av_rescale_q(ctx->avpkt->pts,
919  ctx->time_base, AV_TIME_BASE_Q);
920  if (ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE)
921  sub->end_display_time = UINT32_MAX;
922  else
923  sub->end_display_time = (uint32_t)ctx->caption.wait_duration;
924  }
925 
926  aribcc_caption_cleanup(&ctx->caption);
927  return avpkt->size;
928 }
929 
931 {
932  ARIBCaptionContext *ctx = avctx->priv_data;
933 
934  if (ctx->decoder)
935  aribcc_decoder_flush(ctx->decoder);
936  if (ctx->renderer)
937  aribcc_renderer_flush(ctx->renderer);
938  if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
939  ctx->readorder = 0;
940 }
941 
943 {
944  ARIBCaptionContext *ctx = avctx->priv_data;
945 
946  av_freep(&ctx->clut);
947  if (ctx->renderer)
948  aribcc_renderer_free(ctx->renderer);
949  if (ctx->decoder)
950  aribcc_decoder_free(ctx->decoder);
951  if (ctx->context)
952  aribcc_context_free(ctx->context);
953 
954  return 0;
955 }
956 
958 {
959  ARIBCaptionContext *ctx = avctx->priv_data;
960  aribcc_profile_t profile;
961  int ret = 0;
962 
963  ctx->avctx = avctx;
964 
965  switch (avctx->profile) {
967  profile = ARIBCC_PROFILE_A;
968  /* assume 960x540 at initial state */
969  ctx->plane_width = 960;
970  ctx->plane_height = 540;
971  ctx->font_size = 36;
972  break;
974  profile = ARIBCC_PROFILE_C;
975  ctx->plane_width = 320;
976  ctx->plane_height = 180;
977  ctx->font_size = 16;
978  break;
979  default:
980  av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set.\n");
981  return AVERROR(EINVAL);
982  }
983  /* determine BorderStyle of ASS header */
984  if (ctx->ignore_background)
985  ctx->border_style = 1;
986  else
987  ctx->border_style = 4;
988  ctx->charstyle = ARIBCC_CHARSTYLE_DEFAULT;
989  if (ctx->force_stroke_text || ctx->ignore_background)
990  ctx->charstyle |= ARIBCC_CHARSTYLE_STROKE;
991 
992  if (!(ctx->context = aribcc_context_alloc())) {
993  av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption context.\n");
994  return AVERROR_EXTERNAL;
995  }
996  aribcc_context_set_logcat_callback(ctx->context, logcat_callback, avctx);
997  if (!(ctx->decoder = aribcc_decoder_alloc(ctx->context))) {
998  av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption decoder.\n");
999  return AVERROR_EXTERNAL;
1000  }
1001  if (!aribcc_decoder_initialize(ctx->decoder,
1002  (enum aribcc_encoding_scheme_t) ctx->encoding_scheme,
1003  ARIBCC_CAPTIONTYPE_CAPTION,
1004  profile,
1005  ARIBCC_LANGUAGEID_FIRST)) {
1006  av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption decoder.\n");
1007  return AVERROR_EXTERNAL;
1008  }
1009  aribcc_decoder_set_replace_msz_fullwidth_ascii(ctx->decoder,
1010  ctx->replace_msz_ascii);
1011  aribcc_decoder_set_replace_msz_fullwidth_japanese(ctx->decoder,
1012  ctx->replace_msz_japanese);
1013 
1014  /* Similar behavior as ffmpeg tool to set canvas size */
1015  if (ctx->canvas_width > 0 && ctx->canvas_height > 0 &&
1016  (ctx->avctx->width == 0 || ctx->avctx->height == 0)) {
1017  ctx->avctx->width = ctx->canvas_width;
1018  ctx->avctx->height = ctx->canvas_height;
1019  }
1020 
1021  switch ((enum AVSubtitleType) ctx->subtitle_type) {
1022  case SUBTITLE_ASS:
1023  ret = set_ass_header(ctx);
1024  if (ret != 0) {
1025  av_log(avctx, AV_LOG_ERROR, "Failed to set ASS header: %s\n",
1026  av_err2str(ret));
1027  return ret;
1028  }
1029  break;
1030 
1031  case SUBTITLE_BITMAP:
1032  if(!(ctx->renderer = aribcc_renderer_alloc(ctx->context))) {
1033  av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption renderer.\n");
1034  return AVERROR_EXTERNAL;
1035  }
1036  if(!aribcc_renderer_initialize(ctx->renderer,
1037  ARIBCC_CAPTIONTYPE_CAPTION,
1038  ARIBCC_FONTPROVIDER_TYPE_AUTO,
1039  ARIBCC_TEXTRENDERER_TYPE_AUTO)) {
1040  av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption renderer.\n");
1041  return AVERROR_EXTERNAL;
1042  }
1044  ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n",
1045  ctx->avctx->width, ctx->avctx->height,
1046  ctx->plane_width, ctx->plane_height,
1047  ctx->bitmap_plane_width, ctx->bitmap_plane_height,
1048  ctx->frame_width, ctx->frame_height);
1049  if (!aribcc_renderer_set_frame_size(ctx->renderer,
1050  ctx->frame_width, ctx->frame_height)) {
1052  "aribcc_renderer_set_frame_size() returned with error.\n");
1053  return AVERROR_EXTERNAL;
1054  }
1055 
1056  if (!(ctx->clut = av_mallocz(AVPALETTE_SIZE)))
1057  return AVERROR(ENOMEM);
1058 
1059  aribcc_renderer_set_storage_policy(ctx->renderer, ARIBCC_CAPTION_STORAGE_POLICY_MINIMUM, 0);
1060  aribcc_renderer_set_replace_drcs(ctx->renderer, ctx->replace_drcs);
1061  aribcc_renderer_set_force_stroke_text(ctx->renderer, ctx->force_stroke_text);
1062  aribcc_renderer_set_force_no_background(ctx->renderer, ctx->ignore_background);
1063  aribcc_renderer_set_force_no_ruby(ctx->renderer, ctx->ignore_ruby);
1064  aribcc_renderer_set_stroke_width(ctx->renderer, ctx->stroke_width);
1065  aribcc_renderer_set_replace_msz_halfwidth_glyph(ctx->renderer,
1066  ctx->replace_msz_glyph);
1067  if (ctx->font) {
1068  int is_nomem = 0;
1069  size_t count = 0;
1070  const char **font_families = NULL;
1071  const char *fonts = ctx->font;
1072 
1073  while (*fonts) {
1074  const char **ff = av_realloc_array(font_families, count + 1, sizeof(*font_families));
1075  if (!ff) {
1076  is_nomem = 1;
1077  break;
1078  } else {
1079  font_families = ff;
1080  ff[count++] = av_get_token(&fonts, ",");
1081  if (!ff[count - 1]) {
1082  is_nomem = 1;
1083  break;
1084  } else if (*fonts)
1085  fonts++;
1086  }
1087  }
1088  if (!is_nomem && count)
1089  aribcc_renderer_set_default_font_family(ctx->renderer, font_families, count, true);
1090  while (count)
1091  av_freep(&font_families[--count]);
1092  av_freep(&font_families);
1093  if (is_nomem)
1094  return AVERROR(ENOMEM);
1095  }
1096  break;
1097 
1098  case SUBTITLE_TEXT:
1099  case SUBTITLE_NONE:
1100  default:
1101  /* do nothing */ ;
1102  }
1103 
1104  ctx->readorder = 0;
1105 
1106  return 0;
1107 }
1108 
1109 #if !defined(ASS_SINGLE_RECT)
1110 # define ASS_SINGLE_RECT 0
1111 #endif
1112 
1113 #define OFFSET(x) offsetof(ARIBCaptionContext, x)
1114 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
1115 static const AVOption options[] = {
1116  { "sub_type", "subtitle rendering type",
1117  OFFSET(subtitle_type), AV_OPT_TYPE_INT,
1118  { .i64 = SUBTITLE_ASS }, SUBTITLE_NONE, SUBTITLE_ASS, SD, .unit = "type" },
1119  { "none", "do nothing", 0, AV_OPT_TYPE_CONST,
1120  { .i64 = SUBTITLE_NONE }, .flags = SD, .unit = "type" },
1121  { "bitmap", "bitmap rendering", 0, AV_OPT_TYPE_CONST,
1122  { .i64 = SUBTITLE_BITMAP }, .flags = SD, .unit = "type" },
1123  { "text", "plain text", 0, AV_OPT_TYPE_CONST,
1124  { .i64 = SUBTITLE_TEXT }, .flags = SD, .unit = "type" },
1125  { "ass", "formatted text", 0, AV_OPT_TYPE_CONST,
1126  { .i64 = SUBTITLE_ASS }, .flags = SD, .unit = "type" },
1127  { "caption_encoding", "encoding scheme of subtitle text",
1128  OFFSET(encoding_scheme), AV_OPT_TYPE_INT, { .i64 = ARIBCC_ENCODING_SCHEME_AUTO },
1129  ARIBCC_ENCODING_SCHEME_AUTO, ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN, SD, .unit = "encoding" },
1130  { "auto", "automatically detect encoding scheme", 0, AV_OPT_TYPE_CONST,
1131  { .i64 = ARIBCC_ENCODING_SCHEME_AUTO }, .flags = SD, .unit = "encoding" },
1132  { "jis", "8bit-char JIS encoding (Japanese ISDB captions)", 0, AV_OPT_TYPE_CONST,
1133  { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_JIS }, .flags = SD, .unit = "encoding" },
1134  { "utf8", "UTF-8 encoding (Philippines ISDB-T captions)", 0, AV_OPT_TYPE_CONST,
1135  { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_UTF8 }, .flags = SD, .unit = "encoding" },
1136  { "latin", "latin characters (SBTVD / ISDB-Tb captions used in South America)", 0, AV_OPT_TYPE_CONST,
1137  { .i64 = ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN }, .flags = SD, .unit = "encoding" },
1138  { "ass_single_rect", "workaround of ASS subtitle for players which can't handle multi-rectangle [ass]",
1139  OFFSET(ass_single_rect), AV_OPT_TYPE_BOOL, { .i64 = ASS_SINGLE_RECT }, 0, 1, SD },
1140  { "font", "comma-separated font family [ass, bitmap]",
1141  OFFSET(font), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
1142  { "force_outline_text", "always render characters with outline [(ass), bitmap]",
1143  OFFSET(force_stroke_text), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
1144  { "ignore_background", "ignore rendering caption background [(ass), bitmap]",
1145  OFFSET(ignore_background), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
1146  { "ignore_ruby", "ignore ruby-like characters [ass, bitmap]",
1147  OFFSET(ignore_ruby), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD },
1148  { "outline_width", "outline width of text [(ass), bitmap]",
1149  OFFSET(stroke_width), AV_OPT_TYPE_FLOAT, { .dbl = 1.5 }, 0.0, 3.0, SD },
1150  { "replace_drcs", "replace known DRCS [bitmap]",
1151  OFFSET(replace_drcs), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
1152  { "replace_msz_ascii", "replace MSZ fullwidth alphanumerics with halfwidth alphanumerics [ass, bitmap]",
1153  OFFSET(replace_msz_ascii), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
1154  { "replace_msz_japanese", "replace MSZ fullwidth Japanese with halfwidth [ass, bitmap]",
1155  OFFSET(replace_msz_japanese), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
1156  { "replace_msz_glyph", "replace MSZ characters with halfwidth glyphs [bitmap]",
1157  OFFSET(replace_msz_glyph), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
1158  {"canvas_size", "set input video size (WxH or abbreviation) [bitmap]",
1159  OFFSET(canvas_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, INT_MAX, SD },
1160  { NULL }
1161 };
1162 
1163 static const AVClass aribcaption_class = {
1164  .class_name = "aribcaption decoder",
1165  .item_name = av_default_item_name,
1166  .option = options,
1167  .version = LIBAVUTIL_VERSION_INT,
1168 };
1169 
1171  .p.name = "libaribcaption",
1172  .p.long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption decoder"),
1173  .p.type = AVMEDIA_TYPE_SUBTITLE,
1174  .p.id = AV_CODEC_ID_ARIB_CAPTION,
1175  .priv_data_size = sizeof(ARIBCaptionContext),
1177  .close = aribcaption_close,
1179  .flush = aribcaption_flush,
1180  .p.priv_class = &aribcaption_class,
1181  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
1182 };
AVSubtitle
Definition: avcodec.h:2227
rect::w
int w
Definition: f_ebur128.c:77
aribcaption_class
static const AVClass aribcaption_class
Definition: libaribcaption.c:1163
ARIBCaptionContext::replace_msz_ascii
int replace_msz_ascii
Definition: libaribcaption.c:79
CLUT_RGBA
#define CLUT_RGBA(r, g, b, a)
Definition: libaribcaption.c:49
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
ARIBC_BPRINT_SIZE_INIT
#define ARIBC_BPRINT_SIZE_INIT
Definition: libaribcaption.c:39
level
uint8_t level
Definition: svq3.c:205
FF_CODEC_CAP_INIT_CLEANUP
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: codec_internal.h:42
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
r
const char * r
Definition: vf_curves.c:127
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVSubtitle::rects
AVSubtitleRect ** rects
Definition: avcodec.h:2232
opt.h
ARIBCaptionContext::clut_alpha
uint8_t clut_alpha[ARIBC_ALPHA_MAX_NUM]
Definition: libaribcaption.c:103
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
ARIBCC_COLOR_TO_CLUT_RGBA
#define ARIBCC_COLOR_TO_CLUT_RGBA(c, a)
Definition: libaribcaption.c:55
message
Definition: api-threadmessage-test.c:47
thread.h
ASS_SINGLE_RECT
#define ASS_SINGLE_RECT
Definition: libaribcaption.c:1110
ARIBCaptionContext::replace_drcs
int replace_drcs
Definition: libaribcaption.c:78
rect
Definition: f_ebur128.c:77
ARIBCaptionContext::time_base
AVRational time_base
Definition: libaribcaption.c:84
ARIBCC_COLOR_RGB
#define ARIBCC_COLOR_RGB(c)
Definition: libaribcaption.c:45
AV_TIME_BASE_Q
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:264
ARIBCaptionContext::encoding_scheme
int encoding_scheme
Definition: libaribcaption.c:71
AVSubtitleRect
Definition: avcodec.h:2200
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:115
AVSubtitle::num_rects
unsigned num_rects
Definition: avcodec.h:2231
rect::y
int y
Definition: f_ebur128.c:77
estimate_video_frame_size
static void estimate_video_frame_size(ARIBCaptionContext *ctx)
Definition: libaribcaption.c:140
w
uint8_t w
Definition: llviddspenc.c:38
ASS_DEFAULT_ALIGNMENT
#define ASS_DEFAULT_ALIGNMENT
Definition: ass.h:42
ff_ass_add_rect
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, int readorder, int layer, const char *style, const char *speaker)
Add an ASS dialog to a subtitle.
Definition: ass.c:159
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:524
AVOption
AVOption.
Definition: opt.h:346
clut_set_alpha
static void clut_set_alpha(ARIBCaptionContext *ctx, uint8_t a)
Definition: libaribcaption.c:165
ARIBC_BPRINT_SIZE_MAX
#define ARIBC_BPRINT_SIZE_MAX
Definition: libaribcaption.c:40
b
#define b
Definition: input.c:41
clut_pick_or_set
static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, int a)
Definition: libaribcaption.c:219
logcat_callback
static void logcat_callback(aribcc_loglevel_t level, const char *message, void *userdata)
Definition: libaribcaption.c:119
FFCodec
Definition: codec_internal.h:126
AVCodecContext::subtitle_header
uint8_t * subtitle_header
Definition: avcodec.h:1891
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
ARIBCaptionContext::border_style
int border_style
Definition: libaribcaption.c:95
clut_init
static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region)
Definition: libaribcaption.c:254
AV_PROFILE_ARIB_PROFILE_C
#define AV_PROFILE_ARIB_PROFILE_C
Definition: defs.h:187
ARIBCaptionContext::clut_idx
int clut_idx
Definition: libaribcaption.c:101
aribcaption_init
static int aribcaption_init(AVCodecContext *avctx)
Definition: libaribcaption.c:957
ARIBCaptionContext::sub
AVSubtitle * sub
Definition: libaribcaption.c:64
SUBTITLE_ASS
@ SUBTITLE_ASS
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:2195
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:304
ARIBCaptionContext::frame_height
int frame_height
Definition: libaribcaption.c:90
AV_PROFILE_ARIB_PROFILE_A
#define AV_PROFILE_ARIB_PROFILE_A
Definition: defs.h:186
ARIBCaptionContext::avctx
AVCodecContext * avctx
Definition: libaribcaption.c:62
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:130
OFFSET
#define OFFSET(x)
Definition: libaribcaption.c:1113
ARIBC_ALPHA_MAX_NUM
#define ARIBC_ALPHA_MAX_NUM
Definition: libaribcaption.c:41
clut_find
static int clut_find(ARIBCaptionContext *ctx, uint32_t rgba)
Definition: libaribcaption.c:201
fail
#define fail()
Definition: checkasm.h:179
aribcaption_trans_text_subtitle
static int aribcaption_trans_text_subtitle(ARIBCaptionContext *ctx)
Definition: libaribcaption.c:792
AVSubtitleRect::ass
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:2224
options
static const AVOption options[]
Definition: libaribcaption.c:1115
ARIBCaptionContext::render_result
aribcc_render_result_t render_result
Definition: libaribcaption.c:99
ass.h
ARIBCaptionContext::canvas_height
int canvas_height
Definition: libaribcaption.c:86
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
ARIBCaptionContext::replace_msz_japanese
int replace_msz_japanese
Definition: libaribcaption.c:80
ARIBCaptionContext::readorder
int readorder
Definition: libaribcaption.c:96
set_ass_header
static int set_ass_header(ARIBCaptionContext *ctx)
Definition: libaribcaption.c:499
ARIBCaptionContext::pts
int64_t pts
Definition: libaribcaption.c:83
ARIBCaptionContext::renderer
aribcc_renderer_t * renderer
Definition: libaribcaption.c:68
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1406
ARIBCaptionContext::plane_width
int plane_width
Definition: libaribcaption.c:87
g
const char * g
Definition: vf_curves.c:128
aribcaption_trans_bitmap_subtitle
static int aribcaption_trans_bitmap_subtitle(ARIBCaptionContext *ctx)
aribcaption_trans_{bitmap|ass|text}_subtitle()
Definition: libaribcaption.c:317
ARIBCaptionContext::clut_overflow
int clut_overflow
Definition: libaribcaption.c:102
AVSubtitleType
AVSubtitleType
Definition: avcodec.h:2180
ff_ass_bprint_text_event
void ff_ass_bprint_text_event(AVBPrint *buf, const char *p, int size, const char *linebreaks, int keep_ass_markup)
Escape a text subtitle using ASS syntax into an AVBPrint buffer.
Definition: ass.c:173
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
AVSubtitle::pts
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition: avcodec.h:2233
AV_CODEC_ID_ARIB_CAPTION
@ AV_CODEC_ID_ARIB_CAPTION
Definition: codec_id.h:575
ASS_DEFAULT_BACK_COLOR
#define ASS_DEFAULT_BACK_COLOR
Definition: ass.h:38
aribcaption_flush
static void aribcaption_flush(AVCodecContext *avctx)
Definition: libaribcaption.c:930
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
ARIBCaptionContext::plane_height
int plane_height
Definition: libaribcaption.c:88
NULL
#define NULL
Definition: coverity.c:32
ARIBCaptionContext::ass_single_rect
int ass_single_rect
Definition: libaribcaption.c:72
ARIBCaptionContext::replace_msz_glyph
int replace_msz_glyph
Definition: libaribcaption.c:81
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
ARIBCaptionContext::ignore_ruby
int ignore_ruby
Definition: libaribcaption.c:76
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
AV_OPT_TYPE_IMAGE_SIZE
@ AV_OPT_TYPE_IMAGE_SIZE
offset must point to two consecutive integers
Definition: opt.h:245
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
AVCodecContext::subtitle_header_size
int subtitle_header_size
Header containing style information for text subtitles.
Definition: avcodec.h:1890
ARIBCaptionContext::caption
aribcc_caption_t caption
Definition: libaribcaption.c:98
AVSubtitleRect::data
uint8_t * data[4]
data+linesize for the bitmap of this subtitle.
Definition: avcodec.h:2211
abs
#define abs(x)
Definition: cuda_runtime.h:35
DEFAULT_FONT_ASS
#define DEFAULT_FONT_ASS
Definition: libaribcaption.c:36
ARIBCaptionContext::canvas_width
int canvas_width
Definition: libaribcaption.c:85
CLUT_A
#define CLUT_A(c)
Definition: libaribcaption.c:50
CLUT_R
#define CLUT_R(c)
Definition: libaribcaption.c:51
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVPALETTE_COUNT
#define AVPALETTE_COUNT
Definition: pixfmt.h:33
ARIBCaptionContext::frame_width
int frame_width
Definition: libaribcaption.c:89
ARIBCaptionContext::force_stroke_text
int force_stroke_text
Definition: libaribcaption.c:74
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:28
ARIBCaptionContext::ignore_background
int ignore_background
Definition: libaribcaption.c:75
AVCodecContext::flags2
int flags2
AV_CODEC_FLAG2_*.
Definition: avcodec.h:509
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:366
ASS_DEFAULT_BOLD
#define ASS_DEFAULT_BOLD
Definition: ass.h:39
AVPacket::size
int size
Definition: packet.h:525
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
aribcaption_decode
static int aribcaption_decode(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, const AVPacket *avpkt)
Definition: libaribcaption.c:844
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:240
codec_internal.h
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
ARIBCaptionContext::decoder
aribcc_decoder_t * decoder
Definition: libaribcaption.c:67
ARIBCaptionContext::context
aribcc_context_t * context
Definition: libaribcaption.c:66
AVCodecContext::pkt_timebase
AVRational pkt_timebase
Timebase in which pkt_dts/pts and AVPacket.dts/pts are expressed.
Definition: avcodec.h:551
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
ARIBCaptionContext::font_size
int font_size
Definition: libaribcaption.c:93
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
rect::h
int h
Definition: f_ebur128.c:77
AVSubtitle::end_display_time
uint32_t end_display_time
Definition: avcodec.h:2230
SUBTITLE_TEXT
@ SUBTITLE_TEXT
Plain text, the text field must be set by the decoder and is authoritative.
Definition: avcodec.h:2189
diff
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
Definition: vf_paletteuse.c:165
SUBTITLE_NONE
@ SUBTITLE_NONE
Definition: avcodec.h:2181
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
rect::x
int x
Definition: f_ebur128.c:77
SUBTITLE_BITMAP
@ SUBTITLE_BITMAP
A bitmap, pict will be set.
Definition: avcodec.h:2183
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
ASS_DEFAULT_UNDERLINE
#define ASS_DEFAULT_UNDERLINE
Definition: ass.h:41
AV_OPT_TYPE_FLOAT
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:238
ARIBCaptionContext::font
char * font
Definition: libaribcaption.c:73
ARIBCaptionContext::clut
uint32_t * clut
Definition: libaribcaption.c:100
ARIBCaptionContext::bitmap_plane_height
int bitmap_plane_height
Definition: libaribcaption.c:92
AVSubtitle::format
uint16_t format
Definition: avcodec.h:2228
log.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:517
CLUT_B
#define CLUT_B(c)
Definition: libaribcaption.c:53
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ARIBCaptionContext::avpkt
const AVPacket * avpkt
Definition: libaribcaption.c:63
ARIBCC_COLOR_DIFF_A
#define ARIBCC_COLOR_DIFF_A(c1, c2)
Definition: libaribcaption.c:47
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
aribcaption_close
static int aribcaption_close(AVCodecContext *avctx)
Definition: libaribcaption.c:942
ASS_DEFAULT_ITALIC
#define ASS_DEFAULT_ITALIC
Definition: ass.h:40
ASS_DEFAULT_COLOR
#define ASS_DEFAULT_COLOR
Definition: ass.h:37
profile
int profile
Definition: mxfenc.c:2227
av_rescale
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
ARIBCaptionContext::charstyle
int charstyle
Definition: libaribcaption.c:94
avcodec.h
ret
ret
Definition: filter_design.txt:187
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:71
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:99
CLUT_G
#define CLUT_G(c)
Definition: libaribcaption.c:52
AVCodecContext
main external API structure.
Definition: avcodec.h:445
ARIBCaptionContext::bitmap_plane_width
int bitmap_plane_width
Definition: libaribcaption.c:91
status
ov_status_e status
Definition: dnn_backend_openvino.c:121
SD
#define SD
Definition: libaribcaption.c:1114
clut_color_distance
static int clut_color_distance(uint32_t rgba1, uint32_t rgba2)
Definition: libaribcaption.c:212
set_ass_color
static void set_ass_color(AVBPrint *buf, int color_num, aribcc_color_t new_color, aribcc_color_t old_color)
Definition: libaribcaption.c:571
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
AVCodecContext::profile
int profile
profile
Definition: avcodec.h:1639
av_get_token
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:143
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:232
ARIBC_ALPHA_DEFAULT_FRONT
#define ARIBC_ALPHA_DEFAULT_FRONT
Definition: libaribcaption.c:42
FF_CODEC_DECODE_SUB_CB
#define FF_CODEC_DECODE_SUB_CB(func)
Definition: codec_internal.h:289
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
avutil.h
mem.h
ARIBCaptionContext::subtitle_type
int subtitle_type
Definition: libaribcaption.c:70
avpriv_request_sample
#define avpriv_request_sample(...)
Definition: tableprint_vlc.h:36
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
AVPacket
This structure stores compressed data.
Definition: packet.h:501
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
d
d
Definition: ffmpeg_filter.c:424
ff_libaribcaption_decoder
const FFCodec ff_libaribcaption_decoder
Definition: libaribcaption.c:1170
ARIBCC_COLOR_DIFF_RGB
#define ARIBCC_COLOR_DIFF_RGB(c1, c2)
Definition: libaribcaption.c:46
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2038
aribcaption_trans_ass_subtitle
static int aribcaption_trans_ass_subtitle(ARIBCaptionContext *ctx)
Definition: libaribcaption.c:582
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:239
ARIBCaptionContext
Definition: libaribcaption.c:60
AV_CODEC_FLAG2_RO_FLUSH_NOOP
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
Definition: avcodec.h:392
int
int
Definition: ffmpeg_filter.c:424
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244
hex_dump_debug
static void hex_dump_debug(void *ctx, const char *buf, int buf_size)
Definition: libaribcaption.c:106
ARIBCaptionContext::stroke_width
float stroke_width
Definition: libaribcaption.c:77
clut_find_nearlest_alpha
static uint8_t clut_find_nearlest_alpha(ARIBCaptionContext *ctx, uint8_t a)
Definition: libaribcaption.c:180
ARIBC_ALPHA_DEFAULT_BACK
#define ARIBC_ALPHA_DEFAULT_BACK
Definition: libaribcaption.c:43