From 00e8f1ec08367051e4a2a8c176cba02b1e53a3a4 Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Sun, 14 Sep 2025 04:20:18 +0800 Subject: [PATCH 1/6] HEVC: Parse Dolby Vision RPU and EL --- Source/MediaInfo/Video/File_Hevc.cpp | 613 +++++++++++++++++++++++++++ Source/MediaInfo/Video/File_Hevc.h | 6 + 2 files changed, 619 insertions(+) diff --git a/Source/MediaInfo/Video/File_Hevc.cpp b/Source/MediaInfo/Video/File_Hevc.cpp index bed76176bf..7f8b5aa022 100644 --- a/Source/MediaInfo/Video/File_Hevc.cpp +++ b/Source/MediaInfo/Video/File_Hevc.cpp @@ -1344,6 +1344,8 @@ void File_Hevc::Data_Parse() case 39 : case 40 : sei(); break; + case 62 : Dolby_Vision_reference_processing_unit(); break; + case 63 : Dolby_Vision_enhancement_layer(); break; default : Skip_XX(Element_Size-Element_Offset, "Data"); if (Element_Code>=48) @@ -3761,6 +3763,617 @@ void File_Hevc::three_dimensional_reference_displays_info(int32u payloadSize) FILLING_END(); } +//--------------------------------------------------------------------------- +// Packet "62" +void File_Hevc::Dolby_Vision_reference_processing_unit() +{ + int8u nal_prefix; + Peek_B1(nal_prefix); + if (nal_prefix != 25) { + Skip_XX(Element_Size - Element_Offset, "Data"); + Trusted_IsNot("Unspecified"); + return; + } + + Element_Name("Dolby Vision Reference Processing Unit (RPU)"); + + #define UNSUPPORTED() \ + BS_End(); \ + Skip_XX(Element_Size - Element_Offset, "Data"); \ + Trusted_IsNot("Unsupported"); \ + return; + + auto CRC32_Init{ [](int32u* Table, int32u Polynomial) -> void { + for (size_t Pos = 0; Pos < 256; ++Pos) { + Table[Pos] = static_cast(Pos) << 24; + for (int8u bit = 0; bit < 8; ++bit) { + if (Table[Pos] & 0x80000000) + Table[Pos] = (Table[Pos] << 1) ^ Polynomial; + else + Table[Pos] = Table[Pos] << 1; + } + } + } + }; + + auto DV_content_type{ [](int8u content_type) -> const char* { + switch (content_type) { + case 0: return "Default"; + case 1: return "Movies"; + case 2: return "Game"; + case 3: return "Sport"; + case 4: return "User Generated Content"; + default: return ""; + } + } + }; + + auto DV_white_point{ [](int8u white_point) -> const char* { + switch (white_point) { + case 0: return "D65"; + case 8: return "D93"; + default: return ""; + } + } + }; + + auto DV_intended_setting{ [](int8u setting, bool off) -> const char* { + switch (setting) { + case 0: return "Default"; + case 1: return off ? "Off" : "Low"; + case 2: return "Medium"; + case 3: return "High"; + default: return ""; + } + } + }; + + //Parsing + Skip_B1 ( "nal_prefix"); + + Element_Begin1("rpu_data"); + auto Element_Offset_Begin{ Element_Offset }; + BS_Begin(); + + // EDR RPU header + Element_Begin1("rpu_data_header"); + int8u rpu_type; + int16u rpu_format; + Get_S1 ( 6, rpu_type, "rpu_type"); + Get_S2 (11, rpu_format, "rpu_format"); + if (rpu_type != 2 || (rpu_format & 0x700) != 0) { + UNSUPPORTED(); + } + // if (rpu_type == 2) { + // EDR RPU frame header + int32u coefficient_log2_denom, bl_bit_depth_minus8, el_bit_depth_minus8; + int8u dm_compression, coefficient_data_type; + bool disable_residual_flag; + Skip_S1( 4, "vdr_rpu_profile"); + Skip_S1( 4, "vdr_rpu_level"); + TESTELSE_SB_SKIP( "vdr_seq_info_present_flag"); + // EDR RPU sequence header + Skip_SB( "chroma_resampling_explicit_filter_flag"); + Get_S1 (2, coefficient_data_type, "coefficient_data_type"); + switch (coefficient_data_type) { + case 0: //COEFF_FIXED + Get_UE(coefficient_log2_denom, "coefficient_log2_denom"); + break; + case 1: //COEFF_FLOAT + break; + } + Skip_S1(2, "vdr_rpu_normalized_idc"); + Skip_SB( "BL_video_full_range_flag"); + if ((rpu_format & 0x700) == 0) { + // sequence header + Get_UE (bl_bit_depth_minus8, "BL_bit_depth_minus8"); + Get_UE (el_bit_depth_minus8, "EL_bit_depth_minus8"); + Skip_UE( "vdr_bit_depth_minus8"); + Skip_SB( "spatial_resampling_filter_flag"); + Get_S1 (3, dm_compression, "dm_compression"); + Skip_SB( "el_spatial_resampling_filter_flag"); + Get_SB (disable_residual_flag, "disable_residual_flag"); + } + TESTELSE_SB_ELSE("vdr_seq_info_present"); + UNSUPPORTED(); + TESTELSE_SB_END(); + bool use_prev_vdr_rpu_flag, vdr_dm_metadata_present_flag; + Get_SB (vdr_dm_metadata_present_flag, "vdr_dm_metadata_present_flag"); + Get_SB (use_prev_vdr_rpu_flag, "use_prev_vdr_rpu_flag"); + if (use_prev_vdr_rpu_flag) { + Skip_UE( "prev_vdr_rpu_id"); + } + else { + int32u num_pivots_minus_2[3]{}; + Skip_UE( "vdr_rpu_id"); + Skip_UE( "mapping_color_space"); + Skip_UE( "mapping_chroma_format_idc"); + // pivot points for BL three components + for (int8u cmp = 0; cmp < 3; ++cmp) { + Get_UE(num_pivots_minus_2[cmp], ("num_pivots_minus_2[" + to_string(cmp) + "]").c_str()); + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 2; ++pivot_idx) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, ("pred_pivot_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + } + auto use_nlq{ (rpu_format & 0x700) == 0 && !disable_residual_flag }; + int8u nlq_method_idc; + if (use_nlq) { + // vl.x architecture EL specific + Get_S1(3, nlq_method_idc, "nlq_method_idc"); + for (int8u i = 0; i < 2; ++i) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, "nlq_pred_pivot_value"); + } + } + Skip_UE( "num_x_partitions_minus1"); + Skip_UE( "num_y_partitions_minus1"); + // } + Element_End0(); // rpu_data_header / EDR RPU header + + // if (rpu_type == 2) { + // EDR RPU data + Element_Begin1("vdr_rpu_data_payload"); + Element_Begin1("rpu_data_mapping"); + for (int8u cmp = 0; cmp < 3; ++cmp) { + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 1; ++pivot_idx) { + Element_Begin1("rpu_data_mapping_param"); + int32u mapping_idc; + Get_UE(mapping_idc, ("mapping_idc[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + switch (mapping_idc) { + case 0: //MAPPING_POLYNOMIAL + { + // Polynomial coefficients + int32u poly_order_minus1; + bool linear_interp_flag{}; + Get_UE(poly_order_minus1, ("poly_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0) + Get_SB(linear_interp_flag, ("linear_interp_flag[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0 && linear_interp_flag) { + // Linear interpolation + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (pivot_idx == num_pivots_minus_2[cmp]) { + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + } + else { + // Non-linear + // the i-th order + for (int32u i = 0; i <= poly_order_minus1 + 1; ++i) { + if (coefficient_data_type == 0) { + Skip_SE( ("poly_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + else + Skip_S4(32, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + } + break; + } + case 1: //MAPPING_MMR + { + // MR coefficients + int8u mmr_order_minus1; + Get_S1(2, mmr_order_minus1, ("mmr_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_constant_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + // the i-th order + for (int8u i = 1; i <= mmr_order_minus1 + 1; ++i) { + // the j-th coefficients + for (int8u j = 0; j < 7; ++j) { + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + } + break; + } + } + Element_End0(); // rpu_data_mapping_param + } + } + Element_End0(); // rpu_data_mapping + if (use_nlq) { + Element_Begin1("rpu_data_nlq"); + bool isMEL{ true }; + // nlq_num_pivots_minus2 == 0 so no pivot_idx loop + for (int8u cmp = 0; cmp < 3; ++cmp) { + // Nonlinear Quantization Parameters + Element_Begin1("rpu_data_nlq_param"); + int16u nlq_offset; + int32u vdr_in_max_int, vdr_in_max, linear_deadzone_slope_int, linear_deadzone_slope, linear_deadzone_threshold_int, linear_deadzone_threshold; + Get_S2(static_cast(el_bit_depth_minus8) + 8, nlq_offset, ("nlq_offset[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(vdr_in_max_int, ("vdr_in_max_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + switch (nlq_method_idc) { + case 0: //NLQ_LINEAR_DZ + // Linear dead zone coefficients + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_slope_int, ("linear_deadzone_slope_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_threshold_int, ("linear_deadzone_threshold_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_threshold, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + break; + } + if ((nlq_offset | vdr_in_max | linear_deadzone_slope_int | linear_deadzone_slope | linear_deadzone_threshold_int | linear_deadzone_threshold) != 0 || vdr_in_max_int != 1) + isMEL = false; + Element_End0(); // rpu_data_nlq_param + } + + // TEMPORARY ========================================================================== + if (isMEL) + Param2("EL Type", "Minimum Enhancement Layer (MEL)"); + else + Param2("EL Type", "Full Enhancement Layer (FEL / non-MEL)"); + // end TEMPORARY ====================================================================== + + Element_End0(); // rpu_data_nlq + } + + } + // } + Element_End0(); // vdr_rpu_data_payload + + // Display Management + if (vdr_dm_metadata_present_flag) { + Element_Begin1("vdr_dm_data_payload"); + Skip_UE( "affected_dm_metadata_id"); + Skip_UE( "current_dm_metadata_id"); + Skip_UE( "scene_refresh_flag"); + if (dm_compression) { + UNSUPPORTED(); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("YCCtoRGB_coef" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 3; ++i) { + Skip_S4(32, ("YCCtoRGB_offset" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("RGBtoLMS_coef" + to_string(i)).c_str()); + } + Skip_S2(16, "signal_eotf"); + Skip_S2(16, "signal_eotf_param0"); + Skip_S2(16, "signal_eotf_param1"); + Skip_S4(32, "signal_eotf_param2"); + Skip_S1( 5, "signal_bit_depth"); + Skip_S1( 2, "signal_color_space"); + Skip_S1( 2, "signal_chroma_format"); + Skip_S1( 2, "signal_full_range_flag"); + Skip_S2(12, "source_min_PQ"); + Skip_S2(12, "source_max_PQ"); + Skip_S2(10, "source_diagonal"); + + // Extension blocks + // ---------------------------------------------------------------------------------------- + + // Content Mapping v2.9 (CMv2.9) + int32u num_ext_blocks; + Get_UE(num_ext_blocks, "num_ext_blocks"); + if (num_ext_blocks) { + Skip_BS(Data_BS_Remain() & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 1: // ANALYSIS METADATA (DYNAMIC) + Skip_S2(12, "min_PQ"); + Skip_S2(12, "max_PQ"); + Skip_S2(12, "avg_PQ"); + ext_block_use_bits += 36; + break; + case 2: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S2(12, "target_max_PQ"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(13, "ms_weight"); + ext_block_use_bits += 85; + break; + case 4: + Skip_S2(12, "anchor_pq"); + Skip_S2(12, "anchor_power"); + ext_block_use_bits += 24; + break; + case 5: // PER-SHOT ASPECT RATIO (DYNAMIC) + Skip_S2(13, "active_area_left_offset"); + Skip_S2(13, "active_area_right_offset"); + Skip_S2(13, "active_area_top_offset"); + Skip_S2(13, "active_area_bottom_offset"); + ext_block_use_bits += 52; + break; + case 6: // OPTIONAL HDR10 METADATA (STATIC) + Skip_S2(16, "max_display_mastering_luminance"); + Skip_S2(16, "min_display_mastering_luminance"); + Skip_S2(16, "max_content_light_level"); + Skip_S2(16, "max_frame_average_light_level"); + ext_block_use_bits += 64; + break; + case 255: + Skip_S1(8, "dm_run_mode"); + Skip_S1(8, "dm_run_version"); + Skip_S1(8, "dm_debug0"); + Skip_S1(8, "dm_debug1"); + Skip_S1(8, "dm_debug2"); + Skip_S1(8, "dm_debug3"); + ext_block_use_bits += 48; + break; + default: + Skip_BS(ext_block_len_bits - ext_block_use_bits, "(Not parsed)"); + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + + // Content Mapping v4.0 (CMv4.0) + if (Data_BS_Remain() >= 56) { + int32u num_ext_blocks2; + Get_UE(num_ext_blocks2, "num_ext_blocks"); + if (num_ext_blocks2) { + Skip_BS(Data_BS_Remain() & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks2; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 3: // OFFSETS TO L1 (DYNAMIC) + Skip_S2(12, "min_pq_offset"); + Skip_S2(12, "max_pq_offset"); + Skip_S2(12, "avg_pq_offset"); + ext_block_use_bits += 36; + break; + case 8: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(12, "ms_weight"); + ext_block_use_bits += 80; + if (ext_block_length > 10) { + Skip_S2(12, "target_mid_contrast"); + ext_block_use_bits += 12; + } + if (ext_block_length > 12) { + Skip_S2(12, "clip_trim"); + ext_block_use_bits += 12; + } + if (ext_block_length > 13) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("saturation_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + if (ext_block_length > 19) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("hue_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + break; + case 9: // PER-SHOT SOURCE CONTENT PRIMARIES (DYNAMIC) + Skip_S1(8, "source_primary_index"); + ext_block_use_bits += 8; + if (ext_block_length > 1) { + Skip_S2(16, "source_primary_red_x"); + Skip_S2(16, "source_primary_red_y"); + Skip_S2(16, "source_primary_green_x"); + Skip_S2(16, "source_primary_green_y"); + Skip_S2(16, "source_primary_blue_x"); + Skip_S2(16, "source_primary_blue_y"); + Skip_S2(16, "source_primary_white_x"); + Skip_S2(16, "source_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 10: + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "target_max_pq"); + Skip_S2(12, "target_min_pq"); + Skip_S1( 8, "target_primary_index"); + ext_block_use_bits += 40; + if (ext_block_length > 5) { + Skip_S2(16, "target_primary_red_x"); + Skip_S2(16, "target_primary_red_y"); + Skip_S2(16, "target_primary_green_x"); + Skip_S2(16, "target_primary_green_y"); + Skip_S2(16, "target_primary_blue_x"); + Skip_S2(16, "target_primary_blue_y"); + Skip_S2(16, "target_primary_white_x"); + Skip_S2(16, "target_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 11: + { // Automatic Picture/Playback Optimization (APO) / Dolby Vision IQ - Content Type Metadata (L11) + int8u content_type, white_point, sharpness, noise_reduction, mpeg_noise_reduction, frame_rate_conversion, brightness, color; + Get_S1 (8, content_type, "content_type"); Param_Info1(DV_content_type(content_type)); + Get_S1 (4, white_point, "white_point"); Param_Info1(DV_white_point(white_point)); + Skip_SB( "reference_mode_flag"); + Skip_S1(3, "reserved"); + Get_S1 (2, sharpness, "sharpness"); Param_Info1(DV_intended_setting(sharpness, true)); + Get_S1 (2, noise_reduction, "noise_reduction"); Param_Info1(DV_intended_setting(noise_reduction, true)); + Get_S1 (2, mpeg_noise_reduction, "mpeg_noise_reduction"); Param_Info1(DV_intended_setting(mpeg_noise_reduction, true)); + Get_S1 (2, frame_rate_conversion, "frame_rate_conversion"); Param_Info1(DV_intended_setting(frame_rate_conversion, true)); + Get_S1 (2, brightness, "brightness"); Param_Info1(DV_intended_setting(brightness, false)); + Get_S1 (2, color, "color"); Param_Info1(DV_intended_setting(color, false)); + Skip_S1(2, "reserved1"); + Skip_S1(2, "reserved2"); + ext_block_use_bits += 32; + break; + } + case 254: // CM version + Skip_S1(8, "dm_mode"); + Skip_S1(8, "dm_version_index"); + ext_block_use_bits += 16; + break; + default: + Skip_BS(ext_block_len_bits, "(Not parsed)"); + ext_block_use_bits += ext_block_len_bits; + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + } + Element_End0(); // vdr_dm_data_payload + } + + Skip_BS(Data_BS_Remain() & 7, "rpu_alignment_zero_bit"); + BS_End(); + Skip_B4( "rpu_data_crc32"); + if (!CRC_32_Table_IEEE) { + CRC_32_Table_IEEE.reset(new int32u[256]); + CRC32_Init(CRC_32_Table_IEEE.get(), 0x04C11DB7); + } + int32u CRC_32 = 0xFFFFFFFF; + const int8u* CRC_32_Buffer = Buffer + Buffer_Offset + Element_Offset_Begin; + while (CRC_32_Buffer < Buffer + Buffer_Offset + Element_Offset) { + CRC_32 = (CRC_32 << 8) ^ CRC_32_Table_IEEE[(CRC_32 >> 24) ^ (*CRC_32_Buffer++)]; + } + Param_Info1(CRC_32 ? "NOK" : "OK"); + Element_End0(); // rpu_data + + BS_Begin(); + Mark_1(); // rbsp_stop_one_bit + BS_End(); + + #undef UNSUPPORTED +} + +//--------------------------------------------------------------------------- +// Packet "63" +void File_Hevc::Dolby_Vision_enhancement_layer() +{ +#if MEDIAINFO_TRACE + + Element_Name("Dolby Vision Enhancement Layer (EL)"); + + Element_Begin0(); + Element_Begin1("Header"); + int8u nal_unit_type; + BS_Begin(); + Mark_0(); + Get_S1 (6, nal_unit_type, "nal_unit_type"); + Skip_S1(6, "nuh_layer_id"); + Skip_S1(3, "nuh_temporal_id_plus1"); + BS_End(); + Element_End0(); + + switch (nal_unit_type) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + Element_Name("slice_segment_layer"); break; + case 32: Element_Name("video_parameter_set"); break; + case 33: Element_Name("seq_parameter_set"); break; + case 34: Element_Name("pic_parameter_set"); break; + case 35: + { + Element_Name("access_unit_delimiter"); + BS_Begin(); + Info_S1(3, pic_type, "pic_type"); Param_Info1(Hevc_pic_type[pic_type]); + Mark_1(); + BS_End(); + break; + } + case 36: Element_Name("end_of_seq"); break; + case 37: Element_Name("end_of_bitstream"); break; + case 38: Element_Name("filler_data"); break; + case 39: + case 40: + { + Element_Name("sei"); + Element_Begin1("sei message header"); + int8u payload_type_byte; + Get_B1 (payload_type_byte, "payload_type_byte"); + Skip_B1( "payload_size_byte"); + Element_End0(); + switch (payload_type_byte) + { + case 0: Element_Info1("buffering_period"); break; + case 1: Element_Info1("pic_timing"); break; + case 4: Element_Info1("user_data_registered_itu_t_t35"); break; + case 5: Element_Info1("user_data_unregistered"); break; + case 6: Element_Info1("recovery_point"); break; + case 129: Element_Info1("active_parameter_sets"); break; + case 132: Element_Info1("decoded_picture_hash"); break; + case 136: Element_Info1("time_code"); break; + case 137: Element_Info1("mastering_display_colour_volume"); break; + case 144: Element_Info1("light_level"); break; + case 147: Element_Info1("transfer_characteristics"); break; + case 148: Element_Info1("viewing_environment"); break; + case 176: Element_Info1("three_dimensional_reference_displays_info"); break; + default : Element_Info1(Ztring().From_CC1(payload_type_byte)); break; + } + break; + } + default: Element_Name(Ztring().From_CC1(nal_unit_type)); break; + } + Skip_XX(Element_Size - Element_Offset, "Data"); + Element_End0(); + +#endif // MEDIAINFO_TRACE +} + //*************************************************************************** // Sub-elements //*************************************************************************** diff --git a/Source/MediaInfo/Video/File_Hevc.h b/Source/MediaInfo/Video/File_Hevc.h index e2477f90d6..6a90f8e7bd 100644 --- a/Source/MediaInfo/Video/File_Hevc.h +++ b/Source/MediaInfo/Video/File_Hevc.h @@ -12,6 +12,7 @@ //--------------------------------------------------------------------------- #include "MediaInfo/File__Analyze.h" #include "MediaInfo/TimeCode.h" +#include //--------------------------------------------------------------------------- namespace MediaInfoLib @@ -412,6 +413,8 @@ private : void sei_alternative_transfer_characteristics(); void sei_ambient_viewing_environment(); void three_dimensional_reference_displays_info(int32u payloadSize); + void Dolby_Vision_reference_processing_unit(); + void Dolby_Vision_enhancement_layer(); //Packets - SubElements void slice_segment_header(); @@ -530,6 +533,9 @@ private : Ztring ambient_viewing_environment_chromaticity; bool RapPicFlag{}; bool first_slice_segment_in_pic_flag{}; + + //CRC Tables + std::unique_ptr CRC_32_Table_IEEE; }; } //NameSpace From f7d427f82562efb71da2cdc7d0e6cd713c8dc129 Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Tue, 16 Sep 2025 01:16:32 +0800 Subject: [PATCH 2/6] AV1: Parse Dolby Vision RPU --- Source/MediaInfo/Video/File_Av1.cpp | 705 +++++++++++++++++++++++++++- Source/MediaInfo/Video/File_Av1.h | 3 + 2 files changed, 706 insertions(+), 2 deletions(-) diff --git a/Source/MediaInfo/Video/File_Av1.cpp b/Source/MediaInfo/Video/File_Av1.cpp index 36005b916d..b9dadd5ff6 100644 --- a/Source/MediaInfo/Video/File_Av1.cpp +++ b/Source/MediaInfo/Video/File_Av1.cpp @@ -632,7 +632,7 @@ void File_Av1::metadata_itu_t_t35() switch (itu_t_t35_country_code) { - case 0xB5: metadata_itu_t_t35_B5(); break; // USA + case 0xB5: Param_Info1("United States"); metadata_itu_t_t35_B5(); break; } } @@ -644,10 +644,711 @@ void File_Av1::metadata_itu_t_t35_B5() switch (itu_t_t35_terminal_provider_code) { - case 0x003C: metadata_itu_t_t35_B5_003C(); break; + case 0x003B: Param_Info1("Dolby Laboratories, Inc."); metadata_itu_t_t35_B5_003B(); break; + case 0x003C: Param_Info1("Samsung Electronics America"); metadata_itu_t_t35_B5_003C(); break; } } +//--------------------------------------------------------------------------- +void File_Av1::metadata_itu_t_t35_B5_003B() +{ + int32u itu_t_t35_terminal_provider_oriented_code; + Get_B4(itu_t_t35_terminal_provider_oriented_code, "itu_t_t35_terminal_provider_oriented_code"); + + switch (itu_t_t35_terminal_provider_oriented_code) + { + case 0x00000800: metadata_itu_t_t35_B5_003B_00000800(); break; + } + +} + +//--------------------------------------------------------------------------- +void File_Av1::metadata_itu_t_t35_B5_003B_00000800() +{ + Element_Info1("Extensible Metadata Delivery Format (EMDF)"); + + auto Get_V4{ [this](int8u Bits, int32u& Info, const char* Name) + { + Info = 0; + + #if MEDIAINFO_TRACE + int8u Count = 0; + #endif //MEDIAINFO_TRACE + for (;;) + { + Info += BS->Get4(Bits); + #if MEDIAINFO_TRACE + Count += Bits; + #endif //MEDIAINFO_TRACE + if (!BS->GetB()) + break; + Info <<= Bits; + Info += (1 << Bits); + } + #if MEDIAINFO_TRACE + if (Trace_Activated) + { + Param(Name, Info, Count); + Param_Info(__T("(") + Ztring::ToZtring(Count) + __T(" bits)")); + } + #endif //MEDIAINFO_TRACE + } + }; + + auto Skip_V4{ [&](int8u Bits, const char* Name) { + int32u Info; + Get_V4(Bits, Info, Name); + } + }; + + BS_Begin(); + size_t Start = Data_BS_Remain(); + int32u version, key_id; + Element_Begin1("emdf_container"); + Get_S4 (2, version, "emdf_version"); + if (version == 3) + { + int32u add; + Get_V4(2, add, "emdf_version addition"); + version += add; + } + if (version) + { + Skip_BS(Data_BS_Remain(), "(Unparsed emdf_container data)"); + Element_End0(); + return; + } + + Get_S4 (3, key_id, "key_id"); + if (key_id == 7) + { + int32u add; + Get_V4 (3, add, "key_id addition"); + key_id += add; + } + Param_Info1C(key_id == 0x6, "Ignore protection bits"); + + int32u emdf_payload_id = 0; + + for(;;) + { + Element_Begin1("emdf_payload"); + Get_S4 (5, emdf_payload_id, "emdf_payload_id"); + if (emdf_payload_id==0x1F) + { + int32u add; + Get_V4 (5, add, "emdf_payload_id addition"); + emdf_payload_id += add; + } + + if (emdf_payload_id == 256) + Element_Info1("Dolby Vision Reference Processing Unit (RPU)"); + if (emdf_payload_id == 0x00) + { + Element_End0(); + break; + } + + Element_Begin1("emdf_payload_config"); + + bool smploffste = false; + Get_SB (smploffste, "smploffste"); + if (smploffste) + { + Skip_S2(11, "smploffst"); + Skip_SB( "reserved"); + } + + TEST_SB_SKIP( "duratione"); + Skip_V4(11, "duration"); + TEST_SB_END(); + TEST_SB_SKIP( "groupide"); + Skip_V4(2, "groupid"); + TEST_SB_END(); + TEST_SB_SKIP( "codecdatae"); + Skip_S1(8, "reserved"); + TEST_SB_END(); + + bool discard_unknown_payload = false; + Get_SB(discard_unknown_payload, "discard_unknown_payload"); + if (!discard_unknown_payload) + { + bool payload_frame_aligned = false; + if (!smploffste) + { + Get_SB (payload_frame_aligned, "payload_frame_aligned"); + if (payload_frame_aligned) + { + Skip_SB( "create_duplicate"); + Skip_SB( "remove_duplicate"); + } + } + + if (smploffste || payload_frame_aligned) + { + Skip_S1(5, "priority"); + Skip_S1(2, "proc_allowed"); + } + } + + Element_End0(); // emdf_payload_config + + int32u emdf_payload_size = 0; + Get_V4 (8, emdf_payload_size, "emdf_payload_size"); + size_t emdf_payload_End=Data_BS_Remain()-emdf_payload_size*8; + + Element_Begin1("emdf_payload_bytes"); + switch (emdf_payload_id) + { + case 256: Dolby_Vision_reference_processing_unit(); break; + default : Skip_BS(emdf_payload_size * 8, "(Unknown)"); break; + } + size_t RemainginBits=Data_BS_Remain(); + if (RemainginBits>=emdf_payload_End) + { + if (RemainginBits>emdf_payload_End) + Skip_BS(RemainginBits-emdf_payload_End, "(Unparsed bits)"); + } + else + { + //There is a problem, too many bits were consumed by the parser. //TODO: prevent the parser to consume more bits than count of bits in this element + if (Data_BS_Remain()) + Skip_BS(Data_BS_Remain(), "(Problem during emdf_payload parsing)"); + else + Skip_BS(Data_BS_Remain(), "(Problem during emdf_payload parsing, going to end directly)"); + Element_End0(); + Element_End0(); + break; + } + Element_End0(); // emdf_payload_bytes + + Element_End0(); // emdf_payload + } + + Element_Begin1("emdf_protection"); + + int8u len_primary = 0, len_second = 0; + Get_S1(2, len_primary, "protection_length_primary"); + Get_S1(2, len_second, "protection_length_secondary"); + + switch (len_primary) + { + //case 0: break; //protection_length_primary coherency was already tested in sync layer + case 1: len_primary = 8; break; + case 2: len_primary = 32; break; + case 3: len_primary = 128; break; + default:; //Cannot append, read only 2 bits + }; + switch (len_second) + { + case 0: len_second = 0; break; + case 1: len_second = 8; break; + case 2: len_second = 32; break; + case 3: len_second = 128; break; + default:; //Cannot append, read only 2 bits + }; + Skip_BS(len_primary, "protection_bits_primary"); + if (len_second) + Skip_BS(len_primary, "protection_bits_secondary"); + + Element_End0(); // emdf_protection + + Element_End0(); // emdf_container + BS_End(); +} + +//--------------------------------------------------------------------------- +void File_Av1::Dolby_Vision_reference_processing_unit() +{ + using std::to_string; + + #define UNSUPPORTED() \ + BS_End(); \ + Skip_XX(Element_Size - Element_Offset, "Data"); \ + Trusted_IsNot("Unsupported"); \ + return; + + auto DV_content_type{ [](int8u content_type) -> const char* { + switch (content_type) { + case 0: return "Default"; + case 1: return "Movies"; + case 2: return "Game"; + case 3: return "Sport"; + case 4: return "User Generated Content"; + default: return ""; + } + } + }; + + auto DV_white_point{ [](int8u white_point) -> const char* { + switch (white_point) { + case 0: return "D65"; + case 8: return "D93"; + default: return ""; + } + } + }; + + auto DV_intended_setting{ [](int8u setting, bool off) -> const char* { + switch (setting) { + case 0: return "Default"; + case 1: return off ? "Off" : "Low"; + case 2: return "Medium"; + case 3: return "High"; + default: return ""; + } + } + }; + + //Parsing + Element_Begin1("rpu_data"); + auto RemainingBitsBegin = Data_BS_Remain(); + + // EDR RPU header + Element_Begin1("rpu_data_header"); + int8u rpu_type; + int16u rpu_format; + Get_S1 ( 6, rpu_type, "rpu_type"); + Get_S2 (11, rpu_format, "rpu_format"); + if (rpu_type != 2 || (rpu_format & 0x700) != 0) { + UNSUPPORTED(); + } + // if (rpu_type == 2) { + // EDR RPU frame header + int32u coefficient_log2_denom, bl_bit_depth_minus8, el_bit_depth_minus8; + int8u dm_compression, coefficient_data_type; + bool disable_residual_flag; + Skip_S1( 4, "vdr_rpu_profile"); + Skip_S1( 4, "vdr_rpu_level"); + TESTELSE_SB_SKIP( "vdr_seq_info_present_flag"); + // EDR RPU sequence header + Skip_SB( "chroma_resampling_explicit_filter_flag"); + Get_S1 (2, coefficient_data_type, "coefficient_data_type"); + switch (coefficient_data_type) { + case 0: //COEFF_FIXED + Get_UE(coefficient_log2_denom, "coefficient_log2_denom"); + break; + case 1: //COEFF_FLOAT + break; + } + Skip_S1(2, "vdr_rpu_normalized_idc"); + Skip_SB( "BL_video_full_range_flag"); + if ((rpu_format & 0x700) == 0) { + // sequence header + Get_UE (bl_bit_depth_minus8, "BL_bit_depth_minus8"); + Get_UE (el_bit_depth_minus8, "EL_bit_depth_minus8"); + Skip_UE( "vdr_bit_depth_minus8"); + Skip_SB( "spatial_resampling_filter_flag"); + Get_S1 (3, dm_compression, "dm_compression"); + Skip_SB( "el_spatial_resampling_filter_flag"); + Get_SB (disable_residual_flag, "disable_residual_flag"); + } + TESTELSE_SB_ELSE("vdr_seq_info_present"); + UNSUPPORTED(); + TESTELSE_SB_END(); + bool use_prev_vdr_rpu_flag, vdr_dm_metadata_present_flag; + Get_SB (vdr_dm_metadata_present_flag, "vdr_dm_metadata_present_flag"); + Get_SB (use_prev_vdr_rpu_flag, "use_prev_vdr_rpu_flag"); + if (use_prev_vdr_rpu_flag) { + Skip_UE( "prev_vdr_rpu_id"); + } + else { + int32u num_pivots_minus_2[3]{}; + Skip_UE( "vdr_rpu_id"); + Skip_UE( "mapping_color_space"); + Skip_UE( "mapping_chroma_format_idc"); + // pivot points for BL three components + for (int8u cmp = 0; cmp < 3; ++cmp) { + Get_UE(num_pivots_minus_2[cmp], ("num_pivots_minus_2[" + to_string(cmp) + "]").c_str()); + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 2; ++pivot_idx) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, ("pred_pivot_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + } + auto use_nlq{ (rpu_format & 0x700) == 0 && !disable_residual_flag }; + int8u nlq_method_idc; + if (use_nlq) { + // vl.x architecture EL specific + Get_S1(3, nlq_method_idc, "nlq_method_idc"); + for (int8u i = 0; i < 2; ++i) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, "nlq_pred_pivot_value"); + } + } + Skip_UE( "num_x_partitions_minus1"); + Skip_UE( "num_y_partitions_minus1"); + // } + Element_End0(); // rpu_data_header / EDR RPU header + + // if (rpu_type == 2) { + // EDR RPU data + Element_Begin1("vdr_rpu_data_payload"); + Element_Begin1("rpu_data_mapping"); + for (int8u cmp = 0; cmp < 3; ++cmp) { + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 1; ++pivot_idx) { + Element_Begin1("rpu_data_mapping_param"); + int32u mapping_idc; + Get_UE(mapping_idc, ("mapping_idc[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + switch (mapping_idc) { + case 0: //MAPPING_POLYNOMIAL + { + // Polynomial coefficients + int32u poly_order_minus1; + bool linear_interp_flag{}; + Get_UE(poly_order_minus1, ("poly_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0) + Get_SB(linear_interp_flag, ("linear_interp_flag[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0 && linear_interp_flag) { + // Linear interpolation + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (pivot_idx == num_pivots_minus_2[cmp]) { + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + } + else { + // Non-linear + // the i-th order + for (int32u i = 0; i <= poly_order_minus1 + 1; ++i) { + if (coefficient_data_type == 0) { + Skip_SE( ("poly_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + else + Skip_S4(32, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + } + break; + } + case 1: //MAPPING_MMR + { + // MR coefficients + int8u mmr_order_minus1; + Get_S1(2, mmr_order_minus1, ("mmr_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_constant_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + // the i-th order + for (int8u i = 1; i <= mmr_order_minus1 + 1; ++i) { + // the j-th coefficients + for (int8u j = 0; j < 7; ++j) { + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + } + break; + } + } + Element_End0(); // rpu_data_mapping_param + } + } + Element_End0(); // rpu_data_mapping + if (use_nlq) { + Element_Begin1("rpu_data_nlq"); + bool isMEL{ true }; + // nlq_num_pivots_minus2 == 0 so no pivot_idx loop + for (int8u cmp = 0; cmp < 3; ++cmp) { + // Nonlinear Quantization Parameters + Element_Begin1("rpu_data_nlq_param"); + int16u nlq_offset; + int32u vdr_in_max_int, vdr_in_max, linear_deadzone_slope_int, linear_deadzone_slope, linear_deadzone_threshold_int, linear_deadzone_threshold; + Get_S2(static_cast(el_bit_depth_minus8) + 8, nlq_offset, ("nlq_offset[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(vdr_in_max_int, ("vdr_in_max_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + switch (nlq_method_idc) { + case 0: //NLQ_LINEAR_DZ + // Linear dead zone coefficients + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_slope_int, ("linear_deadzone_slope_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_threshold_int, ("linear_deadzone_threshold_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_threshold, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + break; + } + if ((nlq_offset | vdr_in_max | linear_deadzone_slope_int | linear_deadzone_slope | linear_deadzone_threshold_int | linear_deadzone_threshold) != 0 || vdr_in_max_int != 1) + isMEL = false; + Element_End0(); // rpu_data_nlq_param + } + + // TEMPORARY ========================================================================== + if (isMEL) + Param2("EL Type", "Minimum Enhancement Layer (MEL)"); + else + Param2("EL Type", "Full Enhancement Layer (FEL / non-MEL)"); + // end TEMPORARY ====================================================================== + + Element_End0(); // rpu_data_nlq + } + + } + // } + Element_End0(); // vdr_rpu_data_payload + + // Display Management + if (vdr_dm_metadata_present_flag) { + Element_Begin1("vdr_dm_data_payload"); + Skip_UE( "affected_dm_metadata_id"); + Skip_UE( "current_dm_metadata_id"); + Skip_UE( "scene_refresh_flag"); + if (dm_compression) { + UNSUPPORTED(); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("YCCtoRGB_coef" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 3; ++i) { + Skip_S4(32, ("YCCtoRGB_offset" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("RGBtoLMS_coef" + to_string(i)).c_str()); + } + Skip_S2(16, "signal_eotf"); + Skip_S2(16, "signal_eotf_param0"); + Skip_S2(16, "signal_eotf_param1"); + Skip_S4(32, "signal_eotf_param2"); + Skip_S1( 5, "signal_bit_depth"); + Skip_S1( 2, "signal_color_space"); + Skip_S1( 2, "signal_chroma_format"); + Skip_S1( 2, "signal_full_range_flag"); + Skip_S2(12, "source_min_PQ"); + Skip_S2(12, "source_max_PQ"); + Skip_S2(10, "source_diagonal"); + + // Extension blocks + // ---------------------------------------------------------------------------------------- + + // Content Mapping v2.9 (CMv2.9) + int32u num_ext_blocks; + Get_UE(num_ext_blocks, "num_ext_blocks"); + if (num_ext_blocks) { + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 1: // ANALYSIS METADATA (DYNAMIC) + Skip_S2(12, "min_PQ"); + Skip_S2(12, "max_PQ"); + Skip_S2(12, "avg_PQ"); + ext_block_use_bits += 36; + break; + case 2: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S2(12, "target_max_PQ"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(13, "ms_weight"); + ext_block_use_bits += 85; + break; + case 4: + Skip_S2(12, "anchor_pq"); + Skip_S2(12, "anchor_power"); + ext_block_use_bits += 24; + break; + case 5: // PER-SHOT ASPECT RATIO (DYNAMIC) + Skip_S2(13, "active_area_left_offset"); + Skip_S2(13, "active_area_right_offset"); + Skip_S2(13, "active_area_top_offset"); + Skip_S2(13, "active_area_bottom_offset"); + ext_block_use_bits += 52; + break; + case 6: // OPTIONAL HDR10 METADATA (STATIC) + Skip_S2(16, "max_display_mastering_luminance"); + Skip_S2(16, "min_display_mastering_luminance"); + Skip_S2(16, "max_content_light_level"); + Skip_S2(16, "max_frame_average_light_level"); + ext_block_use_bits += 64; + break; + case 255: + Skip_S1(8, "dm_run_mode"); + Skip_S1(8, "dm_run_version"); + Skip_S1(8, "dm_debug0"); + Skip_S1(8, "dm_debug1"); + Skip_S1(8, "dm_debug2"); + Skip_S1(8, "dm_debug3"); + ext_block_use_bits += 48; + break; + default: + Skip_BS(ext_block_len_bits - ext_block_use_bits, "(Not parsed)"); + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + + // Content Mapping v4.0 (CMv4.0) + if (Data_BS_Remain() >= 56) { + int32u num_ext_blocks2; + Get_UE(num_ext_blocks2, "num_ext_blocks"); + if (num_ext_blocks2) { + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks2; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 3: // OFFSETS TO L1 (DYNAMIC) + Skip_S2(12, "min_pq_offset"); + Skip_S2(12, "max_pq_offset"); + Skip_S2(12, "avg_pq_offset"); + ext_block_use_bits += 36; + break; + case 8: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(12, "ms_weight"); + ext_block_use_bits += 80; + if (ext_block_length > 10) { + Skip_S2(12, "target_mid_contrast"); + ext_block_use_bits += 12; + } + if (ext_block_length > 12) { + Skip_S2(12, "clip_trim"); + ext_block_use_bits += 12; + } + if (ext_block_length > 13) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("saturation_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + if (ext_block_length > 19) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("hue_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + break; + case 9: // PER-SHOT SOURCE CONTENT PRIMARIES (DYNAMIC) + Skip_S1(8, "source_primary_index"); + ext_block_use_bits += 8; + if (ext_block_length > 1) { + Skip_S2(16, "source_primary_red_x"); + Skip_S2(16, "source_primary_red_y"); + Skip_S2(16, "source_primary_green_x"); + Skip_S2(16, "source_primary_green_y"); + Skip_S2(16, "source_primary_blue_x"); + Skip_S2(16, "source_primary_blue_y"); + Skip_S2(16, "source_primary_white_x"); + Skip_S2(16, "source_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 10: + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "target_max_pq"); + Skip_S2(12, "target_min_pq"); + Skip_S1( 8, "target_primary_index"); + ext_block_use_bits += 40; + if (ext_block_length > 5) { + Skip_S2(16, "target_primary_red_x"); + Skip_S2(16, "target_primary_red_y"); + Skip_S2(16, "target_primary_green_x"); + Skip_S2(16, "target_primary_green_y"); + Skip_S2(16, "target_primary_blue_x"); + Skip_S2(16, "target_primary_blue_y"); + Skip_S2(16, "target_primary_white_x"); + Skip_S2(16, "target_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 11: + { // Automatic Picture/Playback Optimization (APO) / Dolby Vision IQ - Content Type Metadata (L11) + int8u content_type, white_point, sharpness, noise_reduction, mpeg_noise_reduction, frame_rate_conversion, brightness, color; + Get_S1 (8, content_type, "content_type"); Param_Info1(DV_content_type(content_type)); + Get_S1 (4, white_point, "white_point"); Param_Info1(DV_white_point(white_point)); + Skip_SB( "reference_mode_flag"); + Skip_S1(3, "reserved"); + Get_S1 (2, sharpness, "sharpness"); Param_Info1(DV_intended_setting(sharpness, true)); + Get_S1 (2, noise_reduction, "noise_reduction"); Param_Info1(DV_intended_setting(noise_reduction, true)); + Get_S1 (2, mpeg_noise_reduction, "mpeg_noise_reduction"); Param_Info1(DV_intended_setting(mpeg_noise_reduction, true)); + Get_S1 (2, frame_rate_conversion, "frame_rate_conversion"); Param_Info1(DV_intended_setting(frame_rate_conversion, true)); + Get_S1 (2, brightness, "brightness"); Param_Info1(DV_intended_setting(brightness, false)); + Get_S1 (2, color, "color"); Param_Info1(DV_intended_setting(color, false)); + Skip_S1(2, "reserved1"); + Skip_S1(2, "reserved2"); + ext_block_use_bits += 32; + break; + } + case 254: // CM version + Skip_S1(8, "dm_mode"); + Skip_S1(8, "dm_version_index"); + ext_block_use_bits += 16; + break; + default: + Skip_BS(ext_block_len_bits, "(Not parsed)"); + ext_block_use_bits += ext_block_len_bits; + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + } + Element_End0(); // vdr_dm_data_payload + } + + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "rpu_alignment_zero_bit"); + Skip_S4(32, "rpu_data_crc32"); + Element_End0(); // rpu_data + + Mark_1(); // rbsp_stop_one_bit + Skip_S1(7, "rbsp_alignment_zero_bit"); + + #undef UNSUPPORTED +} + //--------------------------------------------------------------------------- void File_Av1::metadata_itu_t_t35_B5_003C() { diff --git a/Source/MediaInfo/Video/File_Av1.h b/Source/MediaInfo/Video/File_Av1.h index 21e1029ea0..3daa9dc38f 100644 --- a/Source/MediaInfo/Video/File_Av1.h +++ b/Source/MediaInfo/Video/File_Av1.h @@ -58,6 +58,9 @@ private : void metadata_hdr_mdcv(); void metadata_itu_t_t35(); void metadata_itu_t_t35_B5(); + void metadata_itu_t_t35_B5_003B(); + void metadata_itu_t_t35_B5_003B_00000800(); + void Dolby_Vision_reference_processing_unit(); void metadata_itu_t_t35_B5_003C(); void metadata_itu_t_t35_B5_003C_0001(); void metadata_itu_t_t35_B5_003C_0001_04(); From 9f5380d01f433e09d987ec87ccc4f9f64b5e9009 Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:12:00 +0800 Subject: [PATCH 3/6] AV1: Fix trace offset addresses for Get_leb128 --- Source/MediaInfo/Video/File_Av1.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/MediaInfo/Video/File_Av1.cpp b/Source/MediaInfo/Video/File_Av1.cpp index b9dadd5ff6..58266a155a 100644 --- a/Source/MediaInfo/Video/File_Av1.cpp +++ b/Source/MediaInfo/Video/File_Av1.cpp @@ -1543,8 +1543,10 @@ void File_Av1::Get_leb128(int64u& Info, const char* Name) #if MEDIAINFO_TRACE if (Trace_Activated) { - Param(Name, Info, i+1); + Element_Offset-=(1LL+i); + Param(Name, Info, (i+1)*8); Param_Info(__T("(")+Ztring::ToZtring(i+1)+__T(" bytes)")); + Element_Offset+=(1LL+i); } #endif //MEDIAINFO_TRACE return; From 6905151c250a7825534ea43558ea142c8b6b464d Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Tue, 16 Sep 2025 23:33:19 +0800 Subject: [PATCH 4/6] Unify HEVC & AV1 Dolby Vision RPU parsing codes --- Source/MediaInfo/File__Analyze.h | 31 + Source/MediaInfo/File__Analyze_MinimizeSize.h | 31 + Source/MediaInfo/File__Analyze_Streams.cpp | 623 ++++++++++++++++++ Source/MediaInfo/Video/File_Av1.cpp | 500 +------------- Source/MediaInfo/Video/File_Av1.h | 2 +- Source/MediaInfo/Video/File_Hevc.cpp | 506 +------------- Source/MediaInfo/Video/File_Hevc.h | 5 +- 7 files changed, 693 insertions(+), 1005 deletions(-) diff --git a/Source/MediaInfo/File__Analyze.h b/Source/MediaInfo/File__Analyze.h index c753c55c7c..a9f4901097 100644 --- a/Source/MediaInfo/File__Analyze.h +++ b/Source/MediaInfo/File__Analyze.h @@ -932,6 +932,37 @@ public : #if defined(MEDIAINFO_MPEGPS_YES) || defined(MEDIAINFO_MPEGTS_YES) || defined(MEDIAINFO_MPEG4_YES) || defined(MEDIAINFO_MK_YES) void dvcC(bool has_dependency_pid=false, std::map* Infos=NULL); #endif + #if defined(MEDIAINFO_HEVC_YES) || defined(MEDIAINFO_AV1_YES) + struct DV_RPU { + int8u vdr_rpu_profile{}; + int32u bl_bit_depth{}; + int32u el_bit_depth{}; + int32u vdr_bit_depth{}; + bool BL_video_full_range_flag{}; + int8u isMEL{}; + float CMv{}; + int16u active_area_left_offset{}; + int16u active_area_right_offset{}; + int16u active_area_top_offset{}; + int16u active_area_bottom_offset{}; + int16u max_display_mastering_luminance{}; + int16u min_display_mastering_luminance{}; + int16u max_content_light_level{}; + int16u max_frame_average_light_level{}; + bool L11_present{}; + int8u content_type{}; + int8u white_point{}; + int8u sharpness{}; + int8u noise_reduction{}; + int8u mpeg_noise_reduction{}; + int8u frame_rate_conversion{}; + int8u brightness{}; + int8u color{}; + int8u profile_deduced{}; + }; + // Must be in bitstream before calling this function. + void Get_DolbyVision_ReferenceProcessingUnit(DV_RPU& data); + #endif //*************************************************************************** // Unknown diff --git a/Source/MediaInfo/File__Analyze_MinimizeSize.h b/Source/MediaInfo/File__Analyze_MinimizeSize.h index 40c30ae2b2..e0e1129f66 100644 --- a/Source/MediaInfo/File__Analyze_MinimizeSize.h +++ b/Source/MediaInfo/File__Analyze_MinimizeSize.h @@ -800,6 +800,37 @@ public : #if defined(MEDIAINFO_MPEGPS_YES) || defined(MEDIAINFO_MPEGTS_YES) || defined(MEDIAINFO_MPEG4_YES) || defined(MEDIAINFO_MK_YES) void dvcC(bool has_dependency_pid=false, std::map* Infos=NULL); #endif + #if defined(MEDIAINFO_HEVC_YES) || defined(MEDIAINFO_AV1_YES) + struct DV_RPU { + int8u vdr_rpu_profile{}; + int32u bl_bit_depth{}; + int32u el_bit_depth{}; + int32u vdr_bit_depth{}; + bool BL_video_full_range_flag{}; + int8u isMEL{}; + float CMv{}; + int16u active_area_left_offset{}; + int16u active_area_right_offset{}; + int16u active_area_top_offset{}; + int16u active_area_bottom_offset{}; + int16u max_display_mastering_luminance{}; + int16u min_display_mastering_luminance{}; + int16u max_content_light_level{}; + int16u max_frame_average_light_level{}; + bool L11_present{}; + int8u content_type{}; + int8u white_point{}; + int8u sharpness{}; + int8u noise_reduction{}; + int8u mpeg_noise_reduction{}; + int8u frame_rate_conversion{}; + int8u brightness{}; + int8u color{}; + int8u profile_deduced{}; + }; + // Must be in bitstream before calling this function. + void Get_DolbyVision_ReferenceProcessingUnit(DV_RPU& data); + #endif //*************************************************************************** // Unknown diff --git a/Source/MediaInfo/File__Analyze_Streams.cpp b/Source/MediaInfo/File__Analyze_Streams.cpp index 14cccca65a..121a12faaf 100644 --- a/Source/MediaInfo/File__Analyze_Streams.cpp +++ b/Source/MediaInfo/File__Analyze_Streams.cpp @@ -963,6 +963,629 @@ void File__Analyze::dvcC(bool has_dependency_pid, std::map* } #endif +//--------------------------------------------------------------------------- +#if defined(MEDIAINFO_HEVC_YES) || defined(MEDIAINFO_AV1_YES) + +const char* DV_content_type(int8u content_type) +{ + switch (content_type) { + case 0 : return "Default"; + case 1 : return "Movies"; + case 2 : return "Game"; + case 3 : return "Sport"; + case 4 : return "User Generated Content"; + default : return ""; + } +} + +const char* DV_white_point(int8u white_point) +{ + switch (white_point) { + case 0 : return "D65"; + case 8 : return "D93"; + default : return ""; + } +} + +const char* DV_intended_setting(int8u setting, bool off) +{ + switch (setting) { + case 0 : return "Default"; + case 1 : return off ? "Off" : "Low"; + case 2 : return "Medium"; + case 3 : return "High"; + default : return ""; + } +} + +// CRC Table for CRC-32/MPEG-2 +// Polynomial - 0x04C11DB7 +static const int32u CRC_32_MPEG_2_Table[256] = +{ + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 +}; + +// CRC32 check for Dolby Vision Rererence Processing Unit (RPU) +// Supports non-byte aligned RPU +// Uses CRC-32/MPEG-2 +// Polynomial - 0x04C11DB7 +// Init - 0xFFFFFFFF +// RefIn - false +// RefOut - false +// XorOut - 0x00000000 +// Check - 0x0376E6E7 +static bool DV_CRC32_Check(const int8u* Buffer, int64u BufferOffsetBegin, size_t RemainingBitsBegin, size_t RemainingBitsEnd) +{ + const int8u* CRC_32_Buffer = Buffer + BufferOffsetBegin; + const int32u CRC_Poly{ 0x04C11DB7 }; + int32u CRC_32 = 0xFFFFFFFF; + + const auto first_bits = RemainingBitsBegin & 7; + + for (int8u c = 0; c < first_bits; ++c) { + CRC_32 ^= ((CRC_32_Buffer[0] >> (first_bits - 1 - c)) & 1) << 31; + if (CRC_32 & 0x80000000) + CRC_32 = (CRC_32 << 1) ^ CRC_Poly; + else + CRC_32 <<= 1; + } + + const auto aligned_size = (RemainingBitsBegin - RemainingBitsEnd) + ((8 - first_bits) & 7); + const auto num_bytes = aligned_size / 8; + + for (size_t c = (first_bits != 0); c < num_bytes; ++c) { + CRC_32 = (CRC_32 << 8) ^ CRC_32_MPEG_2_Table[(CRC_32 >> 24) ^ CRC_32_Buffer[c]]; + } + + for (int8u c = 0; c < (aligned_size & 7); ++c) { + CRC_32 ^= ((CRC_32_Buffer[num_bytes] >> (7 - c)) & 1) << 31; + if (CRC_32 & 0x80000000) + CRC_32 = (CRC_32 << 1) ^ CRC_Poly; + else + CRC_32 <<= 1; + } + + return (CRC_32 != 0); +} + +// Must be in bitstream before calling this function. +void File__Analyze::Get_DolbyVision_ReferenceProcessingUnit(DV_RPU& data) +{ + using std::to_string; + + #define UNSUPPORTED() \ + BS_End(); \ + Skip_XX(Element_Size - Element_Offset, "Data"); \ + Trusted_IsNot("Unsupported"); \ + return; + + //Parsing + Element_Begin1("rpu_data"); + auto OffsetBegin{ Element_Offset + BS->Offset_Get() }; + auto RemainingBitsBegin{ Data_BS_Remain() }; + + // EDR RPU header + Element_Begin1("rpu_data_header"); + int8u rpu_type; + int16u rpu_format; + Get_S1 ( 6, rpu_type, "rpu_type"); + Get_S2 (11, rpu_format, "rpu_format"); + if (rpu_type != 2 || (rpu_format & 0x700) != 0) { + UNSUPPORTED(); + } + // if (rpu_type == 2) { + // EDR RPU frame header + int32u coefficient_log2_denom, bl_bit_depth_minus8, el_bit_depth_minus8, vdr_bit_depth_minus8; + int8u vdr_rpu_profile, dm_compression, coefficient_data_type; + bool BL_video_full_range_flag, el_spatial_resampling_filter_flag, disable_residual_flag; + Get_S1 ( 4, vdr_rpu_profile, "vdr_rpu_profile"); + Skip_S1( 4, "vdr_rpu_level"); + TESTELSE_SB_SKIP( "vdr_seq_info_present_flag"); + // EDR RPU sequence header + Skip_SB( "chroma_resampling_explicit_filter_flag"); + Get_S1 (2, coefficient_data_type, "coefficient_data_type"); + switch (coefficient_data_type) { + case 0: //COEFF_FIXED + Get_UE(coefficient_log2_denom, "coefficient_log2_denom"); + break; + case 1: //COEFF_FLOAT + break; + } + Skip_S1(2, "vdr_rpu_normalized_idc"); + Get_SB (BL_video_full_range_flag, "BL_video_full_range_flag"); + if ((rpu_format & 0x700) == 0) { + // sequence header + Get_UE (bl_bit_depth_minus8, "BL_bit_depth_minus8"); + Get_UE (el_bit_depth_minus8, "EL_bit_depth_minus8"); + Get_UE (vdr_bit_depth_minus8, "vdr_bit_depth_minus8"); + Skip_SB( "spatial_resampling_filter_flag"); + Get_S1 (3, dm_compression, "dm_compression"); + Get_SB (el_spatial_resampling_filter_flag, "el_spatial_resampling_filter_flag"); + Get_SB (disable_residual_flag, "disable_residual_flag"); + } + TESTELSE_SB_ELSE("vdr_seq_info_present"); + UNSUPPORTED(); + TESTELSE_SB_END(); + bool use_prev_vdr_rpu_flag, vdr_dm_metadata_present_flag; + int8u isMEL{ 0xFF }; + Get_SB (vdr_dm_metadata_present_flag, "vdr_dm_metadata_present_flag"); + Get_SB (use_prev_vdr_rpu_flag, "use_prev_vdr_rpu_flag"); + if (use_prev_vdr_rpu_flag) { + Skip_UE( "prev_vdr_rpu_id"); + } + else { + int32u num_pivots_minus_2[3]{}; + Skip_UE( "vdr_rpu_id"); + Skip_UE( "mapping_color_space"); + Skip_UE( "mapping_chroma_format_idc"); + // pivot points for BL three components + for (int8u cmp = 0; cmp < 3; ++cmp) { + Get_UE(num_pivots_minus_2[cmp], ("num_pivots_minus_2[" + to_string(cmp) + "]").c_str()); + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 2; ++pivot_idx) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, ("pred_pivot_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + } + auto use_nlq{ (rpu_format & 0x700) == 0 && !disable_residual_flag }; + int8u nlq_method_idc; + if (use_nlq) { + // vl.x architecture EL specific + Get_S1(3, nlq_method_idc, "nlq_method_idc"); + for (int8u i = 0; i < 2; ++i) { + Skip_BS(static_cast(bl_bit_depth_minus8) + 8, "nlq_pred_pivot_value"); + } + } + Skip_UE( "num_x_partitions_minus1"); + Skip_UE( "num_y_partitions_minus1"); + // } + Element_End0(); // rpu_data_header / EDR RPU header + + // if (rpu_type == 2) { + // EDR RPU data + Element_Begin1("vdr_rpu_data_payload"); + Element_Begin1("rpu_data_mapping"); + for (int8u cmp = 0; cmp < 3; ++cmp) { + for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 1; ++pivot_idx) { + Element_Begin1("rpu_data_mapping_param"); + int32u mapping_idc; + Get_UE(mapping_idc, ("mapping_idc[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + switch (mapping_idc) { + case 0: //MAPPING_POLYNOMIAL + { + // Polynomial coefficients + int32u poly_order_minus1; + bool linear_interp_flag{}; + Get_UE(poly_order_minus1, ("poly_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0) + Get_SB(linear_interp_flag, ("linear_interp_flag[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (poly_order_minus1 == 0 && linear_interp_flag) { + // Linear interpolation + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (pivot_idx == num_pivots_minus_2[cmp]) { + if (coefficient_data_type == 0) { + Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + else + Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); + } + } + else { + // Non-linear + // the i-th order + for (int32u i = 0; i <= poly_order_minus1 + 1; ++i) { + if (coefficient_data_type == 0) { + Skip_SE( ("poly_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + else + Skip_S4(32, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); + } + } + break; + } + case 1: //MAPPING_MMR + { + // MR coefficients + int8u mmr_order_minus1; + Get_S1(2, mmr_order_minus1, ("mmr_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_constant_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); + // the i-th order + for (int8u i = 1; i <= mmr_order_minus1 + 1; ++i) { + // the j-th coefficients + for (int8u j = 0; j < 7; ++j) { + if (coefficient_data_type == 0) { + Skip_SE( ("mmr_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + Skip_BS(coefficient_log2_denom, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + else + Skip_S4(32, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); + } + } + break; + } + } + Element_End0(); // rpu_data_mapping_param + } + } + Element_End0(); // rpu_data_mapping + if (use_nlq) { + Element_Begin1("rpu_data_nlq"); + isMEL = 1; + // nlq_num_pivots_minus2 == 0 so no pivot_idx loop + for (int8u cmp = 0; cmp < 3; ++cmp) { + // Nonlinear Quantization Parameters + Element_Begin1("rpu_data_nlq_param"); + int16u nlq_offset; + int32u vdr_in_max_int, vdr_in_max, linear_deadzone_slope_int, linear_deadzone_slope, linear_deadzone_threshold_int, linear_deadzone_threshold; + Get_S2(static_cast(el_bit_depth_minus8) + 8, nlq_offset, ("nlq_offset[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(vdr_in_max_int, ("vdr_in_max_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); + switch (nlq_method_idc) { + case 0: //NLQ_LINEAR_DZ + // Linear dead zone coefficients + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_slope_int, ("linear_deadzone_slope_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); + if (coefficient_data_type == 0) { + Get_UE(linear_deadzone_threshold_int, ("linear_deadzone_threshold_int[0][" + to_string(cmp) + "]").c_str()); + Get_S4(coefficient_log2_denom, linear_deadzone_threshold, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + } + else + Get_S4(32, vdr_in_max, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); + break; + } + if ((nlq_offset | vdr_in_max | linear_deadzone_slope_int | linear_deadzone_slope | linear_deadzone_threshold_int | linear_deadzone_threshold) != 0 || vdr_in_max_int != 1) + isMEL = 0; + Element_End0(); // rpu_data_nlq_param + } + Element_End0(); // rpu_data_nlq + } + + } + // } + Element_End0(); // vdr_rpu_data_payload + + // Display Management + bool L11_present{}; + float CMv{}; + int8u content_type{}, white_point{}, sharpness{}, noise_reduction{}, mpeg_noise_reduction{}, frame_rate_conversion{}, brightness{}, color{}; + int16u active_area_left_offset{}, active_area_right_offset{}, active_area_top_offset{}, active_area_bottom_offset{}, max_display_mastering_luminance{}, min_display_mastering_luminance{}, max_content_light_level{}, max_frame_average_light_level{}; + if (vdr_dm_metadata_present_flag) { + Element_Begin1("vdr_dm_data_payload"); + Skip_UE( "affected_dm_metadata_id"); + Skip_UE( "current_dm_metadata_id"); + Skip_UE( "scene_refresh_flag"); + if (dm_compression) { + UNSUPPORTED(); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("YCCtoRGB_coef" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 3; ++i) { + Skip_S4(32, ("YCCtoRGB_offset" + to_string(i)).c_str()); + } + for (int8u i = 0; i < 9; ++i) { + Skip_S2(16, ("RGBtoLMS_coef" + to_string(i)).c_str()); + } + Skip_S2(16, "signal_eotf"); + Skip_S2(16, "signal_eotf_param0"); + Skip_S2(16, "signal_eotf_param1"); + Skip_S4(32, "signal_eotf_param2"); + Skip_S1( 5, "signal_bit_depth"); + Skip_S1( 2, "signal_color_space"); + Skip_S1( 2, "signal_chroma_format"); + Skip_S1( 2, "signal_full_range_flag"); + Skip_S2(12, "source_min_PQ"); + Skip_S2(12, "source_max_PQ"); + Skip_S2(10, "source_diagonal"); + + // Extension blocks + // ---------------------------------------------------------------------------------------- + + // Content Mapping v2.9 (CMv2.9) + int32u num_ext_blocks; + Get_UE(num_ext_blocks, "num_ext_blocks"); + if (num_ext_blocks) { + CMv = 2.9; + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 1: // ANALYSIS METADATA (DYNAMIC) + Skip_S2(12, "min_PQ"); + Skip_S2(12, "max_PQ"); + Skip_S2(12, "avg_PQ"); + ext_block_use_bits += 36; + break; + case 2: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S2(12, "target_max_PQ"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(13, "ms_weight"); + ext_block_use_bits += 85; + break; + case 4: + Skip_S2(12, "anchor_pq"); + Skip_S2(12, "anchor_power"); + ext_block_use_bits += 24; + break; + case 5: // PER-SHOT ASPECT RATIO (DYNAMIC) + Get_S2(13, active_area_left_offset, "active_area_left_offset"); + Get_S2(13, active_area_right_offset, "active_area_right_offset"); + Get_S2(13, active_area_top_offset, "active_area_top_offset"); + Get_S2(13, active_area_bottom_offset, "active_area_bottom_offset"); + ext_block_use_bits += 52; + break; + case 6: // OPTIONAL HDR10 METADATA (STATIC) + Get_S2(16, max_display_mastering_luminance, "max_display_mastering_luminance"); + Get_S2(16, min_display_mastering_luminance, "min_display_mastering_luminance"); + Get_S2(16, max_content_light_level, "max_content_light_level"); + Get_S2(16, max_frame_average_light_level, "max_frame_average_light_level"); + ext_block_use_bits += 64; + break; + case 255: + Skip_S1(8, "dm_run_mode"); + Skip_S1(8, "dm_run_version"); + Skip_S1(8, "dm_debug0"); + Skip_S1(8, "dm_debug1"); + Skip_S1(8, "dm_debug2"); + Skip_S1(8, "dm_debug3"); + ext_block_use_bits += 48; + break; + default: + Skip_BS(ext_block_len_bits, "(Unknown)"); + ext_block_use_bits += ext_block_len_bits; + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + + // Content Mapping v4.0 (CMv4.0) + if (Data_BS_Remain() >= 56) { + int32u num_ext_blocks2; + Get_UE(num_ext_blocks2, "num_ext_blocks"); + if (num_ext_blocks2) { + CMv = 4.0; + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); + for (int32u i = 0; i < num_ext_blocks2; ++i) { + Element_Begin1("ext_metadata_block"); + int32u ext_block_length; + int8u ext_block_level; + Get_UE(ext_block_length, "ext_block_length"); + Get_S1(8, ext_block_level, "ext_block_level"); + Element_Begin1("ext_block_payload"); + size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; + auto ext_block_use_bits{ 0 }; + switch (ext_block_level) { + case 3: // OFFSETS TO L1 (DYNAMIC) + Skip_S2(12, "min_pq_offset"); + Skip_S2(12, "max_pq_offset"); + Skip_S2(12, "avg_pq_offset"); + ext_block_use_bits += 36; + break; + case 8: // PER-TARGET TRIM METADATA (DYNAMIC) + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "trim_slope"); + Skip_S2(12, "trim_offset"); + Skip_S2(12, "trim_power"); + Skip_S2(12, "trim_chroma_weight"); + Skip_S2(12, "trim_saturation_gain"); + Skip_S2(12, "ms_weight"); + ext_block_use_bits += 80; + if (ext_block_length > 10) { + Skip_S2(12, "target_mid_contrast"); + ext_block_use_bits += 12; + } + if (ext_block_length > 12) { + Skip_S2(12, "clip_trim"); + ext_block_use_bits += 12; + } + if (ext_block_length > 13) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("saturation_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + if (ext_block_length > 19) { + for (int8u i = 0; i < 6; ++i) { + Skip_S1(8, ("hue_vector_field" + to_string(i)).c_str()); + } + ext_block_use_bits += 48; + } + break; + case 9: // PER-SHOT SOURCE CONTENT PRIMARIES (DYNAMIC) + Skip_S1(8, "source_primary_index"); + ext_block_use_bits += 8; + if (ext_block_length > 1) { + Skip_S2(16, "source_primary_red_x"); + Skip_S2(16, "source_primary_red_y"); + Skip_S2(16, "source_primary_green_x"); + Skip_S2(16, "source_primary_green_y"); + Skip_S2(16, "source_primary_blue_x"); + Skip_S2(16, "source_primary_blue_y"); + Skip_S2(16, "source_primary_white_x"); + Skip_S2(16, "source_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 10: + Skip_S1( 8, "target_display_index"); + Skip_S2(12, "target_max_pq"); + Skip_S2(12, "target_min_pq"); + Skip_S1( 8, "target_primary_index"); + ext_block_use_bits += 40; + if (ext_block_length > 5) { + Skip_S2(16, "target_primary_red_x"); + Skip_S2(16, "target_primary_red_y"); + Skip_S2(16, "target_primary_green_x"); + Skip_S2(16, "target_primary_green_y"); + Skip_S2(16, "target_primary_blue_x"); + Skip_S2(16, "target_primary_blue_y"); + Skip_S2(16, "target_primary_white_x"); + Skip_S2(16, "target_primary_white_y"); + ext_block_use_bits += 128; + } + break; + case 11: + { // Automatic Picture/Playback Optimization (APO) / Dolby Vision IQ - Content Type Metadata (L11) + L11_present = true; + Get_S1 (8, content_type, "content_type"); Param_Info1(DV_content_type(content_type)); + Get_S1 (4, white_point, "white_point"); Param_Info1(DV_white_point(white_point)); + Skip_SB( "reference_mode_flag"); + Skip_S1(3, "reserved"); + Get_S1 (2, sharpness, "sharpness"); Param_Info1(DV_intended_setting(sharpness, true)); + Get_S1 (2, noise_reduction, "noise_reduction"); Param_Info1(DV_intended_setting(noise_reduction, true)); + Get_S1 (2, mpeg_noise_reduction, "mpeg_noise_reduction"); Param_Info1(DV_intended_setting(mpeg_noise_reduction, true)); + Get_S1 (2, frame_rate_conversion, "frame_rate_conversion"); Param_Info1(DV_intended_setting(frame_rate_conversion, true)); + Get_S1 (2, brightness, "brightness"); Param_Info1(DV_intended_setting(brightness, false)); + Get_S1 (2, color, "color"); Param_Info1(DV_intended_setting(color, false)); + Skip_S1(2, "reserved1"); + Skip_S1(2, "reserved2"); + ext_block_use_bits += 32; + break; + } + case 254: // CM version + Skip_S1(8, "dm_mode"); + Skip_S1(8, "dm_version_index"); + ext_block_use_bits += 16; + break; + default: + Skip_BS(ext_block_len_bits, "(Unknown)"); + ext_block_use_bits += ext_block_len_bits; + break; + } + Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); + Element_End0(); // ext_block_payload + Element_End0(); // ext_metadata_block + } + } + } + Element_End0(); // vdr_dm_data_payload + } + + auto RemainingBitsEnd = Data_BS_Remain(); + auto size = RemainingBitsBegin - RemainingBitsEnd; + Skip_BS((8 - (size & 7)) & 7, "rpu_alignment_zero_bit"); + Skip_S4(32, "rpu_data_crc32"); + auto CRC32_Check = DV_CRC32_Check(Buffer, Buffer_Offset + OffsetBegin, RemainingBitsBegin, Data_BS_Remain()); + Param_Info1(CRC32_Check ? "NOK" : "OK"); + Element_End0(); // rpu_data + + Element_Begin1("rbsp_trailing_bits"); + Mark_1(); // rbsp_stop_one_bit + Skip_S1(7, "rbsp_alignment_zero_bit"); + Element_End0(); // rbsp_trailing_bits + + #undef UNSUPPORTED + + FILLING_BEGIN(); + if (CRC32_Check) + return; + data.vdr_rpu_profile = vdr_rpu_profile; + data.bl_bit_depth = bl_bit_depth_minus8 + 8; + data.el_bit_depth = el_bit_depth_minus8 + 8; + data.vdr_bit_depth = vdr_bit_depth_minus8 + 8; + data.BL_video_full_range_flag = BL_video_full_range_flag; + data.isMEL = isMEL; + data.CMv = CMv; + data.active_area_left_offset = active_area_left_offset; + data.active_area_right_offset = active_area_right_offset; + data.active_area_top_offset = active_area_top_offset; + data.active_area_bottom_offset = active_area_bottom_offset; + data.max_display_mastering_luminance = max_display_mastering_luminance; + data.min_display_mastering_luminance = min_display_mastering_luminance; + data.max_content_light_level = max_content_light_level; + data.max_frame_average_light_level = max_frame_average_light_level; + data.L11_present = L11_present; + data.content_type = content_type; + data.white_point = white_point; + data.sharpness = sharpness; + data.noise_reduction = noise_reduction; + data.mpeg_noise_reduction = mpeg_noise_reduction; + data.frame_rate_conversion = frame_rate_conversion; + data.brightness = brightness; + data.color = color; + if (vdr_rpu_profile == 0 && BL_video_full_range_flag) { + data.profile_deduced = 5; + } + if (vdr_rpu_profile == 1) { + if (el_spatial_resampling_filter_flag && !disable_residual_flag) { + data.profile_deduced = 7; + } + if (!el_spatial_resampling_filter_flag) { + data.profile_deduced = 8; + } + } + FILLING_END(); +} + +#endif // defined(MEDIAINFO_HEVC_YES) || defined(MEDIAINFO_AV1_YES) + //--------------------------------------------------------------------------- #if defined(MEDIAINFO_AV1_YES) || defined(MEDIAINFO_AVC_YES) || defined(MEDIAINFO_HEVC_YES) || defined(MEDIAINFO_MPEG4_YES) void File__Analyze::Get_LightLevel(Ztring &MaxCLL, Ztring &MaxFALL, int32u Divisor) diff --git a/Source/MediaInfo/Video/File_Av1.cpp b/Source/MediaInfo/Video/File_Av1.cpp index 58266a155a..b953ef91a1 100644 --- a/Source/MediaInfo/Video/File_Av1.cpp +++ b/Source/MediaInfo/Video/File_Av1.cpp @@ -321,7 +321,7 @@ void File_Av1::sequence_header() //Parsing int32u max_frame_width_minus_1, max_frame_height_minus_1; int8u seq_profile, seq_level_idx[33]{}, operating_points_cnt_minus_1, buffer_delay_length_minus_1, frame_width_bits_minus_1, frame_height_bits_minus_1, seq_force_screen_content_tools, BitDepth, color_primaries, transfer_characteristics, matrix_coefficients, chroma_sample_position; - bool reduced_still_picture_header, seq_tier[33], timing_info_present_flag, decoder_model_info_present_flag, seq_choose_screen_content_tools, mono_chrome, color_range, color_description_present_flag, subsampling_x, subsampling_y; + bool reduced_still_picture_header, seq_tier[33]{}, timing_info_present_flag, decoder_model_info_present_flag, seq_choose_screen_content_tools, mono_chrome, color_range, color_description_present_flag, subsampling_x, subsampling_y; BS_Begin(); Get_S1 ( 3, seq_profile, "seq_profile"); Param_Info1(Av1_seq_profile(seq_profile)); Skip_SB( "still_picture"); @@ -795,13 +795,13 @@ void File_Av1::metadata_itu_t_t35_B5_003B_00000800() int32u emdf_payload_size = 0; Get_V4 (8, emdf_payload_size, "emdf_payload_size"); - size_t emdf_payload_End=Data_BS_Remain()-emdf_payload_size*8; + size_t emdf_payload_End = Data_BS_Remain() - static_cast(emdf_payload_size) * 8; Element_Begin1("emdf_payload_bytes"); switch (emdf_payload_id) { - case 256: Dolby_Vision_reference_processing_unit(); break; - default : Skip_BS(emdf_payload_size * 8, "(Unknown)"); break; + case 256: Get_DolbyVision_ReferenceProcessingUnit(DV_RPU_data); break; + default : Skip_BS(static_cast(emdf_payload_size) * 8, "(Unknown)"); break; } size_t RemainginBits=Data_BS_Remain(); if (RemainginBits>=emdf_payload_End) @@ -857,498 +857,6 @@ void File_Av1::metadata_itu_t_t35_B5_003B_00000800() BS_End(); } -//--------------------------------------------------------------------------- -void File_Av1::Dolby_Vision_reference_processing_unit() -{ - using std::to_string; - - #define UNSUPPORTED() \ - BS_End(); \ - Skip_XX(Element_Size - Element_Offset, "Data"); \ - Trusted_IsNot("Unsupported"); \ - return; - - auto DV_content_type{ [](int8u content_type) -> const char* { - switch (content_type) { - case 0: return "Default"; - case 1: return "Movies"; - case 2: return "Game"; - case 3: return "Sport"; - case 4: return "User Generated Content"; - default: return ""; - } - } - }; - - auto DV_white_point{ [](int8u white_point) -> const char* { - switch (white_point) { - case 0: return "D65"; - case 8: return "D93"; - default: return ""; - } - } - }; - - auto DV_intended_setting{ [](int8u setting, bool off) -> const char* { - switch (setting) { - case 0: return "Default"; - case 1: return off ? "Off" : "Low"; - case 2: return "Medium"; - case 3: return "High"; - default: return ""; - } - } - }; - - //Parsing - Element_Begin1("rpu_data"); - auto RemainingBitsBegin = Data_BS_Remain(); - - // EDR RPU header - Element_Begin1("rpu_data_header"); - int8u rpu_type; - int16u rpu_format; - Get_S1 ( 6, rpu_type, "rpu_type"); - Get_S2 (11, rpu_format, "rpu_format"); - if (rpu_type != 2 || (rpu_format & 0x700) != 0) { - UNSUPPORTED(); - } - // if (rpu_type == 2) { - // EDR RPU frame header - int32u coefficient_log2_denom, bl_bit_depth_minus8, el_bit_depth_minus8; - int8u dm_compression, coefficient_data_type; - bool disable_residual_flag; - Skip_S1( 4, "vdr_rpu_profile"); - Skip_S1( 4, "vdr_rpu_level"); - TESTELSE_SB_SKIP( "vdr_seq_info_present_flag"); - // EDR RPU sequence header - Skip_SB( "chroma_resampling_explicit_filter_flag"); - Get_S1 (2, coefficient_data_type, "coefficient_data_type"); - switch (coefficient_data_type) { - case 0: //COEFF_FIXED - Get_UE(coefficient_log2_denom, "coefficient_log2_denom"); - break; - case 1: //COEFF_FLOAT - break; - } - Skip_S1(2, "vdr_rpu_normalized_idc"); - Skip_SB( "BL_video_full_range_flag"); - if ((rpu_format & 0x700) == 0) { - // sequence header - Get_UE (bl_bit_depth_minus8, "BL_bit_depth_minus8"); - Get_UE (el_bit_depth_minus8, "EL_bit_depth_minus8"); - Skip_UE( "vdr_bit_depth_minus8"); - Skip_SB( "spatial_resampling_filter_flag"); - Get_S1 (3, dm_compression, "dm_compression"); - Skip_SB( "el_spatial_resampling_filter_flag"); - Get_SB (disable_residual_flag, "disable_residual_flag"); - } - TESTELSE_SB_ELSE("vdr_seq_info_present"); - UNSUPPORTED(); - TESTELSE_SB_END(); - bool use_prev_vdr_rpu_flag, vdr_dm_metadata_present_flag; - Get_SB (vdr_dm_metadata_present_flag, "vdr_dm_metadata_present_flag"); - Get_SB (use_prev_vdr_rpu_flag, "use_prev_vdr_rpu_flag"); - if (use_prev_vdr_rpu_flag) { - Skip_UE( "prev_vdr_rpu_id"); - } - else { - int32u num_pivots_minus_2[3]{}; - Skip_UE( "vdr_rpu_id"); - Skip_UE( "mapping_color_space"); - Skip_UE( "mapping_chroma_format_idc"); - // pivot points for BL three components - for (int8u cmp = 0; cmp < 3; ++cmp) { - Get_UE(num_pivots_minus_2[cmp], ("num_pivots_minus_2[" + to_string(cmp) + "]").c_str()); - for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 2; ++pivot_idx) { - Skip_BS(static_cast(bl_bit_depth_minus8) + 8, ("pred_pivot_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - } - auto use_nlq{ (rpu_format & 0x700) == 0 && !disable_residual_flag }; - int8u nlq_method_idc; - if (use_nlq) { - // vl.x architecture EL specific - Get_S1(3, nlq_method_idc, "nlq_method_idc"); - for (int8u i = 0; i < 2; ++i) { - Skip_BS(static_cast(bl_bit_depth_minus8) + 8, "nlq_pred_pivot_value"); - } - } - Skip_UE( "num_x_partitions_minus1"); - Skip_UE( "num_y_partitions_minus1"); - // } - Element_End0(); // rpu_data_header / EDR RPU header - - // if (rpu_type == 2) { - // EDR RPU data - Element_Begin1("vdr_rpu_data_payload"); - Element_Begin1("rpu_data_mapping"); - for (int8u cmp = 0; cmp < 3; ++cmp) { - for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 1; ++pivot_idx) { - Element_Begin1("rpu_data_mapping_param"); - int32u mapping_idc; - Get_UE(mapping_idc, ("mapping_idc[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - switch (mapping_idc) { - case 0: //MAPPING_POLYNOMIAL - { - // Polynomial coefficients - int32u poly_order_minus1; - bool linear_interp_flag{}; - Get_UE(poly_order_minus1, ("poly_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (poly_order_minus1 == 0) - Get_SB(linear_interp_flag, ("linear_interp_flag[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (poly_order_minus1 == 0 && linear_interp_flag) { - // Linear interpolation - if (coefficient_data_type == 0) { - Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - else - Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (pivot_idx == num_pivots_minus_2[cmp]) { - if (coefficient_data_type == 0) { - Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - } - else - Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - } - } - else { - // Non-linear - // the i-th order - for (int32u i = 0; i <= poly_order_minus1 + 1; ++i) { - if (coefficient_data_type == 0) { - Skip_SE( ("poly_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - } - else - Skip_S4(32, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - } - } - break; - } - case 1: //MAPPING_MMR - { - // MR coefficients - int8u mmr_order_minus1; - Get_S1(2, mmr_order_minus1, ("mmr_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (coefficient_data_type == 0) { - Skip_SE( ("mmr_constant_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - else - Skip_S4(32, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - // the i-th order - for (int8u i = 1; i <= mmr_order_minus1 + 1; ++i) { - // the j-th coefficients - for (int8u j = 0; j < 7; ++j) { - if (coefficient_data_type == 0) { - Skip_SE( ("mmr_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - } - else - Skip_S4(32, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - } - } - break; - } - } - Element_End0(); // rpu_data_mapping_param - } - } - Element_End0(); // rpu_data_mapping - if (use_nlq) { - Element_Begin1("rpu_data_nlq"); - bool isMEL{ true }; - // nlq_num_pivots_minus2 == 0 so no pivot_idx loop - for (int8u cmp = 0; cmp < 3; ++cmp) { - // Nonlinear Quantization Parameters - Element_Begin1("rpu_data_nlq_param"); - int16u nlq_offset; - int32u vdr_in_max_int, vdr_in_max, linear_deadzone_slope_int, linear_deadzone_slope, linear_deadzone_threshold_int, linear_deadzone_threshold; - Get_S2(static_cast(el_bit_depth_minus8) + 8, nlq_offset, ("nlq_offset[0][" + to_string(cmp) + "]").c_str()); - if (coefficient_data_type == 0) { - Get_UE(vdr_in_max_int, ("vdr_in_max_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); - switch (nlq_method_idc) { - case 0: //NLQ_LINEAR_DZ - // Linear dead zone coefficients - if (coefficient_data_type == 0) { - Get_UE(linear_deadzone_slope_int, ("linear_deadzone_slope_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); - if (coefficient_data_type == 0) { - Get_UE(linear_deadzone_threshold_int, ("linear_deadzone_threshold_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, linear_deadzone_threshold, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, vdr_in_max, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); - break; - } - if ((nlq_offset | vdr_in_max | linear_deadzone_slope_int | linear_deadzone_slope | linear_deadzone_threshold_int | linear_deadzone_threshold) != 0 || vdr_in_max_int != 1) - isMEL = false; - Element_End0(); // rpu_data_nlq_param - } - - // TEMPORARY ========================================================================== - if (isMEL) - Param2("EL Type", "Minimum Enhancement Layer (MEL)"); - else - Param2("EL Type", "Full Enhancement Layer (FEL / non-MEL)"); - // end TEMPORARY ====================================================================== - - Element_End0(); // rpu_data_nlq - } - - } - // } - Element_End0(); // vdr_rpu_data_payload - - // Display Management - if (vdr_dm_metadata_present_flag) { - Element_Begin1("vdr_dm_data_payload"); - Skip_UE( "affected_dm_metadata_id"); - Skip_UE( "current_dm_metadata_id"); - Skip_UE( "scene_refresh_flag"); - if (dm_compression) { - UNSUPPORTED(); - } - for (int8u i = 0; i < 9; ++i) { - Skip_S2(16, ("YCCtoRGB_coef" + to_string(i)).c_str()); - } - for (int8u i = 0; i < 3; ++i) { - Skip_S4(32, ("YCCtoRGB_offset" + to_string(i)).c_str()); - } - for (int8u i = 0; i < 9; ++i) { - Skip_S2(16, ("RGBtoLMS_coef" + to_string(i)).c_str()); - } - Skip_S2(16, "signal_eotf"); - Skip_S2(16, "signal_eotf_param0"); - Skip_S2(16, "signal_eotf_param1"); - Skip_S4(32, "signal_eotf_param2"); - Skip_S1( 5, "signal_bit_depth"); - Skip_S1( 2, "signal_color_space"); - Skip_S1( 2, "signal_chroma_format"); - Skip_S1( 2, "signal_full_range_flag"); - Skip_S2(12, "source_min_PQ"); - Skip_S2(12, "source_max_PQ"); - Skip_S2(10, "source_diagonal"); - - // Extension blocks - // ---------------------------------------------------------------------------------------- - - // Content Mapping v2.9 (CMv2.9) - int32u num_ext_blocks; - Get_UE(num_ext_blocks, "num_ext_blocks"); - if (num_ext_blocks) { - auto RemainingBitsEnd = Data_BS_Remain(); - auto size = RemainingBitsBegin - RemainingBitsEnd; - Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); - for (int32u i = 0; i < num_ext_blocks; ++i) { - Element_Begin1("ext_metadata_block"); - int32u ext_block_length; - int8u ext_block_level; - Get_UE(ext_block_length, "ext_block_length"); - Get_S1(8, ext_block_level, "ext_block_level"); - Element_Begin1("ext_block_payload"); - size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; - auto ext_block_use_bits{ 0 }; - switch (ext_block_level) { - case 1: // ANALYSIS METADATA (DYNAMIC) - Skip_S2(12, "min_PQ"); - Skip_S2(12, "max_PQ"); - Skip_S2(12, "avg_PQ"); - ext_block_use_bits += 36; - break; - case 2: // PER-TARGET TRIM METADATA (DYNAMIC) - Skip_S2(12, "target_max_PQ"); - Skip_S2(12, "trim_slope"); - Skip_S2(12, "trim_offset"); - Skip_S2(12, "trim_power"); - Skip_S2(12, "trim_chroma_weight"); - Skip_S2(12, "trim_saturation_gain"); - Skip_S2(13, "ms_weight"); - ext_block_use_bits += 85; - break; - case 4: - Skip_S2(12, "anchor_pq"); - Skip_S2(12, "anchor_power"); - ext_block_use_bits += 24; - break; - case 5: // PER-SHOT ASPECT RATIO (DYNAMIC) - Skip_S2(13, "active_area_left_offset"); - Skip_S2(13, "active_area_right_offset"); - Skip_S2(13, "active_area_top_offset"); - Skip_S2(13, "active_area_bottom_offset"); - ext_block_use_bits += 52; - break; - case 6: // OPTIONAL HDR10 METADATA (STATIC) - Skip_S2(16, "max_display_mastering_luminance"); - Skip_S2(16, "min_display_mastering_luminance"); - Skip_S2(16, "max_content_light_level"); - Skip_S2(16, "max_frame_average_light_level"); - ext_block_use_bits += 64; - break; - case 255: - Skip_S1(8, "dm_run_mode"); - Skip_S1(8, "dm_run_version"); - Skip_S1(8, "dm_debug0"); - Skip_S1(8, "dm_debug1"); - Skip_S1(8, "dm_debug2"); - Skip_S1(8, "dm_debug3"); - ext_block_use_bits += 48; - break; - default: - Skip_BS(ext_block_len_bits - ext_block_use_bits, "(Not parsed)"); - break; - } - Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); - Element_End0(); // ext_block_payload - Element_End0(); // ext_metadata_block - } - } - - // Content Mapping v4.0 (CMv4.0) - if (Data_BS_Remain() >= 56) { - int32u num_ext_blocks2; - Get_UE(num_ext_blocks2, "num_ext_blocks"); - if (num_ext_blocks2) { - auto RemainingBitsEnd = Data_BS_Remain(); - auto size = RemainingBitsBegin - RemainingBitsEnd; - Skip_BS((8 - (size & 7)) & 7, "dm_alignment_zero_bit"); - for (int32u i = 0; i < num_ext_blocks2; ++i) { - Element_Begin1("ext_metadata_block"); - int32u ext_block_length; - int8u ext_block_level; - Get_UE(ext_block_length, "ext_block_length"); - Get_S1(8, ext_block_level, "ext_block_level"); - Element_Begin1("ext_block_payload"); - size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; - auto ext_block_use_bits{ 0 }; - switch (ext_block_level) { - case 3: // OFFSETS TO L1 (DYNAMIC) - Skip_S2(12, "min_pq_offset"); - Skip_S2(12, "max_pq_offset"); - Skip_S2(12, "avg_pq_offset"); - ext_block_use_bits += 36; - break; - case 8: // PER-TARGET TRIM METADATA (DYNAMIC) - Skip_S1( 8, "target_display_index"); - Skip_S2(12, "trim_slope"); - Skip_S2(12, "trim_offset"); - Skip_S2(12, "trim_power"); - Skip_S2(12, "trim_chroma_weight"); - Skip_S2(12, "trim_saturation_gain"); - Skip_S2(12, "ms_weight"); - ext_block_use_bits += 80; - if (ext_block_length > 10) { - Skip_S2(12, "target_mid_contrast"); - ext_block_use_bits += 12; - } - if (ext_block_length > 12) { - Skip_S2(12, "clip_trim"); - ext_block_use_bits += 12; - } - if (ext_block_length > 13) { - for (int8u i = 0; i < 6; ++i) { - Skip_S1(8, ("saturation_vector_field" + to_string(i)).c_str()); - } - ext_block_use_bits += 48; - } - if (ext_block_length > 19) { - for (int8u i = 0; i < 6; ++i) { - Skip_S1(8, ("hue_vector_field" + to_string(i)).c_str()); - } - ext_block_use_bits += 48; - } - break; - case 9: // PER-SHOT SOURCE CONTENT PRIMARIES (DYNAMIC) - Skip_S1(8, "source_primary_index"); - ext_block_use_bits += 8; - if (ext_block_length > 1) { - Skip_S2(16, "source_primary_red_x"); - Skip_S2(16, "source_primary_red_y"); - Skip_S2(16, "source_primary_green_x"); - Skip_S2(16, "source_primary_green_y"); - Skip_S2(16, "source_primary_blue_x"); - Skip_S2(16, "source_primary_blue_y"); - Skip_S2(16, "source_primary_white_x"); - Skip_S2(16, "source_primary_white_y"); - ext_block_use_bits += 128; - } - break; - case 10: - Skip_S1( 8, "target_display_index"); - Skip_S2(12, "target_max_pq"); - Skip_S2(12, "target_min_pq"); - Skip_S1( 8, "target_primary_index"); - ext_block_use_bits += 40; - if (ext_block_length > 5) { - Skip_S2(16, "target_primary_red_x"); - Skip_S2(16, "target_primary_red_y"); - Skip_S2(16, "target_primary_green_x"); - Skip_S2(16, "target_primary_green_y"); - Skip_S2(16, "target_primary_blue_x"); - Skip_S2(16, "target_primary_blue_y"); - Skip_S2(16, "target_primary_white_x"); - Skip_S2(16, "target_primary_white_y"); - ext_block_use_bits += 128; - } - break; - case 11: - { // Automatic Picture/Playback Optimization (APO) / Dolby Vision IQ - Content Type Metadata (L11) - int8u content_type, white_point, sharpness, noise_reduction, mpeg_noise_reduction, frame_rate_conversion, brightness, color; - Get_S1 (8, content_type, "content_type"); Param_Info1(DV_content_type(content_type)); - Get_S1 (4, white_point, "white_point"); Param_Info1(DV_white_point(white_point)); - Skip_SB( "reference_mode_flag"); - Skip_S1(3, "reserved"); - Get_S1 (2, sharpness, "sharpness"); Param_Info1(DV_intended_setting(sharpness, true)); - Get_S1 (2, noise_reduction, "noise_reduction"); Param_Info1(DV_intended_setting(noise_reduction, true)); - Get_S1 (2, mpeg_noise_reduction, "mpeg_noise_reduction"); Param_Info1(DV_intended_setting(mpeg_noise_reduction, true)); - Get_S1 (2, frame_rate_conversion, "frame_rate_conversion"); Param_Info1(DV_intended_setting(frame_rate_conversion, true)); - Get_S1 (2, brightness, "brightness"); Param_Info1(DV_intended_setting(brightness, false)); - Get_S1 (2, color, "color"); Param_Info1(DV_intended_setting(color, false)); - Skip_S1(2, "reserved1"); - Skip_S1(2, "reserved2"); - ext_block_use_bits += 32; - break; - } - case 254: // CM version - Skip_S1(8, "dm_mode"); - Skip_S1(8, "dm_version_index"); - ext_block_use_bits += 16; - break; - default: - Skip_BS(ext_block_len_bits, "(Not parsed)"); - ext_block_use_bits += ext_block_len_bits; - break; - } - Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); - Element_End0(); // ext_block_payload - Element_End0(); // ext_metadata_block - } - } - } - Element_End0(); // vdr_dm_data_payload - } - - auto RemainingBitsEnd = Data_BS_Remain(); - auto size = RemainingBitsBegin - RemainingBitsEnd; - Skip_BS((8 - (size & 7)) & 7, "rpu_alignment_zero_bit"); - Skip_S4(32, "rpu_data_crc32"); - Element_End0(); // rpu_data - - Mark_1(); // rbsp_stop_one_bit - Skip_S1(7, "rbsp_alignment_zero_bit"); - - #undef UNSUPPORTED -} - //--------------------------------------------------------------------------- void File_Av1::metadata_itu_t_t35_B5_003C() { diff --git a/Source/MediaInfo/Video/File_Av1.h b/Source/MediaInfo/Video/File_Av1.h index 3daa9dc38f..53c5bd7116 100644 --- a/Source/MediaInfo/Video/File_Av1.h +++ b/Source/MediaInfo/Video/File_Av1.h @@ -60,7 +60,6 @@ private : void metadata_itu_t_t35_B5(); void metadata_itu_t_t35_B5_003B(); void metadata_itu_t_t35_B5_003B_00000800(); - void Dolby_Vision_reference_processing_unit(); void metadata_itu_t_t35_B5_003C(); void metadata_itu_t_t35_B5_003C_0001(); void metadata_itu_t_t35_B5_003C_0001_04(); @@ -81,6 +80,7 @@ private : }; typedef std::map hdr; hdr HDR; + DV_RPU DV_RPU_data; //Helpers std::string GOP_Detect(std::string PictureTypes); diff --git a/Source/MediaInfo/Video/File_Hevc.cpp b/Source/MediaInfo/Video/File_Hevc.cpp index 7f8b5aa022..87cd975ddf 100644 --- a/Source/MediaInfo/Video/File_Hevc.cpp +++ b/Source/MediaInfo/Video/File_Hevc.cpp @@ -3777,513 +3777,11 @@ void File_Hevc::Dolby_Vision_reference_processing_unit() Element_Name("Dolby Vision Reference Processing Unit (RPU)"); - #define UNSUPPORTED() \ - BS_End(); \ - Skip_XX(Element_Size - Element_Offset, "Data"); \ - Trusted_IsNot("Unsupported"); \ - return; - - auto CRC32_Init{ [](int32u* Table, int32u Polynomial) -> void { - for (size_t Pos = 0; Pos < 256; ++Pos) { - Table[Pos] = static_cast(Pos) << 24; - for (int8u bit = 0; bit < 8; ++bit) { - if (Table[Pos] & 0x80000000) - Table[Pos] = (Table[Pos] << 1) ^ Polynomial; - else - Table[Pos] = Table[Pos] << 1; - } - } - } - }; - - auto DV_content_type{ [](int8u content_type) -> const char* { - switch (content_type) { - case 0: return "Default"; - case 1: return "Movies"; - case 2: return "Game"; - case 3: return "Sport"; - case 4: return "User Generated Content"; - default: return ""; - } - } - }; - - auto DV_white_point{ [](int8u white_point) -> const char* { - switch (white_point) { - case 0: return "D65"; - case 8: return "D93"; - default: return ""; - } - } - }; - - auto DV_intended_setting{ [](int8u setting, bool off) -> const char* { - switch (setting) { - case 0: return "Default"; - case 1: return off ? "Off" : "Low"; - case 2: return "Medium"; - case 3: return "High"; - default: return ""; - } - } - }; - //Parsing - Skip_B1 ( "nal_prefix"); - - Element_Begin1("rpu_data"); - auto Element_Offset_Begin{ Element_Offset }; - BS_Begin(); - - // EDR RPU header - Element_Begin1("rpu_data_header"); - int8u rpu_type; - int16u rpu_format; - Get_S1 ( 6, rpu_type, "rpu_type"); - Get_S2 (11, rpu_format, "rpu_format"); - if (rpu_type != 2 || (rpu_format & 0x700) != 0) { - UNSUPPORTED(); - } - // if (rpu_type == 2) { - // EDR RPU frame header - int32u coefficient_log2_denom, bl_bit_depth_minus8, el_bit_depth_minus8; - int8u dm_compression, coefficient_data_type; - bool disable_residual_flag; - Skip_S1( 4, "vdr_rpu_profile"); - Skip_S1( 4, "vdr_rpu_level"); - TESTELSE_SB_SKIP( "vdr_seq_info_present_flag"); - // EDR RPU sequence header - Skip_SB( "chroma_resampling_explicit_filter_flag"); - Get_S1 (2, coefficient_data_type, "coefficient_data_type"); - switch (coefficient_data_type) { - case 0: //COEFF_FIXED - Get_UE(coefficient_log2_denom, "coefficient_log2_denom"); - break; - case 1: //COEFF_FLOAT - break; - } - Skip_S1(2, "vdr_rpu_normalized_idc"); - Skip_SB( "BL_video_full_range_flag"); - if ((rpu_format & 0x700) == 0) { - // sequence header - Get_UE (bl_bit_depth_minus8, "BL_bit_depth_minus8"); - Get_UE (el_bit_depth_minus8, "EL_bit_depth_minus8"); - Skip_UE( "vdr_bit_depth_minus8"); - Skip_SB( "spatial_resampling_filter_flag"); - Get_S1 (3, dm_compression, "dm_compression"); - Skip_SB( "el_spatial_resampling_filter_flag"); - Get_SB (disable_residual_flag, "disable_residual_flag"); - } - TESTELSE_SB_ELSE("vdr_seq_info_present"); - UNSUPPORTED(); - TESTELSE_SB_END(); - bool use_prev_vdr_rpu_flag, vdr_dm_metadata_present_flag; - Get_SB (vdr_dm_metadata_present_flag, "vdr_dm_metadata_present_flag"); - Get_SB (use_prev_vdr_rpu_flag, "use_prev_vdr_rpu_flag"); - if (use_prev_vdr_rpu_flag) { - Skip_UE( "prev_vdr_rpu_id"); - } - else { - int32u num_pivots_minus_2[3]{}; - Skip_UE( "vdr_rpu_id"); - Skip_UE( "mapping_color_space"); - Skip_UE( "mapping_chroma_format_idc"); - // pivot points for BL three components - for (int8u cmp = 0; cmp < 3; ++cmp) { - Get_UE(num_pivots_minus_2[cmp], ("num_pivots_minus_2[" + to_string(cmp) + "]").c_str()); - for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 2; ++pivot_idx) { - Skip_BS(static_cast(bl_bit_depth_minus8) + 8, ("pred_pivot_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - } - auto use_nlq{ (rpu_format & 0x700) == 0 && !disable_residual_flag }; - int8u nlq_method_idc; - if (use_nlq) { - // vl.x architecture EL specific - Get_S1(3, nlq_method_idc, "nlq_method_idc"); - for (int8u i = 0; i < 2; ++i) { - Skip_BS(static_cast(bl_bit_depth_minus8) + 8, "nlq_pred_pivot_value"); - } - } - Skip_UE( "num_x_partitions_minus1"); - Skip_UE( "num_y_partitions_minus1"); - // } - Element_End0(); // rpu_data_header / EDR RPU header - - // if (rpu_type == 2) { - // EDR RPU data - Element_Begin1("vdr_rpu_data_payload"); - Element_Begin1("rpu_data_mapping"); - for (int8u cmp = 0; cmp < 3; ++cmp) { - for (int32u pivot_idx = 0; pivot_idx < num_pivots_minus_2[cmp] + 1; ++pivot_idx) { - Element_Begin1("rpu_data_mapping_param"); - int32u mapping_idc; - Get_UE(mapping_idc, ("mapping_idc[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - switch (mapping_idc) { - case 0: //MAPPING_POLYNOMIAL - { - // Polynomial coefficients - int32u poly_order_minus1; - bool linear_interp_flag{}; - Get_UE(poly_order_minus1, ("poly_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (poly_order_minus1 == 0) - Get_SB(linear_interp_flag, ("linear_interp_flag[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (poly_order_minus1 == 0 && linear_interp_flag) { - // Linear interpolation - if (coefficient_data_type == 0) { - Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - else - Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (pivot_idx == num_pivots_minus_2[cmp]) { - if (coefficient_data_type == 0) { - Skip_UE( ("pred_linear_interp_value_int[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - } - else - Skip_S4(32, ("pred_linear_interp_value[" + to_string(cmp) + "][" + to_string(pivot_idx + 1) + "]").c_str()); - } - } - else { - // Non-linear - // the i-th order - for (int32u i = 0; i <= poly_order_minus1 + 1; ++i) { - if (coefficient_data_type == 0) { - Skip_SE( ("poly_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - } - else - Skip_S4(32, ("poly_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "]").c_str()); - } - } - break; - } - case 1: //MAPPING_MMR - { - // MR coefficients - int8u mmr_order_minus1; - Get_S1(2, mmr_order_minus1, ("mmr_order_minus1[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - if (coefficient_data_type == 0) { - Skip_SE( ("mmr_constant_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - } - else - Skip_S4(32, ("mmr_constant[" + to_string(cmp) + "][" + to_string(pivot_idx) + "]").c_str()); - // the i-th order - for (int8u i = 1; i <= mmr_order_minus1 + 1; ++i) { - // the j-th coefficients - for (int8u j = 0; j < 7; ++j) { - if (coefficient_data_type == 0) { - Skip_SE( ("mmr_coef_int[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - Skip_BS(coefficient_log2_denom, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - } - else - Skip_S4(32, ("mmr_coef[" + to_string(cmp) + "][" + to_string(pivot_idx) + "][" + to_string(i) + "][" + to_string(j) + "]").c_str()); - } - } - break; - } - } - Element_End0(); // rpu_data_mapping_param - } - } - Element_End0(); // rpu_data_mapping - if (use_nlq) { - Element_Begin1("rpu_data_nlq"); - bool isMEL{ true }; - // nlq_num_pivots_minus2 == 0 so no pivot_idx loop - for (int8u cmp = 0; cmp < 3; ++cmp) { - // Nonlinear Quantization Parameters - Element_Begin1("rpu_data_nlq_param"); - int16u nlq_offset; - int32u vdr_in_max_int, vdr_in_max, linear_deadzone_slope_int, linear_deadzone_slope, linear_deadzone_threshold_int, linear_deadzone_threshold; - Get_S2(static_cast(el_bit_depth_minus8) + 8, nlq_offset, ("nlq_offset[0][" + to_string(cmp) + "]").c_str()); - if (coefficient_data_type == 0) { - Get_UE(vdr_in_max_int, ("vdr_in_max_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, vdr_in_max, ("vdr_in_max[0][" + to_string(cmp) + "]").c_str()); - switch (nlq_method_idc) { - case 0: //NLQ_LINEAR_DZ - // Linear dead zone coefficients - if (coefficient_data_type == 0) { - Get_UE(linear_deadzone_slope_int, ("linear_deadzone_slope_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, linear_deadzone_slope, ("linear_deadzone_slope[0][" + to_string(cmp) + "]").c_str()); - if (coefficient_data_type == 0) { - Get_UE(linear_deadzone_threshold_int, ("linear_deadzone_threshold_int[0][" + to_string(cmp) + "]").c_str()); - Get_S4(coefficient_log2_denom, linear_deadzone_threshold, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); - } - else - Get_S4(32, vdr_in_max, ("linear_deadzone_threshold[0][" + to_string(cmp) + "]").c_str()); - break; - } - if ((nlq_offset | vdr_in_max | linear_deadzone_slope_int | linear_deadzone_slope | linear_deadzone_threshold_int | linear_deadzone_threshold) != 0 || vdr_in_max_int != 1) - isMEL = false; - Element_End0(); // rpu_data_nlq_param - } - - // TEMPORARY ========================================================================== - if (isMEL) - Param2("EL Type", "Minimum Enhancement Layer (MEL)"); - else - Param2("EL Type", "Full Enhancement Layer (FEL / non-MEL)"); - // end TEMPORARY ====================================================================== - - Element_End0(); // rpu_data_nlq - } - - } - // } - Element_End0(); // vdr_rpu_data_payload - - // Display Management - if (vdr_dm_metadata_present_flag) { - Element_Begin1("vdr_dm_data_payload"); - Skip_UE( "affected_dm_metadata_id"); - Skip_UE( "current_dm_metadata_id"); - Skip_UE( "scene_refresh_flag"); - if (dm_compression) { - UNSUPPORTED(); - } - for (int8u i = 0; i < 9; ++i) { - Skip_S2(16, ("YCCtoRGB_coef" + to_string(i)).c_str()); - } - for (int8u i = 0; i < 3; ++i) { - Skip_S4(32, ("YCCtoRGB_offset" + to_string(i)).c_str()); - } - for (int8u i = 0; i < 9; ++i) { - Skip_S2(16, ("RGBtoLMS_coef" + to_string(i)).c_str()); - } - Skip_S2(16, "signal_eotf"); - Skip_S2(16, "signal_eotf_param0"); - Skip_S2(16, "signal_eotf_param1"); - Skip_S4(32, "signal_eotf_param2"); - Skip_S1( 5, "signal_bit_depth"); - Skip_S1( 2, "signal_color_space"); - Skip_S1( 2, "signal_chroma_format"); - Skip_S1( 2, "signal_full_range_flag"); - Skip_S2(12, "source_min_PQ"); - Skip_S2(12, "source_max_PQ"); - Skip_S2(10, "source_diagonal"); - - // Extension blocks - // ---------------------------------------------------------------------------------------- - - // Content Mapping v2.9 (CMv2.9) - int32u num_ext_blocks; - Get_UE(num_ext_blocks, "num_ext_blocks"); - if (num_ext_blocks) { - Skip_BS(Data_BS_Remain() & 7, "dm_alignment_zero_bit"); - for (int32u i = 0; i < num_ext_blocks; ++i) { - Element_Begin1("ext_metadata_block"); - int32u ext_block_length; - int8u ext_block_level; - Get_UE(ext_block_length, "ext_block_length"); - Get_S1(8, ext_block_level, "ext_block_level"); - Element_Begin1("ext_block_payload"); - size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; - auto ext_block_use_bits{ 0 }; - switch (ext_block_level) { - case 1: // ANALYSIS METADATA (DYNAMIC) - Skip_S2(12, "min_PQ"); - Skip_S2(12, "max_PQ"); - Skip_S2(12, "avg_PQ"); - ext_block_use_bits += 36; - break; - case 2: // PER-TARGET TRIM METADATA (DYNAMIC) - Skip_S2(12, "target_max_PQ"); - Skip_S2(12, "trim_slope"); - Skip_S2(12, "trim_offset"); - Skip_S2(12, "trim_power"); - Skip_S2(12, "trim_chroma_weight"); - Skip_S2(12, "trim_saturation_gain"); - Skip_S2(13, "ms_weight"); - ext_block_use_bits += 85; - break; - case 4: - Skip_S2(12, "anchor_pq"); - Skip_S2(12, "anchor_power"); - ext_block_use_bits += 24; - break; - case 5: // PER-SHOT ASPECT RATIO (DYNAMIC) - Skip_S2(13, "active_area_left_offset"); - Skip_S2(13, "active_area_right_offset"); - Skip_S2(13, "active_area_top_offset"); - Skip_S2(13, "active_area_bottom_offset"); - ext_block_use_bits += 52; - break; - case 6: // OPTIONAL HDR10 METADATA (STATIC) - Skip_S2(16, "max_display_mastering_luminance"); - Skip_S2(16, "min_display_mastering_luminance"); - Skip_S2(16, "max_content_light_level"); - Skip_S2(16, "max_frame_average_light_level"); - ext_block_use_bits += 64; - break; - case 255: - Skip_S1(8, "dm_run_mode"); - Skip_S1(8, "dm_run_version"); - Skip_S1(8, "dm_debug0"); - Skip_S1(8, "dm_debug1"); - Skip_S1(8, "dm_debug2"); - Skip_S1(8, "dm_debug3"); - ext_block_use_bits += 48; - break; - default: - Skip_BS(ext_block_len_bits - ext_block_use_bits, "(Not parsed)"); - break; - } - Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); - Element_End0(); // ext_block_payload - Element_End0(); // ext_metadata_block - } - } - - // Content Mapping v4.0 (CMv4.0) - if (Data_BS_Remain() >= 56) { - int32u num_ext_blocks2; - Get_UE(num_ext_blocks2, "num_ext_blocks"); - if (num_ext_blocks2) { - Skip_BS(Data_BS_Remain() & 7, "dm_alignment_zero_bit"); - for (int32u i = 0; i < num_ext_blocks2; ++i) { - Element_Begin1("ext_metadata_block"); - int32u ext_block_length; - int8u ext_block_level; - Get_UE(ext_block_length, "ext_block_length"); - Get_S1(8, ext_block_level, "ext_block_level"); - Element_Begin1("ext_block_payload"); - size_t ext_block_len_bits{ static_cast(ext_block_length) * 8 }; - auto ext_block_use_bits{ 0 }; - switch (ext_block_level) { - case 3: // OFFSETS TO L1 (DYNAMIC) - Skip_S2(12, "min_pq_offset"); - Skip_S2(12, "max_pq_offset"); - Skip_S2(12, "avg_pq_offset"); - ext_block_use_bits += 36; - break; - case 8: // PER-TARGET TRIM METADATA (DYNAMIC) - Skip_S1( 8, "target_display_index"); - Skip_S2(12, "trim_slope"); - Skip_S2(12, "trim_offset"); - Skip_S2(12, "trim_power"); - Skip_S2(12, "trim_chroma_weight"); - Skip_S2(12, "trim_saturation_gain"); - Skip_S2(12, "ms_weight"); - ext_block_use_bits += 80; - if (ext_block_length > 10) { - Skip_S2(12, "target_mid_contrast"); - ext_block_use_bits += 12; - } - if (ext_block_length > 12) { - Skip_S2(12, "clip_trim"); - ext_block_use_bits += 12; - } - if (ext_block_length > 13) { - for (int8u i = 0; i < 6; ++i) { - Skip_S1(8, ("saturation_vector_field" + to_string(i)).c_str()); - } - ext_block_use_bits += 48; - } - if (ext_block_length > 19) { - for (int8u i = 0; i < 6; ++i) { - Skip_S1(8, ("hue_vector_field" + to_string(i)).c_str()); - } - ext_block_use_bits += 48; - } - break; - case 9: // PER-SHOT SOURCE CONTENT PRIMARIES (DYNAMIC) - Skip_S1(8, "source_primary_index"); - ext_block_use_bits += 8; - if (ext_block_length > 1) { - Skip_S2(16, "source_primary_red_x"); - Skip_S2(16, "source_primary_red_y"); - Skip_S2(16, "source_primary_green_x"); - Skip_S2(16, "source_primary_green_y"); - Skip_S2(16, "source_primary_blue_x"); - Skip_S2(16, "source_primary_blue_y"); - Skip_S2(16, "source_primary_white_x"); - Skip_S2(16, "source_primary_white_y"); - ext_block_use_bits += 128; - } - break; - case 10: - Skip_S1( 8, "target_display_index"); - Skip_S2(12, "target_max_pq"); - Skip_S2(12, "target_min_pq"); - Skip_S1( 8, "target_primary_index"); - ext_block_use_bits += 40; - if (ext_block_length > 5) { - Skip_S2(16, "target_primary_red_x"); - Skip_S2(16, "target_primary_red_y"); - Skip_S2(16, "target_primary_green_x"); - Skip_S2(16, "target_primary_green_y"); - Skip_S2(16, "target_primary_blue_x"); - Skip_S2(16, "target_primary_blue_y"); - Skip_S2(16, "target_primary_white_x"); - Skip_S2(16, "target_primary_white_y"); - ext_block_use_bits += 128; - } - break; - case 11: - { // Automatic Picture/Playback Optimization (APO) / Dolby Vision IQ - Content Type Metadata (L11) - int8u content_type, white_point, sharpness, noise_reduction, mpeg_noise_reduction, frame_rate_conversion, brightness, color; - Get_S1 (8, content_type, "content_type"); Param_Info1(DV_content_type(content_type)); - Get_S1 (4, white_point, "white_point"); Param_Info1(DV_white_point(white_point)); - Skip_SB( "reference_mode_flag"); - Skip_S1(3, "reserved"); - Get_S1 (2, sharpness, "sharpness"); Param_Info1(DV_intended_setting(sharpness, true)); - Get_S1 (2, noise_reduction, "noise_reduction"); Param_Info1(DV_intended_setting(noise_reduction, true)); - Get_S1 (2, mpeg_noise_reduction, "mpeg_noise_reduction"); Param_Info1(DV_intended_setting(mpeg_noise_reduction, true)); - Get_S1 (2, frame_rate_conversion, "frame_rate_conversion"); Param_Info1(DV_intended_setting(frame_rate_conversion, true)); - Get_S1 (2, brightness, "brightness"); Param_Info1(DV_intended_setting(brightness, false)); - Get_S1 (2, color, "color"); Param_Info1(DV_intended_setting(color, false)); - Skip_S1(2, "reserved1"); - Skip_S1(2, "reserved2"); - ext_block_use_bits += 32; - break; - } - case 254: // CM version - Skip_S1(8, "dm_mode"); - Skip_S1(8, "dm_version_index"); - ext_block_use_bits += 16; - break; - default: - Skip_BS(ext_block_len_bits, "(Not parsed)"); - ext_block_use_bits += ext_block_len_bits; - break; - } - Skip_BS(ext_block_len_bits - ext_block_use_bits, "ext_dm_alignment_zero_bit"); - Element_End0(); // ext_block_payload - Element_End0(); // ext_metadata_block - } - } - } - Element_End0(); // vdr_dm_data_payload - } - - Skip_BS(Data_BS_Remain() & 7, "rpu_alignment_zero_bit"); - BS_End(); - Skip_B4( "rpu_data_crc32"); - if (!CRC_32_Table_IEEE) { - CRC_32_Table_IEEE.reset(new int32u[256]); - CRC32_Init(CRC_32_Table_IEEE.get(), 0x04C11DB7); - } - int32u CRC_32 = 0xFFFFFFFF; - const int8u* CRC_32_Buffer = Buffer + Buffer_Offset + Element_Offset_Begin; - while (CRC_32_Buffer < Buffer + Buffer_Offset + Element_Offset) { - CRC_32 = (CRC_32 << 8) ^ CRC_32_Table_IEEE[(CRC_32 >> 24) ^ (*CRC_32_Buffer++)]; - } - Param_Info1(CRC_32 ? "NOK" : "OK"); - Element_End0(); // rpu_data - + Skip_B1( "nal_prefix"); BS_Begin(); - Mark_1(); // rbsp_stop_one_bit + Get_DolbyVision_ReferenceProcessingUnit(DV_RPU_data); BS_End(); - - #undef UNSUPPORTED } //--------------------------------------------------------------------------- diff --git a/Source/MediaInfo/Video/File_Hevc.h b/Source/MediaInfo/Video/File_Hevc.h index 6a90f8e7bd..e690225cb4 100644 --- a/Source/MediaInfo/Video/File_Hevc.h +++ b/Source/MediaInfo/Video/File_Hevc.h @@ -12,7 +12,6 @@ //--------------------------------------------------------------------------- #include "MediaInfo/File__Analyze.h" #include "MediaInfo/TimeCode.h" -#include //--------------------------------------------------------------------------- namespace MediaInfoLib @@ -518,6 +517,7 @@ private : }; typedef std::map hdr; hdr HDR; + DV_RPU DV_RPU_data; Ztring EtsiTS103433; int32u chroma_format_idc{}; int32u slice_pic_parameter_set_id{}; @@ -533,9 +533,6 @@ private : Ztring ambient_viewing_environment_chromaticity; bool RapPicFlag{}; bool first_slice_segment_in_pic_flag{}; - - //CRC Tables - std::unique_ptr CRC_32_Table_IEEE; }; } //NameSpace From 83ac657b5e9433b84af37dac5ba75f2b371198fa Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:57:59 +0800 Subject: [PATCH 5/6] AV1: AOMedia ITU-T T.35 metadata --- Source/MediaInfo/Video/File_Av1.cpp | 28 ++++++++++++++++++++++++++++ Source/MediaInfo/Video/File_Av1.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/Source/MediaInfo/Video/File_Av1.cpp b/Source/MediaInfo/Video/File_Av1.cpp index b953ef91a1..feb7577522 100644 --- a/Source/MediaInfo/Video/File_Av1.cpp +++ b/Source/MediaInfo/Video/File_Av1.cpp @@ -646,6 +646,7 @@ void File_Av1::metadata_itu_t_t35_B5() { case 0x003B: Param_Info1("Dolby Laboratories, Inc."); metadata_itu_t_t35_B5_003B(); break; case 0x003C: Param_Info1("Samsung Electronics America"); metadata_itu_t_t35_B5_003C(); break; + case 0x5890: Param_Info1("AOMedia"); metadata_itu_t_t35_B5_5890(); break; } } @@ -902,6 +903,33 @@ void File_Av1::metadata_itu_t_t35_B5_003C_0001_04() FILLING_END(); } +//--------------------------------------------------------------------------- +void File_Av1::metadata_itu_t_t35_B5_5890() +{ + int8u itu_t_t35_terminal_provider_oriented_code; + Get_B1(itu_t_t35_terminal_provider_oriented_code, "itu_t_t35_terminal_provider_oriented_code"); + + switch (itu_t_t35_terminal_provider_oriented_code) + { + case 0x01: metadata_itu_t_t35_B5_5890_01(); break; + } +} + +//--------------------------------------------------------------------------- +void File_Av1::metadata_itu_t_t35_B5_5890_01() +{ + Element_Info1("AOMedia Film Grain Synthesis 1 (AFGS1)"); + + Element_Begin1("av1_film_grain_param_sets"); + BS_Begin(); + Skip_SB( "afgs1_enable_flag"); + Skip_S1(4, "reserved_4bits"); + Skip_S1(3, "num_film_grain_sets_minus1"); + BS_End(); + Skip_XX(Element_Size - Element_Offset, "(Not parsed)"); + Element_End0(); +} + //--------------------------------------------------------------------------- void File_Av1::frame() { diff --git a/Source/MediaInfo/Video/File_Av1.h b/Source/MediaInfo/Video/File_Av1.h index 53c5bd7116..c7fd278c7c 100644 --- a/Source/MediaInfo/Video/File_Av1.h +++ b/Source/MediaInfo/Video/File_Av1.h @@ -63,6 +63,8 @@ private : void metadata_itu_t_t35_B5_003C(); void metadata_itu_t_t35_B5_003C_0001(); void metadata_itu_t_t35_B5_003C_0001_04(); + void metadata_itu_t_t35_B5_5890(); + void metadata_itu_t_t35_B5_5890_01(); void frame(); void padding(); From c668e4f5ee70fcae0eb39f3d34b6ce8a853216eb Mon Sep 17 00:00:00 2001 From: cjee21 <77721854+cjee21@users.noreply.github.com> Date: Sat, 11 Oct 2025 13:20:33 +0800 Subject: [PATCH 6/6] [TEMP TESTING / To replace with proper filling] --- Source/MediaInfo/Video/File_Av1.cpp | 50 +++++++++++++++++++++++++++- Source/MediaInfo/Video/File_Hevc.cpp | 45 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/Source/MediaInfo/Video/File_Av1.cpp b/Source/MediaInfo/Video/File_Av1.cpp index feb7577522..43ab705217 100644 --- a/Source/MediaInfo/Video/File_Av1.cpp +++ b/Source/MediaInfo/Video/File_Av1.cpp @@ -39,6 +39,10 @@ extern const char* Mpegv_matrix_coefficients(int8u matrix_coefficients); extern const char* Mpegv_matrix_coefficients_ColorSpace(int8u matrix_coefficients); extern const char* Avc_video_full_range[]; +const char* DV_content_type(int8u content_type); +const char* DV_white_point(int8u white_point); +const char* DV_intended_setting(int8u setting, bool off); + //--------------------------------------------------------------------------- const char* Av1_obu_type(int8u obu_type) { @@ -801,7 +805,51 @@ void File_Av1::metadata_itu_t_t35_B5_003B_00000800() Element_Begin1("emdf_payload_bytes"); switch (emdf_payload_id) { - case 256: Get_DolbyVision_ReferenceProcessingUnit(DV_RPU_data); break; + case 256: Get_DolbyVision_ReferenceProcessingUnit(DV_RPU_data); + //Filling + FILLING_BEGIN(); + if (DV_RPU_data.active_area_left_offset || DV_RPU_data.active_area_right_offset || DV_RPU_data.active_area_top_offset || DV_RPU_data.active_area_bottom_offset) { + auto width = Retrieve(StreamKind_Last, StreamPos_Last, Video_Width).To_int16u(); + auto height = Retrieve(StreamKind_Last, StreamPos_Last, Video_Height).To_int16u(); + auto active_width = width - DV_RPU_data.active_area_left_offset - DV_RPU_data.active_area_right_offset; + auto active_height = height - DV_RPU_data.active_area_top_offset - DV_RPU_data.active_area_bottom_offset; + Fill(StreamKind_Last, StreamPos_Last, Video_Active_Width, active_width); + Fill(StreamKind_Last, StreamPos_Last, Video_Active_Height, active_height); + float32 PAR = Retrieve_Const(StreamKind_Last, StreamPos_Last, "PixelAspectRatio").To_float32(); + if (PAR) + Fill(StreamKind_Last, StreamPos_Last, Video_Active_DisplayAspectRatio, ((float32)active_width) / active_height * PAR, 2); + } + if (DV_RPU_data.max_display_mastering_luminance && DV_RPU_data.min_display_mastering_luminance) { + Ztring display_mastering_luminance = __T("min: ") + Ztring::ToZtring((float64)DV_RPU_data.min_display_mastering_luminance / 10000, 4) + + __T(" cd/m2, max: ") + Ztring::ToZtring(DV_RPU_data.max_display_mastering_luminance, 0) + + __T(" cd/m2"); + Fill(StreamKind_Last, StreamPos_Last, "MasteringDisplay_Luminance", display_mastering_luminance); // crash at later calls if filled with enum + } + if (DV_RPU_data.max_content_light_level && DV_RPU_data.max_frame_average_light_level) { + // TODO + } + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision", "RPU Present"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision RPU_Profile", DV_RPU_data.vdr_rpu_profile); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Base_Layer", (std::to_string(DV_RPU_data.bl_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Enhancement_Layer", (std::to_string(DV_RPU_data.el_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision VDR", (std::to_string(DV_RPU_data.vdr_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Base_Layer_Video_Range", DV_RPU_data.BL_video_full_range_flag ? "Full" : "Limited"); + if (DV_RPU_data.isMEL != (int8u)-1) Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Enhancement_Layer_Type", DV_RPU_data.isMEL == 0 ? "Full (FEL)" : "Minimal (MEL)"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Mapping_version", DV_RPU_data.CMv, 1); + if (DV_RPU_data.L11_present) { + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata", "Present"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Content_Type", DV_content_type(DV_RPU_data.content_type)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata White_Point", DV_white_point(DV_RPU_data.white_point)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Sharpness", DV_intended_setting(DV_RPU_data.sharpness, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Noise_Reduction", DV_intended_setting(DV_RPU_data.noise_reduction, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata MPEG_Noise_Reduction", DV_intended_setting(DV_RPU_data.mpeg_noise_reduction, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Frame_Rate_Conversion", DV_intended_setting(DV_RPU_data.frame_rate_conversion, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Brightness", DV_intended_setting(DV_RPU_data.brightness, false)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Color", DV_intended_setting(DV_RPU_data.color, false)); + } + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Deduced_Profile", DV_RPU_data.profile_deduced); + FILLING_END(); + break; default : Skip_BS(static_cast(emdf_payload_size) * 8, "(Unknown)"); break; } size_t RemainginBits=Data_BS_Remain(); diff --git a/Source/MediaInfo/Video/File_Hevc.cpp b/Source/MediaInfo/Video/File_Hevc.cpp index 87cd975ddf..87f24f8e13 100644 --- a/Source/MediaInfo/Video/File_Hevc.cpp +++ b/Source/MediaInfo/Video/File_Hevc.cpp @@ -30,6 +30,10 @@ using namespace ZenLib; namespace MediaInfoLib { +const char* DV_content_type(int8u content_type); +const char* DV_white_point(int8u white_point); +const char* DV_intended_setting(int8u setting, bool off); + //--------------------------------------------------------------------------- extern const char* Hevc_tier_flag(bool tier_flag) { @@ -3782,6 +3786,47 @@ void File_Hevc::Dolby_Vision_reference_processing_unit() BS_Begin(); Get_DolbyVision_ReferenceProcessingUnit(DV_RPU_data); BS_End(); + + //Filling + FILLING_BEGIN(); + if (DV_RPU_data.active_area_left_offset || DV_RPU_data.active_area_right_offset || DV_RPU_data.active_area_top_offset || DV_RPU_data.active_area_bottom_offset) { + auto width = Retrieve(StreamKind_Last, StreamPos_Last, Video_Width).To_int16u(); + auto height = Retrieve(StreamKind_Last, StreamPos_Last, Video_Height).To_int16u(); + auto active_width = width - DV_RPU_data.active_area_left_offset - DV_RPU_data.active_area_right_offset; + auto active_height = height - DV_RPU_data.active_area_top_offset - DV_RPU_data.active_area_bottom_offset; + Fill(StreamKind_Last, StreamPos_Last, Video_Active_Width, active_width); + Fill(StreamKind_Last, StreamPos_Last, Video_Active_Height, active_height); + float32 PAR = Retrieve_Const(StreamKind_Last, StreamPos_Last, "PixelAspectRatio").To_float32(); + if (PAR) + Fill(StreamKind_Last, StreamPos_Last, Video_Active_DisplayAspectRatio, ((float32)active_width) / active_height * PAR, 2); + } + if (DV_RPU_data.max_display_mastering_luminance && DV_RPU_data.min_display_mastering_luminance) { + Ztring display_mastering_luminance = __T("min: ") + Ztring::ToZtring((float64)DV_RPU_data.min_display_mastering_luminance/10000, 4) + + __T(" cd/m2, max: ") + Ztring::ToZtring(DV_RPU_data.max_display_mastering_luminance, 0) + + __T(" cd/m2"); + Fill(StreamKind_Last, StreamPos_Last, "MasteringDisplay_Luminance", display_mastering_luminance); + } + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision", "RPU Present"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision RPU_Profile", DV_RPU_data.vdr_rpu_profile); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Base_Layer", (to_string(DV_RPU_data.bl_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Enhancement_Layer", (to_string(DV_RPU_data.el_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision VDR", (to_string(DV_RPU_data.vdr_bit_depth) + " bits").c_str()); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Base_Layer_Video_Range", DV_RPU_data.BL_video_full_range_flag ? "Full" : "Limited"); + if (DV_RPU_data.isMEL != (int8u)-1) Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Enhancement_Layer_Type", DV_RPU_data.isMEL == 0 ? "Full (FEL)" : "Minimal (MEL)"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Mapping_version", DV_RPU_data.CMv, 1); + if (DV_RPU_data.L11_present) { + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata", "Present"); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Content_Type", DV_content_type(DV_RPU_data.content_type)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata White_Point", DV_white_point(DV_RPU_data.white_point)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Sharpness", DV_intended_setting(DV_RPU_data.sharpness, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Noise_Reduction", DV_intended_setting(DV_RPU_data.noise_reduction, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata MPEG_Noise_Reduction", DV_intended_setting(DV_RPU_data.mpeg_noise_reduction, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Frame_Rate_Conversion", DV_intended_setting(DV_RPU_data.frame_rate_conversion, true)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Brightness", DV_intended_setting(DV_RPU_data.brightness, false)); + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Content_Type_Metadata Color", DV_intended_setting(DV_RPU_data.color, false)); + } + Fill(StreamKind_Last, StreamPos_Last, "Dolby_Vision Deduced_Profile", DV_RPU_data.profile_deduced); + FILLING_END(); } //---------------------------------------------------------------------------