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

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
281 return 0;281 return 0;
282}282}
283 283
284static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver)284static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver,
285 int compression, int err_recognition)
285{286{
286 int num_ext_blocks, ext_block_length, start_pos, parsed_bits, ret;287 int num_ext_blocks, ext_block_length, start_pos, parsed_bits, ret;
287 DOVIExt *ext = s->ext_blocks;288 DOVIExt *ext = s->ext_blocks;
@@ -296,6 +297,7 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) · 8 unmodified lines
296 }297 }
297 298
298 while (num_ext_blocks--) {299 while (num_ext_blocks--) {
300 AVDOVIDmData dummy;
299 AVDOVIDmData *dm;301 AVDOVIDmData *dm;
300 uint8_t level;302 uint8_t level;
301 303
@@ -304,9 +306,17 @@ static int parse_ext_blocks(DOVIContext *s, GetBitContext *gb, int ver) · 2 unmodified lines
304 start_pos = get_bits_count(gb);306 start_pos = get_bits_count(gb);
305 307
306 if (ff_dovi_rpu_extension_is_static(level)) {308 if (ff_dovi_rpu_extension_is_static(level)) {
307 if (ext->num_static >= FF_ARRAY_ELEMS(ext->dm_static))309 if (compression) {
308 return AVERROR_INVALIDDATA;310 av_log(s->logctx, AV_LOG_WARNING, "Compressed DM RPU contains "
309 dm = &ext->dm_static[ext->num_static++];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 }
310 } else {320 } else {
311 if (ext->num_dynamic >= FF_ARRAY_ELEMS(ext->dm_dynamic))321 if (ext->num_dynamic >= FF_ARRAY_ELEMS(ext->dm_dynamic))
312 return AVERROR_INVALIDDATA;322 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
342 uint8_t rpu_type;352 uint8_t rpu_type;
343 uint8_t vdr_seq_info_present;353 uint8_t vdr_seq_info_present;
344 uint8_t vdr_dm_metadata_present;354 uint8_t vdr_dm_metadata_present;
355 uint8_t dm_compression = 0;
345 uint8_t use_prev_vdr_rpu;356 uint8_t use_prev_vdr_rpu;
346 uint8_t use_nlq;357 uint8_t use_nlq;
347 uint8_t profile;358 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
454 int bl_bit_depth_minus8 = get_ue_golomb_31(gb);465 int bl_bit_depth_minus8 = get_ue_golomb_31(gb);
455 int el_bit_depth_minus8 = get_ue_golomb_long(gb);466 int el_bit_depth_minus8 = get_ue_golomb_long(gb);
456 int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);467 int vdr_bit_depth_minus8 = get_ue_golomb_31(gb);
457 int reserved_zero_3bits;
458 /* ext_mapping_idc is in the upper 8 bits of el_bit_depth_minus8 */468 /* ext_mapping_idc is in the upper 8 bits of el_bit_depth_minus8 */
459 int ext_mapping_idc = el_bit_depth_minus8 >> 8;469 int ext_mapping_idc = el_bit_depth_minus8 >> 8;
460 el_bit_depth_minus8 = el_bit_depth_minus8 & 0xFF;470 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
468 hdr->ext_mapping_idc_5_7 = ext_mapping_idc >> 5;478 hdr->ext_mapping_idc_5_7 = ext_mapping_idc >> 5;
469 hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;479 hdr->vdr_bit_depth = vdr_bit_depth_minus8 + 8;
470 hdr->spatial_resampling_filter_flag = get_bits1(gb);480 hdr->spatial_resampling_filter_flag = get_bits1(gb);
471 reserved_zero_3bits = get_bits(gb, 3);481 dm_compression = get_bits(gb, 3);
472 VALIDATE(reserved_zero_3bits, 0, 0);
473 hdr->el_spatial_resampling_filter_flag = get_bits1(gb);482 hdr->el_spatial_resampling_filter_flag = get_bits1(gb);
474 hdr->disable_residual_flag = get_bits1(gb);483 hdr->disable_residual_flag = get_bits1(gb);
475 }484 }
@@ -481,6 +490,17 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 5 unmodified lines
481 }490 }
482 491
483 vdr_dm_metadata_present = get_bits1(gb);492 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
484 use_prev_vdr_rpu = get_bits1(gb);504 use_prev_vdr_rpu = get_bits1(gb);
485 use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;505 use_nlq = (hdr->rpu_format & 0x700) == 0 && !hdr->disable_residual_flag;
486 506
@@ -503,6 +523,12 @@ int ff_dovi_rpu_parse(DOVIContext *s, const uint8_t *rpu, size_t rpu_size, · 16 unmodified lines
503 "use_prev_vdr_rpu=1\n");523 "use_prev_vdr_rpu=1\n");
504 return AVERROR_INVALIDDATA;524 return AVERROR_INVALIDDATA;
505 }525 }
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 }
506 }532 }
507 533
508 if (use_prev_vdr_rpu) {534 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
654 s->color = color = s->dm;680 s->color = color = s->dm;
655 color->dm_metadata_id = affected_dm_id;681 color->dm_metadata_id = affected_dm_id;
656 color->scene_refresh_flag = get_ue_golomb_31(gb);682 color->scene_refresh_flag = get_ue_golomb_31(gb);
657 for (int i = 0; i < 9; i++)683 if (!dm_compression) {
658 color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);684 for (int i = 0; i < 9; i++)
659 for (int i = 0; i < 3; i++) {685 color->ycc_to_rgb_matrix[i] = av_make_q(get_sbits(gb, 16), 1 << 13);
660 int denom = profile == 4 ? (1 << 30) : (1 << 28);686 for (int i = 0; i < 3; i++) {
661 unsigned offset = get_bits_long(gb, 32);687 int denom = profile == 4 ? (1 << 30) : (1 << 28);
662 if (offset > INT_MAX) {688 unsigned offset = get_bits_long(gb, 32);
663 /* Ensure the result fits inside AVRational */689 if (offset > INT_MAX) {
664 offset >>= 1;690 /* Ensure the result fits inside AVRational */
665 denom >>= 1;691 offset >>= 1;
692 denom >>= 1;
693 }
694 color->ycc_to_rgb_offset[i] = av_make_q(offset, denom);
666 }695 }
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);
668 }711 }
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);
684 712
685 /* Parse extension blocks */713 /* Parse extension blocks */
686 if (s->ext_blocks) {714 if (s->ext_blocks) {
687 DOVIExt *ext = s->ext_blocks;715 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;
689 }719 }
690 if ((ret = parse_ext_blocks(s, gb, 1)) < 0) {720 if ((ret = parse_ext_blocks(s, gb, 1, dm_compression, err_recognition)) < 0) {
691 ff_dovi_ctx_unref(s);721 ff_dovi_ctx_unref(s);
692 return ret;722 return ret;
693 }723 }
694 724
695 if (get_bits_left(gb) > 48 /* padding + CRC32 + terminator */) {725 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) {
697 ff_dovi_ctx_unref(s);727 ff_dovi_ctx_unref(s);
698 return ret;728 return ret;
699 }729 }

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