FFmpeg
Loading...
Searching...
No Matches
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
105
106static 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
119static 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
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
201static 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
212static 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
219static 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/* initialize CLUT with each character colors */
254static 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);
416 ret = AVERROR_EXTERNAL;
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
483fail:
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);
525 "[Script Info]\n"
526 "ScriptType: v4.00+\n"
527 "PlayResX: %d\n"
528 "PlayResY: %d\n"
529 "WrapStyle: 2\n" /* 2: no word wrapping */
530 "\n"
531
532 "[V4+ Styles]\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\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\n" /* Encoding */
553 "\n"
554
555 "[Events]\n"
556 "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\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
571static 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
774 return rect_idx;
775
776fail:
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;
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
830fail:
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{
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");
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{
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{
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{
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
1115static 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
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,
1175 .priv_data_size = sizeof(ARIBCaptionContext),
1179 .flush = aribcaption_flush,
1180 .p.priv_class = &aribcaption_class,
1181 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
1182};
const FFCodec ff_libaribcaption_decoder
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
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
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
#define ASS_DEFAULT_ALIGNMENT
Definition ass.h:42
#define ASS_DEFAULT_COLOR
Definition ass.h:37
#define ASS_DEFAULT_BACK_COLOR
Definition ass.h:38
#define ASS_DEFAULT_BOLD
Definition ass.h:39
#define ASS_DEFAULT_UNDERLINE
Definition ass.h:41
#define ASS_DEFAULT_ITALIC
Definition ass.h:40
Libavcodec external API header.
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
Convenience header that includes libavutil's core.
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define SD
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define FF_CODEC_DECODE_SUB_CB(func)
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define abs(x)
#define AV_PROFILE_ARIB_PROFILE_A
Definition defs.h:191
#define AV_PROFILE_ARIB_PROFILE_C
Definition defs.h:192
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define fail
Definition test.h:479
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
Definition opt.h:302
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
Definition avcodec.h:376
AVSubtitleType
Definition avcodec.h:2040
@ SUBTITLE_BITMAP
A bitmap, pict will be set.
Definition avcodec.h:2043
@ SUBTITLE_ASS
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition avcodec.h:2055
@ SUBTITLE_TEXT
Plain text, the text field must be set by the decoder and is authoritative.
Definition avcodec.h:2049
@ SUBTITLE_NONE
Definition avcodec.h:2041
@ AV_CODEC_ID_ARIB_CAPTION
Definition codec_id.h:591
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition bprint.c:235
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition bprint.c:227
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition mem.c:217
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition mem.c:302
@ AVMEDIA_TYPE_SUBTITLE
Definition avutil.h:203
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
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
int a
#define r
Definition input.c:42
#define b
Definition input.c:43
static int aribcaption_trans_bitmap_subtitle(ARIBCaptionContext *ctx)
aribcaption_trans_{bitmap|ass|text}_subtitle()
static int aribcaption_trans_ass_subtitle(ARIBCaptionContext *ctx)
#define ARIBC_ALPHA_DEFAULT_FRONT
#define ARIBC_BPRINT_SIZE_INIT
#define DEFAULT_FONT_ASS
static void estimate_video_frame_size(ARIBCaptionContext *ctx)
static int clut_find(ARIBCaptionContext *ctx, uint32_t rgba)
static void logcat_callback(aribcc_loglevel_t level, const char *message, void *userdata)
static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region)
#define ARIBC_ALPHA_DEFAULT_BACK
static int aribcaption_trans_text_subtitle(ARIBCaptionContext *ctx)
#define ARIBCC_COLOR_DIFF_RGB(c1, c2)
static void set_ass_color(AVBPrint *buf, int color_num, aribcc_color_t new_color, aribcc_color_t old_color)
static av_cold int aribcaption_close(AVCodecContext *avctx)
static int set_ass_header(ARIBCaptionContext *ctx)
#define ARIBC_ALPHA_MAX_NUM
#define CLUT_A(c)
#define CLUT_RGBA(r, g, b, a)
#define CLUT_R(c)
static void aribcaption_flush(AVCodecContext *avctx)
#define ASS_SINGLE_RECT
static uint8_t clut_find_nearlest_alpha(ARIBCaptionContext *ctx, uint8_t a)
static void clut_set_alpha(ARIBCaptionContext *ctx, uint8_t a)
#define ARIBCC_COLOR_DIFF_A(c1, c2)
static const AVClass aribcaption_class
#define CLUT_B(c)
#define ARIBCC_COLOR_TO_CLUT_RGBA(c, a)
static int clut_color_distance(uint32_t rgba1, uint32_t rgba2)
#define OFFSET(x)
#define ARIBCC_COLOR_RGB(c)
#define ARIBC_BPRINT_SIZE_MAX
static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, int a)
static int aribcaption_decode(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, const AVPacket *avpkt)
static av_cold int aribcaption_init(AVCodecContext *avctx)
#define CLUT_G(c)
common internal api header.
#define hex_dump_debug(class, buf, size)
Definition internal.h:39
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
uint8_t w
Definition llvidencdsp.c:39
#define FFMIN(a, b)
Definition macros.h:49
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
int profile
Definition mxfenc.c:2299
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
#define AVPALETTE_COUNT
Definition pixfmt.h:33
#define AVPALETTE_SIZE
Definition pixfmt.h:32
uint8_t clut_alpha[ARIBC_ALPHA_MAX_NUM]
aribcc_decoder_t * decoder
aribcc_context_t * context
AVCodecContext * avctx
aribcc_renderer_t * renderer
aribcc_render_result_t render_result
aribcc_caption_t caption
const AVPacket * avpkt
Describe the class of an AVClass context structure.
Definition log.h:76
main external API structure.
Definition avcodec.h:443
int subtitle_header_size
Header containing style information for text subtitles.
Definition avcodec.h:1743
int flags2
AV_CODEC_FLAG2_*.
Definition avcodec.h:507
AVRational pkt_timebase
Timebase in which pkt_dts/pts and AVPacket.dts/pts are expressed.
Definition avcodec.h:554
int profile
profile
Definition avcodec.h:1636
uint8_t * subtitle_header
Definition avcodec.h:1744
void * priv_data
Definition avcodec.h:470
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
int size
Definition packet.h:604
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition packet.h:596
uint8_t * data
Definition packet.h:603
Rational number (pair of numerator and denominator).
Definition rational.h:58
char * ass
0 terminated ASS/SSA compatible event line.
Definition avcodec.h:2084
uint8_t * data[4]
data+linesize for the bitmap of this subtitle.
Definition avcodec.h:2071
uint16_t format
Definition avcodec.h:2088
uint32_t end_display_time
Definition avcodec.h:2090
unsigned num_rects
Definition avcodec.h:2091
AVSubtitleRect ** rects
Definition avcodec.h:2092
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition avcodec.h:2093
int w
Definition f_ebur128.c:78
int y
Definition f_ebur128.c:78
int h
Definition f_ebur128.c:78
int x
Definition f_ebur128.c:78
uint8_t level
Definition svq3.c:208
#define av_mallocz(s)
#define ff_dlog(a,...)
#define avpriv_request_sample(...)
#define av_freep(p)
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
const char * g
Definition vf_curves.c:128
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
static double c[64]