History

avcodec/dovi_rpudec: implement limited DM decompression

This implements the limited DM metadata compression scheme described in chapter 9 of the dolby vision bitstream specification. The spec is a bit unclear about how to handle the presence of static metadata inside compressed frames; in that it doesn't explicitly forbid an encoder from repeating redundant metadata. In theory, we would need to detect this case and then strip the corresponding duplicate metadata from the existing set of static metadata. However, this is difficult to implement - esspecially for the case of metadata blocks which may be internally repeated (e.g. level 10). That said, the spec states outright that static metadata should be constant throughout the entire sequence, so a sane bitstream should not have any static metadata values changing from one frame to the next (at least up to a keyframe boundary), and therefore they should never be present in compressed frames. As a consequence, it makes sense to treat this as an error state regardless. (Ignoring them by default, or erroring if either AV_EF_EXPLODE or AV_EF_AGGRESSIVE are set) I was not able to find such samples in the wild (outside of artificially produced test cases for this exact scenario), so I don't think we need to worry about it until somebody produces one.

Niklas Haas committed 2 years ago

Commit 45f5f4d1 parent 1c4d4cc1 file · +65 −35Browse files

Showing the changes to libavcodec (1 of 1 file). Show all

Unified · Split

libavcodec/dovi_rpudec.c+65−35
@@ -281,7 +281,8 @@ static int parse_ext_v2(DOVIContext *s, GetBitContext *gb, AVDOVIDmData *dm, · 280 unmodified lines
281281 return 0;
282282 }
283283
284−static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver)
284+static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver,
285+ int compression, int err_recognition)
285286 {
286287 int num_ext_blocks, ext_block_length, start_pos, parsed_bits, ret;
287288 DOVIExt *ext = s->ext_blocks;
@@ -296,6 +297,7 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) · 8 unmodified lines
296297 }
297298
298299 while (num_ext_blocks--) {
300+ AVDOVIDmData dummy;
299301 AVDOVIDmData *dm;
300302 uint8_t level;
301303
@@ -304,9 +306,17 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) · 2 unmodified lines
304306 start_pos = get_bits_count(gb);
305307
306308 if (ff_dovi_rpu_extension_is_static(level)) {
307− if (ext->num_static >= FF_ARRAY_ELEMS(ext->dm_static))
308− return AVERROR_INVALIDDATA;
309− dm = &ext->dm_static[ext->num_static++];
309+ if (compression) {
310+ av_log(s->logctx, AV_LOG_WARNING, "Compressed DM RPU contains "
311+ "static extension block level %d\n", level);
312+ if (err_recognition & (AV_EF_AGGRESSIVE | AV_EF_EXPLODE))
313+ return AVERROR_INVALIDDATA;
314+ dm = &dummy;
315+ } else {
316+ if (ext->num_static >= FF_ARRAY_ELEMS(ext->dm_static))
317+ return AVERROR_INVALIDDATA;
318+ dm = &ext->dm_static[ext->num_static++];
319+ }
310320 } else {
311321 if (ext->num_dynamic >= FF_ARRAY_ELEMS(ext->dm_dynamic))
312322 return AVERROR_INVALIDDATA;
@@ -342,6 +352,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 29 unmodified lines
342352 uint8_t rpu_type;
343353 uint8_t vdr_seq_info_present;
344354 uint8_t vdr_dm_metadata_present;
355+ uint8_t dm_compression = 0;
345356 uint8_t use_prev_vdr_rpu;
346357 uint8_t use_nlq;
347358 uint8_t profile;
@@ -454,7 +465,6 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 106 unmodified lines
454465 int bl_bit_depth_minus8 = get_ue_golomb_31(gb);
455466 int el_bit_depth_minus8 = get_ue_golomb_long(gb);
456467 int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);
457− int reserved_zero_3bits;
458468 /* ext_mapping_idc is in the upper 8 bits of el_bit_depth_minus8 */
459469 int ext_mapping_idc = el_bit_depth_minus8 >> 8;
460470 el_bit_depth_minus8 = el_bit_depth_minus8 & 0xFF;
@@ -468,8 +478,7 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 7 unmodified lines
468478 hdr->ext_mapping_idc_5_7 = ext_mapping_idc >> 5;
469479 hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;
470480 hdr->spatial_resampling_filter_flag = get_bits1(gb);
471− reserved_zero_3bits = get_bits(gb, 3);
472− VALIDATE(reserved_zero_3bits, 0, 0);
481+ dm_compression = get_bits(gb, 3);
473482 hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
474483 hdr->disable_residual_flag = get_bits1(gb);
475484 }
@@ -481,6 +490,17 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 5 unmodified lines
481490 }
482491
483492 vdr_dm_metadata_present = get_bits1(gb);
493+ if (dm_compression > 1) {
494+ /* It seems no device supports this */
495+ av_log(s->logctx, AV_LOG_ERROR, "Dynamic metadata compression is not "
496+ "yet implemented");
497+ return AVERROR_PATCHWELCOME;
498+ } else if (dm_compression && !vdr_dm_metadata_present) {
499+ av_log(s->logctx, AV_LOG_ERROR, "Nonzero DM metadata compression method "
500+ "but no DM metadata present");
501+ return AVERROR_INVALIDDATA;
502+ }
503+
484504 use_prev_vdr_rpu = get_bits1(gb);
485505 use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
486506
@@ -503,6 +523,12 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 16 unmodified lines
503523 "use_prev_vdr_rpu=1\n");
504524 return AVERROR_INVALIDDATA;
505525 }
526+
527+ if (dm_compression && !compression) {
528+ av_log(s->logctx, AV_LOG_ERROR, "Uncompressed RPUs should not use "
529+ "dm_compression=%d\n", dm_compression);
530+ return AVERROR_INVALIDDATA;
531+ }
506532 }
507533
508534 if (use_prev_vdr_rpu) {
@@ -654,46 +680,50 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 145 unmodified lines
654680 s->color = color = s->dm;
655681 color->dm_metadata_id = affected_dm_id;
656682 color->scene_refresh_flag = get_ue_golomb_31(gb);
657− for (int i = 0; i < 9; i++)
658− color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
659− for (int i = 0; i < 3; i++) {
660− int denom = profile == 4 ? (1 << 30) : (1 << 28);
661− unsigned offset = get_bits_long(gb, 32);
662− if (offset > INT_MAX) {
663− /* Ensure the result fits inside AVRational */
664− offset >>= 1;
665− denom >>= 1;
683+ if (!dm_compression) {
684+ for (int i = 0; i < 9; i++)
685+ color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
686+ for (int i = 0; i < 3; i++) {
687+ int denom = profile == 4 ? (1 << 30) : (1 << 28);
688+ unsigned offset = get_bits_long(gb, 32);
689+ if (offset > INT_MAX) {
690+ /* Ensure the result fits inside AVRational */
691+ offset >>= 1;
692+ denom >>= 1;
693+ }
694+ color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
666695 }
667− color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
696+ for (int i = 0; i < 9; i++)
697+ color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14);
698+
699+ color->signal_eotf = get_bits(gb, 16);
700+ color->signal_eotf_param0 = get_bits(gb, 16);
701+ color->signal_eotf_param1 = get_bits(gb, 16);
702+ color->signal_eotf_param2 = get_bits_long(gb, 32);
703+ color->signal_bit_depth = get_bits(gb, 5);
704+ VALIDATE(color->signal_bit_depth, 8, 16);
705+ color->signal_color_space = get_bits(gb, 2);
706+ color->signal_chroma_format = get_bits(gb, 2);
707+ color->signal_full_range_flag = get_bits(gb, 2);
708+ color->source_min_pq = get_bits(gb, 12);
709+ color->source_max_pq = get_bits(gb, 12);
710+ color->source_diagonal = get_bits(gb, 10);
668711 }
669− for (int i = 0; i < 9; i++)
670− color->rgb_to_lms_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 14);
671−
672− color->signal_eotf = get_bits(gb, 16);
673− color->signal_eotf_param0 = get_bits(gb, 16);
674− color->signal_eotf_param1 = get_bits(gb, 16);
675− color->signal_eotf_param2 = get_bits_long(gb, 32);
676− color->signal_bit_depth = get_bits(gb, 5);
677− VALIDATE(color->signal_bit_depth, 8, 16);
678− color->signal_color_space = get_bits(gb, 2);
679− color->signal_chroma_format = get_bits(gb, 2);
680− color->signal_full_range_flag = get_bits(gb, 2);
681− color->source_min_pq = get_bits(gb, 12);
682− color->source_max_pq = get_bits(gb, 12);
683− color->source_diagonal = get_bits(gb, 10);
684712
685713 /* Parse extension blocks */
686714 if (s->ext_blocks) {
687715 DOVIExt *ext = s->ext_blocks;
688− ext->num_static = ext->num_dynamic = 0;
716+ if (!dm_compression)
717+ ext->num_static = 0;
718+ ext->num_dynamic = 0;
689719 }
690− if ((ret = parse_ext_blocks(s, gb, 1)) < 0) {
720+ if ((ret = parse_ext_blocks(s, gb, 1, dm_compression, err_recognition)) < 0) {
691721 ff_dovi_ctx_unref(s);
692722 return ret;
693723 }
694724
695725 if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) {
696− if ((ret = parse_ext_blocks(s, gb, 2)) < 0) {
726+ if ((ret = parse_ext_blocks(s, gb, 2, dm_compression, err_recognition)) < 0) {
697727 ff_dovi_ctx_unref(s);
698728 return ret;
699729 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t