[FFmpeg-devel] [PATCH 1/2 v3] add libaribb24 ARIB STD-B24 caption decoder
Jan Ekström
jeebjp at gmail.com
Mon Feb 11 01:27:44 EET 2019
On Mon, Feb 11, 2019 at 1:01 AM Michael Niedermayer <michaelni at gmx.at> wrote:
>
> On Sun, Feb 03, 2019 at 09:38:40PM +0200, Jan Ekström wrote:
> > +#define RGB_TO_BGR(c) ((c & 0xff) << 16 | (c & 0xff00) | ((c >> 16) & 0xff))
>
> c should be protected by a ()
>
First of all, thank you for the technical review.
But yes, it seems like I was too focused on single values it seems (in
which case there is no ambiguity regarding order). Will do.
>
> > +
> > +static void libaribb24_handle_regions(AVCodecContext *avctx, AVSubtitle *sub)
> > +{
> > + Libaribb24Context *b24 = avctx->priv_data;
> > + const arib_buf_region_t *region = arib_decoder_get_regions(b24->decoder);
> > + unsigned int profile_font_size = get_profile_font_size(avctx->profile);
> > + AVBPrint buf = { 0 };
> > +
> > + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
> > +
> > + while (region) {
> > + ptrdiff_t region_length = region->p_end - region->p_start;
> > + unsigned int ruby_region =
> > + region->i_fontheight == (profile_font_size / 2);
> > +
> > + // ASS requires us to make the colors BGR, so we convert here
> > + int foreground_bgr_color = RGB_TO_BGR(region->i_foreground_color);
> > + int background_bgr_color = RGB_TO_BGR(region->i_background_color);
> > +
> > + if (region_length < 0) {
> > + av_log(avctx, AV_LOG_ERROR, "Invalid negative region length!\n");
> > + break;
> > + }
> > +
> > + if (region_length == 0 || (ruby_region && b24->aribb24_skip_ruby)) {
> > + goto next_region;
> > + }
> > +
> > + // color and alpha
> > + if (foreground_bgr_color != ASS_DEFAULT_COLOR)
> > + av_bprintf(&buf, "{\\1c&H%06x&}", foreground_bgr_color);
> > +
> > + if (region->i_foreground_alpha != 0)
> > + av_bprintf(&buf, "{\\1a&H%02x&}", region->i_foreground_alpha);
> > +
> > + if (background_bgr_color != ASS_DEFAbufULT_BACK_COLOR)
> > + av_bprintf(&buf, "{\\3c&H%06x&}", background_bgr_color);
> > +
> > + if (region->i_background_alpha != 0)
> > + av_bprintf(&buf, "{\\3a&H%02x&}", region->i_background_alpha);
> > +
> > + // font size
> > + if (region->i_fontwidth != profile_font_size ||
> > + region->i_fontheight != profile_font_size) {
>
> > + av_bprintf(&buf, "{\\fscx%d\\fscy%d}",
> > + (int)round(((double)region->i_fontwidth /
> > + (double)profile_font_size) * 100),
> > + (int)round(((double)region->i_fontheight /
> > + (double)profile_font_size) * 100));
>
> Please use integers ((u)int64_t) not floating point. This ensures that the results
> are reliably reproducable.
> av_rescale*() may be usefull for this
>
Yes, I was planning to work on this if someone brought it up, but so
far nobody had commented on it.
Will try to post a recalc patch ASAP.
>
>
> > + }
> > +
> > + // TODO: positioning
> > +
> > + av_bprint_append_data(&buf, region->p_start, region_length);
> > +
> > + av_bprintf(&buf, "{\\r}");
> > +
> > +next_region:
> > + region = region->p_next;
> > + }
> > +
> > + av_log(avctx, AV_LOG_DEBUG, "Styled ASS line: %s\n",
> > + buf.str);
>
> is this function missing malloc failure checks for bprintf* ?
> or is there something that avoids this ?
>
I looked at other subtitle decoders (such as ccaption_dec and libzvbi)
and i didn't notice any checks when adding things to the buffer or
when initializing the bprint context.
Now that you have brought this up, it seems like I was missing
av_bprint_finalize, is this what is meant by this? That seems to be
the only thing where memory allocation is checked with these APIs in
many places. If that is it, I will post a fixup patch ASAP. It did
feel kind of weird not seeing memory allocation checks at each step.
>
> > + ff_ass_add_rect(sub, buf.str, b24->read_order++,
> > + 0, NULL, NULL);
> > +
> > + av_bprint_finalize(&buf, NULL);
> > +}
> > +
> > +static int libaribb24_decode(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *pkt)
> > +{
> > + Libaribb24Context *b24 = avctx->priv_data;
> > + AVSubtitle *sub = data;
> > + size_t parsed_data_size = 0;
> > + size_t decoded_subtitle_size = 0;
> > + const unsigned char *parsed_data = NULL;
> > + char *decoded_subtitle = NULL;
> > + time_t subtitle_duration = 0;
> > +
> > + if (pkt->size <= 0)
> > + return pkt->size;
> > +
> > + arib_parse_pes(b24->parser, pkt->data, pkt->size);
> > +
> > + parsed_data = arib_parser_get_data(b24->parser,
> > + &parsed_data_size);
> > + if (!parsed_data || !parsed_data_size) {
> > + av_log(avctx, AV_LOG_DEBUG, "No decode'able data was received from "
> > + "packet (dts: %"PRId64", pts: %"PRId64").\n",
> > + pkt->dts, pkt->pts);
> > + return pkt->size;
> > + }
> > +
> > + decoded_subtitle_size = parsed_data_size * 4;
> > + if (!(decoded_subtitle = av_mallocz(decoded_subtitle_size + 1))) {
> > + av_log(avctx, AV_LOG_ERROR,
> > + "Failed to allocate buffer for decoded subtitle!\n");
> > + return AVERROR(ENOMEM);
> > + }
> > +
> > + decoded_subtitle_size = arib_decode_buffer(b24->decoder,
> > + parsed_data,
> > + parsed_data_size,
> > + decoded_subtitle,
> > + decoded_subtitle_size);
> > +
> > + subtitle_duration = arib_decoder_get_time(b24->decoder);
> > +
> > + if (avctx->pkt_timebase.num && pkt->pts != AV_NOPTS_VALUE)
> > + sub->pts = av_rescale_q(pkt->pts,
> > + avctx->pkt_timebase, AV_TIME_BASE_Q);
> > +
> > + sub->end_display_time = subtitle_duration ?
> > + av_rescale_q(subtitle_duration,
> > + AV_TIME_BASE_Q,
> > + (AVRational){1, 1000}) :
> > + UINT32_MAX;
> > +
> > + av_log(avctx, AV_LOG_DEBUG,
> > + "Result: '%s' (size: %zu, pkt_pts: %"PRId64", sub_pts: %"PRId64" "
> > + "duration: %"PRIu32", pkt_timebase: %d/%d, time_base: %d/%d')\n",
> > + decoded_subtitle ? decoded_subtitle : "<no subtitle>",
> > + decoded_subtitle_size,
> > + pkt->pts, sub->pts,
> > + sub->end_display_time,
> > + avctx->pkt_timebase.num, avctx->pkt_timebase.den,
> > + avctx->time_base.num, avctx->time_base.den);
> > +
> > + if (decoded_subtitle)
> > + libaribb24_handle_regions(avctx, sub);
> > +
> > + *got_sub_ptr = sub->num_rects > 0;
> > +
> > + av_free(decoded_subtitle);
> > +
> > + // flush the region buffers, otherwise the linked list keeps getting
> > + // longer and longer...
> > + arib_finalize_decoder(b24->decoder);
> > +
> > + return pkt->size;
> > +}
> > +
> > +static void libaribb24_flush(AVCodecContext *avctx)
> > +{
> > + Libaribb24Context *b24 = avctx->priv_data;
> > + if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
> > + b24->read_order = 0;
> > +}
> > +
> > +#define OFFSET(x) offsetof(Libaribb24Context, x)
> > +#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
> > +static const AVOption options[] = {
> > + { "aribb24-base-path", "set the base path for the libaribb24 library",
> > + OFFSET(aribb24_base_path), AV_OPT_TYPE_STRING, { 0 }, 0, 0, SD },
> > + { "aribb24-skip-ruby-text", "skip ruby text blocks during decoding",
> > + OFFSET(aribb24_skip_ruby), AV_OPT_TYPE_BOOL, { 1 }, 0, 1, SD },
> ^^^
> This should state which type is set here , same for AV_OPT_TYPE_STRING
>
Yes, sorry. No idea how I missed that one for the default value. Will
post a fixup patch set in a moment.
Jan
More information about the ffmpeg-devel
mailing list