1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * ARIB STD-B24 caption decoder using the libaribb24 library 3cabdff1aSopenharmony_ci * Copyright (c) 2019 Jan Ekström 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "avcodec.h" 23cabdff1aSopenharmony_ci#include "libavcodec/ass.h" 24cabdff1aSopenharmony_ci#include "codec_internal.h" 25cabdff1aSopenharmony_ci#include "libavutil/log.h" 26cabdff1aSopenharmony_ci#include "libavutil/opt.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include <aribb24/aribb24.h> 29cabdff1aSopenharmony_ci#include <aribb24/parser.h> 30cabdff1aSopenharmony_ci#include <aribb24/decoder.h> 31cabdff1aSopenharmony_ci 32cabdff1aSopenharmony_citypedef struct Libaribb24Context { 33cabdff1aSopenharmony_ci AVClass *class; 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci arib_instance_t *lib_instance; 36cabdff1aSopenharmony_ci arib_parser_t *parser; 37cabdff1aSopenharmony_ci arib_decoder_t *decoder; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci int read_order; 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci char *aribb24_base_path; 42cabdff1aSopenharmony_ci unsigned int aribb24_skip_ruby; 43cabdff1aSopenharmony_ci} Libaribb24Context; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_cistatic unsigned int get_profile_font_size(int profile) 46cabdff1aSopenharmony_ci{ 47cabdff1aSopenharmony_ci switch (profile) { 48cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_A: 49cabdff1aSopenharmony_ci return 36; 50cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_C: 51cabdff1aSopenharmony_ci return 18; 52cabdff1aSopenharmony_ci default: 53cabdff1aSopenharmony_ci return 0; 54cabdff1aSopenharmony_ci } 55cabdff1aSopenharmony_ci} 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_cistatic void libaribb24_log(void *p, const char *msg) 58cabdff1aSopenharmony_ci{ 59cabdff1aSopenharmony_ci av_log((AVCodecContext *)p, AV_LOG_INFO, "%s\n", msg); 60cabdff1aSopenharmony_ci} 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_cistatic int libaribb24_generate_ass_header(AVCodecContext *avctx) 63cabdff1aSopenharmony_ci{ 64cabdff1aSopenharmony_ci unsigned int plane_width = 0; 65cabdff1aSopenharmony_ci unsigned int plane_height = 0; 66cabdff1aSopenharmony_ci unsigned int font_size = 0; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci switch (avctx->profile) { 69cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_A: 70cabdff1aSopenharmony_ci plane_width = 960; 71cabdff1aSopenharmony_ci plane_height = 540; 72cabdff1aSopenharmony_ci font_size = get_profile_font_size(avctx->profile); 73cabdff1aSopenharmony_ci break; 74cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_C: 75cabdff1aSopenharmony_ci plane_width = 320; 76cabdff1aSopenharmony_ci plane_height = 180; 77cabdff1aSopenharmony_ci font_size = get_profile_font_size(avctx->profile); 78cabdff1aSopenharmony_ci break; 79cabdff1aSopenharmony_ci default: 80cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n"); 81cabdff1aSopenharmony_ci return AVERROR(EINVAL); 82cabdff1aSopenharmony_ci } 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci avctx->subtitle_header = av_asprintf( 85cabdff1aSopenharmony_ci "[Script Info]\r\n" 86cabdff1aSopenharmony_ci "; Script generated by FFmpeg/Lavc%s\r\n" 87cabdff1aSopenharmony_ci "ScriptType: v4.00+\r\n" 88cabdff1aSopenharmony_ci "PlayResX: %d\r\n" 89cabdff1aSopenharmony_ci "PlayResY: %d\r\n" 90cabdff1aSopenharmony_ci "\r\n" 91cabdff1aSopenharmony_ci "[V4+ Styles]\r\n" 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci /* ASSv4 header */ 94cabdff1aSopenharmony_ci "Format: Name, " 95cabdff1aSopenharmony_ci "Fontname, Fontsize, " 96cabdff1aSopenharmony_ci "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " 97cabdff1aSopenharmony_ci "Bold, Italic, Underline, StrikeOut, " 98cabdff1aSopenharmony_ci "ScaleX, ScaleY, " 99cabdff1aSopenharmony_ci "Spacing, Angle, " 100cabdff1aSopenharmony_ci "BorderStyle, Outline, Shadow, " 101cabdff1aSopenharmony_ci "Alignment, MarginL, MarginR, MarginV, " 102cabdff1aSopenharmony_ci "Encoding\r\n" 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_ci "Style: " 105cabdff1aSopenharmony_ci "Default," /* Name */ 106cabdff1aSopenharmony_ci "%s,%d," /* Font{name,size} */ 107cabdff1aSopenharmony_ci "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */ 108cabdff1aSopenharmony_ci "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */ 109cabdff1aSopenharmony_ci "100,100," /* Scale{X,Y} */ 110cabdff1aSopenharmony_ci "0,0," /* Spacing, Angle */ 111cabdff1aSopenharmony_ci "%d,1,0," /* BorderStyle, Outline, Shadow */ 112cabdff1aSopenharmony_ci "%d,10,10,10," /* Alignment, Margin[LRV] */ 113cabdff1aSopenharmony_ci "0\r\n" /* Encoding */ 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_ci "\r\n" 116cabdff1aSopenharmony_ci "[Events]\r\n" 117cabdff1aSopenharmony_ci "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", 118cabdff1aSopenharmony_ci !(avctx->flags & AV_CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "", 119cabdff1aSopenharmony_ci plane_width, plane_height, 120cabdff1aSopenharmony_ci ASS_DEFAULT_FONT, font_size, ASS_DEFAULT_COLOR, 121cabdff1aSopenharmony_ci ASS_DEFAULT_COLOR, ASS_DEFAULT_BACK_COLOR, ASS_DEFAULT_BACK_COLOR, 122cabdff1aSopenharmony_ci -ASS_DEFAULT_BOLD, -ASS_DEFAULT_ITALIC, -ASS_DEFAULT_UNDERLINE, 123cabdff1aSopenharmony_ci ASS_DEFAULT_BORDERSTYLE, ASS_DEFAULT_ALIGNMENT); 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci if (!avctx->subtitle_header) 126cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci avctx->subtitle_header_size = strlen(avctx->subtitle_header); 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci return 0; 131cabdff1aSopenharmony_ci} 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_cistatic int libaribb24_init(AVCodecContext *avctx) 134cabdff1aSopenharmony_ci{ 135cabdff1aSopenharmony_ci Libaribb24Context *b24 = avctx->priv_data; 136cabdff1aSopenharmony_ci void(* arib_dec_init)(arib_decoder_t* decoder) = NULL; 137cabdff1aSopenharmony_ci int ret_code = AVERROR_EXTERNAL; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci if (!(b24->lib_instance = arib_instance_new(avctx))) { 140cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24!\n"); 141cabdff1aSopenharmony_ci goto init_fail; 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci if (b24->aribb24_base_path) { 145cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_INFO, "Setting the libaribb24 base path to '%s'\n", 146cabdff1aSopenharmony_ci b24->aribb24_base_path); 147cabdff1aSopenharmony_ci arib_set_base_path(b24->lib_instance, b24->aribb24_base_path); 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci arib_register_messages_callback(b24->lib_instance, libaribb24_log); 151cabdff1aSopenharmony_ci 152cabdff1aSopenharmony_ci if (!(b24->parser = arib_get_parser(b24->lib_instance))) { 153cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 PES parser!\n"); 154cabdff1aSopenharmony_ci goto init_fail; 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci if (!(b24->decoder = arib_get_decoder(b24->lib_instance))) { 157cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 decoder!\n"); 158cabdff1aSopenharmony_ci goto init_fail; 159cabdff1aSopenharmony_ci } 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci switch (avctx->profile) { 162cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_A: 163cabdff1aSopenharmony_ci arib_dec_init = arib_initialize_decoder_a_profile; 164cabdff1aSopenharmony_ci break; 165cabdff1aSopenharmony_ci case FF_PROFILE_ARIB_PROFILE_C: 166cabdff1aSopenharmony_ci arib_dec_init = arib_initialize_decoder_c_profile; 167cabdff1aSopenharmony_ci break; 168cabdff1aSopenharmony_ci default: 169cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n"); 170cabdff1aSopenharmony_ci ret_code = AVERROR(EINVAL); 171cabdff1aSopenharmony_ci goto init_fail; 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci arib_dec_init(b24->decoder); 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci if (libaribb24_generate_ass_header(avctx) < 0) { 177cabdff1aSopenharmony_ci ret_code = AVERROR(ENOMEM); 178cabdff1aSopenharmony_ci goto init_fail; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci return 0; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ciinit_fail: 184cabdff1aSopenharmony_ci if (b24->decoder) 185cabdff1aSopenharmony_ci arib_finalize_decoder(b24->decoder); 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (b24->lib_instance) 188cabdff1aSopenharmony_ci arib_instance_destroy(b24->lib_instance); 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci return ret_code; 191cabdff1aSopenharmony_ci} 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_cistatic int libaribb24_close(AVCodecContext *avctx) 194cabdff1aSopenharmony_ci{ 195cabdff1aSopenharmony_ci Libaribb24Context *b24 = avctx->priv_data; 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci if (b24->decoder) 198cabdff1aSopenharmony_ci arib_finalize_decoder(b24->decoder); 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci if (b24->lib_instance) 201cabdff1aSopenharmony_ci arib_instance_destroy(b24->lib_instance); 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci return 0; 204cabdff1aSopenharmony_ci} 205cabdff1aSopenharmony_ci 206cabdff1aSopenharmony_ci#define RGB_TO_BGR(c) (((c) & 0xff) << 16 | ((c) & 0xff00) | (((c) >> 16) & 0xff)) 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_cistatic int libaribb24_handle_regions(AVCodecContext *avctx, AVSubtitle *sub) 209cabdff1aSopenharmony_ci{ 210cabdff1aSopenharmony_ci Libaribb24Context *b24 = avctx->priv_data; 211cabdff1aSopenharmony_ci const arib_buf_region_t *region = arib_decoder_get_regions(b24->decoder); 212cabdff1aSopenharmony_ci unsigned int profile_font_size = get_profile_font_size(avctx->profile); 213cabdff1aSopenharmony_ci AVBPrint buf = { 0 }; 214cabdff1aSopenharmony_ci int ret = 0; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci while (region) { 219cabdff1aSopenharmony_ci ptrdiff_t region_length = region->p_end - region->p_start; 220cabdff1aSopenharmony_ci unsigned int ruby_region = 221cabdff1aSopenharmony_ci region->i_fontheight == (profile_font_size / 2); 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci // ASS requires us to make the colors BGR, so we convert here 224cabdff1aSopenharmony_ci int foreground_bgr_color = RGB_TO_BGR(region->i_foreground_color); 225cabdff1aSopenharmony_ci int background_bgr_color = RGB_TO_BGR(region->i_background_color); 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_ci if (region_length < 0) { 228cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid negative region length!\n"); 229cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 230cabdff1aSopenharmony_ci break; 231cabdff1aSopenharmony_ci } 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci if (region_length == 0 || (ruby_region && b24->aribb24_skip_ruby)) { 234cabdff1aSopenharmony_ci goto next_region; 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci // color and alpha 238cabdff1aSopenharmony_ci if (foreground_bgr_color != ASS_DEFAULT_COLOR) 239cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\1c&H%06x&}", foreground_bgr_color); 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_ci if (region->i_foreground_alpha != 0) 242cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\1a&H%02x&}", region->i_foreground_alpha); 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci if (background_bgr_color != ASS_DEFAULT_BACK_COLOR) 245cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\3c&H%06x&}", background_bgr_color); 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci if (region->i_background_alpha != 0) 248cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\3a&H%02x&}", region->i_background_alpha); 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci // font size 251cabdff1aSopenharmony_ci if (region->i_fontwidth != profile_font_size || 252cabdff1aSopenharmony_ci region->i_fontheight != profile_font_size) { 253cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\fscx%"PRId64"\\fscy%"PRId64"}", 254cabdff1aSopenharmony_ci av_rescale(region->i_fontwidth, 100, 255cabdff1aSopenharmony_ci profile_font_size), 256cabdff1aSopenharmony_ci av_rescale(region->i_fontheight, 100, 257cabdff1aSopenharmony_ci profile_font_size)); 258cabdff1aSopenharmony_ci } 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci // TODO: positioning 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci av_bprint_append_data(&buf, region->p_start, region_length); 263cabdff1aSopenharmony_ci 264cabdff1aSopenharmony_ci av_bprintf(&buf, "{\\r}"); 265cabdff1aSopenharmony_ci 266cabdff1aSopenharmony_cinext_region: 267cabdff1aSopenharmony_ci region = region->p_next; 268cabdff1aSopenharmony_ci } 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci if (!av_bprint_is_complete(&buf)) 271cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci if (ret == 0) { 274cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "Styled ASS line: %s\n", 275cabdff1aSopenharmony_ci buf.str); 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci ret = ff_ass_add_rect(sub, buf.str, b24->read_order++, 278cabdff1aSopenharmony_ci 0, NULL, NULL); 279cabdff1aSopenharmony_ci } 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_ci av_bprint_finalize(&buf, NULL); 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci return ret; 284cabdff1aSopenharmony_ci} 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_cistatic int libaribb24_decode(AVCodecContext *avctx, AVSubtitle *sub, 287cabdff1aSopenharmony_ci int *got_sub_ptr, const AVPacket *pkt) 288cabdff1aSopenharmony_ci{ 289cabdff1aSopenharmony_ci Libaribb24Context *b24 = avctx->priv_data; 290cabdff1aSopenharmony_ci size_t parsed_data_size = 0; 291cabdff1aSopenharmony_ci size_t decoded_subtitle_size = 0; 292cabdff1aSopenharmony_ci const unsigned char *parsed_data = NULL; 293cabdff1aSopenharmony_ci char *decoded_subtitle = NULL; 294cabdff1aSopenharmony_ci time_t subtitle_duration = 0; 295cabdff1aSopenharmony_ci int ret = 0; 296cabdff1aSopenharmony_ci 297cabdff1aSopenharmony_ci if (pkt->size <= 0) 298cabdff1aSopenharmony_ci return pkt->size; 299cabdff1aSopenharmony_ci 300cabdff1aSopenharmony_ci arib_parse_pes(b24->parser, pkt->data, pkt->size); 301cabdff1aSopenharmony_ci 302cabdff1aSopenharmony_ci parsed_data = arib_parser_get_data(b24->parser, 303cabdff1aSopenharmony_ci &parsed_data_size); 304cabdff1aSopenharmony_ci if (!parsed_data || !parsed_data_size) { 305cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, "No decode'able data was received from " 306cabdff1aSopenharmony_ci "packet (dts: %"PRId64", pts: %"PRId64").\n", 307cabdff1aSopenharmony_ci pkt->dts, pkt->pts); 308cabdff1aSopenharmony_ci return pkt->size; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci decoded_subtitle_size = parsed_data_size * 4; 312cabdff1aSopenharmony_ci if (!(decoded_subtitle = av_mallocz(decoded_subtitle_size + 1))) { 313cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 314cabdff1aSopenharmony_ci "Failed to allocate buffer for decoded subtitle!\n"); 315cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 316cabdff1aSopenharmony_ci } 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci decoded_subtitle_size = arib_decode_buffer(b24->decoder, 319cabdff1aSopenharmony_ci parsed_data, 320cabdff1aSopenharmony_ci parsed_data_size, 321cabdff1aSopenharmony_ci decoded_subtitle, 322cabdff1aSopenharmony_ci decoded_subtitle_size); 323cabdff1aSopenharmony_ci 324cabdff1aSopenharmony_ci subtitle_duration = arib_decoder_get_time(b24->decoder); 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci if (avctx->pkt_timebase.num && pkt->pts != AV_NOPTS_VALUE) 327cabdff1aSopenharmony_ci sub->pts = av_rescale_q(pkt->pts, 328cabdff1aSopenharmony_ci avctx->pkt_timebase, AV_TIME_BASE_Q); 329cabdff1aSopenharmony_ci 330cabdff1aSopenharmony_ci sub->end_display_time = subtitle_duration ? 331cabdff1aSopenharmony_ci av_rescale_q(subtitle_duration, 332cabdff1aSopenharmony_ci AV_TIME_BASE_Q, 333cabdff1aSopenharmony_ci (AVRational){1, 1000}) : 334cabdff1aSopenharmony_ci UINT32_MAX; 335cabdff1aSopenharmony_ci 336cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, 337cabdff1aSopenharmony_ci "Result: '%s' (size: %zu, pkt_pts: %"PRId64", sub_pts: %"PRId64" " 338cabdff1aSopenharmony_ci "duration: %"PRIu32", pkt_timebase: %d/%d, time_base: %d/%d')\n", 339cabdff1aSopenharmony_ci decoded_subtitle ? decoded_subtitle : "<no subtitle>", 340cabdff1aSopenharmony_ci decoded_subtitle_size, 341cabdff1aSopenharmony_ci pkt->pts, sub->pts, 342cabdff1aSopenharmony_ci sub->end_display_time, 343cabdff1aSopenharmony_ci avctx->pkt_timebase.num, avctx->pkt_timebase.den, 344cabdff1aSopenharmony_ci avctx->time_base.num, avctx->time_base.den); 345cabdff1aSopenharmony_ci 346cabdff1aSopenharmony_ci if (decoded_subtitle) 347cabdff1aSopenharmony_ci ret = libaribb24_handle_regions(avctx, sub); 348cabdff1aSopenharmony_ci 349cabdff1aSopenharmony_ci *got_sub_ptr = sub->num_rects > 0; 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci av_free(decoded_subtitle); 352cabdff1aSopenharmony_ci 353cabdff1aSopenharmony_ci // flush the region buffers, otherwise the linked list keeps getting 354cabdff1aSopenharmony_ci // longer and longer... 355cabdff1aSopenharmony_ci arib_finalize_decoder(b24->decoder); 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_ci return ret < 0 ? ret : pkt->size; 358cabdff1aSopenharmony_ci} 359cabdff1aSopenharmony_ci 360cabdff1aSopenharmony_cistatic void libaribb24_flush(AVCodecContext *avctx) 361cabdff1aSopenharmony_ci{ 362cabdff1aSopenharmony_ci Libaribb24Context *b24 = avctx->priv_data; 363cabdff1aSopenharmony_ci if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) 364cabdff1aSopenharmony_ci b24->read_order = 0; 365cabdff1aSopenharmony_ci} 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(Libaribb24Context, x) 368cabdff1aSopenharmony_ci#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM 369cabdff1aSopenharmony_cistatic const AVOption options[] = { 370cabdff1aSopenharmony_ci { "aribb24-base-path", "set the base path for the libaribb24 library", 371cabdff1aSopenharmony_ci OFFSET(aribb24_base_path), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, 372cabdff1aSopenharmony_ci { "aribb24-skip-ruby-text", "skip ruby text blocks during decoding", 373cabdff1aSopenharmony_ci OFFSET(aribb24_skip_ruby), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD }, 374cabdff1aSopenharmony_ci { NULL } 375cabdff1aSopenharmony_ci}; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_cistatic const AVClass aribb24_class = { 378cabdff1aSopenharmony_ci .class_name = "libaribb24 decoder", 379cabdff1aSopenharmony_ci .item_name = av_default_item_name, 380cabdff1aSopenharmony_ci .option = options, 381cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 382cabdff1aSopenharmony_ci}; 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ciconst FFCodec ff_libaribb24_decoder = { 385cabdff1aSopenharmony_ci .p.name = "libaribb24", 386cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("libaribb24 ARIB STD-B24 caption decoder"), 387cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_SUBTITLE, 388cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_ARIB_CAPTION, 389cabdff1aSopenharmony_ci .p.priv_class = &aribb24_class, 390cabdff1aSopenharmony_ci .p.wrapper_name = "libaribb24", 391cabdff1aSopenharmony_ci .priv_data_size = sizeof(Libaribb24Context), 392cabdff1aSopenharmony_ci .init = libaribb24_init, 393cabdff1aSopenharmony_ci .close = libaribb24_close, 394cabdff1aSopenharmony_ci FF_CODEC_DECODE_SUB_CB(libaribb24_decode), 395cabdff1aSopenharmony_ci .flush = libaribb24_flush, 396cabdff1aSopenharmony_ci}; 397