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
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
65
69
82
97
105
107 {
109
110 for (
i = 0;
i < buf_size;
i++) {
114 }
117 }
118
120 {
122 int lvl;
123
126 case ARIBCC_LOGLEVEL_ERROR:
128 break;
129 case ARIBCC_LOGLEVEL_WARNING:
131 break;
132 default:
134 }
135
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 {
168
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 {
183
186 d = 256;
187 j = 0;
189 if (
ctx->clut_alpha[
i] ==
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]);
196 }
197 }
198 return ctx->clut_alpha[j];
199 }
200
202 {
204
205 for (
i = 0;
i <
ctx->clut_idx;
i++) {
206 if (
ctx->clut[
i] == rgba)
208 }
209 return -1;
210 }
211
213 {
217 }
218
220 {
222 uint32_t rgba;
223
226 return 0; /* transparent */
228
229 d_min = 256 * 3;
231 for (
i = 0;
i <
ctx->clut_idx;
i++) {
232 if (
ctx->clut[
i] == rgba)
235 continue;
237 if (d < d_min) {
238 d_min = d;
240 }
241 }
242 if (d_min > 3) {
244 ctx->clut_overflow++;
245 else {
247 ctx->clut[
ctx->clut_idx++] = rgba;
248 }
249 }
251 }
252
253 /* initialize CLUT with each character colors */
255 {
256 aribcc_color_t text_color, back_color, stroke_color;
257 uint32_t rgba;
258
260 ctx->clut_alpha[0] = 0xFF;
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;
270 ctx->clut[
ctx->clut_idx++] = rgba;
274 ctx->clut[
ctx->clut_idx++] = rgba;
276 }
277
278 for (
int i = 1;
i < region->char_count;
i++) {
279 if (region->chars[
i].text_color != text_color) {
283 ctx->clut[
ctx->clut_idx++] = rgba;
285 }
286 }
287 if (region->chars[
i].back_color != back_color) {
291 ctx->clut[
ctx->clut_idx++] = rgba;
293 }
294 }
295 if (region->chars[
i].stroke_color != stroke_color) {
300 ctx->clut[
ctx->clut_idx++] = 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 {
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");
341 }
342 }
343
344 status = aribcc_renderer_append_caption(
ctx->renderer, &
ctx->caption);
347 "aribcc_renderer_append_caption() returned with error.\n");
349 }
350
351 status = aribcc_renderer_render(
ctx->renderer,
ctx->pts, &
ctx->render_result);
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);
359 return 0;
360
361 case ARIBCC_RENDER_STATUS_NO_IMAGE:
363 return 0;
364
365 case ARIBCC_RENDER_STATUS_ERROR:
367 "aribcc_renderer_render() returned with error.\n");
369
370 default:
371 aribcc_render_result_cleanup(&
ctx->render_result);
373 "aribcc_renderer_render() returned unknown status: %d\n",
status);
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 */
388 }
389 for (
int i = 0;
i <
ctx->render_result.image_count;
i++) {
394 }
395 }
396
397 for (rect_idx = 0; rect_idx <
ctx->caption.region_count; rect_idx++) {
399 aribcc_image_t *image = &
ctx->render_result.images[rect_idx];
400 int w,
h, shrink_height, dst_idx;
401
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;
407 if (!
rect->data[0]) {
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) {
415 image->width, image->stride / 4, image->height,
rect->
w,
rect->
h);
418 }
419
420 shrink_height = image->height !=
rect->
h;
421 dst_idx = 0;
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;
450 }
451 }
453 if (!
rect->data[1]) {
456 }
457
459 /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */
460 /* No position information is provided for profile C */
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 }
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,
475 rect_idx,
ctx->clut_idx);
476 if (
ctx->clut_overflow)
478 }
480
481 return rect_idx;
482
485 for (
int i = 0;
i <
ctx->caption.region_count;
i++) {
490 }
491 }
493 }
495
497 }
498
500 {
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)
518 else
520 if (!font_name)
522
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,
563
568 return 0;
569 }
570
572 aribcc_color_t new_color, aribcc_color_t old_color)
573 {
579 0xFF - ARIBCC_COLOR_A(new_color));
580 }
581
583 {
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;
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 */
601 single_rect = true;
602
603 sub->
format = 1;
/* text */
604 if (
ctx->caption.region_count == 0) {
605 /* clear previous caption for indefinite duration */
607 return 1;
608 }
609
611
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 }
625 if (y < 0)
626 y +=
ctx->plane_height;
627 if (x > 0 || y > 0)
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;
657 if (x > 0 || y > 0)
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 = ®ion->chars[j];
665
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) {
676 char_width = ch->char_width;
677 }
678 if (ch->char_height != char_height) {
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)
690 (
int)(
ctx->stroke_width * 4.0 / 3.0));
691 else
693 } else
695 }
696 if (
diff & ARIBCC_CHARSTYLE_BOLD) {
697 if (charstyle & ARIBCC_CHARSTYLE_BOLD)
699 else
701 }
702 if (
diff & ARIBCC_CHARSTYLE_ITALIC) {
703 if (charstyle & ARIBCC_CHARSTYLE_ITALIC)
705 else
707 }
708 if (
diff & ARIBCC_CHARSTYLE_UNDERLINE) {
709 if (charstyle & ARIBCC_CHARSTYLE_UNDERLINE)
711 else
713 }
714 charstyle = ch->style;
715 }
716 if (ch->text_color != text_color) {
718 text_color = ch->text_color;
719 }
720 if (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)
727 else
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
735 }
736
737 if (single_rect) {
738 if (
i + 1 <
ctx->caption.region_count)
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 {
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
757 rect_idx++;
758 }
759 }
760 if (single_rect) {
764 }
766
770 rect_idx++;
771 }
772
774 return rect_idx;
775
778 for (
int i = 0;
i <
ctx->caption.region_count;
i++) {
782 }
783 }
785 }
788
790 }
791
793 {
797 const char *text;
798
803 }
805
807 if (!sub->
rects[0]) {
810 }
812
813 if (
ctx->caption.region_count == 0)
814 text = ""; /* clear previous caption */
815 else {
816 text =
ctx->caption.text;
818 }
823 }
824
825 sub->
format = 1;
/* text */
827
828 return 1;
829
836 }
838 }
840
842 }
843
845 int *got_sub_ptr,
const AVPacket *avpkt)
846 {
849
850 ff_dlog(
ctx,
"ARIB caption packet pts=%"PRIx64
":\n", avpkt->
pts);
854 }
856
860 if (
ctx->time_base.num <= 0 ||
ctx->time_base.den <= 0) {
863 }
865 ctx->pts = ARIBCC_PTS_NOPTS;
866 else
868
871 if (
status == ARIBCC_DECODE_STATUS_ERROR) {
873 "aribcc_decoder_decode() returned with error.\n");
875 }
876 if (
status == ARIBCC_DECODE_STATUS_NO_CAPTION) {
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
894 break;
895
898 break;
899
902 break;
903
905 default:
907 }
908
912 aribcc_caption_cleanup(&
ctx->caption);
914 }
916 *got_sub_ptr = 1;
920 if (
ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE)
922 else
924 }
925
926 aribcc_caption_cleanup(&
ctx->caption);
928 }
929
931 {
933
935 aribcc_decoder_flush(
ctx->decoder);
937 aribcc_renderer_flush(
ctx->renderer);
940 }
941
943 {
945
948 aribcc_renderer_free(
ctx->renderer);
950 aribcc_decoder_free(
ctx->decoder);
952 aribcc_context_free(
ctx->context);
953
954 return 0;
955 }
956
958 {
962
964
968 /* assume 960x540 at initial state */
969 ctx->plane_width = 960;
970 ctx->plane_height = 540;
972 break;
975 ctx->plane_width = 320;
976 ctx->plane_height = 180;
978 break;
979 default:
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())) {
995 }
997 if (!(
ctx->decoder = aribcc_decoder_alloc(
ctx->context))) {
1000 }
1001 if (!aribcc_decoder_initialize(
ctx->decoder,
1002 (
enum aribcc_encoding_scheme_t)
ctx->encoding_scheme,
1003 ARIBCC_CAPTIONTYPE_CAPTION,
1005 ARIBCC_LANGUAGEID_FIRST)) {
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
1028 }
1029 break;
1030
1032 if(!(
ctx->renderer = aribcc_renderer_alloc(
ctx->context))) {
1035 }
1036 if(!aribcc_renderer_initialize(
ctx->renderer,
1037 ARIBCC_CAPTIONTYPE_CAPTION,
1038 ARIBCC_FONTPROVIDER_TYPE_AUTO,
1039 ARIBCC_TEXTRENDERER_TYPE_AUTO)) {
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");
1054 }
1055
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);
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;
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)
1093 if (is_nomem)
1095 }
1096 break;
1097
1100 default:
1101 /* do nothing */ ;
1102 }
1103
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
1116 { "sub_type", "subtitle rendering type",
1127 { "caption_encoding", "encoding scheme of subtitle text",
1129 ARIBCC_ENCODING_SCHEME_AUTO, ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN,
SD, .unit =
"encoding" },
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" },
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]",
1140 { "font", "comma-separated font family [ass, bitmap]",
1142 { "force_outline_text", "always render characters with outline [(ass), bitmap]",
1144 { "ignore_background", "ignore rendering caption background [(ass), bitmap]",
1146 { "ignore_ruby", "ignore ruby-like characters [ass, bitmap]",
1148 { "outline_width", "outline width of text [(ass), bitmap]",
1150 { "replace_drcs", "replace known DRCS [bitmap]",
1152 { "replace_msz_ascii", "replace MSZ fullwidth alphanumerics with halfwidth alphanumerics [ass, bitmap]",
1154 { "replace_msz_japanese", "replace MSZ fullwidth Japanese with halfwidth [ass, bitmap]",
1156 { "replace_msz_glyph", "replace MSZ characters with halfwidth glyphs [bitmap]",
1158 {"canvas_size", "set input video size (WxH or abbreviation) [bitmap]",
1161 };
1162
1168 };
1169
1171 .
p.
name =
"libaribcaption",
1182 };