Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Niklas Haas <ffmpeg@haasn.xyz>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH 6/6] avcodec/dovi_rpu: parse extension blocks
Date: Sat, 23 Mar 2024 19:23:11 +0100
Message-ID: <20240323192311.GB10400@haasn.xyz> (raw)
In-Reply-To: <GV1P250MB0737962C9E680D36437F03CE8F302@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM>

On Sat, 23 Mar 2024 19:00:59 +0100 Andreas Rheinhardt <andreas.rheinhardt@outlook.com> wrote:
> Niklas Haas:
> > From: Niklas Haas <git@haasn.dev>
> > 
> > We split the inner loop between v1 and v2 extension blocks to print
> > a warning where an extension block was encountered in an unexpected
> > context.
> > 
> > Co-authored-by: quietvoid <tcChlisop0@gmail.com>
> > ---
> >  libavcodec/dovi_rpu.c | 178 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 178 insertions(+)
> > 
> > diff --git a/libavcodec/dovi_rpu.c b/libavcodec/dovi_rpu.c
> > index 21cb1850e3e..99a983f65dd 100644
> > --- a/libavcodec/dovi_rpu.c
> > +++ b/libavcodec/dovi_rpu.c
> > @@ -199,6 +199,174 @@ static inline unsigned get_variable_bits(GetBitContext *gb, int n)
> >          }                                                                       \
> >      } while (0)
> >  
> > +static void parse_ext_v1(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm)
> > +{
> > +    switch (dm->level) {
> > +    case 1:
> > +        dm->l1.min_pq = get_bits(gb, 12);
> > +        dm->l1.max_pq = get_bits(gb, 12);
> > +        dm->l1.avg_pq = get_bits(gb, 12);
> > +        break;
> > +    case 2:
> > +        dm->l2.target_max_pq = get_bits(gb, 12);
> > +        dm->l2.trim_slope = get_bits(gb, 12);
> > +        dm->l2.trim_offset = get_bits(gb, 12);
> > +        dm->l2.trim_power = get_bits(gb, 12);
> > +        dm->l2.trim_chroma_weight = get_bits(gb, 12);
> > +        dm->l2.trim_saturation_gain = get_bits(gb, 12);
> > +        dm->l2.ms_weight = get_bits(gb, 13) - 8192;
> > +        break;
> > +    case 4:
> > +        dm->l4.anchor_pq = get_bits(gb, 12);
> > +        dm->l4.anchor_power = get_bits(gb, 12);
> > +        break;
> > +    case 5:
> > +        dm->l5.left_offset = get_bits(gb, 13);
> > +        dm->l5.right_offset = get_bits(gb, 13);
> > +        dm->l5.top_offset = get_bits(gb, 13);
> > +        dm->l5.bottom_offset = get_bits(gb, 13);
> > +        break;
> > +    case 6:
> > +        dm->l6.max_luminance = get_bits(gb, 16);
> > +        dm->l6.min_luminance = get_bits(gb, 16);
> > +        dm->l6.max_cll = get_bits(gb, 16);
> > +        dm->l6.max_fall = get_bits(gb, 16);
> > +        break;
> > +    case 255:
> > +        dm->l255.dm_run_mode = get_bits(gb, 8);
> > +        dm->l255.dm_run_version = get_bits(gb, 8);
> > +        for (int i = 0; i < 4; i++)
> > +            dm->l255.dm_debug[i] = get_bits(gb, 8);
> > +        break;
> > +    default:
> > +        av_log(s->logctx, AV_LOG_WARNING,
> > +               "Unknown Dolby Vision DM v1 level: %u\n", dm->level);
> > +    }
> > +}
> > +
> > +static inline AVCIExy get_cie_xy(GetBitContext *gb)
> > +{
> > +    const int denom = 32767;
> > +    return (AVCIExy) {
> > +        .x = { get_sbits(gb, 16), denom },
> > +        .y = { get_sbits(gb, 16), denom },
> > +    };
> 
> The order of initializations is undefined.

Fixed.

> > +}
> > +
> > +static void parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm,
> > +                         int ext_block_length)
> > +{
> > +    switch (dm->level) {
> > +    case 3:
> > +        dm->l3.min_pq_offset = get_bits(gb, 12);
> > +        dm->l3.max_pq_offset = get_bits(gb, 12);
> > +        dm->l3.avg_pq_offset = get_bits(gb, 12);
> > +        break;
> > +    case 8:
> > +        dm->l8.target_display_index = get_bits(gb, 8);
> > +        dm->l8.trim_slope = get_bits(gb, 12);
> > +        dm->l8.trim_offset = get_bits(gb, 12);
> > +        dm->l8.trim_power = get_bits(gb, 12);
> > +        dm->l8.trim_chroma_weight = get_bits(gb, 12);
> > +        dm->l8.trim_saturation_gain = get_bits(gb, 12);
> > +        dm->l8.ms_weight = get_bits(gb, 12) - 8192;
> > +        if (ext_block_length < 12)
> > +            break;
> > +        dm->l8.target_mid_contrast = get_bits(gb, 12);
> > +        if (ext_block_length < 13)
> > +            break;
> > +        dm->l8.clip_trim = get_bits(gb, 12);
> > +        if (ext_block_length < 19)
> > +            break;
> > +        for (int i = 0; i < 6; i++)
> > +            dm->l8.saturation_vector_field[i] = get_bits(gb, 8);
> > +        if (ext_block_length < 25)
> > +            break;
> > +        for (int i = 0; i < 6; i++)
> > +            dm->l8.hue_vector_field[i] = get_bits(gb, 8);
> > +        break;
> > +    case 9:
> > +        dm->l9.source_primary_index = get_bits(gb, 8);
> > +        if (ext_block_length < 17)
> > +            break;
> > +        dm->l9.source_display_primaries.prim.r = get_cie_xy(gb);
> > +        dm->l9.source_display_primaries.prim.g = get_cie_xy(gb);
> > +        dm->l9.source_display_primaries.prim.b = get_cie_xy(gb);
> > +        dm->l9.source_display_primaries.wp = get_cie_xy(gb);
> > +        break;
> > +    case 10:
> > +        dm->l10.target_display_index = get_bits(gb, 8);
> > +        dm->l10.target_max_pq = get_bits(gb, 12);
> > +        dm->l10.target_min_pq = get_bits(gb, 12);
> > +        dm->l10.target_primary_index = get_bits(gb, 8);
> > +        if (ext_block_length < 21)
> > +            break;
> > +        dm->l10.target_display_primaries.prim.r = get_cie_xy(gb);
> > +        dm->l10.target_display_primaries.prim.g = get_cie_xy(gb);
> > +        dm->l10.target_display_primaries.prim.b = get_cie_xy(gb);
> > +        dm->l10.target_display_primaries.wp = get_cie_xy(gb);
> > +        break;
> > +    case 11:
> > +        dm->l11.content_type = get_bits(gb, 8);
> > +        dm->l11.whitepoint = get_bits(gb, 4);
> > +        dm->l11.reference_mode_flag = get_bits(gb, 1);
> > +        skip_bits(gb, 3); /* reserved */
> > +        dm->l11.sharpness = get_bits(gb, 2);
> > +        dm->l11.noise_reduction = get_bits(gb, 2);
> > +        dm->l11.mpeg_noise_reduction = get_bits(gb, 2);
> > +        dm->l11.frame_rate_conversion = get_bits(gb, 2);
> > +        dm->l11.brightness = get_bits(gb, 2);
> > +        dm->l11.color = get_bits(gb, 2);
> > +        break;
> > +    case 254:
> > +        dm->l254.dm_mode = get_bits(gb, 8);
> > +        dm->l254.dm_version_index = get_bits(gb, 8);
> > +        break;
> > +    default:
> > +        av_log(s->logctx, AV_LOG_WARNING,
> > +               "Unknown Dolby Vision DM v2 level: %u\n", dm->level);
> > +    }
> > +}
> > +
> > +static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver)
> > +{
> > +    int num_ext_blocks, ext_block_length, start_pos, parsed_bits;
> > +    AVDOVIDmData *ext_blocks;
> > +    size_t alloc_sz;
> > +
> > +    num_ext_blocks = get_ue_golomb_31(gb);
> 
> get_ue_golomb_31() currently returns small values when encountering
> golomb values outside of the 0-31 range; but this is not guaranteed to
> be so.

Fixed.

And in doing so, I noticed that the total number of blocks is actually
fairly constrained, so there's probably no point in allocating this
dynamically at all.

> 
> > +    align_get_bits(gb);
> > +
> > +    alloc_sz = (s->num_ext_blocks + num_ext_blocks) * sizeof(AVDOVIDmData);
> > +    ext_blocks = av_fast_realloc(s->ext_blocks, &s->ext_blocks_sz, alloc_sz);
> > +    if (!ext_blocks) {
> > +        ff_dovi_ctx_unref(s);
> > +        return AVERROR(ENOMEM);
> > +    }
> > +    s->ext_blocks = ext_blocks;
> > +
> > +    while (num_ext_blocks--) {
> > +        AVDOVIDmData *dm = &s->ext_blocks[s->num_ext_blocks++];
> > +        ext_block_length = get_ue_golomb_31(gb);
> > +        dm->level = get_bits(gb, 8);
> > +        start_pos = get_bits_count(gb);
> > +
> > +        switch (ver) {
> > +        case 1: parse_ext_v1(s, gb, dm); break;
> > +        case 2: parse_ext_v2(s, gb, dm, ext_block_length); break;
> > +        }
> > +
> > +        parsed_bits = get_bits_count(gb) - start_pos;
> > +        if (parsed_bits > ext_block_length * 8) {
> > +            ff_dovi_ctx_unref(s);
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        skip_bits(gb, ext_block_length * 8 - parsed_bits);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
> >                        int err_recognition)
> >  {
> > @@ -524,6 +692,16 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size,
> >          color->source_diagonal = get_bits(gb, 10);
> >      }
> >  
> > +    /* Parse extension blocks */
> > +    s->num_ext_blocks = 0;
> > +    if ((ret = parse_ext_blocks(s, gb, 1)) < 0)
> > +        return ret;
> > +
> > +    if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) {
> > +        if ((ret = parse_ext_blocks(s, gb, 2)) < 0)
> > +            return ret;
> > +    }
> > +
> >      return 0;
> >  
> >  fail:
> 
> Why do you implement parsing for something that does not get used at all?

Oops, I forgot to submit the commit that actually exposes this in
ff_dovi_attach_side_data()!

For context, there are at least two valid use-cases:

1. Downstream clients want access to these (e.g. VLC, mpv); libplacebo
   currently uses custom code to parse the RPU but having it done inside
   FFmpeg would be better for everybody involved.

2. For transcoding, we want to be able to preserve the information
   inside the extension blocks. This requires parsing them in the first
   place, so we can synthesize them back into binary form.

> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

      reply	other threads:[~2024-03-23 18:23 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-23 17:37 [FFmpeg-devel] [PATCH 1/6] avutil/dovi_meta: add AVDOVIDataMapping.nlq_pivots Niklas Haas
2024-03-23 17:37 ` [FFmpeg-devel] [PATCH 2/6] avutil/dovi_meta: add dolby vision extension blocks Niklas Haas
2024-03-23 17:58   ` Andreas Rheinhardt
2024-03-23 18:08     ` Niklas Haas
2024-03-23 18:45       ` Niklas Haas
2024-03-23 17:37 ` [FFmpeg-devel] [PATCH 3/6] avcodec/dovi_rpu: strip container in separate step Niklas Haas
2024-03-23 18:02   ` Andreas Rheinhardt
2024-03-23 18:06     ` Niklas Haas
2024-03-23 17:37 ` [FFmpeg-devel] [PATCH 4/6] avcodec/dovi_rpu: verify RPU data CRC32 Niklas Haas
2024-03-23 17:37 ` [FFmpeg-devel] [PATCH 5/6] avcodec/dovi_rpu: add ext_blocks array to DOVIContext Niklas Haas
2024-03-23 17:37 ` [FFmpeg-devel] [PATCH 6/6] avcodec/dovi_rpu: parse extension blocks Niklas Haas
2024-03-23 18:00   ` Andreas Rheinhardt
2024-03-23 18:23     ` Niklas Haas [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240323192311.GB10400@haasn.xyz \
    --to=ffmpeg@haasn.xyz \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git