| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/video/h266_parser.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <cstring> |
| |
| #include "base/bits.h" |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "media/base/decrypt_config.h" |
| #include "media/base/video_codecs.h" |
| #include "media/video/bit_reader_macros.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace media { |
| |
| namespace { |
| // Equation 24. kDiagScanOrderMxM[i][0] is the horizontal component, and |
| // kDiagScanOrderMxM[i][1] is the vertical component. |
| constexpr uint8_t kDiagScanOrder8x8[64][2] = { |
| {0, 0}, {0, 1}, {1, 0}, {0, 2}, {1, 1}, {2, 0}, {0, 3}, {1, 2}, |
| {2, 1}, {3, 0}, {0, 4}, {1, 3}, {2, 2}, {3, 1}, {4, 0}, {0, 5}, |
| {1, 4}, {2, 3}, {3, 2}, {4, 1}, {5, 0}, {0, 6}, {1, 5}, {2, 4}, |
| {3, 3}, {4, 2}, {5, 1}, {6, 0}, {0, 7}, {1, 6}, {2, 5}, {3, 4}, |
| {4, 3}, {5, 2}, {6, 1}, {7, 0}, {1, 7}, {2, 6}, {3, 5}, {4, 4}, |
| {5, 3}, {6, 2}, {7, 1}, {2, 7}, {3, 6}, {4, 5}, {5, 4}, {6, 3}, |
| {7, 2}, {3, 7}, {4, 6}, {5, 5}, {6, 4}, {7, 3}, {4, 7}, {5, 6}, |
| {6, 5}, {7, 4}, {5, 7}, {6, 6}, {7, 5}, {6, 7}, {7, 6}, {7, 7}}; |
| |
| constexpr uint8_t kDiagScanOrder4x4[16][2] = { |
| {0, 0}, {0, 1}, {1, 0}, {0, 2}, {1, 1}, {2, 0}, {0, 3}, {1, 2}, |
| {2, 1}, {3, 0}, {1, 3}, {2, 2}, {3, 1}, {2, 3}, {3, 2}, {3, 3}}; |
| |
| constexpr uint8_t kDiagScanOrder2x2[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}}; |
| |
| } // namespace |
| |
| H266ProfileTierLevel::H266ProfileTierLevel() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266VPS::H266VPS() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266VPS::~H266VPS() = default; |
| |
| H266SPS::H266SPS() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266SPS::~H266SPS() = default; |
| |
| H266RefPicListStruct::H266RefPicListStruct() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266RefPicLists::H266RefPicLists() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266SublayerHrdParameters::H266SublayerHrdParameters() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266OlsTimingHrdParameters::H266OlsTimingHrdParameters() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266PPS::H266PPS() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266APS::H266APS(int aps_type) : aps_params_type(aps_type) { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| switch (aps_type) { |
| case 0: |
| data.emplace<H266AlfData>(); |
| break; |
| case 1: |
| data.emplace<H266LmcsData>(); |
| break; |
| case 2: |
| data.emplace<H266ScalingListData>(); |
| break; |
| } |
| } |
| |
| H266APS::~H266APS() = default; |
| |
| H266ScalingListData::H266ScalingListData() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266AlfData::H266AlfData() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266LmcsData::H266LmcsData() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266PredWeightTable::H266PredWeightTable() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266PictureHeader::H266PictureHeader() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266SliceHeader::H266SliceHeader() { |
| memset(reinterpret_cast<void*>(this), 0, sizeof(*this)); |
| } |
| |
| H266SliceHeader::~H266SliceHeader() = default; |
| |
| H266Parser::H266Parser() = default; |
| |
| H266Parser::~H266Parser() = default; |
| |
| int H266ProfileTierLevel::MaxLumaPs() const { |
| // From Table A.8 - General tier and level limits. |
| // |general_level_idc| is major_level * 16 + minor_level * 3 |
| if (general_level_idc <= 16) { // level 1 |
| return 36864; |
| } |
| if (general_level_idc <= 32) { // level 2 |
| return 122880; |
| } |
| if (general_level_idc <= 35) { // level 2.1 |
| return 245760; |
| } |
| if (general_level_idc <= 48) { // level 3 |
| return 552960; |
| } |
| if (general_level_idc <= 51) { // level 3.1 |
| return 983040; |
| } |
| if (general_level_idc <= 67) { // level 4, 4.1 |
| return 2228224; |
| } |
| if (general_level_idc <= 86) { // level 5, 5.1, 5.2 |
| return 8912896; |
| } |
| if (general_level_idc <= 102) { // level 6, 6.1, 6.2 |
| return 35651584; |
| } |
| // level 6.3 - beyond that there's no actual limit. |
| return 80216064; |
| } |
| |
| int H266ProfileTierLevel::MaxSlicesPerAu() const { |
| // Table A.2 |
| if (general_level_idc <= 32) { // level 1, 2 |
| return 16; |
| } |
| if (general_level_idc <= 35) { // level 2.1 |
| return 20; |
| } |
| if (general_level_idc <= 48) { // level 3 |
| return 30; |
| } |
| if (general_level_idc <= 51) { // level 3.1 |
| return 40; |
| } |
| if (general_level_idc <= 67) { // level 4, 4.1 |
| return 75; |
| } |
| if (general_level_idc <= 86) { // level 5, 5.1, 5.2 |
| return 200; |
| } |
| if (general_level_idc <= 102) { // level 6, 6.1, 6.2 |
| return 600; |
| } |
| // level 6.3 - beyond that there's no actual limit. |
| return 1000; |
| } |
| |
| int H266ProfileTierLevel::MaxTilesPerAu() const { |
| // Table A.2 |
| if (general_level_idc <= 35) { // level 1, 2, 2.1 |
| return 1; |
| } |
| if (general_level_idc <= 48) { // level 3 |
| return 4; |
| } |
| if (general_level_idc <= 51) { // level 3.1 |
| return 9; |
| } |
| if (general_level_idc <= 67) { // level 4, 4.1 |
| return 25; |
| } |
| if (general_level_idc <= 86) { // level 5, 5.1, 5.2 |
| return 110; |
| } |
| if (general_level_idc <= 102) { // level 6, 6.1, 6.2 |
| return 440; |
| } |
| // level 6.3 - beyond that there's no actual limit. |
| return 990; |
| } |
| |
| // Coded size and visible rect here only reflects the largest layer |
| // picture size in the stream. |
| gfx::Size H266SPS::GetCodedSize() const { |
| return gfx::Size(sps_pic_width_max_in_luma_samples, |
| sps_pic_height_max_in_luma_samples); |
| } |
| |
| // This is the stream level visible rect. |
| gfx::Rect H266SPS::GetVisibleRect() const { |
| // 7.4.3.4 |
| // These are verified in the parser that they won't overflow. |
| int left = sps_conf_win_left_offset * sub_width_c; |
| int top = sps_conf_win_top_offset * sub_height_c; |
| int right = sps_conf_win_right_offset * sub_width_c; |
| int bottom = sps_conf_win_bottom_offset * sub_height_c; |
| return gfx::Rect(left, top, sps_pic_width_max_in_luma_samples - left - right, |
| sps_pic_height_max_in_luma_samples - top - bottom); |
| } |
| |
| // Refer to vui_parameters syntax for more details. |
| VideoColorSpace H266SPS::GetColorSpace() const { |
| if (!vui_parameters.vui_colour_description_present_flag) { |
| return VideoColorSpace(); |
| } |
| |
| return VideoColorSpace(vui_parameters.vui_colour_primaries, |
| vui_parameters.vui_transfer_characteristics, |
| vui_parameters.vui_matrix_coeffs, |
| vui_parameters.vui_full_range_flag |
| ? gfx::ColorSpace::RangeID::FULL |
| : gfx::ColorSpace::RangeID::LIMITED); |
| } |
| |
| VideoChromaSampling H266SPS::GetChromaSampling() const { |
| switch (sps_chroma_format_idc) { |
| case 0: |
| return VideoChromaSampling::k400; |
| case 1: |
| return VideoChromaSampling::k420; |
| case 2: |
| return VideoChromaSampling::k422; |
| case 3: |
| return VideoChromaSampling::k444; |
| default: |
| NOTREACHED(); |
| return VideoChromaSampling::kUnknown; |
| } |
| } |
| |
| int H266VPS::GetGeneralLayerIdx(int nuh_layer_id) const { |
| auto match = general_layer_idx.find(nuh_layer_id); |
| if (match == general_layer_idx.end()) { |
| return -1; |
| } else { |
| return match->second; |
| } |
| } |
| |
| bool H266SliceHeader::IsISlice() const { |
| return sh_slice_type == H266SliceHeader::kSliceTypeI; |
| } |
| |
| bool H266SliceHeader::IsPSlice() const { |
| return sh_slice_type == H266SliceHeader::kSliceTypeP; |
| } |
| |
| bool H266SliceHeader::IsBSlice() const { |
| return sh_slice_type == H266SliceHeader::kSliceTypeB; |
| } |
| |
| #define READ_BOOL_GENERAL_CONSTRAINT_INFO(a) \ |
| READ_BOOL_OR_RETURN(&(profile_tier_level->general_constraints_info.a)) |
| #define READ_BITS_GENERAL_CONSTRAINT_INFO(bits, a) \ |
| READ_BITS_OR_RETURN((bits), &(profile_tier_level->general_constraints_info.a)) |
| H266Parser::Result H266Parser::ParseProfileTierLevel( |
| bool profile_tier_present, |
| int max_num_sub_layers_minus1, |
| H266ProfileTierLevel* profile_tier_level) { |
| // 7.3.3.1: General profile, tier, and level syntax |
| DVLOG(4) << "Parsing profile_tier_level."; |
| |
| if (profile_tier_present) { |
| READ_BITS_OR_RETURN(7, &profile_tier_level->general_profile_idc); |
| READ_BOOL_OR_RETURN(&profile_tier_level->general_tier_flag); |
| } |
| |
| READ_BITS_OR_RETURN(8, &profile_tier_level->general_level_idc); |
| READ_BOOL_OR_RETURN(&profile_tier_level->ptl_frame_only_constraint_flag); |
| READ_BOOL_OR_RETURN(&profile_tier_level->ptl_multilayer_enabled_flag); |
| if (profile_tier_present) { |
| // 7.3.3.2: General constraints information syntax. |
| READ_BOOL_OR_RETURN( |
| &profile_tier_level->general_constraints_info.gci_present_flag); |
| |
| if (profile_tier_level->general_constraints_info.gci_present_flag) { |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_intra_only_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_all_layers_independent_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_one_au_only_constraint_flag); |
| |
| READ_BITS_GENERAL_CONSTRAINT_INFO( |
| 4, gci_sixteen_minus_max_bitdepth_constraint_idc); |
| IN_RANGE_OR_RETURN(profile_tier_level->general_constraints_info |
| .gci_sixteen_minus_max_bitdepth_constraint_idc, |
| 0, 8); |
| READ_BITS_GENERAL_CONSTRAINT_INFO( |
| 2, gci_three_minus_max_chroma_format_constraint_idc); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_mixed_nalu_types_in_pic_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_trail_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_stsa_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_rasl_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_radl_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_idr_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_cra_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_gdr_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_aps_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_idr_rpl_constraint_flag); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_one_tile_per_pic_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_pic_header_in_slice_header_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_one_slice_per_pic_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_rectangular_slice_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_one_slice_per_subpic_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_subpic_info_constraint_flag); |
| |
| READ_BITS_GENERAL_CONSTRAINT_INFO( |
| 2, gci_three_minus_max_log2_ctu_size_constraint_idc); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_partition_constraints_override_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_mtt_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_qtbtt_dual_tree_intra_constraint_flag); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_palette_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_ibc_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_isp_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_mrl_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_mip_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_cclm_constraint_flag); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_ref_pic_resampling_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_res_change_in_clvs_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_weighted_prediction_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_ref_wraparound_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_temporal_mvp_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_sbtmvp_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_amvr_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_bdof_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_smvd_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_dmvr_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_mmvd_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_affine_motion_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_prof_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_bcw_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_ciip_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_gpm_constraint_flag); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_luma_transform_size_64_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_transform_skip_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_bdpcm_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_mts_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_lfnst_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_joint_cbcr_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_sbt_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_act_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_explicit_scaling_list_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_dep_quant_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_sign_data_hiding_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_cu_qp_delta_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_chroma_qp_offset_constraint_flag); |
| |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_sao_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_alf_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_ccalf_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_lmcs_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_no_ladf_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_virtual_boundaries_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_num_additional_bits); |
| int num_additional_bits_used = 0; |
| int num_additional_bits = |
| profile_tier_level->general_constraints_info.gci_num_additional_bits; |
| if (num_additional_bits > 5) { |
| READ_BOOL_GENERAL_CONSTRAINT_INFO(gci_all_rap_pictures_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_extended_precision_processing_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_ts_residual_coding_rice_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_rrc_rice_extension_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_persistent_rice_adaptation_constraint_flag); |
| READ_BOOL_GENERAL_CONSTRAINT_INFO( |
| gci_no_reverse_last_sig_coeff_constraint_flag); |
| num_additional_bits_used = 6; |
| } |
| |
| for (int i = 0; i < num_additional_bits - num_additional_bits_used; i++) { |
| SKIP_BITS_OR_RETURN(1); |
| } |
| } |
| BYTE_ALIGNMENT(); |
| } |
| |
| for (int i = max_num_sub_layers_minus1 - 1; i >= 0; i--) { |
| READ_BOOL_OR_RETURN( |
| &profile_tier_level->ptl_sublayer_level_present_flag[i]); |
| } |
| BYTE_ALIGNMENT(); |
| |
| // sublayer_level_idc[MaxNumSubLayersMinus1] is inferred to be equal to |
| // general_level_idc of the same profile_tier_level() structure. |
| profile_tier_level->sub_layer_level_idc[max_num_sub_layers_minus1] = |
| profile_tier_level->general_level_idc; |
| for (int i = max_num_sub_layers_minus1 - 1; i >= 0; i--) { |
| if (profile_tier_level->ptl_sublayer_level_present_flag[i]) { |
| READ_BITS_OR_RETURN(8, &profile_tier_level->sub_layer_level_idc[i]); |
| } else { |
| profile_tier_level->sub_layer_level_idc[i] = |
| profile_tier_level->sub_layer_level_idc[i + 1]; |
| } |
| } |
| |
| if (profile_tier_present) { |
| READ_BITS_OR_RETURN(8, &profile_tier_level->ptl_num_sub_profiles); |
| IN_RANGE_OR_RETURN(profile_tier_level->ptl_num_sub_profiles, 0, |
| kMaxSubProfiles); |
| for (int i = 0; i < profile_tier_level->ptl_num_sub_profiles; i++) { |
| // Reader does not support more than 31-bits, so we have to read twice. |
| int general_sub_profile_idc_msb = 0, general_sub_profile_idc_lsb; |
| READ_BITS_OR_RETURN(16, &general_sub_profile_idc_msb); |
| READ_BITS_OR_RETURN(16, &general_sub_profile_idc_lsb); |
| profile_tier_level->general_sub_profiles_idc[i] = |
| (general_sub_profile_idc_msb << 16) + general_sub_profile_idc_lsb; |
| } |
| } |
| |
| return kOk; |
| } |
| #undef READ_BITS_GENERAL_CONSTRAINT_INFO |
| #undef READ_BOOL_GENERAL_CONSTRAINT_INFO |
| |
| H266Parser::Result H266Parser::ParseDpbParameters( |
| int max_sublayers_minus1, |
| bool sublayer_info_flag, |
| H266DPBParameters* dpb_parameters) { |
| DCHECK(dpb_parameters); |
| |
| for (int i = (sublayer_info_flag ? 0 : max_sublayers_minus1); |
| i <= max_sublayers_minus1; i++) { |
| READ_UE_OR_RETURN(&dpb_parameters->dpb_max_dec_pic_buffering_minus1[i]); |
| // When parsing VPS, there is no information about maximum dpb size, so |
| // using the upper bound 16 for range check. |
| IN_RANGE_OR_RETURN(dpb_parameters->dpb_max_dec_pic_buffering_minus1[i], 0, |
| kMaxDpbPicBuffer * 2); |
| READ_UE_OR_RETURN(&dpb_parameters->dpb_max_num_reorder_pics[i]); |
| IN_RANGE_OR_RETURN(dpb_parameters->dpb_max_num_reorder_pics[i], 0, |
| dpb_parameters->dpb_max_dec_pic_buffering_minus1[i]); |
| if (i > 0) { |
| GT_OR_RETURN(dpb_parameters->dpb_max_num_reorder_pics[i], |
| dpb_parameters->dpb_max_num_reorder_pics[i - 1]); |
| } |
| READ_UE_OR_RETURN(&dpb_parameters->dpb_max_latency_increase_plus1[i]); |
| } |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParseVuiPayload(int payload_size, |
| const H266SPS& sps, |
| H266VUIParameters* vui) { |
| DCHECK(vui); |
| |
| int start_remain_size = br_.NumBitsLeft(); |
| H266Parser::Result res = ParseVuiParameters(sps, vui); |
| if (res != kOk) { |
| DVLOG(1) << "Failed to parse VUI param."; |
| return res; |
| } |
| int bits_unread = payload_size * 8 - (start_remain_size - br_.NumBitsLeft()); |
| // Skip the VUI extension data till sei_payload_bit_equal_to_one |
| while (bits_unread > 0) { |
| SKIP_BITS_OR_RETURN(1); |
| bits_unread--; |
| } |
| |
| BYTE_ALIGNMENT(); |
| return kOk; |
| } |
| |
| // ITU-T H.274|ISO/IEC 23002-7 VUI parameters |
| H266Parser::Result H266Parser::ParseVuiParameters(const H266SPS& sps, |
| H266VUIParameters* vui) { |
| DCHECK(vui); |
| |
| READ_BOOL_OR_RETURN(&vui->vui_progressive_source_flag); |
| READ_BOOL_OR_RETURN(&vui->vui_interlaced_source_flag); |
| READ_BOOL_OR_RETURN(&vui->vui_non_packed_constraint_flag); |
| READ_BOOL_OR_RETURN(&vui->vui_non_projected_constraint_flag); |
| READ_BOOL_OR_RETURN(&vui->vui_aspect_ratio_info_present_flag); |
| if (vui->vui_aspect_ratio_info_present_flag) { |
| READ_BOOL_OR_RETURN(&vui->vui_aspect_ratio_constant_flag); |
| READ_BITS_OR_RETURN(8, &vui->vui_aspect_ratio_idc); |
| if (vui->vui_aspect_ratio_idc == 255) { |
| READ_BITS_OR_RETURN(16, &vui->vui_sar_width); |
| READ_BITS_OR_RETURN(16, &vui->vui_sar_height); |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&vui->vui_overscan_info_present_flag); |
| if (vui->vui_overscan_info_present_flag) { |
| READ_BOOL_OR_RETURN(&vui->vui_overscan_appropriate_flag); |
| } |
| READ_BOOL_OR_RETURN(&vui->vui_colour_description_present_flag); |
| if (vui->vui_colour_description_present_flag) { |
| READ_BITS_OR_RETURN(8, &vui->vui_colour_primaries); |
| READ_BITS_OR_RETURN(8, &vui->vui_transfer_characteristics); |
| READ_BITS_OR_RETURN(8, &vui->vui_matrix_coeffs); |
| READ_BOOL_OR_RETURN(&vui->vui_full_range_flag); |
| } else { |
| vui->vui_colour_primaries = 2; |
| vui->vui_transfer_characteristics = 2; |
| vui->vui_matrix_coeffs = 2; |
| vui->vui_full_range_flag = 0; |
| } |
| READ_BOOL_OR_RETURN(&vui->vui_chroma_loc_info_present_flag); |
| if (sps.sps_chroma_format_idc != 1 && vui->vui_chroma_loc_info_present_flag) { |
| return kInvalidStream; |
| } |
| if (vui->vui_chroma_loc_info_present_flag) { |
| if (vui->vui_progressive_source_flag && !vui->vui_interlaced_source_flag) { |
| READ_UE_OR_RETURN(&vui->vui_chroma_sample_loc_type_frame); |
| IN_RANGE_OR_RETURN(vui->vui_chroma_sample_loc_type_frame, 0, 6); |
| } else { |
| READ_UE_OR_RETURN(&vui->vui_chroma_sample_loc_type_top_field); |
| IN_RANGE_OR_RETURN(vui->vui_chroma_sample_loc_type_top_field, 0, 6); |
| READ_UE_OR_RETURN(&vui->vui_chroma_sample_loc_type_bottom_field); |
| IN_RANGE_OR_RETURN(vui->vui_chroma_sample_loc_type_bottom_field, 0, 6); |
| } |
| } else { |
| if (sps.sps_chroma_format_idc == 1) { |
| vui->vui_chroma_sample_loc_type_frame = 6; |
| vui->vui_chroma_sample_loc_type_top_field = 6; |
| vui->vui_chroma_sample_loc_type_bottom_field = 6; |
| } |
| } |
| |
| return kOk; |
| } |
| |
| // 7.3.2.3 Video parameter set. |
| // Provides overall information of a bitstream, mainly about |
| // number of layers/sublayers, dependency among layers, number of |
| // OLSs(output layer sets), PTL of OPs(temporal subset of an OLS), |
| // DBP and HRD parameters. |
| // VPS is only used for multi-layer bistreams and decoders can ignore |
| // them for single-layer stream. Unlike HEVC, for single-layer bitsream, |
| // it is allowed no VPS is present in the bitstream(when SPS is referring |
| // to VPS id 0). |
| H266Parser::Result H266Parser::ParseVPS(int* vps_id) { |
| DVLOG(4) << "Parsing VPS"; |
| Result res = kOk; |
| DCHECK(vps_id); |
| |
| *vps_id = -1; |
| std::unique_ptr<H266VPS> vps = std::make_unique<H266VPS>(); |
| READ_BITS_OR_RETURN(4, &vps->vps_video_parameter_set_id); |
| GT_OR_RETURN(vps->vps_video_parameter_set_id, 0); |
| READ_BITS_OR_RETURN(6, &vps->vps_max_layers_minus1); |
| IN_RANGE_OR_RETURN(vps->vps_max_layers_minus1, 0, 64); |
| READ_BITS_OR_RETURN(3, &vps->vps_max_sublayers_minus1); |
| IN_RANGE_OR_RETURN(vps->vps_max_sublayers_minus1, 0, 6); |
| |
| // Inferred value of vps_default_ptl_dpb_hrd_max_tid_flag and |
| // vps_all_independent_layers_flags are both 1 if not present. |
| vps->vps_default_ptl_dpb_hrd_max_tid_flag = 1; |
| vps->vps_all_independent_layers_flags = 1; |
| if (vps->vps_max_layers_minus1 > 0) { |
| if (vps->vps_max_sublayers_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&vps->vps_default_ptl_dpb_hrd_max_tid_flag); |
| } |
| READ_BOOL_OR_RETURN(&vps->vps_all_independent_layers_flags); |
| } |
| |
| for (int i = 0; i <= vps->vps_max_layers_minus1; i++) { |
| READ_BITS_OR_RETURN(6, &vps->vps_layer_id[i]); |
| if (i > 0) { |
| GT_OR_RETURN(vps->vps_layer_id[i], vps->vps_layer_id[i - 1]); |
| } |
| if (i > 0 && !vps->vps_all_independent_layers_flags) { |
| READ_BOOL_OR_RETURN(&vps->vps_independent_layer_flag[i]); |
| if (!vps->vps_independent_layer_flag[i]) { |
| READ_BOOL_OR_RETURN(&vps->vps_max_tid_ref_present_flag[i]); |
| for (int j = 0; j < i; j++) { |
| READ_BOOL_OR_RETURN(&vps->vps_direct_ref_layer_flag[i][j]); |
| if (vps->vps_max_tid_ref_present_flag[i] && |
| vps->vps_direct_ref_layer_flag[i][j]) { |
| READ_BITS_OR_RETURN(3, &vps->vps_max_tid_il_ref_pics_plus1[i][j]); |
| } else { |
| // 7.4.3.3: inferred value when not present. |
| vps->vps_max_tid_il_ref_pics_plus1[i][j] = |
| vps->vps_max_sublayers_minus1 + 1; |
| } |
| } |
| } |
| } |
| } |
| |
| // Equation 29. This maps layer id to nuh_layer_id. |
| for (int i = 0; i <= vps->vps_max_layers_minus1; i++) { |
| vps->general_layer_idx[vps->vps_layer_id[i]] = i; |
| } |
| int ols_mode_idc = 0; |
| int total_num_olss = 0; |
| if (vps->vps_max_layers_minus1 > 0) { |
| if (vps->vps_all_independent_layers_flags) { |
| READ_BOOL_OR_RETURN(&vps->vps_each_layer_is_an_ols_flag); |
| } |
| if (!vps->vps_each_layer_is_an_ols_flag) { |
| if (!vps->vps_all_independent_layers_flags) { |
| READ_BITS_OR_RETURN(2, &vps->vps_ols_mode_idc); |
| } else { |
| vps->vps_ols_mode_idc = 2; |
| } |
| // Caution!!! vps_ols_mode_idc might be inferred to 2 instead of read |
| // from bitstream. |
| if (vps->vps_ols_mode_idc == 2) { |
| READ_BITS_OR_RETURN(8, &vps->vps_num_output_layer_sets_minus2); |
| for (int i = 1; i <= vps->vps_num_output_layer_sets_minus2 + 1; i++) { |
| for (int j = 0; j <= vps->vps_max_layers_minus1; j++) { |
| READ_BOOL_OR_RETURN(&vps->vps_ols_output_layer_flag[i][j]); |
| } |
| } |
| } |
| // Equation 30: ols_mode_idc derivation. |
| ols_mode_idc = vps->vps_ols_mode_idc; |
| } else { |
| ols_mode_idc = 4; |
| } |
| |
| // Equation 31: total_num_olss derivation. |
| if (ols_mode_idc == 0 || ols_mode_idc == 1 || ols_mode_idc == 4) { |
| total_num_olss = vps->vps_max_layers_minus1 + 1; |
| } else { |
| total_num_olss = vps->vps_num_output_layer_sets_minus2 + 2; |
| } |
| READ_BITS_OR_RETURN(8, &vps->vps_num_ptls_minus1); |
| IN_RANGE_OR_RETURN(vps->vps_num_ptls_minus1, 0, total_num_olss - 1); |
| } else { |
| vps->vps_each_layer_is_an_ols_flag = 1; |
| vps->vps_num_ptls_minus1 = 0; |
| } |
| |
| for (int i = 0; i <= vps->vps_num_ptls_minus1; i++) { |
| if (i > 0) { |
| READ_BOOL_OR_RETURN(&vps->vps_pt_present_flag[i]); |
| } else { |
| vps->vps_pt_present_flag[i] = 1; |
| } |
| if (!vps->vps_default_ptl_dpb_hrd_max_tid_flag) { |
| READ_BITS_OR_RETURN(3, &vps->vps_ptl_max_tid[i]); |
| IN_RANGE_OR_RETURN(vps->vps_ptl_max_tid[i], 0, |
| vps->vps_max_sublayers_minus1); |
| } else { |
| vps->vps_ptl_max_tid[i] = vps->vps_max_sublayers_minus1; |
| } |
| } |
| |
| BYTE_ALIGNMENT(); |
| |
| // Read profile-tier-level info in VPS. |
| for (int i = 0; i <= vps->vps_num_ptls_minus1; i++) { |
| ParseProfileTierLevel(vps->vps_pt_present_flag[i], vps->vps_ptl_max_tid[i], |
| &vps->profile_tier_level[i]); |
| if (i > 0 && !vps->vps_pt_present_flag[i]) { |
| // Section 7.4.3.3, vps_pt_present_flag[i] equal to 0, the profile/tier |
| // and general constraints information are copied from the i-1 the |
| // profile_tier_level() syntax structure in the VPS. (This should include |
| // the sub_profile_idc info.) |
| vps->profile_tier_level[i].general_profile_idc = |
| vps->profile_tier_level[i - 1].general_profile_idc; |
| vps->profile_tier_level[i].general_tier_flag = |
| vps->profile_tier_level[i - 1].general_tier_flag; |
| memcpy(&vps->profile_tier_level[i].general_constraints_info, |
| &vps->profile_tier_level[i - 1].general_constraints_info, |
| sizeof(vps->profile_tier_level[i - 1].general_constraints_info)); |
| LE_OR_RETURN(vps->profile_tier_level[i - 1].ptl_num_sub_profiles, |
| kMaxSubProfiles); |
| vps->profile_tier_level[i].ptl_num_sub_profiles = |
| vps->profile_tier_level[i - 1].ptl_num_sub_profiles; |
| memcpy( |
| &vps->profile_tier_level[i].general_sub_profiles_idc[0], |
| &vps->profile_tier_level[i - 1].general_sub_profiles_idc[0], |
| vps->profile_tier_level[i - 1].ptl_num_sub_profiles * |
| sizeof( |
| vps->profile_tier_level[i - 1].general_sub_profiles_idc[0])); |
| } |
| } |
| |
| for (int i = 0; i < total_num_olss; i++) { |
| if (vps->vps_num_ptls_minus1 > 0 && |
| vps->vps_num_ptls_minus1 + 1 != total_num_olss) { |
| READ_BITS_OR_RETURN(8, &vps->vps_ols_ptl_idx[i]); |
| IN_RANGE_OR_RETURN(vps->vps_ols_ptl_idx[i], 0, vps->vps_num_ptls_minus1); |
| } else if (vps->vps_num_ptls_minus1 == 0) { |
| vps->vps_ols_ptl_idx[i] = 0; |
| } else { |
| // vps->vps_num_ptls_minus1 > 0 && vps->vps_num_ptls_minus1 + 1 == |
| // total_num_olss |
| vps->vps_ols_ptl_idx[i] = i; |
| } |
| } |
| |
| // Equation 28. Ideally we should define vps_direct_ref_layer_flag to be of |
| // size vps_max_layers_minus1 * (vps_max_layers_minus1 - 1). However the |
| // equation defined in spec requires it to be of size vps_max_layers_minus1 * |
| // vps_max_layers_minus1. |
| for (int i = 0; i <= vps->vps_max_layers_minus1; i++) { |
| for (int j = 0; j <= vps->vps_max_layers_minus1; j++) { |
| vps->dependency_flag[i][j] = vps->vps_direct_ref_layer_flag[i][j]; |
| for (int k = 0; k < i; k++) { |
| if (vps->vps_direct_ref_layer_flag[i][k] && |
| vps->dependency_flag[k][j]) { |
| vps->dependency_flag[i][j] = 1; |
| } |
| } |
| } |
| vps->layer_used_as_ref_layer_flag[i] = 0; |
| } |
| for (int i = 0; i <= vps->vps_max_layers_minus1; i++) { |
| int j, d, r; |
| for (j = 0, d = 0, r = 0; j <= vps->vps_max_layers_minus1; j++) { |
| if (vps->vps_direct_ref_layer_flag[i][j]) { |
| vps->direct_ref_layer_idx[i][d++] = j; |
| vps->layer_used_as_ref_layer_flag[j] = 1; |
| } |
| if (vps->dependency_flag[i][j]) { |
| vps->reference_layer_idx[i][r++] = j; |
| } |
| } |
| vps->num_direct_ref_layers[i] = d; |
| vps->num_ref_layers[i] = r; |
| } |
| |
| // Equation 32: calculation of |
| // num_output_layers_in_ols/num_sublayers_in_layer_in_ols, etc. |
| int num_output_layers_in_ols[kMaxTotalNumOLSs]; |
| int num_sublayers_in_layer_in_ols[kMaxTotalNumOLSs][kMaxTotalNumOLSs]; |
| int output_layer_id_in_ols[kMaxTotalNumOLSs][kMaxTotalNumOLSs]; |
| bool layer_used_as_output_flag[kMaxSubLayers]; |
| bool layer_included_in_ols_flag[kMaxTotalNumOLSs][kMaxLayers]; |
| int output_layer_idx[kMaxTotalNumOLSs][kMaxLayers]; |
| num_output_layers_in_ols[0] = 1; |
| output_layer_id_in_ols[0][0] = vps->vps_layer_id[0]; |
| num_sublayers_in_layer_in_ols[0][0] = |
| vps->vps_ptl_max_tid[vps->vps_ols_ptl_idx[0]] + 1; |
| for (int i = 1; i <= vps->vps_max_layers_minus1; i++) { |
| if (ols_mode_idc == 4 || ols_mode_idc < 2) { |
| layer_used_as_output_flag[i] = 1; |
| } else if (vps->vps_ols_mode_idc == 2) { |
| layer_used_as_output_flag[i] = 0; |
| } |
| } |
| for (int i = 1; i < total_num_olss; i++) { |
| if (ols_mode_idc == 4 || ols_mode_idc == 0) { |
| num_output_layers_in_ols[i] = 1; |
| output_layer_id_in_ols[i][0] = vps->vps_layer_id[i]; |
| if (vps->vps_each_layer_is_an_ols_flag) { |
| num_sublayers_in_layer_in_ols[i][0] = |
| vps->vps_ptl_max_tid[vps->vps_ols_ptl_idx[i]] + 1; |
| } else { |
| num_sublayers_in_layer_in_ols[i][i] = |
| vps->vps_ptl_max_tid[vps->vps_ols_ptl_idx[i]] + 1; |
| for (int k = i - 1; k >= 0; k--) { |
| num_sublayers_in_layer_in_ols[i][i] = 0; |
| for (int m = k + 1; m <= i; m++) { |
| int max_sublayer_needed = |
| std::min(num_sublayers_in_layer_in_ols[i][m], |
| vps->vps_max_tid_il_ref_pics_plus1[m][k]); |
| if (vps->vps_direct_ref_layer_flag[m][k] && |
| num_sublayers_in_layer_in_ols[i][k] < max_sublayer_needed) { |
| num_sublayers_in_layer_in_ols[i][k] = max_sublayer_needed; |
| } |
| } |
| } |
| } |
| } else if (vps->vps_ols_mode_idc == 1) { |
| num_output_layers_in_ols[i] = i + 1; |
| for (int j = 0; j < num_output_layers_in_ols[i]; j++) { |
| output_layer_id_in_ols[i][j] = vps->vps_layer_id[j]; |
| num_sublayers_in_layer_in_ols[i][j] = |
| vps->vps_ptl_max_tid[vps->vps_ols_ptl_idx[i]] + 1; |
| } |
| } else if (vps->vps_ols_mode_idc == 2) { |
| int j, k; |
| for (j = 0; j <= vps->vps_max_layers_minus1; j++) { |
| layer_included_in_ols_flag[i][j] = 0; |
| num_sublayers_in_layer_in_ols[i][j] = 0; |
| } |
| int highest_included_layer = 0; |
| for (k = 0, j = 0; k <= vps->vps_max_layers_minus1; k++) { |
| if (vps->vps_ols_output_layer_flag[i][k]) { |
| layer_included_in_ols_flag[i][k] = 1; |
| highest_included_layer = k; |
| layer_used_as_output_flag[k] = 1; |
| output_layer_idx[i][j] = k; |
| output_layer_id_in_ols[i][j++] = vps->vps_layer_id[k]; |
| num_sublayers_in_layer_in_ols[i][k] = |
| vps->vps_ptl_max_tid[vps->vps_ols_ptl_idx[i]] + 1; |
| } |
| } |
| num_output_layers_in_ols[i] = j; |
| for (j = 0; j < num_output_layers_in_ols[i]; j++) { |
| int idx = output_layer_idx[i][j]; |
| for (k = 0; k < vps->num_ref_layers[idx]; k++) { |
| if (!layer_included_in_ols_flag[i] |
| [vps->reference_layer_idx[idx][k]]) { |
| layer_included_in_ols_flag[i][vps->reference_layer_idx[idx][k]] = 1; |
| } |
| } |
| for (k = highest_included_layer - 1; k >= 0; k--) { |
| if (layer_included_in_ols_flag[i][k] && |
| !vps->vps_ols_output_layer_flag[i][k]) { |
| for (int m = k + 1; m <= highest_included_layer; m++) { |
| int max_sublayer_needed = |
| std::min(num_sublayers_in_layer_in_ols[i][m], |
| vps->vps_max_tid_il_ref_pics_plus1[m][k]); |
| if (vps->vps_direct_ref_layer_flag[m][k] && |
| layer_included_in_ols_flag[i][m] && |
| num_sublayers_in_layer_in_ols[i][k] < max_sublayer_needed) { |
| num_sublayers_in_layer_in_ols[i][k] = max_sublayer_needed; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // Equation 33: num_layers_in_ols/layer_id_in_ols, etc. |
| int num_layers_in_ols[kMaxTotalNumOLSs]; |
| int layer_id_in_ols[kMaxTotalNumOLSs][kMaxLayers]; |
| int num_muliti_layer_olss = 0; |
| int multi_layer_ols_idx[kMaxTotalNumOLSs]; |
| num_layers_in_ols[0] = 1; |
| layer_id_in_ols[0][0] = vps->vps_layer_id[0]; |
| for (int i = 1; i < total_num_olss; i++) { |
| if (vps->vps_each_layer_is_an_ols_flag) { |
| num_layers_in_ols[i] = 1; |
| layer_id_in_ols[i][0] = vps->vps_layer_id[i]; |
| } else if (vps->vps_ols_mode_idc == 0 || vps->vps_ols_mode_idc == 1) { |
| num_layers_in_ols[i] = i + 1; |
| for (int j = 0; j < num_layers_in_ols[i]; j++) { |
| layer_id_in_ols[i][j] = vps->vps_layer_id[j]; |
| } |
| } else if (vps->vps_ols_mode_idc == 2) { |
| for (int k = 0, j = 0; k <= vps->vps_max_layers_minus1; k++) { |
| if (layer_included_in_ols_flag[i][k]) { |
| layer_id_in_ols[i][j++] = vps->vps_layer_id[k]; |
| } |
| num_layers_in_ols[i] = j; |
| } |
| } |
| if (num_layers_in_ols[i] > 1) { |
| multi_layer_ols_idx[i] = num_muliti_layer_olss; |
| num_muliti_layer_olss++; |
| } |
| } |
| |
| int vps_num_dbp_params = 0; |
| if (!vps->vps_each_layer_is_an_ols_flag) { |
| READ_UE_OR_RETURN(&vps->vps_num_dpb_params_minus1); |
| IN_RANGE_OR_RETURN(vps->vps_num_dpb_params_minus1, 0, |
| num_muliti_layer_olss - 1); |
| |
| // Equation 34: Variable VpsNumDpbParams that specifies number |
| // of dpb_parameters() syntax structures in the VPS. |
| vps_num_dbp_params = vps->vps_num_dpb_params_minus1 + 1; |
| if (vps->vps_max_sublayers_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&vps->vps_sublayer_dpb_params_present_flag); |
| } |
| for (int i = 0; i < vps_num_dbp_params; i++) { |
| if (!vps->vps_default_ptl_dpb_hrd_max_tid_flag) { |
| READ_BITS_OR_RETURN(3, &vps->vps_dpb_max_tid[i]); |
| } else { |
| vps->vps_dpb_max_tid[i] = vps->vps_max_sublayers_minus1; |
| } |
| ParseDpbParameters(vps->vps_dpb_max_tid[i], |
| vps->vps_sublayer_dpb_params_present_flag, |
| &vps->dpb_parameters[i]); |
| } |
| for (int i = 0; i < num_muliti_layer_olss; i++) { |
| READ_UE_OR_RETURN(&vps->vps_ols_dpb_pic_width[i]); |
| READ_UE_OR_RETURN(&vps->vps_ols_dpb_pic_height[i]); |
| READ_BITS_OR_RETURN(2, &vps->vps_ols_dpb_chroma_format[i]); |
| READ_UE_OR_RETURN(&vps->vps_ols_dpb_bitdepth_minus8[i]); |
| IN_RANGE_OR_RETURN(vps->vps_ols_dpb_bitdepth_minus8[i], 0, 8); |
| if (vps_num_dbp_params > 1 && |
| vps_num_dbp_params != num_muliti_layer_olss) { |
| READ_UE_OR_RETURN(&vps->vps_ols_dpb_params_idx[i]); |
| IN_RANGE_OR_RETURN(vps->vps_ols_dpb_params_idx[i], 0, |
| vps_num_dbp_params - 1); |
| } else if (vps_num_dbp_params == 1) { |
| vps->vps_ols_dpb_params_idx[i] = 0; |
| } else { |
| vps->vps_ols_dpb_params_idx[i] = i; |
| } |
| } |
| READ_BOOL_OR_RETURN(&vps->vps_timing_hrd_params_present_flag); |
| // We stop here without parsing remaining syntax elements. |
| } |
| |
| // If a VPS with the same id already exists, replace it. |
| *vps_id = vps->vps_video_parameter_set_id; |
| active_vps_[*vps_id] = std::move(vps); |
| return res; |
| } |
| |
| // 7.3.10 |
| H266Parser::Result H266Parser::ParseRefPicListStruct( |
| int list_idx, |
| int rpl_idx, |
| const H266SPS& sps, |
| H266RefPicListStruct* ref_pic_list_struct) { |
| DCHECK(ref_pic_list_struct); |
| |
| const H266VPS* vps = GetVPS(sps.sps_video_parameter_set_id); |
| if (!vps) { |
| DVLOG(1) << "Invalid VPS."; |
| return kMissingParameterSet; |
| } |
| |
| ref_pic_list_struct->num_ltrp_entries = 0; |
| int abs_delta_poc_st = 0; |
| |
| READ_UE_OR_RETURN(&ref_pic_list_struct->num_ref_entries); |
| IN_RANGE_OR_RETURN(ref_pic_list_struct->num_ref_entries, 0, |
| sps.max_dpb_size + 13); |
| // When ltrp_in_header_flag is 1, it means we do not signal |
| // the LTR here, but instead it exists in the ref_pic_lists() syntax |
| // in picture header or slice header. |
| if (sps.sps_long_term_ref_pics_flag && |
| rpl_idx < sps.sps_num_ref_pic_lists[list_idx] && |
| ref_pic_list_struct->num_ref_entries > 0) { |
| READ_BOOL_OR_RETURN(&ref_pic_list_struct->ltrp_in_header_flag); |
| } else if (sps.sps_long_term_ref_pics_flag && |
| rpl_idx == sps.sps_num_ref_pic_lists[list_idx]) { |
| ref_pic_list_struct->ltrp_in_header_flag = 1; |
| } |
| // If the inter_layer_ref_pic_flag[list_idx][rpl_idx] is 0, |
| // corresponding entry into ref_pic_list_struct[0/1] is a combination of |
| // {inter_layer_ref_pic_flag, st_ref_pic_flag, abs_delta_poc_st, |
| // strp_entry_sign_flag, rpls_poc_lsb_lt}; Otherwise, each entry into the |
| // ref_pic_list_struct will contain the index of entry of the direct reference |
| // layers. |
| for (int i = 0, j = 0; i < ref_pic_list_struct->num_ref_entries; i++) { |
| if (sps.sps_inter_layer_prediction_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ref_pic_list_struct->inter_layer_ref_pic_flag[i]); |
| } else { |
| ref_pic_list_struct->inter_layer_ref_pic_flag[i] = false; |
| } |
| if (!ref_pic_list_struct->inter_layer_ref_pic_flag[i]) { |
| if (sps.sps_long_term_ref_pics_flag) { |
| READ_BOOL_OR_RETURN(&ref_pic_list_struct->st_ref_pic_flag[i]); |
| } else { |
| // If LTR is disabled, VVC does not explicitly signal STR flag. |
| ref_pic_list_struct->st_ref_pic_flag[i] = 1; |
| } |
| if (ref_pic_list_struct->st_ref_pic_flag[i]) { |
| READ_UE_OR_RETURN(&ref_pic_list_struct->abs_delta_poc_st[i]); |
| IN_RANGE_OR_RETURN(ref_pic_list_struct->abs_delta_poc_st[i], 0, |
| std::pow(2, 15) - 1); |
| // Equation 150. For the first abs_delta_poc_st in the |
| // ref_pic_list_struct, or when weighted prediction is used, the short |
| // term POC delta is the absolute delta; Otherwise this needs to be |
| // added by 1 to reflect the real delta. |
| if ((sps.sps_weighted_pred_flag || sps.sps_weighted_bipred_flag) && |
| i != 0) { |
| abs_delta_poc_st = ref_pic_list_struct->abs_delta_poc_st[i]; |
| } else { |
| abs_delta_poc_st = ref_pic_list_struct->abs_delta_poc_st[i] + 1; |
| } |
| |
| if (abs_delta_poc_st > 0) { |
| READ_BOOL_OR_RETURN(&ref_pic_list_struct->strp_entry_sign_flag[i]); |
| } |
| } else if (!ref_pic_list_struct->ltrp_in_header_flag) { |
| READ_BITS_OR_RETURN(sps.sps_log2_max_pic_order_cnt_lsb_minus4 + 4, |
| &ref_pic_list_struct->rpls_poc_lsb_lt[j++]); |
| } |
| } else { |
| READ_UE_OR_RETURN(&ref_pic_list_struct->ilrp_idx[i]); |
| int general_layer_id = vps->GetGeneralLayerIdx(sps.nuh_layer_id); |
| if (general_layer_id != -1) { |
| IN_RANGE_OR_RETURN(ref_pic_list_struct->ilrp_idx[i], 0, |
| vps->num_direct_ref_layers[general_layer_id] - 1); |
| } |
| } |
| |
| // Equation 149 & Equation 151 |
| if (!ref_pic_list_struct->inter_layer_ref_pic_flag[i]) { |
| if (!ref_pic_list_struct->st_ref_pic_flag[i]) { |
| ref_pic_list_struct->num_ltrp_entries++; |
| } else { |
| // Combine short term ref delta POC values with their signs. |
| ref_pic_list_struct->delta_poc_val_st[i] = |
| (1 - 2 * ref_pic_list_struct->strp_entry_sign_flag[i]) * |
| abs_delta_poc_st; |
| } |
| } |
| } |
| |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParseGeneralTimingHrdParameters( |
| H266GeneralTimingHrdParameters* general_timing_hrd_parameters) { |
| DCHECK(general_timing_hrd_parameters); |
| |
| int num_units_in_tick_high16 = 0, num_units_in_tick_low16 = 0; |
| READ_BITS_OR_RETURN(16, &num_units_in_tick_high16); |
| READ_BITS_OR_RETURN(16, &num_units_in_tick_low16); |
| general_timing_hrd_parameters->num_units_in_tick = |
| (num_units_in_tick_high16 << 16) + num_units_in_tick_low16; |
| |
| int time_scale_high16 = 0, time_scale_low16 = 0; |
| READ_BITS_OR_RETURN(16, &time_scale_high16); |
| READ_BITS_OR_RETURN(16, &time_scale_low16); |
| general_timing_hrd_parameters->time_scale = |
| (time_scale_high16 << 16) + time_scale_low16; |
| |
| READ_BOOL_OR_RETURN( |
| &general_timing_hrd_parameters->general_nal_hrd_params_present_flag); |
| READ_BOOL_OR_RETURN( |
| &general_timing_hrd_parameters->general_vcl_hrd_params_present_flag); |
| if (general_timing_hrd_parameters->general_nal_hrd_params_present_flag || |
| general_timing_hrd_parameters->general_vcl_hrd_params_present_flag) { |
| READ_BOOL_OR_RETURN(&general_timing_hrd_parameters |
| ->general_same_pic_timing_in_all_ols_flag); |
| READ_BOOL_OR_RETURN( |
| &general_timing_hrd_parameters->general_du_hrd_params_present_flag); |
| if (general_timing_hrd_parameters->general_du_hrd_params_present_flag) { |
| READ_BITS_OR_RETURN(8, |
| &general_timing_hrd_parameters->tick_divisor_minus2); |
| } |
| READ_BITS_OR_RETURN(4, &general_timing_hrd_parameters->bit_rate_scale); |
| READ_BITS_OR_RETURN(4, &general_timing_hrd_parameters->cpb_size_scale); |
| if (general_timing_hrd_parameters->general_du_hrd_params_present_flag) { |
| READ_BITS_OR_RETURN(4, &general_timing_hrd_parameters->cpb_size_du_scale); |
| } |
| READ_UE_OR_RETURN(&general_timing_hrd_parameters->hrd_cpb_cnt_minus1); |
| IN_RANGE_OR_RETURN(general_timing_hrd_parameters->hrd_cpb_cnt_minus1, 0, |
| 31); |
| } else { |
| general_timing_hrd_parameters->general_du_hrd_params_present_flag = 0; |
| } |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParseOlsTimingHrdParameters( |
| int first_sublayer, |
| int max_sublayer_val, |
| const H266GeneralTimingHrdParameters& general_timing_hrd_parameters, |
| H266OlsTimingHrdParameters* ols_timing_hrd_parameters) { |
| DCHECK(ols_timing_hrd_parameters); |
| DCHECK(first_sublayer >= 0); |
| DCHECK(max_sublayer_val >= 0); |
| |
| for (int i = first_sublayer; i <= max_sublayer_val; i++) { |
| READ_BOOL_OR_RETURN( |
| &ols_timing_hrd_parameters->fixed_pic_rate_general_flag[i]); |
| if (!ols_timing_hrd_parameters->fixed_pic_rate_general_flag[i]) { |
| READ_BOOL_OR_RETURN( |
| &ols_timing_hrd_parameters->fixed_pic_rate_within_cvs_flag[i]); |
| } else { |
| ols_timing_hrd_parameters->fixed_pic_rate_within_cvs_flag[i] = 1; |
| } |
| if (ols_timing_hrd_parameters->fixed_pic_rate_within_cvs_flag[i]) { |
| READ_UE_OR_RETURN( |
| &ols_timing_hrd_parameters->element_duration_in_tc_minus1[i]); |
| IN_RANGE_OR_RETURN( |
| ols_timing_hrd_parameters->element_duration_in_tc_minus1[i], 0, 2047); |
| } else if ((general_timing_hrd_parameters |
| .general_nal_hrd_params_present_flag || |
| general_timing_hrd_parameters |
| .general_vcl_hrd_params_present_flag) && |
| general_timing_hrd_parameters.hrd_cpb_cnt_minus1 == 0) { |
| READ_BOOL_OR_RETURN(&ols_timing_hrd_parameters->low_delay_hrd_flag[i]); |
| } |
| |
| if (general_timing_hrd_parameters.general_nal_hrd_params_present_flag) { |
| ParseSublayerHrdParameters( |
| i, general_timing_hrd_parameters, |
| &ols_timing_hrd_parameters->nal_sublayer_hrd_parameters[i]); |
| } |
| if (general_timing_hrd_parameters.general_vcl_hrd_params_present_flag) { |
| ParseSublayerHrdParameters( |
| i, general_timing_hrd_parameters, |
| &ols_timing_hrd_parameters->vcl_sublayer_hrd_parameters[i]); |
| } |
| } |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParseSublayerHrdParameters( |
| int sublayer_id, |
| const H266GeneralTimingHrdParameters& general_timing_hrd_parameters, |
| H266SublayerHrdParameters* sublayer_hrd_parameters) { |
| DCHECK(sublayer_id >= 0 && sublayer_id < kMaxSubLayers); |
| DCHECK(sublayer_hrd_parameters); |
| |
| for (int j = 0; j <= general_timing_hrd_parameters.hrd_cpb_cnt_minus1; j++) { |
| READ_UE_OR_RETURN(&sublayer_hrd_parameters->bit_rate_value_minus1[j]); |
| IN_RANGE_OR_RETURN(sublayer_hrd_parameters->bit_rate_du_value_minus1[j], 0, |
| std::pow(2, 32) - 2); |
| if (j > 0) { |
| GT_OR_RETURN(sublayer_hrd_parameters->bit_rate_du_value_minus1[j], |
| sublayer_hrd_parameters->bit_rate_du_value_minus1[j - 1]); |
| } |
| READ_UE_OR_RETURN(&sublayer_hrd_parameters->cpb_size_value_minus1[j]); |
| IN_RANGE_OR_RETURN(sublayer_hrd_parameters->cpb_size_value_minus1[j], 0, |
| std::pow(2, 32) - 2); |
| if (j > 0) { |
| LE_OR_RETURN(sublayer_hrd_parameters->cpb_size_value_minus1[j], |
| sublayer_hrd_parameters->cpb_size_value_minus1[j - 1]); |
| } |
| READ_BOOL_OR_RETURN(&sublayer_hrd_parameters->cbr_flag[j]); |
| } |
| return kOk; |
| } |
| |
| // The SPS might be indirectly referenced by PH->PPS->SPS, where PH is either |
| // a PH_NUT or picture header structure in slice header. |
| H266Parser::Result H266Parser::ParseSPS(const H266NALU& nalu, int* sps_id) { |
| // 7.4.3.4 |
| DVLOG(4) << "Parsing SPS"; |
| Result res = kOk; |
| |
| DCHECK(sps_id); |
| *sps_id = -1; |
| |
| std::unique_ptr<H266SPS> sps = std::make_unique<H266SPS>(); |
| |
| sps->nuh_layer_id = nalu.nuh_layer_id; |
| READ_BITS_OR_RETURN(4, &sps->sps_seq_parameter_set_id); |
| IN_RANGE_OR_RETURN(sps->sps_seq_parameter_set_id, 0, 15); |
| READ_BITS_OR_RETURN(4, &sps->sps_video_parameter_set_id); |
| GE_OR_RETURN(sps->sps_video_parameter_set_id, 0); |
| READ_BITS_OR_RETURN(3, &sps->sps_max_sublayers_minus1); |
| if (sps->sps_video_parameter_set_id > 0) { |
| const H266VPS* vps = GetVPS(sps->sps_video_parameter_set_id); |
| if (!vps) { |
| return kMissingParameterSet; |
| } |
| IN_RANGE_OR_RETURN(sps->sps_max_sublayers_minus1, 0, |
| vps->vps_max_sublayers_minus1); |
| } else { |
| IN_RANGE_OR_RETURN(sps->sps_max_sublayers_minus1, 0, 6); |
| if (!GetVPS(0)) { |
| // Create a fake VPS for the inferred VPS members. |
| std::unique_ptr<H266VPS> vps = std::make_unique<H266VPS>(); |
| vps->vps_video_parameter_set_id = 0; |
| vps->vps_max_layers_minus1 = 0; |
| vps->vps_max_sublayers_minus1 = sps->sps_max_sublayers_minus1; |
| vps->vps_independent_layer_flag[0] = 1; |
| vps->vps_layer_id[0] = nalu.nuh_layer_id; |
| vps->general_layer_idx[nalu.nuh_layer_id] = 0; |
| vps->vps_ols_ptl_idx[0] = 0; |
| vps->vps_ptl_max_tid[0] = sps->sps_max_sublayers_minus1; |
| active_vps_[0] = std::move(vps); |
| } |
| } |
| READ_BITS_OR_RETURN(2, &sps->sps_chroma_format_idc); |
| IN_RANGE_OR_RETURN(sps->sps_chroma_format_idc, 0, 3); |
| switch (sps->sps_chroma_format_idc) { |
| case 0: // monochrome |
| case 3: // 4:4:4 |
| sps->sub_width_c = 1; |
| sps->sub_height_c = 1; |
| break; |
| case 1: // 4:2:0 |
| sps->sub_width_c = 2; |
| sps->sub_height_c = 2; |
| break; |
| case 2: // 4:2:2 |
| sps->sub_width_c = 2; |
| sps->sub_height_c = 1; |
| break; |
| } |
| |
| READ_BITS_OR_RETURN(2, &sps->sps_log2_ctu_size_minus5); |
| IN_RANGE_OR_RETURN(sps->sps_log2_ctu_size_minus5, 0, 2); |
| |
| // Equation 35 & 36 |
| sps->ctb_log2_size_y = sps->sps_log2_ctu_size_minus5 + 5; |
| sps->ctb_size_y = 1 << sps->ctb_log2_size_y; |
| READ_BOOL_OR_RETURN(&sps->sps_ptl_dpb_hrd_params_present_flag); |
| // When present, profile_tier_level/dpb/hrd syntax structures |
| // are in SPS. If not present, we should use corresponding info |
| // in VPS. |
| if (sps->sps_ptl_dpb_hrd_params_present_flag) { |
| ParseProfileTierLevel(true, sps->sps_max_sublayers_minus1, |
| &sps->profile_tier_level); |
| } else { |
| // profile-tier-level info must be in SPS when VPS id is 0. |
| TRUE_OR_RETURN(sps->sps_video_parameter_set_id != 0); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_gdr_enabled_flag); |
| // Below two indicates dynamic frame scaling on/off. |
| READ_BOOL_OR_RETURN(&sps->sps_ref_pic_resampling_enabled_flag); |
| if (sps->sps_ref_pic_resampling_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_res_change_in_clvs_allowed_flag); |
| } |
| READ_UE_OR_RETURN(&sps->sps_pic_width_max_in_luma_samples); |
| READ_UE_OR_RETURN(&sps->sps_pic_height_max_in_luma_samples); |
| TRUE_OR_RETURN(sps->sps_pic_width_max_in_luma_samples != 0 && |
| sps->sps_pic_height_max_in_luma_samples != 0); |
| |
| // A.4.2. Equation 1587, calculate the max_dpb_size. |
| int max_luma_ps = sps->profile_tier_level.MaxLumaPs(); |
| base::CheckedNumeric<int> pic_size = sps->sps_pic_height_max_in_luma_samples; |
| pic_size *= sps->sps_pic_width_max_in_luma_samples; |
| if (!pic_size.IsValid()) { |
| return kInvalidStream; |
| } |
| int pic_size_in_samples_y = pic_size.ValueOrDefault(0); |
| if (2 * pic_size_in_samples_y <= max_luma_ps) { |
| sps->max_dpb_size = 2 * kMaxDpbPicBuffer; |
| } else if (3 * pic_size_in_samples_y <= (2 * max_luma_ps)) { |
| sps->max_dpb_size = 3 * kMaxDpbPicBuffer / 2; |
| } else { |
| sps->max_dpb_size = kMaxDpbPicBuffer; |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_conformance_window_flag); |
| if (sps->sps_conformance_window_flag) { |
| READ_UE_OR_RETURN(&sps->sps_conf_win_left_offset); |
| READ_UE_OR_RETURN(&sps->sps_conf_win_right_offset); |
| READ_UE_OR_RETURN(&sps->sps_conf_win_top_offset); |
| READ_UE_OR_RETURN(&sps->sps_conf_win_bottom_offset); |
| base::CheckedNumeric<int> width_crop = sps->sps_conf_win_left_offset; |
| width_crop += sps->sps_conf_win_right_offset; |
| width_crop *= sps->sub_width_c; |
| if (!width_crop.IsValid()) { |
| return kInvalidStream; |
| } |
| TRUE_OR_RETURN(width_crop.ValueOrDefault(0) < |
| sps->sps_pic_width_max_in_luma_samples); |
| base::CheckedNumeric<int> height_crop = sps->sps_conf_win_top_offset; |
| height_crop += sps->sps_conf_win_bottom_offset; |
| height_crop *= sps->sub_height_c; |
| if (!height_crop.IsValid()) { |
| return kInvalidStream; |
| } |
| TRUE_OR_RETURN(height_crop.ValueOrDefault(0) < |
| sps->sps_pic_height_max_in_luma_samples); |
| } |
| |
| // Number of luma CTBs in width and height. |
| int tmp_width_val = |
| (sps->sps_pic_width_max_in_luma_samples + sps->ctb_size_y - 1) / |
| sps->ctb_size_y; |
| int tmp_height_val = |
| (sps->sps_pic_height_max_in_luma_samples + sps->ctb_size_y - 1) / |
| sps->ctb_size_y; |
| |
| // Subpictures in VVC are functionally MCTSs(motion-constrained tile sets) in |
| // HEVC. The layout of subpictures is signalled in SPS, while subpicture ID |
| // mapping is either statically signalled in SPS, or dynamic across pictures |
| // when signalled in PPS. Subpictures are rectangular regions covering |
| // multiple slices, and it is required following conditions to be fulfilled: |
| // - All CTUs in a subpicture belong to the same tile, and, |
| // - All CTUs in a tile belong to the same subpicture. |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_info_present_flag); |
| if (sps->sps_subpic_info_present_flag) { |
| READ_UE_OR_RETURN(&sps->sps_num_subpics_minus1); |
| IN_RANGE_OR_RETURN(sps->sps_num_subpics_minus1, 0, |
| sps->profile_tier_level.MaxSlicesPerAu() - 1); |
| if (sps->sps_num_subpics_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_independent_subpics_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_same_size_flag); |
| } else { |
| sps->sps_independent_subpics_flag = 1; |
| } |
| |
| int width_bits = base::bits::Log2Ceiling(tmp_width_val); |
| int height_bits = base::bits::Log2Ceiling(tmp_height_val); |
| IN_RANGE_OR_RETURN(width_bits, 0, 31); |
| IN_RANGE_OR_RETURN(height_bits, 0, 31); |
| |
| if (sps->sps_num_subpics_minus1 > 0) { |
| // For the 0-th subpicture, do not overlook sps_subpic_same_size_flag |
| // when parsing, and left_x/left_y is implied to be 0. |
| sps->sps_subpic_ctu_top_left_x[0] = 0; |
| sps->sps_subpic_ctu_top_left_y[0] = 0; |
| if (sps->sps_pic_width_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(width_bits, &sps->sps_subpic_width_minus1[0]); |
| } else { |
| // For 0-th subpicture in raster scan order this would be 0. |
| sps->sps_subpic_width_minus1[0] = |
| tmp_width_val - sps->sps_subpic_ctu_top_left_x[0] - 1; |
| } |
| if (sps->sps_pic_height_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(height_bits, &sps->sps_subpic_height_minus1[0]); |
| } else { |
| sps->sps_subpic_height_minus1[0] = |
| tmp_height_val - sps->sps_subpic_ctu_top_left_y[0] - 1; |
| } |
| if (!sps->sps_independent_subpics_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_treated_as_pic_flag[0]); |
| READ_BOOL_OR_RETURN( |
| &sps->sps_loop_filter_across_subpic_enabled_flag[0]); |
| } |
| |
| if (!sps->sps_subpic_same_size_flag) { |
| for (int i = 1; i <= sps->sps_num_subpics_minus1; i++) { |
| if (sps->sps_pic_width_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(width_bits, &sps->sps_subpic_ctu_top_left_x[i]); |
| } else { |
| sps->sps_subpic_ctu_top_left_x[i] = 0; |
| } |
| if (sps->sps_pic_height_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(height_bits, |
| &sps->sps_subpic_ctu_top_left_y[i]); |
| } else { |
| sps->sps_subpic_ctu_top_left_y[i] = 0; |
| } |
| if (i < sps->sps_num_subpics_minus1 && |
| sps->sps_pic_width_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(width_bits, &sps->sps_subpic_width_minus1[i]); |
| } else { |
| sps->sps_subpic_width_minus1[i] = |
| tmp_width_val - sps->sps_subpic_ctu_top_left_x[i] - 1; |
| } |
| if (i < sps->sps_num_subpics_minus1 && |
| sps->sps_pic_height_max_in_luma_samples > sps->ctb_size_y) { |
| READ_BITS_OR_RETURN(height_bits, &sps->sps_subpic_height_minus1[i]); |
| } else { |
| sps->sps_subpic_height_minus1[i] = |
| tmp_height_val - sps->sps_subpic_ctu_top_left_y[i] - 1; |
| } |
| if (!sps->sps_independent_subpics_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_treated_as_pic_flag[i]); |
| READ_BOOL_OR_RETURN( |
| &sps->sps_loop_filter_across_subpic_enabled_flag[i]); |
| } |
| } |
| } else { // sps_subpic_same_size_flag = 1 |
| int num_subpic_cols = tmp_width_val / (sps->sps_subpic_width_minus1[0] + |
| 1); // Equation 37 |
| GT_OR_RETURN(num_subpic_cols, 0); |
| for (int i = 1; i <= sps->sps_num_subpics_minus1; i++) { |
| sps->sps_subpic_ctu_top_left_x[i] = |
| (i % num_subpic_cols) * (sps->sps_subpic_width_minus1[0] + 1); |
| sps->sps_subpic_ctu_top_left_y[i] = |
| (i / num_subpic_cols) * (sps->sps_subpic_height_minus1[0] + 1); |
| sps->sps_subpic_width_minus1[i] = sps->sps_subpic_width_minus1[0]; |
| sps->sps_subpic_height_minus1[i] = sps->sps_subpic_height_minus1[0]; |
| if (!sps->sps_independent_subpics_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_treated_as_pic_flag[i]); |
| READ_BOOL_OR_RETURN( |
| &sps->sps_loop_filter_across_subpic_enabled_flag[i]); |
| } |
| } |
| } |
| } |
| |
| READ_UE_OR_RETURN(&sps->sps_subpic_id_len_minus1); |
| IN_RANGE_OR_RETURN(sps->sps_subpic_id_len_minus1, 0, 15); |
| TRUE_OR_RETURN((1 << (sps->sps_subpic_id_len_minus1 + 1)) >= |
| sps->sps_num_subpics_minus1 + 1); |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_id_mapping_explicitly_signaled_flag); |
| if (sps->sps_subpic_id_mapping_explicitly_signaled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_subpic_id_mapping_present_flag); |
| if (sps->sps_subpic_id_mapping_present_flag) { |
| for (int i = 0; i <= sps->sps_num_subpics_minus1; i++) { |
| READ_BITS_OR_RETURN(sps->sps_subpic_id_len_minus1 + 1, |
| &sps->sps_subpic_id[i]); |
| } |
| } |
| } |
| } else { |
| sps->sps_subpic_width_minus1[0] = tmp_width_val - 1; |
| sps->sps_subpic_height_minus1[0] = tmp_height_val - 1; |
| } |
| |
| READ_UE_OR_RETURN(&sps->sps_bitdepth_minus8); |
| IN_RANGE_OR_RETURN(sps->sps_bitdepth_minus8, 0, 8); |
| // Equation 39 |
| sps->qp_bd_offset = 6 * sps->sps_bitdepth_minus8; |
| |
| // This controls the wavefront parallel processing(WPP) tool on/off. |
| READ_BOOL_OR_RETURN(&sps->sps_entropy_coding_sync_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_entry_point_offsets_present_flag); |
| READ_BITS_OR_RETURN(4, &sps->sps_log2_max_pic_order_cnt_lsb_minus4); |
| IN_RANGE_OR_RETURN(sps->sps_log2_max_pic_order_cnt_lsb_minus4, 0, 12); |
| sps->max_pic_order_cnt_lsb = |
| std::pow(2, sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4); |
| READ_BOOL_OR_RETURN(&sps->sps_poc_msb_cycle_flag); |
| if (sps->sps_poc_msb_cycle_flag) { |
| READ_UE_OR_RETURN(&sps->sps_poc_msb_cycle_len_minus1); |
| IN_RANGE_OR_RETURN(sps->sps_poc_msb_cycle_len_minus1, 0, |
| 32 - sps->sps_log2_max_pic_order_cnt_lsb_minus4 - 5); |
| } |
| |
| // Be noted spec requires sps_num_extra_ph_bytes/sps_num_extra_sh_bytes to |
| // be 0, but allows 1 or 2 to appear in the syntax. |
| READ_BITS_OR_RETURN(2, &sps->sps_num_extra_ph_bytes); |
| IN_RANGE_OR_RETURN(sps->sps_num_extra_ph_bytes, 0, 2); |
| |
| // Equation 41. |
| for (int i = 0; i < (sps->sps_num_extra_ph_bytes * 8); i++) { |
| READ_BOOL_OR_RETURN(&sps->sps_extra_ph_bit_present_flag[i]); |
| if (sps->sps_extra_ph_bit_present_flag[i]) { |
| sps->num_extra_ph_bits++; |
| } |
| } |
| READ_BITS_OR_RETURN(2, &sps->sps_num_extra_sh_bytes); |
| IN_RANGE_OR_RETURN(sps->sps_num_extra_sh_bytes, 0, 2); |
| |
| // Equation 42. |
| for (int i = 0; i < (sps->sps_num_extra_sh_bytes * 8); i++) { |
| READ_BOOL_OR_RETURN(&sps->sps_extra_sh_bit_present_flag[i]); |
| if (sps->sps_extra_sh_bit_present_flag[i]) { |
| sps->num_extra_sh_bits++; |
| } |
| } |
| if (sps->sps_ptl_dpb_hrd_params_present_flag) { |
| if (sps->sps_max_sublayers_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_sublayer_dpb_params_flag); |
| } |
| ParseDpbParameters(sps->sps_max_sublayers_minus1, |
| sps->sps_sublayer_dpb_params_flag, &sps->dpb_params); |
| } |
| |
| READ_UE_OR_RETURN(&sps->sps_log2_min_luma_coding_block_size_minus2); |
| // Allowed minimum CB size would be 4x4 to 64x64 and it must not |
| // be larger than 1/4 of CTU width. |
| IN_RANGE_OR_RETURN(sps->sps_log2_min_luma_coding_block_size_minus2, 0, |
| std::min(4, sps->sps_log2_ctu_size_minus5 + 3)); |
| |
| // TODO(crbugs.com/1417910): Equation 43 - 49. Calculation of IbcBufWidthY, |
| // IbcBufWidthC and VSize, CtbWidthC, CTbHeightC if needed for decoding |
| // process. |
| sps->min_cb_log2_size_y = sps->sps_log2_min_luma_coding_block_size_minus2 + 2; |
| sps->min_cb_size_y = 1 << sps->min_cb_log2_size_y; |
| |
| // Recheck pic width/height alignment as min_cb_size_y is unknown when parsing |
| // them. They must be at least 8-aligned, but if a larger min CB size is |
| // selected during encoding, will need to align to min CB size. |
| int pic_size_alignment = std::max(8, sps->min_cb_size_y); |
| TRUE_OR_RETURN( |
| sps->sps_pic_width_max_in_luma_samples % pic_size_alignment == 0 && |
| sps->sps_pic_height_max_in_luma_samples % pic_size_alignment == 0); |
| |
| READ_BOOL_OR_RETURN(&sps->sps_partition_constraints_override_enabled_flag); |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_min_qt_min_cb_intra_slice_luma); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_luma, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| |
| // Equation 50. This calculates the min log2 luma leaf CB size after a |
| // quadtree splitting of CTU. |
| int min_qt_log2_size_intra_y = |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_luma + |
| sps->min_cb_log2_size_y; |
| int min_qt_log2_size_intra_c = 0; |
| |
| // Below syntax elements specify constraints for quadtree/ternary/binary split |
| // of CTUs. |
| READ_UE_OR_RETURN(&sps->sps_max_mtt_hierarchy_depth_intra_slice_luma); |
| IN_RANGE_OR_RETURN(sps->sps_max_mtt_hierarchy_depth_intra_slice_luma, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| if (sps->sps_max_mtt_hierarchy_depth_intra_slice_luma) { |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma); |
| IN_RANGE_OR_RETURN(sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma, 0, |
| sps->ctb_log2_size_y - min_qt_log2_size_intra_y); |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma, 0, |
| std::min(6, sps->ctb_log2_size_y) - min_qt_log2_size_intra_y); |
| } |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_qtbtt_dual_tree_intra_flag); |
| } |
| if (sps->sps_qtbtt_dual_tree_intra_flag) { |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| min_qt_log2_size_intra_c = |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma + |
| sps->min_cb_log2_size_y; |
| READ_UE_OR_RETURN(&sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma); |
| IN_RANGE_OR_RETURN(sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| if (sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma != 0) { |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - min_qt_log2_size_intra_c); |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - min_qt_log2_size_intra_c); |
| } |
| } |
| |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_min_qt_min_cb_inter_slice); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_min_qt_min_cb_inter_slice, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| // Equation 52 |
| int min_qt_log2_size_inter_y = |
| sps->sps_log2_diff_min_qt_min_cb_inter_slice + sps->min_cb_log2_size_y; |
| READ_UE_OR_RETURN(&sps->sps_max_mtt_hierarchy_depth_inter_slice); |
| IN_RANGE_OR_RETURN(sps->sps_max_mtt_hierarchy_depth_inter_slice, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| if (sps->sps_max_mtt_hierarchy_depth_inter_slice != 0) { |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_bt_min_qt_inter_slice); |
| IN_RANGE_OR_RETURN(sps->sps_log2_diff_max_bt_min_qt_inter_slice, 0, |
| sps->ctb_log2_size_y - min_qt_log2_size_inter_y); |
| READ_UE_OR_RETURN(&sps->sps_log2_diff_max_tt_min_qt_inter_slice); |
| IN_RANGE_OR_RETURN( |
| sps->sps_log2_diff_max_tt_min_qt_inter_slice, 0, |
| std::min(6, sps->ctb_log2_size_y) - min_qt_log2_size_inter_y); |
| } |
| |
| // Transform block size cannot be larger than CTB size. |
| if (sps->ctb_size_y > 32) { |
| READ_BOOL_OR_RETURN(&sps->sps_max_luma_transform_size_64_flag); |
| } else { |
| sps->sps_max_luma_transform_size_64_flag = 0; |
| } |
| // Equation 53 - 56. Transform unit/block related information. |
| int min_tb_log2_size_y = 2; |
| int max_tb_log2_size_y = sps->sps_max_luma_transform_size_64_flag ? 6 : 5; |
| sps->min_tb_size_y = (1 << min_tb_log2_size_y); |
| sps->max_tb_size_y = (1 << max_tb_log2_size_y); |
| |
| READ_BOOL_OR_RETURN(&sps->sps_transform_skip_enabled_flag); |
| if (sps->sps_transform_skip_enabled_flag) { |
| READ_UE_OR_RETURN(&sps->sps_log2_transform_skip_max_size_minus2); |
| IN_RANGE_OR_RETURN(sps->sps_log2_transform_skip_max_size_minus2, 0, 3); |
| READ_BOOL_OR_RETURN(&sps->sps_bdpcm_enabled_flag); |
| } |
| sps->max_ts_size_y = |
| (1 << (sps->sps_log2_transform_skip_max_size_minus2 + 2)); |
| |
| // Multiple transform selection on/off. |
| READ_BOOL_OR_RETURN(&sps->sps_mts_enabled_flag); |
| if (sps->sps_mts_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_explicit_mts_intra_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_explicit_mts_inter_enabled_flag); |
| } |
| |
| // Low frequency non-separable transform on/off. It is only applied for |
| // intra blocks for both luma/chroma component. |
| READ_BOOL_OR_RETURN(&sps->sps_lfnst_enabled_flag); |
| |
| int num_qp_tables = 0; |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_joint_cbcr_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_same_qp_table_for_chroma_flag); |
| num_qp_tables = sps->sps_same_qp_table_for_chroma_flag |
| ? 1 |
| : (sps->sps_joint_cbcr_enabled_flag ? 3 : 2); |
| for (int i = 0; i < num_qp_tables; i++) { |
| READ_SE_OR_RETURN(&sps->sps_qp_table_start_minus26[i]); |
| IN_RANGE_OR_RETURN(sps->sps_qp_table_start_minus26[i], |
| -26 - sps->qp_bd_offset, 36); |
| READ_UE_OR_RETURN(&sps->sps_num_points_in_qp_table_minus1[i]); |
| IN_RANGE_OR_RETURN(sps->sps_num_points_in_qp_table_minus1[i], 0, |
| 36 - sps->sps_qp_table_start_minus26[i]); |
| LE_OR_RETURN(sps->sps_num_points_in_qp_table_minus1[i], |
| kMaxPointsInQpTable); |
| for (int j = 0; j <= sps->sps_num_points_in_qp_table_minus1[i]; j++) { |
| READ_UE_OR_RETURN(&sps->sps_delta_qp_in_val_minus1[i][j]); |
| READ_UE_OR_RETURN(&sps->sps_delta_qp_diff_val[i][j]); |
| } |
| } |
| } else { |
| sps->sps_same_qp_table_for_chroma_flag = 1; |
| } |
| // Equation 57. Set up the ChromaQpTables. |
| // In the spec, keys into ChromaQpTable[i] might be negative values in |
| // [-QpBdoffset, 63], so sps->chroma_qp_table[i][m] provided by the parser |
| // corresponds to ChromaQpTable[i][m - QpBdOffset] in the spec. |
| int qp_in_val[3][kMaxPointsInQpTable + 1]; |
| int qp_out_val[3][kMaxPointsInQpTable + 1]; |
| |
| for (int i = 0; i < num_qp_tables; i++) { |
| qp_in_val[i][0] = sps->sps_qp_table_start_minus26[i] + 26; |
| qp_out_val[i][0] = qp_in_val[i][0]; |
| int j, k, m; |
| for (j = 0; j <= sps->sps_num_points_in_qp_table_minus1[i]; j++) { |
| qp_in_val[i][j + 1] = |
| qp_in_val[i][j] + sps->sps_delta_qp_in_val_minus1[i][j] + 1; |
| qp_out_val[i][j + 1] = |
| qp_out_val[i][j] + (sps->sps_delta_qp_in_val_minus1[i][j] ^ |
| sps->sps_delta_qp_diff_val[i][j]); |
| } |
| sps->chroma_qp_table[i][qp_in_val[i][0] + sps->qp_bd_offset] = |
| qp_out_val[i][0]; |
| for (k = qp_in_val[i][0] - 1 + sps->qp_bd_offset; k >= 0; k--) { |
| sps->chroma_qp_table[i][k] = std::clamp( |
| sps->chroma_qp_table[i][k + 1] - 1, -sps->qp_bd_offset, 63); |
| } |
| for (j = 0; j <= sps->sps_num_points_in_qp_table_minus1[i]; j++) { |
| int sh = (sps->sps_delta_qp_in_val_minus1[i][j] + 1) >> 1; |
| for (k = qp_in_val[i][j] + 1, m = 1; k <= qp_in_val[i][j + 1]; k++, m++) { |
| LE_OR_RETURN(j, kMaxPointsInQpTable - 1); |
| IN_RANGE_OR_RETURN(k + sps->qp_bd_offset, 0, kMaxPointsInQpTable - 1); |
| IN_RANGE_OR_RETURN(qp_in_val[i][j] + sps->qp_bd_offset, 0, |
| kMaxPointsInQpTable - 1); |
| sps->chroma_qp_table[i][k + sps->qp_bd_offset] = |
| sps->chroma_qp_table[i][qp_in_val[i][j] + sps->qp_bd_offset] + |
| ((qp_out_val[i][j + 1] - qp_out_val[i][j]) * m + sh) / |
| (sps->sps_delta_qp_in_val_minus1[i][j] + 1); |
| } |
| } |
| for (k = qp_in_val[i][sps->sps_num_points_in_qp_table_minus1[i] + 1] + 1; |
| k <= 63; k++) { |
| IN_RANGE_OR_RETURN(k + sps->qp_bd_offset, 0, kMaxPointsInQpTable - 1); |
| sps->chroma_qp_table[i][k + sps->qp_bd_offset] = |
| std::clamp(sps->chroma_qp_table[i][k + sps->qp_bd_offset - 1] + 1, |
| -sps->qp_bd_offset, 63); |
| } |
| } |
| // If same qp table is used, replicate chroma_qp_table[0][k] to |
| // chroma_qp_table[1][k] and chroma_qp_table[2][k]. |
| if (sps->sps_same_qp_table_for_chroma_flag) { |
| memcpy(&sps->chroma_qp_table[1][0], &sps->chroma_qp_table[0][0], |
| sizeof(sps->chroma_qp_table) / 3); |
| memcpy(&sps->chroma_qp_table[2][0], &sps->chroma_qp_table[0][0], |
| sizeof(sps->chroma_qp_table) / 3); |
| } |
| |
| // Sample adaptive offset filter and adaptive loop filter on/off. |
| READ_BOOL_OR_RETURN(&sps->sps_sao_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_alf_enabled_flag); |
| if (sps->sps_alf_enabled_flag && sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_ccalf_enabled_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_lmcs_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_weighted_pred_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_weighted_bipred_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_long_term_ref_pics_flag); |
| if (sps->sps_video_parameter_set_id > 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_inter_layer_prediction_enabled_flag); |
| } |
| |
| // Reference picture list structure handling. When ref_pic_list_struct |
| // syntax elements are in SPS, they're merely listed as candidates for |
| // RPL 0 and RPL 1. |
| // When sps_idr_rpl_present_flag is 1, the RPL syntax elements could |
| // be present in slice headers of IDR_N_LP/IDR_W_RADL slices. |
| READ_BOOL_OR_RETURN(&sps->sps_idr_rpl_present_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_rpl1_same_as_rpl0_flag); |
| for (int i = 0; i < (sps->sps_rpl1_same_as_rpl0_flag ? 1 : 2); i++) { |
| READ_UE_OR_RETURN(&sps->sps_num_ref_pic_lists[i]); |
| // Be noted decoder could allocate sps_num_ref_pic_list[i] + 1 |
| // ref_pic_list_struct(list_idx, rpls_idx) syntax structures, because |
| // there could be one ref_pic_list_struct that is directly signalled in |
| // picture header structure. |
| IN_RANGE_OR_RETURN(sps->sps_num_ref_pic_lists[i], 0, 64); |
| for (int j = 0; j < sps->sps_num_ref_pic_lists[i]; j++) { |
| ParseRefPicListStruct(i, j, *sps, &sps->ref_pic_list_struct[i][j]); |
| } |
| } |
| // sps_num_ref_pic_list[1] and ref_pic_list_struct(1, rplsIdx) not present. |
| if (sps->sps_rpl1_same_as_rpl0_flag) { |
| sps->sps_num_ref_pic_lists[1] = sps->sps_num_ref_pic_lists[0]; |
| // 7.4.3.4: Infer ref_pic_list_struct(1, rplsIdx) from |
| // ref_pic_list_struct(0, rplsIdx) for rplsIdx ranging from 0 to |
| // sps_num_ref_pic_lists[0] - 1; |
| memcpy(&sps->ref_pic_list_struct[1][0], &sps->ref_pic_list_struct[0][0], |
| sizeof(sps->ref_pic_list_struct[0])); |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_ref_wraparound_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_temporal_mvp_enabled_flag); |
| if (sps->sps_temporal_mvp_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_sbtmvp_enabled_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_amvr_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_bdof_enabled_flag); |
| if (sps->sps_bdof_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_bdof_control_present_in_ph_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_smvd_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_dmvr_enabled_flag); |
| if (sps->sps_dmvr_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_dmvr_control_present_in_ph_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_mmvd_enabled_flag); |
| if (sps->sps_mmvd_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_mmvd_fullpel_only_enabled_flag); |
| } |
| READ_UE_OR_RETURN(&sps->sps_six_minus_max_num_merge_cand); |
| IN_RANGE_OR_RETURN(sps->sps_six_minus_max_num_merge_cand, 0, 5); |
| READ_BOOL_OR_RETURN(&sps->sps_sbt_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_affine_enabled_flag); |
| if (sps->sps_affine_enabled_flag) { |
| READ_UE_OR_RETURN(&sps->sps_five_minus_max_num_subblock_merge_cand); |
| IN_RANGE_OR_RETURN(sps->sps_five_minus_max_num_subblock_merge_cand, 0, |
| 5 - sps->sps_sbtmvp_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_6param_affine_enabled_flag); |
| if (sps->sps_amvr_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_affine_amvr_enabled_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_affine_prof_enabled_flag); |
| if (sps->sps_affine_prof_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_prof_control_present_in_ph_flag); |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_bcw_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_ciip_enabled_flag); |
| |
| // Equation 58. |
| int max_num_merge_cand = 6 - sps->sps_six_minus_max_num_merge_cand; |
| if (max_num_merge_cand >= 2) { |
| READ_BOOL_OR_RETURN(&sps->sps_gpm_enabled_flag); |
| } |
| if (sps->sps_gpm_enabled_flag && max_num_merge_cand >= 3) { |
| READ_UE_OR_RETURN(&sps->sps_max_num_merge_cand_minus_max_num_gpm_cand); |
| IN_RANGE_OR_RETURN(sps->sps_max_num_merge_cand_minus_max_num_gpm_cand, 0, |
| max_num_merge_cand - 2); |
| } |
| READ_UE_OR_RETURN(&sps->sps_log2_parallel_merge_level_minus2); |
| IN_RANGE_OR_RETURN(sps->sps_log2_parallel_merge_level_minus2, 0, |
| sps->ctb_log2_size_y - 2); |
| |
| READ_BOOL_OR_RETURN(&sps->sps_isp_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_mrl_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_mip_enabled_flag); |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_cclm_enabled_flag); |
| } |
| if (sps->sps_chroma_format_idc == 1) { |
| READ_BOOL_OR_RETURN(&sps->sps_chroma_horizontal_collocated_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_chroma_vertical_collocated_flag); |
| } else { |
| sps->sps_chroma_horizontal_collocated_flag = 1; |
| sps->sps_chroma_vertical_collocated_flag = 1; |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_palette_enabled_flag); |
| if (sps->sps_chroma_format_idc == 3 && |
| !sps->sps_max_luma_transform_size_64_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_act_enabled_flag); |
| } |
| |
| if (sps->sps_transform_skip_enabled_flag || sps->sps_palette_enabled_flag) { |
| READ_UE_OR_RETURN(&sps->sps_min_qp_prime_ts); |
| IN_RANGE_OR_RETURN(sps->sps_min_qp_prime_ts, 0, 8); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_ibc_enabled_flag); |
| if (sps->sps_ibc_enabled_flag) { |
| READ_UE_OR_RETURN(&sps->sps_six_minus_max_num_ibc_merge_cand); |
| IN_RANGE_OR_RETURN(sps->sps_six_minus_max_num_ibc_merge_cand, 0, 5); |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_ladf_enabled_flag); |
| if (sps->sps_ladf_enabled_flag) { |
| READ_BITS_OR_RETURN(2, &sps->sps_num_ladf_intervals_minus2); |
| IN_RANGE_OR_RETURN(sps->sps_num_ladf_intervals_minus2, 0, 3); |
| READ_SE_OR_RETURN(&sps->sps_ladf_lowest_interval_qp_offset); |
| IN_RANGE_OR_RETURN(sps->sps_ladf_lowest_interval_qp_offset, -63, 63); |
| for (int i = 0; i < sps->sps_num_ladf_intervals_minus2 + 1; i++) { |
| READ_SE_OR_RETURN(&sps->sps_ladf_qp_offset[i]); |
| IN_RANGE_OR_RETURN(sps->sps_ladf_qp_offset[i], -63, 63); |
| READ_UE_OR_RETURN(&sps->sps_ladf_delta_threshold_minus1[i]); |
| IN_RANGE_OR_RETURN(sps->sps_ladf_delta_threshold_minus1[i], 0, |
| std::pow(2, sps->sps_bitdepth_minus8 + 8) - 3); |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_explicit_scaling_list_enabled_flag); |
| if (sps->sps_lfnst_enabled_flag && |
| sps->sps_explicit_scaling_list_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_scaling_matrix_for_lfnst_disabled_flag); |
| } |
| if (sps->sps_act_enabled_flag && |
| sps->sps_explicit_scaling_list_enabled_flag) { |
| READ_BOOL_OR_RETURN( |
| &sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag); |
| } |
| if (sps->sps_scaling_matrix_for_alternative_colour_space_disabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_scaling_matrix_designated_colour_space_flag); |
| } |
| READ_BOOL_OR_RETURN(&sps->sps_dep_quant_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_sign_data_hiding_enabled_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_virtual_boundaries_enabled_flag); |
| if (sps->sps_virtual_boundaries_enabled_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_virtual_boundaries_present_flag); |
| if (sps->sps_virtual_boundaries_present_flag) { |
| READ_UE_OR_RETURN(&sps->sps_num_ver_virtual_boundaries); |
| IN_RANGE_OR_RETURN(sps->sps_num_ver_virtual_boundaries, 0, |
| (sps->sps_pic_width_max_in_luma_samples <= 8) ? 0 : 3); |
| for (int i = 0; i < sps->sps_num_ver_virtual_boundaries; i++) { |
| READ_UE_OR_RETURN(&sps->sps_virtual_boundary_pos_x_minus1[i]); |
| IN_RANGE_OR_RETURN( |
| sps->sps_virtual_boundary_pos_x_minus1[i], 0, |
| (sps->sps_pic_width_max_in_luma_samples + 7) / 8 - 2); |
| } |
| READ_UE_OR_RETURN(&sps->sps_num_hor_virtual_boundaries); |
| IN_RANGE_OR_RETURN( |
| sps->sps_num_hor_virtual_boundaries, 0, |
| (sps->sps_pic_height_max_in_luma_samples <= 8) ? 0 : 3); |
| for (int i = 0; i < sps->sps_num_hor_virtual_boundaries; i++) { |
| READ_UE_OR_RETURN(&sps->sps_virtual_boundary_pos_y_minus1[i]); |
| IN_RANGE_OR_RETURN( |
| sps->sps_virtual_boundary_pos_y_minus1[i], 0, |
| (sps->sps_pic_height_max_in_luma_samples + 7) / 8 - 2); |
| } |
| } |
| } |
| |
| if (sps->sps_ptl_dpb_hrd_params_present_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_timing_hrd_params_present_flag); |
| if (sps->sps_timing_hrd_params_present_flag) { |
| ParseGeneralTimingHrdParameters(&sps->general_timing_hrd_parameters); |
| if (sps->sps_max_sublayers_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&sps->sps_sublayer_cpb_params_present_flag); |
| } |
| int first_sublayer = sps->sps_sublayer_cpb_params_present_flag |
| ? 0 |
| : sps->sps_max_sublayers_minus1; |
| ParseOlsTimingHrdParameters(first_sublayer, sps->sps_max_sublayers_minus1, |
| sps->general_timing_hrd_parameters, |
| &sps->ols_timing_hrd_parameters); |
| if (!sps->sps_sublayer_cpb_params_present_flag) { |
| for (int i = 0; i < sps->sps_max_sublayers_minus1; i++) { |
| sps->ols_timing_hrd_parameters.element_duration_in_tc_minus1[i] = |
| sps->ols_timing_hrd_parameters |
| .element_duration_in_tc_minus1[first_sublayer]; |
| sps->ols_timing_hrd_parameters.fixed_pic_rate_general_flag[i] = |
| sps->ols_timing_hrd_parameters |
| .fixed_pic_rate_general_flag[first_sublayer]; |
| sps->ols_timing_hrd_parameters.fixed_pic_rate_within_cvs_flag[i] = |
| sps->ols_timing_hrd_parameters |
| .fixed_pic_rate_within_cvs_flag[first_sublayer]; |
| sps->ols_timing_hrd_parameters.low_delay_hrd_flag[i] = |
| sps->ols_timing_hrd_parameters.low_delay_hrd_flag[first_sublayer]; |
| memcpy( |
| &(sps->ols_timing_hrd_parameters.nal_sublayer_hrd_parameters[i]), |
| &(sps->ols_timing_hrd_parameters |
| .nal_sublayer_hrd_parameters[first_sublayer]), |
| sizeof(sps->ols_timing_hrd_parameters |
| .nal_sublayer_hrd_parameters[first_sublayer])); |
| memcpy( |
| &(sps->ols_timing_hrd_parameters.vcl_sublayer_hrd_parameters[i]), |
| &(sps->ols_timing_hrd_parameters |
| .vcl_sublayer_hrd_parameters[first_sublayer]), |
| sizeof(sps->ols_timing_hrd_parameters |
| .vcl_sublayer_hrd_parameters[first_sublayer])); |
| } |
| } |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_field_seq_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_vui_parameters_present_flag); |
| if (sps->sps_vui_parameters_present_flag) { |
| READ_UE_OR_RETURN(&sps->sps_vui_payload_size_minus1); |
| IN_RANGE_OR_RETURN(sps->sps_vui_payload_size_minus1, 0, 1023); |
| |
| BYTE_ALIGNMENT(); |
| ParseVuiPayload(sps->sps_vui_payload_size_minus1 + 1, *sps, |
| &sps->vui_parameters); |
| } |
| |
| READ_BOOL_OR_RETURN(&sps->sps_extension_flag); |
| if (sps->sps_extension_flag) { |
| READ_BOOL_OR_RETURN(&sps->sps_range_extension_flag); |
| SKIP_BITS_OR_RETURN(7); |
| if (sps->sps_range_extension_flag) { |
| READ_BOOL_OR_RETURN( |
| &sps->sps_range_extension.sps_extended_precision_flag); |
| if (sps->sps_range_extension.sps_extended_precision_flag) { |
| READ_BOOL_OR_RETURN( |
| &sps->sps_range_extension |
| .sps_ts_residual_coding_rice_present_in_sh_flag); |
| } |
| READ_BOOL_OR_RETURN( |
| &sps->sps_range_extension.sps_rrc_rice_extension_flag); |
| READ_BOOL_OR_RETURN(&sps->sps_range_extension |
| .sps_persistent_rice_adaptation_enabled_flag); |
| READ_BOOL_OR_RETURN( |
| &sps->sps_range_extension.sps_reverse_last_sig_coeff_enabled_flag); |
| } |
| } |
| // Stop here. Skip trailing bits at the end of SPS when sps_extension_7bits |
| // is true. |
| |
| // If an SPS with the same id already exists, replace it. |
| *sps_id = sps->sps_seq_parameter_set_id; |
| active_sps_[*sps_id] = std::move(sps); |
| |
| return res; |
| } |
| |
| // Picture parameter set contains information that's not changed frequently |
| // across pictures, thus typically shared by many pictures. Since VVC |
| // supports adaptive resolution change, the width and height information may be |
| // in PPS instead of SPS. Also PPS includes information of reference picture |
| // resamping scaling window, layout of tiles and rectangular slices, default |
| // numbers of current active RPL entries, deblocking params/QP initials at |
| // picture level, as well as many other flags. |
| H266Parser::Result H266Parser::ParsePPS(const H266NALU& nalu, int* pps_id) { |
| // 7.3.2.5 |
| DVLOG(4) << "Parsing PPS"; |
| DCHECK(pps_id); |
| *pps_id = -1; |
| |
| std::unique_ptr<H266PPS> pps = std::make_unique<H266PPS>(); |
| |
| READ_BITS_OR_RETURN(6, &pps->pps_pic_parameter_set_id); |
| READ_BITS_OR_RETURN(4, &pps->pps_seq_parameter_set_id); |
| IN_RANGE_OR_RETURN(pps->pps_seq_parameter_set_id, 0, 15); |
| const H266SPS* sps = GetSPS(pps->pps_seq_parameter_set_id); |
| if (!sps) { |
| return kMissingParameterSet; |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_mixed_nalu_types_in_pic_flag); |
| READ_UE_OR_RETURN(&pps->pps_pic_width_in_luma_samples); |
| IN_RANGE_OR_RETURN(pps->pps_pic_width_in_luma_samples, 1, |
| sps->sps_pic_width_max_in_luma_samples); |
| |
| READ_UE_OR_RETURN(&pps->pps_pic_height_in_luma_samples); |
| IN_RANGE_OR_RETURN(pps->pps_pic_height_in_luma_samples, 1, |
| sps->sps_pic_height_max_in_luma_samples); |
| |
| int multipler = std::max(8, sps->min_cb_size_y); |
| if ((pps->pps_pic_width_in_luma_samples % multipler != 0) || |
| (pps->pps_pic_height_in_luma_samples % multipler != 0)) { |
| DVLOG(1) << "Invalid pps pic width/height"; |
| return kInvalidStream; |
| } |
| |
| if (!sps->sps_res_change_in_clvs_allowed_flag && |
| (pps->pps_pic_width_in_luma_samples != |
| sps->sps_pic_width_max_in_luma_samples || |
| (pps->pps_pic_height_in_luma_samples != |
| sps->sps_pic_height_max_in_luma_samples))) { |
| DVLOG(1) << "pps pic width/height is different from sps pic width/height " |
| "when sps_res_change_in_clvs_allowed_flag is false."; |
| return kInvalidStream; |
| } |
| if (sps->sps_ref_wraparound_enabled_flag) { |
| LE_OR_RETURN(sps->ctb_size_y / sps->min_cb_size_y + 1, |
| pps->pps_pic_width_in_luma_samples / sps->min_cb_size_y - 1); |
| } |
| |
| pps->pic_width_in_ctbs_y = |
| (pps->pps_pic_width_in_luma_samples + sps->ctb_size_y - 1) / |
| sps->ctb_size_y; |
| pps->pic_height_in_ctbs_y = |
| (pps->pps_pic_height_in_luma_samples + sps->ctb_size_y - 1) / |
| sps->ctb_size_y; |
| pps->pic_size_in_ctbs_y = |
| pps->pic_width_in_ctbs_y * pps->pic_height_in_ctbs_y; |
| pps->pic_width_in_min_cbs_y = |
| pps->pps_pic_width_in_luma_samples / sps->min_cb_size_y; |
| pps->pic_height_in_min_cbs_y = |
| pps->pps_pic_height_in_luma_samples / sps->min_cb_size_y; |
| pps->pic_size_in_min_cbs_y = |
| pps->pic_width_in_min_cbs_y * pps->pic_height_in_min_cbs_y; |
| pps->pic_size_in_samples_y = |
| pps->pps_pic_width_in_luma_samples * pps->pps_pic_height_in_luma_samples; |
| pps->pic_width_in_samples_c = |
| pps->pps_pic_width_in_luma_samples / sps->sub_width_c; |
| pps->pic_height_in_samples_c = |
| pps->pps_pic_height_in_luma_samples / sps->sub_width_c; |
| |
| READ_BOOL_OR_RETURN(&pps->pps_conformance_window_flag); |
| if (pps->pps_pic_width_in_luma_samples == |
| sps->sps_pic_width_max_in_luma_samples && |
| pps->pps_pic_height_in_luma_samples == |
| sps->sps_pic_height_max_in_luma_samples) { |
| if (pps->pps_conformance_window_flag) { |
| DVLOG(1) << "Invalid pps_conformance_window_flag."; |
| return kInvalidStream; |
| } |
| } |
| if (pps->pps_conformance_window_flag) { |
| READ_UE_OR_RETURN(&pps->pps_conf_win_left_offset); |
| READ_UE_OR_RETURN(&pps->pps_conf_win_right_offset); |
| READ_UE_OR_RETURN(&pps->pps_conf_win_top_offset); |
| READ_UE_OR_RETURN(&pps->pps_conf_win_bottom_offset); |
| // Verify cropping window. |
| if ((sps->sub_width_c * |
| (pps->pps_conf_win_left_offset + pps->pps_conf_win_right_offset) >= |
| pps->pps_pic_width_in_luma_samples) || |
| (sps->sub_height_c * |
| (pps->pps_conf_win_top_offset + pps->pps_conf_win_bottom_offset) >= |
| pps->pps_pic_height_in_luma_samples)) { |
| DVLOG(1) << "Invalid cropping window in PPS."; |
| return kInvalidStream; |
| } |
| } else { |
| if (pps->pps_pic_width_in_luma_samples == |
| sps->sps_pic_width_max_in_luma_samples && |
| pps->pps_pic_height_in_luma_samples == |
| sps->sps_pic_height_max_in_luma_samples) { |
| pps->pps_conf_win_left_offset = sps->sps_conf_win_left_offset; |
| pps->pps_conf_win_right_offset = sps->sps_conf_win_right_offset; |
| pps->pps_conf_win_top_offset = sps->sps_conf_win_top_offset; |
| pps->pps_conf_win_bottom_offset = sps->sps_conf_win_bottom_offset; |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_scaling_window_explicit_signaling_flag); |
| if (!sps->sps_ref_pic_resampling_enabled_flag && |
| pps->pps_scaling_window_explicit_signaling_flag) { |
| DVLOG(1) << "Scaling window cannot be explicitly signaled in PPS if ref " |
| "picture resampling is disabled."; |
| return kInvalidStream; |
| } |
| if (pps->pps_scaling_window_explicit_signaling_flag) { |
| READ_SE_OR_RETURN(&pps->pps_scaling_win_left_offset); |
| READ_SE_OR_RETURN(&pps->pps_scaling_win_right_offset); |
| READ_SE_OR_RETURN(&pps->pps_scaling_win_top_offset); |
| READ_SE_OR_RETURN(&pps->pps_scaling_win_bottom_offset); |
| // Verify scaling window. |
| IN_RANGE_OR_RETURN(sps->sub_width_c * pps->pps_scaling_win_left_offset, |
| -15 * pps->pps_pic_width_in_luma_samples, |
| pps->pps_pic_width_in_luma_samples - 1); |
| IN_RANGE_OR_RETURN(sps->sub_width_c * pps->pps_scaling_win_right_offset, |
| -15 * pps->pps_pic_width_in_luma_samples, |
| pps->pps_pic_width_in_luma_samples - 1); |
| IN_RANGE_OR_RETURN(sps->sub_height_c * pps->pps_scaling_win_top_offset, |
| -15 * pps->pps_pic_height_in_luma_samples, |
| pps->pps_pic_height_in_luma_samples - 1); |
| IN_RANGE_OR_RETURN(sps->sub_height_c * pps->pps_scaling_win_bottom_offset, |
| -15 * pps->pps_pic_height_in_luma_samples, |
| pps->pps_pic_height_in_luma_samples - 1); |
| IN_RANGE_OR_RETURN(sps->sub_width_c * (pps->pps_scaling_win_left_offset + |
| pps->pps_scaling_win_right_offset), |
| -15 * pps->pps_pic_width_in_luma_samples, |
| pps->pps_pic_width_in_luma_samples - 1); |
| IN_RANGE_OR_RETURN(sps->sub_height_c * (pps->pps_scaling_win_top_offset + |
| pps->pps_scaling_win_bottom_offset), |
| -15 * pps->pps_pic_height_in_luma_samples, |
| pps->pps_pic_height_in_luma_samples - 1); |
| } else { |
| pps->pps_scaling_win_left_offset = pps->pps_conf_win_left_offset; |
| pps->pps_scaling_win_right_offset = pps->pps_conf_win_right_offset; |
| pps->pps_scaling_win_top_offset = pps->pps_conf_win_top_offset; |
| pps->pps_scaling_win_bottom_offset = pps->pps_conf_win_bottom_offset; |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_output_flag_present_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_no_pic_partition_flag); |
| if (sps->sps_num_subpics_minus1 > 0 || |
| pps->pps_mixed_nalu_types_in_pic_flag == 1) { |
| TRUE_OR_RETURN(!pps->pps_no_pic_partition_flag); |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_subpic_id_mapping_present_flag); |
| if (!sps->sps_subpic_id_mapping_explicitly_signaled_flag || |
| sps->sps_subpic_id_mapping_present_flag) { |
| TRUE_OR_RETURN(!pps->pps_subpic_id_mapping_present_flag); |
| } else { |
| TRUE_OR_RETURN(pps->pps_subpic_id_mapping_present_flag); |
| } |
| |
| if (pps->pps_subpic_id_mapping_present_flag) { |
| if (!pps->pps_no_pic_partition_flag) { |
| READ_UE_OR_RETURN(&pps->pps_num_subpics_minus1); |
| TRUE_OR_RETURN(pps->pps_num_subpics_minus1 == |
| sps->sps_num_subpics_minus1); |
| } |
| |
| READ_UE_OR_RETURN(&pps->pps_subpic_id_len_minus1); |
| TRUE_OR_RETURN(pps->pps_subpic_id_len_minus1 == |
| sps->sps_subpic_id_len_minus1); |
| for (int i = 0; i <= pps->pps_num_subpics_minus1; i++) { |
| READ_BITS_OR_RETURN(pps->pps_subpic_id_len_minus1 + 1, |
| &pps->pps_subpic_id[i]); |
| } |
| } |
| |
| // Handle tile/slice layout information. |
| if (!pps->pps_no_pic_partition_flag) { |
| READ_BITS_OR_RETURN(2, &pps->pps_log2_ctu_size_minus5); |
| // CTU size info in PPS must be exactly the same as SPS. |
| TRUE_OR_RETURN(pps->pps_log2_ctu_size_minus5 == |
| sps->sps_log2_ctu_size_minus5); |
| READ_UE_OR_RETURN(&pps->pps_num_exp_tile_columns_minus1); |
| IN_RANGE_OR_RETURN(pps->pps_num_exp_tile_columns_minus1, 0, |
| pps->pic_width_in_ctbs_y - 1); |
| READ_UE_OR_RETURN(&pps->pps_num_exp_tile_rows_minus1); |
| IN_RANGE_OR_RETURN(pps->pps_num_exp_tile_rows_minus1, 0, |
| pps->pic_height_in_ctbs_y - 1); |
| |
| // Clause 6.5.1, equation 14 & equation 15: calculate number |
| // of tile columns and rows. |
| // For those tile column/row sizes not explicitly signalled, |
| // use the last explicitly signalled size as the implicit |
| // tile size, unless it is the last tile column/row. |
| int remaining_width_in_ctbs_y = pps->pic_width_in_ctbs_y; |
| int explicit_tile_width = 0; |
| for (int i = 0; i <= pps->pps_num_exp_tile_columns_minus1; i++) { |
| READ_UE_OR_RETURN(&pps->pps_tile_column_width_minus1[i]); |
| IN_RANGE_OR_RETURN(pps->pps_tile_column_width_minus1[i], 0, |
| pps->pic_width_in_ctbs_y - 1); |
| explicit_tile_width += pps->pps_tile_column_width_minus1[i] + 1; |
| } |
| remaining_width_in_ctbs_y -= explicit_tile_width; |
| int uniform_tile_col_width = pps->pps_tile_column_width_minus1 |
| [pps->pps_num_exp_tile_columns_minus1] + |
| 1; |
| int next_tile_column_idx = pps->pps_num_exp_tile_columns_minus1 + 1; |
| while (remaining_width_in_ctbs_y >= uniform_tile_col_width) { |
| pps->pps_tile_column_width_minus1[next_tile_column_idx++] = |
| uniform_tile_col_width - 1; |
| remaining_width_in_ctbs_y -= uniform_tile_col_width; |
| } |
| if (remaining_width_in_ctbs_y > 0) { |
| pps->pps_tile_column_width_minus1[next_tile_column_idx++] = |
| remaining_width_in_ctbs_y; |
| } |
| pps->num_tile_columns = next_tile_column_idx; |
| |
| int remaining_height_in_ctbs_y = pps->pic_height_in_ctbs_y; |
| int explicit_tile_height = 0; |
| for (int i = 0; i <= pps->pps_num_exp_tile_rows_minus1; i++) { |
| READ_UE_OR_RETURN(&pps->pps_tile_row_height_minus1[i]); |
| IN_RANGE_OR_RETURN(pps->pps_tile_row_height_minus1[i], 0, |
| pps->pic_height_in_ctbs_y - 1); |
| explicit_tile_height += pps->pps_tile_row_height_minus1[i] + 1; |
| } |
| remaining_height_in_ctbs_y -= explicit_tile_height; |
| int uniform_tile_row_height = |
| pps->pps_tile_row_height_minus1[pps->pps_num_exp_tile_rows_minus1] + 1; |
| int next_tile_row_idx = pps->pps_num_exp_tile_rows_minus1 + 1; |
| while (remaining_height_in_ctbs_y >= uniform_tile_row_height) { |
| pps->pps_tile_row_height_minus1[next_tile_row_idx++] = |
| uniform_tile_row_height - 1; |
| remaining_height_in_ctbs_y -= uniform_tile_row_height; |
| } |
| if (remaining_height_in_ctbs_y > 0) { |
| pps->pps_tile_row_height_minus1[next_tile_row_idx++] = |
| remaining_height_in_ctbs_y; |
| } |
| pps->num_tile_rows = next_tile_row_idx; |
| pps->num_tiles_in_pic = pps->num_tile_columns * pps->num_tile_rows; |
| |
| if (pps->num_tiles_in_pic > 1) { |
| READ_BOOL_OR_RETURN(&pps->pps_loop_filter_across_tiles_enabled_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_rect_slice_flag); |
| } else { |
| pps->pps_rect_slice_flag = 1; |
| } |
| if (pps->pps_rect_slice_flag) { |
| READ_BOOL_OR_RETURN(&pps->pps_single_slice_per_subpic_flag); |
| } |
| |
| // When pps_rect_slice_flag is 0, PPS will not contain the slice |
| // width/height measured in units of tiles. In that case, VVC depends on |
| // sh_slice_address and sh_num_tiles_in_slice_minus1 syntax for the slice |
| // layout in the picture. |
| if (pps->pps_rect_slice_flag && !pps->pps_single_slice_per_subpic_flag) { |
| READ_UE_OR_RETURN(&pps->pps_num_slices_in_pic_minus1); |
| IN_RANGE_OR_RETURN(pps->pps_num_slices_in_pic_minus1, 0, |
| sps->profile_tier_level.MaxSlicesPerAu() - 1); |
| |
| if (pps->pps_num_slices_in_pic_minus1 > 1) { |
| // When this flag is 0, all pictures referring to current PPS are |
| // partitioned into rectangular slice columns and rows in slice raster |
| // order. Otherwise all rectangular slices in picture are specified in |
| // the order by the values of pps_tile_idx_delta_val[i] in increasing |
| // values of i. |
| READ_BOOL_OR_RETURN(&pps->pps_tile_idx_delta_present_flag); |
| } |
| |
| int tile_idx = 0, tile_x = 0, tile_y = 0, ctu_x = 0, ctu_y = 0; |
| int slice_top_left_ctu_x[kMaxSlices]; |
| int slice_top_left_ctu_y[kMaxSlices]; |
| int i; |
| |
| for (i = 0; i < pps->pps_num_slices_in_pic_minus1; i++) { |
| // Equation 21. tile_x is the 0-based index horizontally; tile_y is the |
| // 0-based tile row. |
| tile_x = tile_idx % pps->num_tile_columns; |
| tile_y = tile_idx / pps->num_tile_columns; |
| ctu_x = ctu_y = 0; |
| if (tile_x != pps->num_tile_columns - 1) { |
| READ_UE_OR_RETURN(&pps->pps_slice_width_in_tiles_minus1[i]); |
| IN_RANGE_OR_RETURN(pps->pps_slice_width_in_tiles_minus1[i], 0, |
| pps->num_tile_columns - 1); |
| } |
| |
| if ((tile_y != pps->num_tile_rows - 1) && |
| (pps->pps_tile_idx_delta_present_flag || tile_x == 0)) { |
| READ_UE_OR_RETURN(&pps->pps_slice_height_in_tiles_minus1[i]); |
| IN_RANGE_OR_RETURN(pps->pps_slice_height_in_tiles_minus1[i], 0, |
| pps->num_tile_rows - 1); |
| } else { |
| if (tile_y == pps->num_tile_rows - 1) { |
| pps->pps_slice_height_in_tiles_minus1[i] = 0; |
| } else { |
| if (i > 0) { |
| pps->pps_slice_height_in_tiles_minus1[i] = |
| pps->pps_slice_height_in_tiles_minus1[i - 1]; |
| } |
| } |
| } |
| |
| for (int j = 0; j < tile_x; j++) { |
| ctu_x += pps->pps_tile_column_width_minus1[j] + 1; |
| } |
| for (int j = 0; j < tile_y; j++) { |
| ctu_y += pps->pps_tile_row_height_minus1[j] + 1; |
| } |
| |
| int num_slices_in_tile = 0, uniform_slice_height = 0; |
| remaining_height_in_ctbs_y = 0; |
| if (pps->pps_slice_width_in_tiles_minus1[i] == 0 && |
| pps->pps_slice_height_in_tiles_minus1[i] == 0 && |
| pps->pps_tile_row_height_minus1[tile_y] > 0) { |
| remaining_height_in_ctbs_y = |
| pps->pps_tile_row_height_minus1[tile_y] + 1; |
| READ_UE_OR_RETURN(&pps->pps_num_exp_slices_in_tile[i]); |
| IN_RANGE_OR_RETURN(pps->pps_num_exp_slices_in_tile[i], 0, |
| pps->pps_tile_row_height_minus1[tile_y]); |
| |
| if (!pps->pps_num_exp_slices_in_tile[i]) { |
| slice_top_left_ctu_x[i] = ctu_x; |
| slice_top_left_ctu_y[i] = ctu_y; |
| pps->slice_height_in_ctus[i] = |
| pps->pps_tile_row_height_minus1[tile_y] + 1; |
| num_slices_in_tile = 1; |
| } else { |
| int slice_height_in_ctus = 0, j; |
| for (j = 0; j < pps->pps_num_exp_slices_in_tile[i]; j++) { |
| READ_UE_OR_RETURN( |
| &pps->pps_exp_slice_height_in_ctus_minus1[i][j]); |
| IN_RANGE_OR_RETURN(pps->pps_exp_slice_height_in_ctus_minus1[i][j], |
| 0, pps->pps_tile_row_height_minus1[tile_y]); |
| slice_height_in_ctus = |
| pps->pps_exp_slice_height_in_ctus_minus1[i][j] + 1; |
| pps->slice_height_in_ctus[i + j] = slice_height_in_ctus; |
| slice_top_left_ctu_x[i + j] = ctu_x; |
| slice_top_left_ctu_y[i + j] = ctu_y; |
| ctu_y += slice_height_in_ctus; |
| remaining_height_in_ctbs_y -= slice_height_in_ctus; |
| } |
| uniform_slice_height = |
| 1 + pps->pps_exp_slice_height_in_ctus_minus1[i][j - 1]; |
| while (remaining_height_in_ctbs_y > uniform_slice_height) { |
| pps->slice_height_in_ctus[i + j] = uniform_slice_height; |
| slice_top_left_ctu_x[i + j] = ctu_x; |
| slice_top_left_ctu_y[i + j] = ctu_y; |
| ctu_y += uniform_slice_height; |
| j++; |
| } |
| if (remaining_height_in_ctbs_y > 0) { |
| pps->slice_height_in_ctus[i + j] = remaining_height_in_ctbs_y; |
| slice_top_left_ctu_x[i + j] = ctu_x; |
| slice_top_left_ctu_y[i + j] = ctu_y; |
| j++; |
| } |
| num_slices_in_tile = j; |
| } |
| i += num_slices_in_tile - 1; |
| } else { |
| int height = 0; |
| pps->pps_num_exp_slices_in_tile[i] = 0; |
| for (int j = 0; j <= pps->pps_slice_height_in_tiles_minus1[i]; j++) { |
| height += pps->pps_tile_row_height_minus1[tile_y + j] + 1; |
| } |
| pps->slice_height_in_ctus[i] = height; |
| slice_top_left_ctu_x[i] = ctu_x; |
| slice_top_left_ctu_y[i] = ctu_y; |
| } |
| |
| // Fetch next slice's tile idx, which is used for calculating next |
| // tile_x & tile_y. |
| if (i < pps->pps_num_slices_in_pic_minus1) { |
| if (pps->pps_tile_idx_delta_present_flag) { |
| READ_SE_OR_RETURN(&pps->pps_tile_idx_delta_val[i]); |
| IN_RANGE_OR_RETURN(pps->pps_tile_idx_delta_val[i], 1 - tile_idx, |
| pps->num_tiles_in_pic - 1 - tile_idx); |
| TRUE_OR_RETURN(pps->pps_tile_idx_delta_val[i] != 0); |
| tile_idx += pps->pps_tile_idx_delta_val[i]; |
| } else { |
| pps->pps_tile_idx_delta_val[i] = 0; |
| tile_idx += pps->pps_slice_width_in_tiles_minus1[i] + 1; |
| if (tile_idx % pps->num_tile_columns == 0) { |
| tile_idx += pps->pps_slice_height_in_tiles_minus1[i] * |
| pps->num_tile_columns; |
| } |
| } |
| } |
| } |
| |
| // Handle the last slice. |
| if (i == pps->pps_num_slices_in_pic_minus1) { |
| int height = 0; |
| tile_x = tile_idx % pps->num_tile_columns; |
| tile_y = tile_idx / pps->num_tile_columns; |
| |
| ctu_x = ctu_y = 0; |
| for (int j = 0; j < tile_x; j++) { |
| ctu_x += pps->pps_tile_column_width_minus1[j] + 1; |
| } |
| for (int j = 0; j < tile_y; j++) { |
| ctu_y += pps->pps_tile_row_height_minus1[j] + 1; |
| } |
| slice_top_left_ctu_x[i] = ctu_x; |
| slice_top_left_ctu_y[i] = ctu_y; |
| pps->pps_slice_width_in_tiles_minus1[i] = |
| pps->num_tile_columns - tile_x - 1; |
| pps->pps_slice_height_in_tiles_minus1[i] = |
| pps->num_tile_rows - tile_y - 1; |
| |
| for (int j = 0; j <= pps->pps_slice_height_in_tiles_minus1[i]; j++) { |
| height += pps->pps_tile_row_height_minus1[tile_y + j] + 1; |
| } |
| pps->slice_height_in_ctus[i] = height; |
| pps->pps_num_exp_slices_in_tile[i] = 0; |
| } |
| |
| for (int p = 0; p <= sps->sps_num_subpics_minus1; p++) { |
| pps->num_slices_in_subpic[p] = 0; |
| for (int k = 0; k <= pps->pps_num_slices_in_pic_minus1; k++) { |
| int pos_x = 0, pos_y = 0; |
| pos_x = slice_top_left_ctu_x[k]; |
| pos_y = slice_top_left_ctu_y[k]; |
| if ((pos_x >= sps->sps_subpic_ctu_top_left_x[p]) && |
| (pos_x < sps->sps_subpic_ctu_top_left_x[p] + |
| sps->sps_subpic_width_minus1[p] + 1) && |
| (pos_y >= sps->sps_subpic_ctu_top_left_y[p]) && |
| (pos_y < sps->sps_subpic_ctu_top_left_y[p] + |
| sps->sps_subpic_height_minus1[p] + 1)) { |
| pps->num_slices_in_subpic[p]++; |
| } |
| } |
| } |
| // pps_rect_slice_flag && !pps_single_slice_per_subpic_flag |
| } |
| |
| if (!pps->pps_rect_slice_flag || pps->pps_single_slice_per_subpic_flag || |
| pps->pps_num_slices_in_pic_minus1 > 0) { |
| READ_BOOL_OR_RETURN(&pps->pps_loop_filter_across_slices_enabled_flag); |
| } else { |
| pps->pps_loop_filter_across_slices_enabled_flag = 0; |
| } |
| |
| } else { |
| // pps_no_pic_partition_flag = 1, so that tiling and slicing layout |
| // need to be inferred. |
| pps->pps_num_exp_tile_columns_minus1 = 0; |
| pps->pps_num_exp_tile_rows_minus1 = 0; |
| pps->pps_tile_column_width_minus1[0] = pps->pic_width_in_ctbs_y - 1; |
| pps->pps_tile_row_height_minus1[0] = pps->pic_height_in_ctbs_y - 1; |
| pps->pps_loop_filter_across_tiles_enabled_flag = 0; |
| pps->pps_rect_slice_flag = 1; |
| pps->pps_single_slice_per_subpic_flag = 1; |
| // Spec requires when pps_no_pic_partition_flag is 1, |
| // pps_num_slices_in_pic_minus1 should be 0; But at the same time, if |
| // pps_single_slcie_per_subpic_flag is 1, it should be inferred to |
| // sps_num_subpics_minus1. |
| pps->pps_num_slices_in_pic_minus1 = 0; |
| pps->pps_tile_idx_delta_present_flag = 0; |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_cabac_init_present_flag); |
| for (int i = 0; i < 2; i++) { |
| READ_UE_OR_RETURN(&pps->pps_num_ref_idx_default_active_minus1[i]); |
| IN_RANGE_OR_RETURN(pps->pps_num_ref_idx_default_active_minus1[i], 0, 14); |
| } |
| READ_BOOL_OR_RETURN(&pps->pps_rpl1_idx_present_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_weighted_pred_flag); |
| if (!sps->sps_weighted_pred_flag) { |
| TRUE_OR_RETURN(!pps->pps_weighted_pred_flag); |
| } |
| READ_BOOL_OR_RETURN(&pps->pps_weighted_bipred_flag); |
| if (!sps->sps_weighted_bipred_flag) { |
| TRUE_OR_RETURN(!pps->pps_weighted_bipred_flag); |
| } |
| READ_BOOL_OR_RETURN(&pps->pps_ref_wraparound_enabled_flag); |
| if (sps->sps_ref_pic_resampling_enabled_flag == 0 || |
| sps->ctb_size_y / sps->min_cb_size_y + 1 > |
| pps->pps_pic_width_in_luma_samples / sps->min_cb_size_y - 1) { |
| TRUE_OR_RETURN(pps->pps_ref_wraparound_enabled_flag == 0); |
| } |
| |
| if (pps->pps_ref_wraparound_enabled_flag) { |
| READ_UE_OR_RETURN(&pps->pps_pic_width_minus_wraparound_offset); |
| IN_RANGE_OR_RETURN( |
| pps->pps_pic_width_minus_wraparound_offset, 0, |
| (pps->pps_pic_width_in_luma_samples / sps->min_cb_size_y) - |
| (sps->ctb_size_y / sps->min_cb_size_y) - 2); |
| } |
| |
| // QP |
| READ_SE_OR_RETURN(&pps->pps_init_qp_minus26); |
| IN_RANGE_OR_RETURN(pps->pps_init_qp_minus26, -(26 + sps->qp_bd_offset), 37); |
| READ_BOOL_OR_RETURN(&pps->pps_cu_qp_delta_enabled_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_chroma_tool_offsets_present_flag); |
| if (sps->sps_chroma_format_idc == 0) { |
| TRUE_OR_RETURN(pps->pps_chroma_tool_offsets_present_flag == 0); |
| } |
| |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| READ_SE_OR_RETURN(&pps->pps_cb_qp_offset); |
| READ_SE_OR_RETURN(&pps->pps_cr_qp_offset); |
| IN_RANGE_OR_RETURN(pps->pps_cb_qp_offset, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cr_qp_offset, -12, 12); |
| READ_BOOL_OR_RETURN(&pps->pps_joint_cbcr_qp_offset_present_flag); |
| if (sps->sps_chroma_format_idc == 0 || |
| sps->sps_joint_cbcr_enabled_flag == 0) { |
| TRUE_OR_RETURN(pps->pps_joint_cbcr_qp_offset_present_flag == 0); |
| } |
| |
| if (pps->pps_joint_cbcr_qp_offset_present_flag) { |
| READ_SE_OR_RETURN(&pps->pps_joint_cbcr_qp_offset_value); |
| IN_RANGE_OR_RETURN(pps->pps_joint_cbcr_qp_offset_value, -12, 12); |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_slice_chroma_qp_offsets_present_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_cu_chroma_qp_offset_list_enabled_flag); |
| if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) { |
| READ_UE_OR_RETURN(&pps->pps_chroma_qp_offset_list_len_minus1); |
| IN_RANGE_OR_RETURN(pps->pps_chroma_qp_offset_list_len_minus1, 0, 5); |
| |
| for (int i = 0; i <= pps->pps_chroma_qp_offset_list_len_minus1; i++) { |
| READ_SE_OR_RETURN(&pps->pps_cb_qp_offset_list[i]); |
| READ_SE_OR_RETURN(&pps->pps_cr_qp_offset_list[i]); |
| IN_RANGE_OR_RETURN(pps->pps_cb_qp_offset_list[i], -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cr_qp_offset_list[i], -12, 12); |
| |
| if (pps->pps_joint_cbcr_qp_offset_present_flag) { |
| READ_SE_OR_RETURN(&pps->pps_joint_cbcr_qp_offset_list[i]); |
| IN_RANGE_OR_RETURN(pps->pps_joint_cbcr_qp_offset_list[i], -12, 12); |
| } else { |
| pps->pps_joint_cbcr_qp_offset_list[i] = 0; |
| } |
| } |
| } |
| } |
| |
| // Deblocking filter |
| READ_BOOL_OR_RETURN(&pps->pps_deblocking_filter_control_present_flag); |
| if (pps->pps_deblocking_filter_control_present_flag) { |
| READ_BOOL_OR_RETURN(&pps->pps_deblocking_filter_override_enabled_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_deblocking_filter_disabled_flag); |
| if (!pps->pps_no_pic_partition_flag && |
| pps->pps_deblocking_filter_override_enabled_flag) { |
| READ_BOOL_OR_RETURN(&pps->pps_dbf_info_in_ph_flag); |
| } else { |
| pps->pps_dbf_info_in_ph_flag = 0; |
| } |
| if (!pps->pps_deblocking_filter_disabled_flag) { |
| READ_SE_OR_RETURN(&pps->pps_luma_beta_offset_div2); |
| READ_SE_OR_RETURN(&pps->pps_luma_tc_offset_div2); |
| IN_RANGE_OR_RETURN(pps->pps_luma_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_luma_tc_offset_div2, -12, 12); |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| READ_SE_OR_RETURN(&pps->pps_cb_beta_offset_div2); |
| READ_SE_OR_RETURN(&pps->pps_cb_tc_offset_div2); |
| READ_SE_OR_RETURN(&pps->pps_cr_beta_offset_div2); |
| READ_SE_OR_RETURN(&pps->pps_cr_tc_offset_div2); |
| IN_RANGE_OR_RETURN(pps->pps_cb_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cb_tc_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cr_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cr_tc_offset_div2, -12, 12); |
| } else { |
| pps->pps_cb_beta_offset_div2 = pps->pps_luma_beta_offset_div2; |
| pps->pps_cb_tc_offset_div2 = pps->pps_luma_tc_offset_div2; |
| pps->pps_cr_beta_offset_div2 = pps->pps_luma_beta_offset_div2; |
| pps->pps_cr_tc_offset_div2 = pps->pps_luma_tc_offset_div2; |
| } |
| } else { |
| pps->pps_luma_beta_offset_div2 = pps->pps_luma_tc_offset_div2 = 0; |
| } |
| } else { |
| pps->pps_deblocking_filter_override_enabled_flag = 0; |
| pps->pps_deblocking_filter_disabled_flag = 0; |
| pps->pps_dbf_info_in_ph_flag = 0; |
| pps->pps_luma_beta_offset_div2 = pps->pps_luma_tc_offset_div2 = 0; |
| pps->pps_cb_beta_offset_div2 = pps->pps_luma_beta_offset_div2; |
| pps->pps_cb_tc_offset_div2 = pps->pps_luma_tc_offset_div2; |
| pps->pps_cr_beta_offset_div2 = pps->pps_luma_beta_offset_div2; |
| pps->pps_cr_tc_offset_div2 = pps->pps_luma_tc_offset_div2; |
| } |
| |
| if (!pps->pps_no_pic_partition_flag) { |
| READ_BOOL_OR_RETURN(&pps->pps_rpl_info_in_ph_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_sao_info_in_ph_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_alf_info_in_ph_flag); |
| |
| if ((pps->pps_weighted_pred_flag || pps->pps_weighted_bipred_flag) && |
| pps->pps_rpl_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&pps->pps_wp_info_in_ph_flag); |
| } else { |
| pps->pps_wp_info_in_ph_flag = 0; |
| } |
| READ_BOOL_OR_RETURN(&pps->pps_qp_delta_info_in_ph_flag); |
| } else { |
| pps->pps_rpl_info_in_ph_flag = 0; |
| pps->pps_sao_info_in_ph_flag = 0; |
| pps->pps_alf_info_in_ph_flag = 0; |
| pps->pps_wp_info_in_ph_flag = 0; |
| pps->pps_qp_delta_info_in_ph_flag = 0; |
| } |
| |
| READ_BOOL_OR_RETURN(&pps->pps_picture_header_extension_present_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_slice_header_extension_present_flag); |
| READ_BOOL_OR_RETURN(&pps->pps_extension_flag); |
| // We stop here. |
| |
| // If a PPS with the same id already exists, replace it. |
| *pps_id = pps->pps_pic_parameter_set_id; |
| active_pps_[*pps_id] = std::move(pps); |
| |
| return kOk; |
| } |
| |
| // 7.3.2.6 Adaptation parameter set |
| // APS conveys slice level information which may be shared by |
| // multiple slices of a picture or slices of different pictures. |
| // There might be many APSs for a bitstream, and would be typically |
| // updated very frequently. |
| H266Parser::Result H266Parser::ParseAPS(const H266NALU& nalu, |
| int* aps_id, |
| H266APS::ParamType* type) { |
| DCHECK(aps_id); |
| |
| int aps_type; |
| READ_BITS_OR_RETURN(3, &aps_type); |
| IN_RANGE_OR_RETURN(aps_type, 0, 2); |
| std::unique_ptr<H266APS> aps = std::make_unique<H266APS>(aps_type); |
| |
| aps->nal_unit_type = nalu.nal_unit_type; |
| aps->nuh_layer_id = nalu.nuh_layer_id; |
| aps->aps_params_type = aps_type; |
| |
| READ_BITS_OR_RETURN(5, &aps->aps_adaptation_parameter_set_id); |
| if (aps->aps_params_type == H266APS::kAlf || |
| aps->aps_params_type == H266APS::kScalingList) { |
| IN_RANGE_OR_RETURN(aps->aps_adaptation_parameter_set_id, 0, 7); |
| } else if (aps->aps_params_type == H266APS::kLmcs) { |
| IN_RANGE_OR_RETURN(aps->aps_adaptation_parameter_set_id, 0, 3); |
| } |
| READ_BOOL_OR_RETURN(&aps->aps_chroma_present_flag); |
| |
| if (aps->aps_params_type == H266APS::kAlf) { |
| // 7.3.2.18: Adaptive loop filter |
| H266AlfData* alf_data = &std::get<H266AlfData>(aps->data); |
| READ_BOOL_OR_RETURN(&alf_data->alf_luma_filter_signal_flag); |
| if (aps->aps_chroma_present_flag) { |
| READ_BOOL_OR_RETURN(&alf_data->alf_chroma_filter_signal_flag); |
| READ_BOOL_OR_RETURN(&alf_data->alf_cc_cb_filter_signal_flag); |
| READ_BOOL_OR_RETURN(&alf_data->alf_cc_cr_filter_signal_flag); |
| } else { |
| alf_data->alf_chroma_filter_signal_flag = 0; |
| alf_data->alf_cc_cb_filter_signal_flag = 0; |
| alf_data->alf_cc_cr_filter_signal_flag = 0; |
| } |
| // 7.4.3.18: at least one of above signal flag should be 1. |
| TRUE_OR_RETURN(alf_data->alf_luma_filter_signal_flag || |
| alf_data->alf_chroma_filter_signal_flag || |
| alf_data->alf_cc_cb_filter_signal_flag || |
| alf_data->alf_cc_cr_filter_signal_flag); |
| |
| if (alf_data->alf_luma_filter_signal_flag) { |
| READ_BOOL_OR_RETURN(&alf_data->alf_luma_clip_flag); |
| READ_UE_OR_RETURN(&alf_data->alf_luma_num_filters_signalled_minus1); |
| IN_RANGE_OR_RETURN(alf_data->alf_luma_num_filters_signalled_minus1, 0, |
| kNumAlfFilters - 1); |
| |
| if (alf_data->alf_luma_num_filters_signalled_minus1 > 0) { |
| int signaled_filters_len = base::bits::Log2Ceiling( |
| alf_data->alf_luma_num_filters_signalled_minus1 + 1); |
| for (int filter_idx = 0; filter_idx < kNumAlfFilters; filter_idx++) { |
| READ_BITS_OR_RETURN(signaled_filters_len, |
| &std::get<H266AlfData>(aps->data) |
| .alf_luma_coeff_delta_idx[filter_idx]); |
| IN_RANGE_OR_RETURN(alf_data->alf_luma_coeff_delta_idx[filter_idx], 0, |
| alf_data->alf_luma_num_filters_signalled_minus1); |
| } |
| } |
| |
| for (int sf_idx = 0; |
| sf_idx <= alf_data->alf_luma_num_filters_signalled_minus1; |
| sf_idx++) { |
| for (int j = 0; j < 12; j++) { |
| READ_UE_OR_RETURN( |
| &std::get<H266AlfData>(aps->data).alf_luma_coeff_abs[sf_idx][j]); |
| IN_RANGE_OR_RETURN(alf_data->alf_luma_coeff_abs[sf_idx][j], 0, 128); |
| if (alf_data->alf_luma_coeff_abs[sf_idx][j]) { |
| // alf_luma_coeff_sign[sf_idx][j] equals to 0 indicates a positive |
| // value and otherwise a negative value. |
| READ_BOOL_OR_RETURN(&std::get<H266AlfData>(aps->data) |
| .alf_luma_coeff_sign[sf_idx][j]); |
| } else { |
| alf_data->alf_luma_coeff_sign[sf_idx][j] = 0; |
| } |
| } |
| } |
| |
| if (alf_data->alf_luma_clip_flag) { |
| for (int sf_idx = 0; |
| sf_idx <= alf_data->alf_luma_num_filters_signalled_minus1; |
| sf_idx++) { |
| for (int j = 0; j < 12; j++) { |
| READ_BITS_OR_RETURN( |
| 2, |
| &std::get<H266AlfData>(aps->data).alf_luma_clip_idx[sf_idx][j]); |
| } |
| } |
| } |
| } |
| |
| if (alf_data->alf_chroma_filter_signal_flag) { |
| READ_BOOL_OR_RETURN( |
| &std::get<H266AlfData>(aps->data).alf_chroma_clip_flag); |
| READ_UE_OR_RETURN( |
| &std::get<H266AlfData>(aps->data).alf_chroma_num_alt_filters_minus1); |
| IN_RANGE_OR_RETURN(alf_data->alf_chroma_num_alt_filters_minus1, 0, 7); |
| |
| for (int alt_idx = 0; |
| alt_idx <= alf_data->alf_chroma_num_alt_filters_minus1; alt_idx++) { |
| for (int j = 0; j < 6; j++) { |
| READ_UE_OR_RETURN(&std::get<H266AlfData>(aps->data) |
| .alf_chroma_coeff_abs[alt_idx][j]); |
| IN_RANGE_OR_RETURN(alf_data->alf_chroma_coeff_abs[alt_idx][j], 0, |
| 128); |
| if (alf_data->alf_chroma_coeff_abs[alt_idx][j] > 0) { |
| READ_BOOL_OR_RETURN(&std::get<H266AlfData>(aps->data) |
| .alf_chroma_coeff_sign[alt_idx][j]); |
| } else { |
| alf_data->alf_chroma_coeff_sign[alt_idx][j] = 0; |
| } |
| } |
| |
| if (alf_data->alf_chroma_clip_flag) { |
| for (int j = 0; j < 6; j++) { |
| READ_BITS_OR_RETURN(2, &alf_data->alf_chroma_clip_idx[alt_idx][j]); |
| } |
| } |
| } |
| } else { |
| alf_data->alf_chroma_clip_flag = 0; |
| } |
| |
| if (alf_data->alf_cc_cb_filter_signal_flag) { |
| READ_UE_OR_RETURN(&alf_data->alf_cc_cb_filters_signalled_minus1); |
| IN_RANGE_OR_RETURN(alf_data->alf_cc_cb_filters_signalled_minus1, 0, 3); |
| |
| for (int k = 0; k < alf_data->alf_cc_cb_filters_signalled_minus1 + 1; |
| k++) { |
| for (int j = 0; j < 7; j++) { |
| READ_BITS_OR_RETURN(3, &alf_data->alf_cc_cb_mapped_coeff_abs[k][j]); |
| if (alf_data->alf_cc_cb_mapped_coeff_abs[k][j]) { |
| READ_BOOL_OR_RETURN(&alf_data->alf_cc_cb_coeff_sign[k][j]); |
| } else { |
| alf_data->alf_cc_cb_coeff_sign[k][j] = 0; |
| } |
| } |
| } |
| } |
| |
| if (alf_data->alf_cc_cr_filter_signal_flag) { |
| READ_UE_OR_RETURN(&alf_data->alf_cc_cr_filters_signalled_minus1); |
| IN_RANGE_OR_RETURN(alf_data->alf_cc_cr_filters_signalled_minus1, 0, 3); |
| |
| for (int k = 0; k < alf_data->alf_cc_cr_filters_signalled_minus1 + 1; |
| k++) { |
| for (int j = 0; j < 7; j++) { |
| READ_BITS_OR_RETURN(3, &alf_data->alf_cc_cr_mapped_coeff_abs[k][j]); |
| if (alf_data->alf_cc_cr_mapped_coeff_abs[k][j]) { |
| READ_BOOL_OR_RETURN(&alf_data->alf_cc_cr_coeff_sign[k][j]); |
| } else { |
| alf_data->alf_cc_cr_coeff_sign[k][j] = 0; |
| } |
| } |
| } |
| } |
| } else if (aps->aps_params_type == H266APS::kLmcs) { |
| H266LmcsData* lmcs_data = &std::get<H266LmcsData>(aps->data); |
| READ_UE_OR_RETURN(&lmcs_data->lmcs_min_bin_idx); |
| IN_RANGE_OR_RETURN(lmcs_data->lmcs_min_bin_idx, 0, 15); |
| READ_UE_OR_RETURN(&lmcs_data->lmcs_delta_max_bin_idx); |
| IN_RANGE_OR_RETURN(lmcs_data->lmcs_delta_max_bin_idx, 0, 15); |
| READ_UE_OR_RETURN(&lmcs_data->lmcs_delta_cw_prec_minus1); |
| IN_RANGE_OR_RETURN(lmcs_data->lmcs_delta_cw_prec_minus1, 0, 14); |
| |
| int lmcs_max_bin_idx = 15 - lmcs_data->lmcs_delta_max_bin_idx; |
| TRUE_OR_RETURN(lmcs_max_bin_idx >= lmcs_data->lmcs_min_bin_idx); |
| |
| for (int i = lmcs_data->lmcs_min_bin_idx; i <= lmcs_max_bin_idx; i++) { |
| READ_BITS_OR_RETURN(lmcs_data->lmcs_delta_cw_prec_minus1 + 1, |
| &lmcs_data->lmcs_delta_abs_cw[i]); |
| if (lmcs_data->lmcs_delta_abs_cw[i] > 0) { |
| READ_BOOL_OR_RETURN(&lmcs_data->lmcs_delta_sign_cw_flag[i]); |
| } else { |
| lmcs_data->lmcs_delta_sign_cw_flag[i] = 0; |
| } |
| } |
| if (aps->aps_chroma_present_flag) { |
| READ_BITS_OR_RETURN(3, &lmcs_data->lmcs_delta_abs_crs); |
| if (lmcs_data->lmcs_delta_abs_crs > 0) { |
| READ_BOOL_OR_RETURN(&lmcs_data->lmcs_delta_sign_crs_flag); |
| } else { |
| lmcs_data->lmcs_delta_sign_crs_flag = 0; |
| } |
| } else { |
| lmcs_data->lmcs_delta_abs_crs = 0; |
| lmcs_data->lmcs_delta_sign_crs_flag = 0; |
| } |
| } else if (aps->aps_params_type == H266APS::kScalingList) { |
| // VVC defines default quantization matrices(QM) for INTER_2x2, |
| // INTER_4x4, INTRA_8x8 & INTER_8x8 with flat value of 16 in them. |
| // Other sizes, including 16x16, 32x32, 64x64 are upsampled from the 8x8 |
| // quantization matrix. |
| // If explicit scaling list is signaled in SPS/PH/SH/APS, VVC allows encoder |
| // customize up to 28 quantization matrices. For QM of 16x16, 32x32 and |
| // 64x64, the DC values are coded explicitly, while only 64(8x8) AC values |
| // for every such matrix may be coded explicitly, with the entire matrix |
| // upsampled to desired size. |
| |
| H266ScalingListData* scaling_list_data = |
| &(std::get<H266ScalingListData>(aps->data)); |
| |
| int max_id_delta = 0, matrix_size = 0, ref_id = 0; |
| int scaling_matrix_pred2x2[2][2][2], scaling_matrix_pred4x4[6][4][4], |
| scaling_matrix_pred8x8[20][8][8]; |
| int scaling_matrix_dc_pred[28]; |
| |
| // id: [0, 1]: 2x2, INTRA2x2 & INTER2x2 |
| // [2, 7]: 4x4, INTRA4x4_Y|U|V & INTER4x4_Y|U|V |
| // [8, 13]: 8x8, INTRA8x8_Y|U|V & INTER8x8_Y|U|V |
| // [14, 19]: 16x16, INTRA16x16_Y|U|V & INTER16x16_Y|U|V |
| // [20, 25]: 32x32, INTRA32x32_Y|U|V & INTER32x32_Y|U|V |
| // [26, 27]: 64x64, INTRA64x64_Y & INTER64x64_Y |
| |
| for (int id = 0; id < 28; id++) { |
| // Equation 101 |
| max_id_delta = (id < 2) ? id : ((id < 8) ? (id - 2) : (id - 8)); |
| // Equation 103 |
| matrix_size = (id < 2) ? 2 : ((id < 8) ? 4 : 8); |
| |
| scaling_list_data->scaling_list_copy_mode_flag[id] = 1; |
| if (aps->aps_chroma_present_flag || id % 3 == 2 || id == 27) { |
| READ_BOOL_OR_RETURN( |
| &scaling_list_data->scaling_list_copy_mode_flag[id]); |
| if (!scaling_list_data->scaling_list_copy_mode_flag[id]) { |
| READ_BOOL_OR_RETURN( |
| &scaling_list_data->scaling_list_pred_mode_flag[id]); |
| } |
| |
| // id 0/2/8 are for 2x2/4x4/8x8 initial lists so they don't have |
| // the scaling_list_pred_id_delta syntax signaled. |
| if ((scaling_list_data->scaling_list_copy_mode_flag[id] || |
| scaling_list_data->scaling_list_pred_mode_flag[id]) && |
| id != 0 && id != 2 && id != 8) { |
| READ_UE_OR_RETURN(&scaling_list_data->scaling_list_pred_id_delta[id]); |
| IN_RANGE_OR_RETURN(scaling_list_data->scaling_list_pred_id_delta[id], |
| 0, max_id_delta); |
| } |
| |
| if (!scaling_list_data->scaling_list_copy_mode_flag[id]) { |
| int next_coef = 0; |
| if (id > 13) { |
| READ_SE_OR_RETURN( |
| &scaling_list_data->scaling_list_dc_coef[id - 14]); |
| IN_RANGE_OR_RETURN(scaling_list_data->scaling_list_dc_coef[id - 14], |
| -128, 127); |
| |
| next_coef += scaling_list_data->scaling_matrix_dc_rec[id - 14]; |
| } |
| |
| for (int i = 0; i < matrix_size * matrix_size; i++) { |
| int x = kDiagScanOrder8x8[i][0], y = kDiagScanOrder8x8[i][1]; |
| if (!(id > 25 && x >= 4 && y >= 4)) { |
| READ_SE_OR_RETURN( |
| &scaling_list_data->scaling_list_delta_coef[id][i]); |
| IN_RANGE_OR_RETURN( |
| scaling_list_data->scaling_list_delta_coef[id][i], -128, 127); |
| |
| next_coef += scaling_list_data->scaling_list_delta_coef[id][i]; |
| } |
| if (id < 2) { |
| scaling_list_data->scaling_list_2x2[id][i] = next_coef; |
| } else if (id < 8) { |
| scaling_list_data->scaling_list_4x4[id - 2][i] = next_coef; |
| } else { |
| scaling_list_data->scaling_list_8x8[id - 8][i] = next_coef; |
| } |
| } |
| } |
| |
| // Equation 102 |
| ref_id = id - scaling_list_data->scaling_list_pred_id_delta[id]; |
| |
| if (!scaling_list_data->scaling_list_copy_mode_flag[id] && |
| !scaling_list_data->scaling_list_pred_mode_flag[id]) { |
| scaling_matrix_dc_pred[id] = 8; |
| if (id < 2) { |
| std::fill_n(scaling_matrix_pred2x2[id][0], |
| matrix_size * matrix_size, 8); |
| } else if (id < 8) { |
| std::fill_n(scaling_matrix_pred4x4[id - 2][0], |
| matrix_size * matrix_size, 8); |
| } else { |
| std::fill_n(scaling_matrix_pred8x8[id - 8][0], |
| matrix_size * matrix_size, 8); |
| } |
| } else if (scaling_list_data->scaling_list_pred_id_delta[id] == 0) { |
| scaling_matrix_dc_pred[id] = 16; |
| if (id < 2) { |
| std::fill_n(scaling_matrix_pred2x2[id][0], |
| matrix_size * matrix_size, 16); |
| } else if (id < 8) { |
| std::fill_n(scaling_matrix_pred4x4[id - 2][0], |
| matrix_size * matrix_size, 16); |
| } else { |
| std::fill_n(scaling_matrix_pred8x8[id - 8][0], |
| matrix_size * matrix_size, 16); |
| } |
| } else { |
| if (id < 2 && id > 0 & ref_id >= 0) { |
| memcpy(&scaling_matrix_pred2x2[id][0], |
| &scaling_list_data->scaling_matrix_rec_2x2[ref_id][0][0], |
| 4 * sizeof(int)); |
| } else if (id < 8 && id > 2 && ref_id >= 2) { |
| memcpy(&scaling_matrix_pred4x4[id - 2][0][0], |
| &scaling_list_data->scaling_matrix_rec_4x4[ref_id - 2][0][0], |
| 16 * sizeof(int)); |
| } else if (ref_id >= 8) { |
| memcpy(&scaling_matrix_pred8x8[id - 8][0][0], |
| &scaling_list_data->scaling_matrix_rec_8x8[ref_id - 8][0][0], |
| 64 * sizeof(int)); |
| } |
| if (ref_id > 13) { |
| scaling_matrix_dc_pred[id] = |
| scaling_list_data->scaling_matrix_dc_rec[ref_id - 14]; |
| } else { |
| if (id < 2) { |
| scaling_matrix_dc_pred[id] = scaling_matrix_pred2x2[id][0][0]; |
| } else if (id < 8) { |
| scaling_matrix_dc_pred[id] = scaling_matrix_pred4x4[id - 2][0][0]; |
| } else { |
| scaling_matrix_dc_pred[id] = scaling_matrix_pred8x8[id - 8][0][0]; |
| } |
| } |
| } |
| |
| // Equation 104 |
| if (id > 13) { |
| scaling_list_data->scaling_matrix_dc_rec[id - 14] = |
| (scaling_matrix_dc_pred[id] + |
| scaling_list_data->scaling_list_dc_coef[id - 14]) & |
| 255; |
| } |
| } |
| |
| // Equation 105 |
| int rec_x = 0, rec_y = 0, k = 0; |
| if (id < 2) { |
| for (k = 0; k <= 3; k++) { |
| rec_x = kDiagScanOrder2x2[k][0]; |
| rec_y = kDiagScanOrder2x2[k][1]; |
| scaling_list_data->scaling_matrix_rec_2x2[id][rec_x][rec_y] = |
| (scaling_matrix_pred2x2[id][rec_x][rec_y] + |
| scaling_list_data->scaling_list_2x2[id][k]) & |
| 255; |
| } |
| } else if (id < 8) { |
| for (k = 0; k <= 15; k++) { |
| rec_x = kDiagScanOrder4x4[k][0]; |
| rec_y = kDiagScanOrder4x4[k][1]; |
| scaling_list_data->scaling_matrix_rec_4x4[id - 2][rec_x][rec_y] = |
| (scaling_matrix_pred4x4[id - 2][rec_x][rec_y] + |
| scaling_list_data->scaling_list_4x4[id - 2][k]) & |
| 255; |
| } |
| } else { |
| for (k = 0; k <= 63; k++) { |
| rec_x = kDiagScanOrder8x8[k][0]; |
| rec_y = kDiagScanOrder8x8[k][1]; |
| scaling_list_data->scaling_matrix_rec_8x8[id - 8][rec_x][rec_y] = |
| (scaling_matrix_pred8x8[id - 8][rec_x][rec_y] + |
| scaling_list_data->scaling_list_8x8[id - 8][k]) & |
| 255; |
| } |
| } |
| } |
| } |
| |
| // If an APS with the same id already exists, replace it. |
| *aps_id = aps->aps_adaptation_parameter_set_id; |
| switch (aps->aps_params_type) { |
| case 0: |
| *type = H266APS::ParamType::kAlf; |
| active_alf_aps_[*aps_id] = std::move(aps); |
| break; |
| case 1: |
| *type = H266APS::ParamType::kLmcs; |
| active_lmcs_aps_[*aps_id] = std::move(aps); |
| break; |
| case 2: |
| *type = H266APS::ParamType::kScalingList; |
| active_scaling_list_aps_[*aps_id] = std::move(aps); |
| break; |
| } |
| |
| return kOk; |
| } |
| |
| // 7.3.9 & 7.4.10 |
| H266Parser::Result H266Parser::ParseRefPicLists( |
| const H266SPS& sps, |
| const H266PPS& pps, |
| H266RefPicLists* ref_pic_lists) { |
| DCHECK(ref_pic_lists); |
| |
| for (int i = 0; i < 2; i++) { |
| if (sps.sps_num_ref_pic_lists[i] > 0 && |
| (i == 0 || (i == 1 && pps.pps_rpl1_idx_present_flag))) { |
| READ_BOOL_OR_RETURN(&ref_pic_lists->rpl_sps_flag[i]); |
| } else { |
| if (sps.sps_num_ref_pic_lists[i] == 0) { |
| ref_pic_lists->rpl_sps_flag[i] = 0; |
| } else if (sps.sps_num_ref_pic_lists[i] > 0) { |
| if (pps.pps_rpl1_idx_present_flag == 0 && i == 1) { |
| ref_pic_lists->rpl_sps_flag[i] = ref_pic_lists->rpl_sps_flag[0]; |
| } |
| } |
| } |
| |
| if (ref_pic_lists->rpl_sps_flag[i]) { |
| if (sps.sps_num_ref_pic_lists[i] > 1 && |
| (i == 0 || (i == 1 && pps.pps_rpl1_idx_present_flag))) { |
| READ_BITS_OR_RETURN(base::bits::Log2Ceiling(static_cast<uint32_t>( |
| sps.sps_num_ref_pic_lists[i])), |
| &ref_pic_lists->rpl_idx[i]); |
| IN_RANGE_OR_RETURN(ref_pic_lists->rpl_idx[i], 0, |
| sps.sps_num_ref_pic_lists[i] - 1); |
| } else { |
| if (sps.sps_num_ref_pic_lists[i] == 1) { |
| ref_pic_lists->rpl_idx[i] = 0; |
| } |
| if (i == 1 && pps.pps_rpl1_idx_present_flag == 0 && |
| sps.sps_num_ref_pic_lists[1] > 1) { |
| ref_pic_lists->rpl_idx[i] = ref_pic_lists->rpl_idx[0]; |
| } |
| } |
| } else { |
| ParseRefPicListStruct(i, sps.sps_num_ref_pic_lists[i], sps, |
| &ref_pic_lists->rpl_ref_lists[i]); |
| } |
| |
| int num_ltrp_entries = |
| !ref_pic_lists->rpl_sps_flag[i] |
| ? ref_pic_lists->rpl_ref_lists[i].num_ltrp_entries |
| : sps.ref_pic_list_struct[i][ref_pic_lists->rpl_idx[i]] |
| .num_ltrp_entries; |
| bool ltrp_in_header = |
| !ref_pic_lists->rpl_sps_flag[i] |
| ? ref_pic_lists->rpl_ref_lists[i].ltrp_in_header_flag |
| : sps.ref_pic_list_struct[i][ref_pic_lists->rpl_idx[i]] |
| .ltrp_in_header_flag; |
| for (int j = 0; j < num_ltrp_entries; j++) { |
| if (ltrp_in_header) { |
| READ_BITS_OR_RETURN(sps.sps_log2_max_pic_order_cnt_lsb_minus4 + 4, |
| &ref_pic_lists->poc_lsb_lt[i][j]); |
| } |
| READ_BOOL_OR_RETURN( |
| &ref_pic_lists->delta_poc_msb_cycle_present_flag[i][j]); |
| if (ref_pic_lists->delta_poc_msb_cycle_present_flag[i][j]) { |
| READ_UE_OR_RETURN(&ref_pic_lists->delta_poc_msb_cycle_lt[i][j]); |
| IN_RANGE_OR_RETURN( |
| ref_pic_lists->delta_poc_msb_cycle_lt[i][j], 0, |
| std::pow(2, 32 - sps.sps_log2_max_pic_order_cnt_lsb_minus4 - 4)); |
| } else { |
| ref_pic_lists->delta_poc_msb_cycle_lt[i][j] = 0; |
| } |
| |
| // Equation 148 |
| if (j == 0) { |
| ref_pic_lists->unpacked_delta_poc_msb_cycle_lt[i][j] = |
| ref_pic_lists->delta_poc_msb_cycle_lt[i][j]; |
| } else { |
| ref_pic_lists->unpacked_delta_poc_msb_cycle_lt[i][j] = |
| ref_pic_lists->delta_poc_msb_cycle_lt[i][j] + |
| ref_pic_lists->unpacked_delta_poc_msb_cycle_lt[i][j - 1]; |
| } |
| } |
| |
| // Equation 146 |
| ref_pic_lists->rpls_idx[i] = ref_pic_lists->rpl_sps_flag[i] |
| ? ref_pic_lists->rpl_idx[i] |
| : sps.sps_num_ref_pic_lists[i]; |
| } |
| |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParsePredWeightTable( |
| const H266SPS& sps, |
| const H266PPS& pps, |
| const H266RefPicLists& ref_pic_lists, |
| int num_ref_idx_active[2], |
| H266PredWeightTable* pred_weight_table) { |
| DCHECK(pred_weight_table); |
| |
| // 7.3.8 |
| READ_UE_OR_RETURN(&pred_weight_table->luma_log2_weight_denom); |
| IN_RANGE_OR_RETURN(pred_weight_table->luma_log2_weight_denom, 0, 7); |
| if (sps.sps_chroma_format_idc != 0) { |
| READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_log2_weight_denom); |
| } else { |
| pred_weight_table->delta_chroma_log2_weight_denom = 0; |
| } |
| pred_weight_table->chroma_log2_weight_denom = |
| pred_weight_table->luma_log2_weight_denom + |
| pred_weight_table->delta_chroma_log2_weight_denom; |
| IN_RANGE_OR_RETURN(pred_weight_table->chroma_log2_weight_denom, 0, 7); |
| |
| if (pps.pps_wp_info_in_ph_flag) { |
| READ_UE_OR_RETURN(&pred_weight_table->num_l0_weights); |
| IN_RANGE_OR_RETURN( |
| pred_weight_table->num_l0_weights, 0, |
| std::min(15, ref_pic_lists.rpl_ref_lists[0].num_ref_entries)); |
| pred_weight_table->num_weights_l0 = pred_weight_table->num_l0_weights; |
| } else { |
| pred_weight_table->num_weights_l0 = num_ref_idx_active[0]; |
| } |
| for (int i = 0; i < pred_weight_table->num_weights_l0; i++) { |
| READ_BOOL_OR_RETURN(&pred_weight_table->luma_weight_l0_flag[i]); |
| } |
| if (sps.sps_chroma_format_idc != 0) { |
| for (int i = 0; i < pred_weight_table->num_weights_l0; i++) { |
| READ_BOOL_OR_RETURN(&pred_weight_table->chroma_weight_l0_flag[i]); |
| } |
| } |
| for (int i = 0; i < pred_weight_table->num_weights_l0; i++) { |
| if (pred_weight_table->luma_weight_l0_flag[i]) { |
| READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l0[i]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l0[i], -128, 127); |
| READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l0[i]); |
| IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l0[i], -128, 127); |
| } else { |
| pred_weight_table->delta_luma_weight_l0[i] = 0; |
| pred_weight_table->luma_offset_l0[i] = 0; |
| } |
| if (pred_weight_table->chroma_weight_l0_flag[i]) { |
| for (int j = 0; j < 2; j++) { |
| READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l0[i][j]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l0[i][j], |
| -128, 127); |
| READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l0[i][j]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l0[i][j], |
| -4 * 128, 4 * 127); |
| } |
| } |
| } |
| |
| if (pps.pps_weighted_bipred_flag && pps.pps_wp_info_in_ph_flag && |
| ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) { |
| READ_UE_OR_RETURN(&pred_weight_table->num_l1_weights); |
| IN_RANGE_OR_RETURN( |
| pred_weight_table->num_l1_weights, 0, |
| std::min(15, ref_pic_lists.rpl_ref_lists[1].num_ref_entries)); |
| } |
| // Equation 145 |
| if (!pps.pps_weighted_bipred_flag || |
| (pps.pps_wp_info_in_ph_flag && |
| ref_pic_lists.rpl_ref_lists[1].num_ref_entries == 0)) { |
| pred_weight_table->num_weights_l1 = 0; |
| } else if (pps.pps_wp_info_in_ph_flag) { |
| pred_weight_table->num_weights_l1 = pred_weight_table->num_l1_weights; |
| } else { |
| pred_weight_table->num_weights_l1 = num_ref_idx_active[1]; |
| } |
| |
| for (int i = 0; i < pred_weight_table->num_weights_l1; i++) { |
| READ_BOOL_OR_RETURN(&pred_weight_table->luma_weight_l1_flag[i]); |
| } |
| if (sps.sps_chroma_format_idc != 0) { |
| for (int i = 0; i < pred_weight_table->num_weights_l1; i++) { |
| READ_BOOL_OR_RETURN(&pred_weight_table->chroma_weight_l1_flag[i]); |
| } |
| } |
| for (int i = 0; i < pred_weight_table->num_weights_l1; i++) { |
| if (pred_weight_table->luma_weight_l1_flag[i]) { |
| READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l1[i]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l1[i], -128, 127); |
| READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l1[i]); |
| IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l1[i], -128, 127); |
| } else { |
| pred_weight_table->delta_luma_weight_l1[i] = 0; |
| pred_weight_table->luma_offset_l1[i] = 0; |
| } |
| if (pred_weight_table->chroma_weight_l1_flag[i]) { |
| for (int j = 0; j < 2; j++) { |
| READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l1[i][j]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l1[i][j], |
| -128, 127); |
| READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l1[i][j]); |
| IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l1[i][j], |
| -4 * 128, 4 * 127); |
| } |
| } |
| } |
| |
| return kOk; |
| } |
| |
| H266Parser::Result H266Parser::ParsePHNut(const H266NALU& nalu, |
| H266PictureHeader* ph) { |
| DCHECK(ph); |
| memset(reinterpret_cast<void*>(ph), 0, sizeof(H266PictureHeader)); |
| |
| if (nalu.nal_unit_type != H266NALU::kPH) { |
| DVLOG(1) << "Not a picture header NALU."; |
| return kIgnored; |
| } |
| |
| ph->nal_unit_type = nalu.nal_unit_type; |
| return ParsePictureHeaderStructure(nalu, ph); |
| } |
| |
| H266Parser::Result H266Parser::ParsePHInSlice(const H266NALU& nalu, |
| H266PictureHeader* ph) { |
| DCHECK(ph); |
| memset(reinterpret_cast<void*>(ph), 0, sizeof(H266PictureHeader)); |
| |
| if (!(nalu.nal_unit_type >= H266NALU::kTrail && |
| nalu.nal_unit_type <= H266NALU::kReservedIRAP11)) { |
| DVLOG(1) << "Embedded picture header structure must be in slice."; |
| return kInvalidStream; |
| } |
| |
| // The nalu type of slice that current picture header is embedded into. |
| ph->nal_unit_type = nalu.nal_unit_type; |
| return ParsePictureHeaderStructure(nalu, ph); |
| } |
| |
| // 7.3.2.8 Picture header structure |
| // May be in separate PH_NUT or included in slice header. They convey |
| // information for a particular picture including but not limited to: |
| // 1. Indication of IRAP/GDR, and if inter-intra slices are allowed. |
| // 2. LSB and MSB of POC, coding partitioning. |
| // 3. Picture level collocated info and tool switches. |
| // 4. RPLs, deblocking/QP info, etc. |
| // Be noted for each picture there needs to be exactly one PH associated |
| // with it. |
| H266Parser::Result H266Parser::ParsePictureHeaderStructure( |
| const H266NALU& nalu, |
| H266PictureHeader* ph) { |
| READ_BOOL_OR_RETURN(&ph->ph_gdr_or_irap_pic_flag); |
| READ_BOOL_OR_RETURN(&ph->ph_non_ref_pic_flag); |
| if (ph->ph_gdr_or_irap_pic_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_gdr_pic_flag); |
| } else { |
| ph->ph_gdr_pic_flag = 0; |
| } |
| READ_BOOL_OR_RETURN(&ph->ph_inter_slice_allowed_flag); |
| |
| if (ph->ph_inter_slice_allowed_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_intra_slice_allowed_flag); |
| } else { |
| ph->ph_intra_slice_allowed_flag = 1; |
| } |
| |
| READ_UE_OR_RETURN(&ph->ph_pic_parameter_set_id); |
| IN_RANGE_OR_RETURN(ph->ph_pic_parameter_set_id, 0, 63); |
| |
| const H266PPS* pps = GetPPS(ph->ph_pic_parameter_set_id); |
| if (!pps) { |
| DVLOG(1) << "Invalid PPS in picture header."; |
| return kInvalidStream; |
| } |
| |
| const H266SPS* sps = GetSPS(pps->pps_seq_parameter_set_id); |
| if (!sps) { |
| DVLOG(1) << "Failed to find SPS for current PPS."; |
| return kInvalidStream; |
| } |
| const H266VPS* vps = GetVPS(sps->sps_video_parameter_set_id); |
| if (!vps) { |
| DVLOG(1) << "VPS for current SPS is not found."; |
| return kInvalidStream; |
| } |
| |
| if (ph->ph_gdr_or_irap_pic_flag && !ph->ph_gdr_pic_flag) { |
| int general_layer_idx = vps->GetGeneralLayerIdx(nalu.nuh_layer_id); |
| if (general_layer_idx > 0 & general_layer_idx < kMaxLayers && |
| vps->vps_independent_layer_flag[general_layer_idx]) { |
| TRUE_OR_RETURN(!ph->ph_inter_slice_allowed_flag); |
| } |
| } |
| |
| // Late validation of ph_gdr_pic_flag as pps id is fetched after |
| // ph_gdr_pic_flag. |
| if (sps->sps_gdr_enabled_flag == 0) { |
| TRUE_OR_RETURN(ph->ph_gdr_pic_flag == 0); |
| } |
| |
| READ_BITS_OR_RETURN(sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4, |
| &ph->ph_pic_order_cnt_lsb); |
| IN_RANGE_OR_RETURN(ph->ph_pic_order_cnt_lsb, 0, |
| sps->max_pic_order_cnt_lsb - 1); |
| if (ph->ph_gdr_pic_flag) { |
| READ_UE_OR_RETURN(&ph->ph_recovery_poc_cnt); |
| IN_RANGE_OR_RETURN(ph->ph_recovery_poc_cnt, 0, |
| sps->max_pic_order_cnt_lsb - 1); |
| } |
| |
| if (sps->num_extra_ph_bits > 0) { |
| SKIP_BITS_OR_RETURN(sps->num_extra_ph_bits); |
| } |
| |
| if (sps->sps_poc_msb_cycle_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_poc_msb_cycle_present_flag); |
| if (ph->ph_poc_msb_cycle_present_flag) { |
| READ_BITS_OR_RETURN(sps->sps_poc_msb_cycle_len_minus1 + 1, |
| &ph->ph_poc_msb_cycle_val); |
| } |
| } |
| |
| // PH alf info. |
| if (sps->sps_alf_enabled_flag && pps->pps_alf_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_alf_enabled_flag); |
| if (ph->ph_alf_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &ph->ph_num_alf_aps_ids_luma); |
| for (int i = 0; i < ph->ph_num_alf_aps_ids_luma; i++) { |
| READ_BITS_OR_RETURN(3, &ph->ph_alf_aps_id_luma[i]); |
| } |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&ph->ph_alf_cb_enabled_flag); |
| READ_BOOL_OR_RETURN(&ph->ph_alf_cr_enabled_flag); |
| } else { |
| ph->ph_alf_cb_enabled_flag = ph->ph_alf_cr_enabled_flag = 0; |
| } |
| if (ph->ph_alf_cb_enabled_flag || ph->ph_alf_cr_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &ph->ph_alf_aps_id_chroma); |
| } |
| if (sps->sps_ccalf_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_alf_cc_cb_enabled_flag); |
| if (ph->ph_alf_cc_cb_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &ph->ph_alf_cc_cb_aps_id); |
| } |
| READ_BOOL_OR_RETURN(&ph->ph_alf_cc_cr_enabled_flag); |
| if (ph->ph_alf_cc_cr_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &ph->ph_alf_cc_cr_aps_id); |
| } |
| } else { |
| ph->ph_alf_cc_cb_enabled_flag = 0; |
| ph->ph_alf_cc_cr_enabled_flag = 0; |
| } |
| } |
| } else { |
| ph->ph_alf_enabled_flag = 0; |
| ph->ph_alf_cb_enabled_flag = ph->ph_alf_cr_enabled_flag = 0; |
| ph->ph_alf_cc_cb_enabled_flag = 0; |
| ph->ph_alf_cc_cr_enabled_flag = 0; |
| } |
| |
| if (sps->sps_lmcs_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_lmcs_enabled_flag); |
| if (ph->ph_lmcs_enabled_flag) { |
| READ_BITS_OR_RETURN(2, &ph->ph_lmcs_aps_id); |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&ph->ph_chroma_residual_scale_flag); |
| } else { |
| ph->ph_chroma_residual_scale_flag = 0; |
| } |
| } |
| } else { |
| ph->ph_lmcs_enabled_flag = 0; |
| ph->ph_chroma_residual_scale_flag = 0; |
| } |
| |
| if (sps->sps_explicit_scaling_list_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_explicit_scaling_list_enabled_flag); |
| if (ph->ph_explicit_scaling_list_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &ph->ph_scaling_list_aps_id); |
| } |
| } else { |
| ph->ph_explicit_scaling_list_enabled_flag = 0; |
| } |
| |
| if (sps->sps_virtual_boundaries_enabled_flag && |
| !sps->sps_virtual_boundaries_present_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_virtual_boundaries_present_flag); |
| // Equation 77. |
| ph->virtual_boundaries_present_flag = 0; |
| if (sps->sps_virtual_boundaries_enabled_flag) { |
| ph->virtual_boundaries_present_flag = |
| sps->sps_virtual_boundaries_present_flag || |
| ph->ph_virtual_boundaries_present_flag; |
| } |
| if (ph->ph_virtual_boundaries_present_flag) { |
| READ_UE_OR_RETURN(&ph->ph_num_ver_virtual_boundaries); |
| IN_RANGE_OR_RETURN(ph->ph_num_ver_virtual_boundaries, 0, |
| (pps->pps_pic_width_in_luma_samples <= 8) ? 0 : 3); |
| for (int i = 0; i < ph->ph_num_ver_virtual_boundaries; i++) { |
| READ_UE_OR_RETURN(&ph->ph_virtual_boundary_pos_x_minus1[i]); |
| IN_RANGE_OR_RETURN(ph->ph_virtual_boundary_pos_x_minus1[i], 0, |
| (pps->pps_pic_width_in_luma_samples + 7 / 8) - 2); |
| } |
| |
| READ_UE_OR_RETURN(&ph->ph_num_hor_virtual_boundaries); |
| IN_RANGE_OR_RETURN(ph->ph_num_hor_virtual_boundaries, 0, |
| (pps->pps_pic_height_in_luma_samples <= 8) ? 0 : 3); |
| for (int i = 0; i < ph->ph_num_hor_virtual_boundaries; i++) { |
| READ_UE_OR_RETURN(&ph->ph_virtual_boundary_pos_y_minus1[i]); |
| IN_RANGE_OR_RETURN(ph->ph_virtual_boundary_pos_y_minus1[i], 0, |
| (pps->pps_pic_height_in_luma_samples + 7 / 8) - 2); |
| } |
| } else { |
| ph->ph_num_ver_virtual_boundaries = 0; |
| } |
| } else { |
| ph->ph_virtual_boundaries_present_flag = 0; |
| ph->ph_num_ver_virtual_boundaries = 0; |
| } |
| |
| if (pps->pps_output_flag_present_flag && !ph->ph_non_ref_pic_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_pic_output_flag); |
| } else { |
| ph->ph_pic_output_flag = 1; |
| } |
| |
| if (pps->pps_rpl_info_in_ph_flag) { |
| ParseRefPicLists(*sps, *pps, &ph->ref_pic_lists); |
| } |
| |
| if (sps->sps_partition_constraints_override_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_partition_constraints_override_flag); |
| } else { |
| ph->ph_partition_constraints_override_flag = 0; |
| } |
| |
| if (ph->ph_intra_slice_allowed_flag) { |
| if (ph->ph_partition_constraints_override_flag) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| // Equation 82 |
| ph->min_qt_log2_size_intra_y = |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma + |
| sps->min_cb_log2_size_y; |
| |
| READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_intra_slice_luma); |
| IN_RANGE_OR_RETURN(ph->ph_max_mtt_hierarchy_depth_intra_slice_luma, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| |
| if (ph->ph_max_mtt_hierarchy_depth_intra_slice_luma != 0) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma); |
| IN_RANGE_OR_RETURN(ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma, 0, |
| (sps->sps_qtbtt_dual_tree_intra_flag |
| ? std::min(6, sps->ctb_log2_size_y) |
| : sps->ctb_log2_size_y) - |
| ph->min_qt_log2_size_intra_y); |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma, 0, |
| std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_y); |
| } else { |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma = |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma; |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma = |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma; |
| } |
| |
| if (sps->sps_qtbtt_dual_tree_intra_flag) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| |
| // Equation 83 |
| ph->min_qt_log2_size_intra_c = |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma + |
| sps->min_cb_log2_size_y; |
| |
| if (ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_c); |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma, 0, |
| std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_c); |
| } else { |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma; |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma; |
| } |
| } else { |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma; |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma; |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma = |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma; |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma = |
| sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma; |
| } |
| } else { |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma = |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_luma; |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_luma = |
| sps->sps_max_mtt_hierarchy_depth_intra_slice_luma; |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma = |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma; |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma = |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma; |
| ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma; |
| ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma = |
| sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma; |
| ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma = |
| sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma; |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma = |
| sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma; |
| } |
| if (pps->pps_cu_qp_delta_enabled_flag) { |
| READ_UE_OR_RETURN(&ph->ph_cu_qp_delta_subdiv_intra_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_cu_qp_delta_subdiv_intra_slice, 0, |
| 2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_intra_y + |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_luma)); |
| } else { |
| ph->ph_cu_qp_delta_subdiv_intra_slice = 0; |
| } |
| if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) { |
| READ_UE_OR_RETURN(&ph->ph_cu_chroma_qp_offset_subdiv_intra_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_cu_chroma_qp_offset_subdiv_intra_slice, 0, |
| 2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_intra_y + |
| ph->ph_max_mtt_hierarchy_depth_intra_slice_luma)); |
| } else { |
| ph->ph_cu_chroma_qp_offset_subdiv_intra_slice = 0; |
| } |
| } // ph_intra_slice_allowed_flag |
| |
| if (ph->ph_inter_slice_allowed_flag) { // Syntax parsing till before |
| // ph_qp_delta |
| if (ph->ph_partition_constraints_override_flag) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_inter_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_min_qt_min_cb_inter_slice, 0, |
| std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y); |
| // Equation 84 |
| ph->min_qt_log2_size_inter_y = |
| ph->ph_log2_diff_min_qt_min_cb_inter_slice + sps->min_cb_log2_size_y; |
| |
| READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_inter_slice); |
| IN_RANGE_OR_RETURN(ph->ph_max_mtt_hierarchy_depth_inter_slice, 0, |
| 2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y)); |
| |
| if (ph->ph_max_mtt_hierarchy_depth_inter_slice != 0) { |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_inter_slice); |
| IN_RANGE_OR_RETURN(ph->ph_log2_diff_max_bt_min_qt_inter_slice, 0, |
| sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y); |
| READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_inter_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_log2_diff_max_tt_min_qt_inter_slice, 0, |
| std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_inter_y); |
| } else { |
| ph->ph_log2_diff_max_bt_min_qt_inter_slice = |
| sps->sps_log2_diff_max_bt_min_qt_inter_slice; |
| ph->ph_log2_diff_max_tt_min_qt_inter_slice = |
| sps->sps_log2_diff_max_tt_min_qt_inter_slice; |
| } |
| } else { |
| ph->ph_log2_diff_min_qt_min_cb_inter_slice = |
| sps->sps_log2_diff_max_bt_min_qt_inter_slice; |
| ph->ph_max_mtt_hierarchy_depth_inter_slice = |
| sps->sps_max_mtt_hierarchy_depth_inter_slice; |
| ph->ph_log2_diff_max_bt_min_qt_inter_slice = |
| sps->sps_log2_diff_max_bt_min_qt_inter_slice; |
| ph->ph_log2_diff_max_tt_min_qt_inter_slice = |
| sps->sps_log2_diff_max_tt_min_qt_inter_slice; |
| } |
| |
| if (pps->pps_cu_qp_delta_enabled_flag) { |
| READ_UE_OR_RETURN(&ph->ph_cu_qp_delta_subdiv_inter_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_cu_qp_delta_subdiv_inter_slice, 0, |
| 2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y + |
| ph->ph_max_mtt_hierarchy_depth_inter_slice)); |
| } else { |
| ph->ph_cu_qp_delta_subdiv_inter_slice = 0; |
| } |
| |
| if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) { |
| READ_UE_OR_RETURN(&ph->ph_cu_chroma_qp_offset_subdiv_inter_slice); |
| IN_RANGE_OR_RETURN( |
| ph->ph_cu_chroma_qp_offset_subdiv_inter_slice, 0, |
| 2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y + |
| ph->ph_max_mtt_hierarchy_depth_inter_slice)); |
| } else { |
| ph->ph_cu_chroma_qp_offset_subdiv_inter_slice = 0; |
| } |
| |
| if (sps->sps_temporal_mvp_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_temporal_mvp_enabled_flag); |
| |
| if (ph->ph_temporal_mvp_enabled_flag && pps->pps_rpl_info_in_ph_flag) { |
| if (ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) { |
| READ_BOOL_OR_RETURN(&ph->ph_collocated_from_l0_flag); |
| } else { |
| ph->ph_collocated_from_l0_flag = 1; |
| } |
| |
| if ((ph->ph_collocated_from_l0_flag && |
| ph->ref_pic_lists.rpl_ref_lists[0].num_ref_entries > 1) || |
| (!ph->ph_collocated_from_l0_flag && |
| ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 1)) { |
| READ_UE_OR_RETURN(&ph->ph_collocated_ref_idx); |
| if (ph->ph_collocated_from_l0_flag) { |
| IN_RANGE_OR_RETURN( |
| ph->ph_collocated_ref_idx, 0, |
| ph->ref_pic_lists.rpl_ref_lists[0].num_ref_entries - 1); |
| } else { |
| IN_RANGE_OR_RETURN( |
| ph->ph_collocated_ref_idx, 0, |
| ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries - 1); |
| } |
| } else { |
| ph->ph_collocated_ref_idx = 0; |
| } |
| } |
| } |
| |
| if (sps->sps_mmvd_fullpel_only_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_mmvd_fullpel_only_flag); |
| } else { |
| ph->ph_mmvd_fullpel_only_flag = 0; |
| } |
| |
| bool presence_flag = 0; |
| if (!pps->pps_rpl_info_in_ph_flag) { |
| presence_flag = 1; |
| } else if (ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) { |
| presence_flag = 1; |
| } |
| if (presence_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_mvd_l1_zero_flag); |
| if (sps->sps_bdof_control_present_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_bdof_disabled_flag); |
| } else { |
| ph->ph_bdof_disabled_flag = 1 - sps->sps_bdof_enabled_flag; |
| } |
| if (sps->sps_dmvr_control_present_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_dmvr_disabled_flag); |
| } else { |
| ph->ph_dmvr_disabled_flag = 1 - sps->sps_dmvr_enabled_flag; |
| } |
| } else { |
| ph->ph_mvd_l1_zero_flag = 1; |
| ph->ph_bdof_disabled_flag = 1; |
| } |
| |
| if (sps->sps_prof_control_present_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_prof_disabled_flag); |
| } else { |
| if (sps->sps_affine_prof_enabled_flag) { |
| ph->ph_prof_disabled_flag = 0; |
| } else { |
| ph->ph_prof_disabled_flag = 1; |
| } |
| } |
| |
| if ((pps->pps_weighted_pred_flag || pps->pps_weighted_bipred_flag) && |
| pps->pps_wp_info_in_ph_flag) { |
| int num_active_ref_idx[2] = {0, 0}; |
| ParsePredWeightTable(*sps, *pps, ph->ref_pic_lists, num_active_ref_idx, |
| &ph->pred_weight_table); |
| } |
| } // ph_inter_slice_allowed_flag |
| |
| if (pps->pps_qp_delta_info_in_ph_flag) { |
| READ_SE_OR_RETURN(&ph->ph_qp_delta); |
| // Equation 86 |
| ph->slice_qp_y = 26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta; |
| IN_RANGE_OR_RETURN(ph->slice_qp_y, -sps->qp_bd_offset, 63); |
| } |
| |
| if (sps->sps_joint_cbcr_enabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_joint_cbcr_sign_flag); |
| } |
| |
| if (sps->sps_sao_enabled_flag && pps->pps_sao_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_sao_luma_enabled_flag); |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&ph->ph_sao_chroma_enabled_flag); |
| } else { |
| ph->ph_sao_chroma_enabled_flag = 0; |
| } |
| } else { |
| ph->ph_sao_luma_enabled_flag = 0; |
| ph->ph_sao_chroma_enabled_flag = 0; |
| } |
| |
| if (pps->pps_dbf_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_deblocking_params_present_flag); |
| if (ph->ph_deblocking_params_present_flag) { |
| if (!pps->pps_deblocking_filter_disabled_flag) { |
| READ_BOOL_OR_RETURN(&ph->ph_deblocking_filter_disabled_flag); |
| } else { |
| if (pps->pps_deblocking_filter_disabled_flag && |
| ph->ph_deblocking_params_present_flag) { |
| ph->ph_deblocking_filter_disabled_flag = 0; |
| } else { |
| ph->ph_deblocking_filter_disabled_flag = |
| pps->pps_deblocking_filter_disabled_flag; |
| } |
| } |
| } |
| if (!ph->ph_deblocking_filter_disabled_flag) { |
| READ_SE_OR_RETURN(&ph->ph_luma_beta_offset_div2); |
| READ_SE_OR_RETURN(&ph->ph_luma_tc_offset_div2); |
| IN_RANGE_OR_RETURN(ph->ph_luma_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(ph->ph_luma_tc_offset_div2, -12, 12); |
| |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| READ_SE_OR_RETURN(&ph->ph_cb_beta_offset_div2); |
| READ_SE_OR_RETURN(&ph->ph_cb_tc_offset_div2); |
| READ_SE_OR_RETURN(&ph->ph_cr_beta_offset_div2); |
| READ_SE_OR_RETURN(&ph->ph_cr_tc_offset_div2); |
| IN_RANGE_OR_RETURN(ph->ph_cb_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(ph->ph_cb_tc_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(ph->ph_cr_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(ph->ph_cr_tc_offset_div2, -12, 12); |
| } else { |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| ph->ph_cb_beta_offset_div2 = pps->pps_cb_beta_offset_div2; |
| ph->ph_cb_tc_offset_div2 = pps->pps_cb_tc_offset_div2; |
| ph->ph_cr_beta_offset_div2 = pps->pps_cr_beta_offset_div2; |
| ph->ph_cr_tc_offset_div2 = pps->pps_cr_tc_offset_div2; |
| } else { |
| ph->ph_cb_beta_offset_div2 = ph->ph_luma_beta_offset_div2; |
| ph->ph_cb_tc_offset_div2 = ph->ph_luma_tc_offset_div2; |
| ph->ph_cr_beta_offset_div2 = ph->ph_luma_beta_offset_div2; |
| ph->ph_cr_tc_offset_div2 = ph->ph_luma_tc_offset_div2; |
| } |
| } |
| } else { |
| ph->ph_luma_beta_offset_div2 = pps->pps_luma_beta_offset_div2; |
| ph->ph_luma_tc_offset_div2 = pps->pps_luma_tc_offset_div2; |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| ph->ph_cb_beta_offset_div2 = pps->pps_cb_beta_offset_div2; |
| ph->ph_cb_tc_offset_div2 = pps->pps_cb_tc_offset_div2; |
| ph->ph_cr_beta_offset_div2 = pps->pps_cr_beta_offset_div2; |
| ph->ph_cr_tc_offset_div2 = pps->pps_cr_tc_offset_div2; |
| } else { |
| ph->ph_cb_beta_offset_div2 = ph->ph_luma_beta_offset_div2; |
| ph->ph_cb_tc_offset_div2 = ph->ph_luma_tc_offset_div2; |
| ph->ph_cr_beta_offset_div2 = ph->ph_luma_beta_offset_div2; |
| ph->ph_cr_tc_offset_div2 = ph->ph_luma_tc_offset_div2; |
| } |
| } |
| } else { |
| ph->ph_deblocking_params_present_flag = 0; |
| } |
| |
| // We stop here and do not parse ph extension when |
| // pps_picture_header_extension_present_flag is 1. |
| |
| return kOk; |
| } |
| |
| // Decoder may pass |picture_header| which is already retrieved |
| // from PH_NUT, so for current slice we're not expecting any picture header |
| // structure parsed from current slice; Or alternatively, decoder may pass |
| // nullptr for |picture_header|, which decoder expects the parser to avoid any |
| // picture header parsing, and return error in case it does exist in current |
| // slice. |
| H266Parser::Result H266Parser::ParseSliceHeader( |
| const H266NALU& nalu, |
| bool first_picture, |
| const H266PictureHeader* picture_header, |
| H266SliceHeader* shdr) { |
| // 7.3.7 Slice header |
| DVLOG(4) << "Parsing slice header"; |
| |
| Result res = kOk; |
| const H266SPS* sps; |
| const H266PPS* pps; |
| H266PictureHeader* ph = nullptr; |
| |
| // Decoder may pass |picture_header| as nullptr here when |
| // picture header structure is in slice header. |
| DCHECK(shdr); |
| // Clear the slice header. |
| memset(reinterpret_cast<void*>(shdr), 0, sizeof(H266SliceHeader)); |
| |
| shdr->nal_unit_type = nalu.nal_unit_type; |
| shdr->nuh_layer_id = nalu.nuh_layer_id; |
| shdr->temporal_id = nalu.nuh_temporal_id_plus1 - 1; |
| shdr->nalu_data = nalu.data; |
| shdr->nalu_size = nalu.size; |
| |
| bool is_irap = shdr->nal_unit_type <= H266NALU::kCRA && |
| shdr->nal_unit_type >= H266NALU::kIDRWithRADL; |
| bool is_gdr = shdr->nal_unit_type == H266NALU::kGDR; |
| |
| // 8.1.1 |
| if (is_irap) { |
| if (first_picture || |
| (shdr->nal_unit_type == H266NALU::kIDRWithRADL || |
| shdr->nal_unit_type == H266NALU::kIDRNoLeadingPicture)) { |
| shdr->no_output_before_recovery_flag = 1; |
| } else if (shdr->handle_cra_as_clvs_start_flag.has_value()) { |
| shdr->cra_as_clvs_start_flag = |
| shdr->handle_cra_as_clvs_start_flag.value(); |
| shdr->no_output_before_recovery_flag = shdr->cra_as_clvs_start_flag; |
| } else { |
| shdr->cra_as_clvs_start_flag = 0; |
| shdr->no_output_before_recovery_flag = 0; |
| } |
| } |
| |
| if (is_gdr) { |
| if (first_picture) { |
| shdr->no_output_before_recovery_flag = 1; |
| } else if (shdr->handle_gdr_as_clvs_start_flag.has_value()) { |
| shdr->gdr_as_clvs_start_flag = |
| shdr->handle_gdr_as_clvs_start_flag.value(); |
| shdr->no_output_before_recovery_flag = shdr->gdr_as_clvs_start_flag; |
| } else { |
| shdr->gdr_as_clvs_start_flag = 0; |
| shdr->no_output_before_recovery_flag = 0; |
| } |
| } |
| |
| READ_BOOL_OR_RETURN(&shdr->sh_picture_header_in_slice_header_flag); |
| if (shdr->sh_picture_header_in_slice_header_flag) { |
| res = ParsePHInSlice(nalu, &shdr->picture_header); |
| if (res != kOk) { |
| DVLOG(1) << "Failed to parse picture header structure in slice header."; |
| return kMissingPictureHeader; |
| } |
| } |
| |
| if (!shdr->sh_picture_header_in_slice_header_flag) { |
| if (!picture_header) { |
| DVLOG(1) << "No picture header available for current slice."; |
| return kMissingPictureHeader; |
| } else { |
| memcpy(&shdr->picture_header, picture_header, sizeof(H266PictureHeader)); |
| } |
| } |
| ph = &shdr->picture_header; |
| |
| pps = GetPPS(ph->ph_pic_parameter_set_id); |
| if (!pps) { |
| DVLOG(1) << "Cannot find the PPS associated with current slice."; |
| return kMissingParameterSet; |
| } |
| |
| sps = GetSPS(pps->pps_seq_parameter_set_id); |
| if (!sps) { |
| DVLOG(1) << "Cannnot find the SPS associated with current slice."; |
| return kMissingParameterSet; |
| } |
| |
| if (shdr->sh_picture_header_in_slice_header_flag) { |
| if (sps->sps_subpic_info_present_flag || !pps->pps_rect_slice_flag || |
| pps->pps_rpl_info_in_ph_flag || pps->pps_dbf_info_in_ph_flag || |
| pps->pps_sao_info_in_ph_flag || pps->pps_alf_info_in_ph_flag || |
| pps->pps_wp_info_in_ph_flag || pps->pps_qp_delta_info_in_ph_flag) { |
| // TODO(crbugs.com/1417910): Return instead of just raise a warning here. |
| // By now VTM does not follow spec for sh_picture_header_in_slice_flag. |
| DVLOG(1) << "PH is required to be in PH_NUT for current stream, while it " |
| "is in slice header instead."; |
| } |
| } |
| int curr_subpic_idx = -1; |
| if (sps->sps_subpic_info_present_flag) { |
| READ_BITS_OR_RETURN(sps->sps_subpic_id_len_minus1 + 1, &shdr->sh_subpic_id); |
| if (sps->sps_subpic_id_mapping_explicitly_signaled_flag) { |
| for (int i = 0; i <= sps->sps_num_subpics_minus1; i++) { |
| int subpic_id_val = pps->pps_subpic_id_mapping_present_flag |
| ? pps->pps_subpic_id[i] |
| : sps->sps_subpic_id[i]; |
| if (subpic_id_val == shdr->sh_subpic_id) { |
| curr_subpic_idx = i; |
| } |
| } |
| } else { |
| curr_subpic_idx = shdr->sh_subpic_id; |
| if (curr_subpic_idx > sps->sps_num_subpics_minus1) { |
| DVLOG(1) << "Invalid subpicture ID in slice header."; |
| return kInvalidStream; |
| } |
| } |
| } else { |
| curr_subpic_idx = 0; |
| } |
| |
| if ((pps->pps_rect_slice_flag && |
| pps->num_slices_in_subpic[curr_subpic_idx] > 1) || |
| (!pps->pps_rect_slice_flag && pps->num_tiles_in_pic > 1)) { |
| if (!pps->pps_rect_slice_flag) { |
| READ_BITS_OR_RETURN(base::bits::Log2Ceiling(pps->num_tiles_in_pic), |
| &shdr->sh_slice_address); |
| IN_RANGE_OR_RETURN(shdr->sh_slice_address, 0, pps->num_tiles_in_pic - 1); |
| } else { |
| READ_BITS_OR_RETURN( |
| base::bits::Log2Ceiling(pps->num_slices_in_subpic[curr_subpic_idx]), |
| &shdr->sh_slice_address); |
| IN_RANGE_OR_RETURN(shdr->sh_slice_address, 0, |
| pps->num_slices_in_subpic[curr_subpic_idx] - 1); |
| } |
| } |
| |
| if (sps->num_extra_sh_bits > 0) { |
| SKIP_BITS_OR_RETURN(sps->num_extra_sh_bits); |
| } |
| |
| if (!pps->pps_rect_slice_flag && |
| (pps->num_tiles_in_pic - shdr->sh_slice_address) > 1) { |
| READ_UE_OR_RETURN(&shdr->sh_num_tiles_in_slice_minus1); |
| IN_RANGE_OR_RETURN(shdr->sh_num_tiles_in_slice_minus1, 0, |
| pps->num_tiles_in_pic - 1); |
| } |
| |
| if (ph->ph_inter_slice_allowed_flag) { |
| READ_UE_OR_RETURN(&shdr->sh_slice_type); |
| } else { |
| shdr->sh_slice_type = 2; |
| } |
| |
| if (!ph->ph_intra_slice_allowed_flag && shdr->sh_slice_type == 2) { |
| DVLOG(1) << "I-slice disallowed when intra-slice is not allowed in picture " |
| "header."; |
| return kInvalidStream; |
| } |
| |
| if (shdr->nal_unit_type >= H266NALU::kIDRWithRADL && |
| shdr->nal_unit_type <= H266NALU::kGDR) { |
| READ_BOOL_OR_RETURN(&shdr->sh_no_output_of_prior_pics_flag); |
| } |
| |
| // Alf info is not in picture header, but instead in slice header directly. |
| if (sps->sps_alf_enabled_flag && !pps->pps_alf_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_alf_enabled_flag); |
| // When sh_alf_enabled_flag is not inferred but read from SH, current slice |
| // is not using alf, so we don't need to infer alf params from PH as they |
| // default to 0. |
| if (shdr->sh_alf_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_num_alf_aps_ids_luma); |
| for (int i = 0; i < shdr->sh_num_alf_aps_ids_luma; i++) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_alf_aps_id_luma[i]); |
| } |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&shdr->sh_alf_cb_enabled_flag); |
| READ_BOOL_OR_RETURN(&shdr->sh_alf_cr_enabled_flag); |
| } else { |
| // When pps->alf_info_in_ph_flag is 0, expecting sh_alf_cb_enabled_flag |
| // and sh_alf_cr_enabled_flag to be 0 as well. So they're not impacting |
| // the parsing logic. |
| shdr->sh_alf_cb_enabled_flag = ph->ph_alf_cb_enabled_flag; |
| shdr->sh_alf_cr_enabled_flag = ph->ph_alf_cr_enabled_flag; |
| } |
| if (shdr->sh_alf_cb_enabled_flag || shdr->sh_alf_cr_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_alf_aps_id_chroma); |
| } else { |
| shdr->sh_alf_aps_id_chroma = ph->ph_alf_aps_id_chroma; |
| } |
| if (sps->sps_ccalf_enabled_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_alf_cc_cb_enabled_flag); |
| if (shdr->sh_alf_cc_cb_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_alf_cc_cb_aps_id); |
| } else { |
| shdr->sh_alf_cc_cr_enabled_flag = ph->ph_alf_cc_cb_enabled_flag; |
| } |
| READ_BOOL_OR_RETURN(&shdr->sh_alf_cc_cr_enabled_flag); |
| if (shdr->sh_alf_cc_cr_enabled_flag) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_alf_cc_cr_aps_id); |
| } else { |
| shdr->sh_alf_cc_cr_aps_id = ph->ph_alf_cc_cr_aps_id; |
| } |
| } else { |
| shdr->sh_alf_cc_cb_enabled_flag = ph->ph_alf_cc_cb_enabled_flag; |
| shdr->sh_alf_cc_cb_aps_id = ph->ph_alf_cc_cb_aps_id; |
| shdr->sh_alf_cc_cr_aps_id = ph->ph_alf_cc_cr_aps_id; |
| } |
| } |
| } else { |
| shdr->sh_alf_enabled_flag = ph->ph_alf_enabled_flag; |
| if (shdr->sh_alf_enabled_flag) { |
| shdr->sh_num_alf_aps_ids_luma = ph->ph_num_alf_aps_ids_luma; |
| for (int i = 0; i < shdr->sh_num_alf_aps_ids_luma; i++) { |
| shdr->sh_alf_aps_id_luma[i] = ph->ph_alf_aps_id_luma[i]; |
| } |
| shdr->sh_alf_aps_id_chroma = ph->ph_alf_aps_id_chroma; |
| shdr->sh_alf_cb_enabled_flag = ph->ph_alf_cb_enabled_flag; |
| shdr->sh_alf_cr_enabled_flag = ph->ph_alf_cr_enabled_flag; |
| shdr->sh_alf_cc_cb_enabled_flag = ph->ph_alf_cc_cb_enabled_flag; |
| shdr->sh_alf_cc_cr_enabled_flag = ph->ph_alf_cc_cr_enabled_flag; |
| shdr->sh_alf_cc_cb_aps_id = ph->ph_alf_cc_cb_aps_id; |
| shdr->sh_alf_cc_cr_aps_id = ph->ph_alf_cc_cr_aps_id; |
| } |
| } |
| |
| if (ph->ph_lmcs_enabled_flag && |
| !shdr->sh_picture_header_in_slice_header_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_lmcs_used_flag); |
| } else { |
| shdr->sh_lmcs_used_flag = shdr->sh_picture_header_in_slice_header_flag |
| ? ph->ph_lmcs_enabled_flag |
| : 0; |
| } |
| |
| if (ph->ph_explicit_scaling_list_enabled_flag && |
| !shdr->sh_picture_header_in_slice_header_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_explicit_scaling_list_used_flag); |
| } else { |
| shdr->sh_explicit_scaling_list_used_flag = |
| shdr->sh_picture_header_in_slice_header_flag |
| ? ph->ph_explicit_scaling_list_enabled_flag |
| : 0; |
| } |
| |
| const H266RefPicLists* ref_pic_lists = nullptr; |
| if (!pps->pps_rpl_info_in_ph_flag && |
| ((shdr->nal_unit_type != H266NALU::kIDRWithRADL && |
| shdr->nal_unit_type != H266NALU::kIDRNoLeadingPicture) || |
| sps->sps_idr_rpl_present_flag)) { |
| ParseRefPicLists(*sps, *pps, &shdr->ref_pic_lists); |
| ref_pic_lists = &shdr->ref_pic_lists; |
| } else { |
| ref_pic_lists = &ph->ref_pic_lists; |
| } |
| |
| const H266RefPicListStruct* ref_pic_list_structs[2] = {nullptr, nullptr}; |
| for (int i = 0; i < 2; i++) { |
| if (ref_pic_lists->rpl_sps_flag[i]) { |
| ref_pic_list_structs[i] = |
| &sps->ref_pic_list_struct[0][ref_pic_lists->rpl_idx[i]]; |
| } else { |
| ref_pic_list_structs[i] = &ref_pic_lists->rpl_ref_lists[i]; |
| } |
| } |
| |
| // Caution!!! |sh_num_ref_idx_active_override| might be inferred |
| // instead of read from bitstream, and used for subsequent syntax |
| // parsing after it. |
| shdr->sh_num_ref_idx_active_override_flag = 1; |
| if ((shdr->sh_slice_type != H266SliceHeader::kSliceTypeI && |
| ref_pic_list_structs[0]->num_ref_entries > 1) || |
| (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB && |
| ref_pic_list_structs[1]->num_ref_entries > 1)) { |
| READ_BOOL_OR_RETURN(&shdr->sh_num_ref_idx_active_override_flag); |
| if (shdr->sh_num_ref_idx_active_override_flag) { |
| for (int i = 0; |
| i < (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB ? 2 : 1); |
| i++) { |
| if (ref_pic_list_structs[i]->num_ref_entries > 1) { |
| READ_UE_OR_RETURN(&shdr->sh_num_ref_idx_active_minus1[i]); |
| IN_RANGE_OR_RETURN(shdr->sh_num_ref_idx_active_minus1[i], 0, 14); |
| } else { |
| shdr->sh_num_ref_idx_active_minus1[i] = 0; |
| } |
| } |
| } |
| } |
| |
| // Equation 139 |
| for (int i = 0; i < 2; i++) { |
| if (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB || |
| (shdr->sh_slice_type == H266SliceHeader::kSliceTypeP && i == 0)) { |
| if (shdr->sh_num_ref_idx_active_override_flag) { |
| shdr->num_ref_idx_active[i] = shdr->sh_num_ref_idx_active_minus1[i] + 1; |
| } else { |
| if (ref_pic_list_structs[i]->num_ref_entries >= |
| pps->pps_num_ref_idx_default_active_minus1[i] + 1) { |
| shdr->num_ref_idx_active[i] = |
| pps->pps_num_ref_idx_default_active_minus1[i] + 1; |
| } else { |
| shdr->num_ref_idx_active[i] = |
| ref_pic_list_structs[i]->num_ref_entries; |
| } |
| } |
| } else { |
| shdr->num_ref_idx_active[i] = 0; |
| } |
| } |
| |
| if (shdr->sh_slice_type != H266SliceHeader::kSliceTypeI) { |
| if (pps->pps_cabac_init_present_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_cabac_init_flag); |
| } else { |
| shdr->sh_cabac_init_flag = 0; |
| } |
| |
| if (ph->ph_temporal_mvp_enabled_flag && !pps->pps_rpl_info_in_ph_flag) { |
| if (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB) { |
| READ_BOOL_OR_RETURN(&shdr->sh_collocated_from_l0_flag); |
| } else { |
| shdr->sh_collocated_from_l0_flag = 1; |
| } |
| if ((shdr->sh_collocated_from_l0_flag && |
| shdr->num_ref_idx_active[0] > 1) || |
| (!shdr->sh_collocated_from_l0_flag && |
| shdr->num_ref_idx_active[1] > 1)) { |
| READ_UE_OR_RETURN(&shdr->sh_collocated_ref_idx); |
| if (shdr->sh_slice_type == H266SliceHeader::kSliceTypeP || |
| (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB && |
| shdr->sh_collocated_from_l0_flag)) { |
| IN_RANGE_OR_RETURN(shdr->sh_collocated_ref_idx, 0, |
| shdr->num_ref_idx_active[0] - 1); |
| } else if (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB && |
| !shdr->sh_collocated_from_l0_flag) { |
| IN_RANGE_OR_RETURN(shdr->sh_collocated_ref_idx, 0, |
| shdr->num_ref_idx_active[1] - 1); |
| } |
| } |
| } else { |
| if (ph->ph_temporal_mvp_enabled_flag) { |
| if (shdr->sh_slice_type == H266SliceHeader::kSliceTypeB) { |
| shdr->sh_collocated_from_l0_flag = ph->ph_collocated_from_l0_flag; |
| } else { |
| shdr->sh_collocated_from_l0_flag = 1; |
| } |
| } |
| } |
| |
| if (!pps->pps_wp_info_in_ph_flag && |
| ((pps->pps_weighted_pred_flag && |
| shdr->sh_slice_type == H266SliceHeader::kSliceTypeP) || |
| (pps->pps_weighted_bipred_flag && |
| shdr->sh_slice_type == H266SliceHeader::kSliceTypeB))) { |
| ParsePredWeightTable(*sps, *pps, *ref_pic_lists, |
| &shdr->num_ref_idx_active[0], |
| &shdr->sh_pred_weight_table); |
| } |
| } |
| |
| if (!pps->pps_qp_delta_info_in_ph_flag) { |
| READ_SE_OR_RETURN(&shdr->sh_qp_delta); |
| // Equation 140 |
| shdr->slice_qp_y = 26 + pps->pps_init_qp_minus26 + shdr->sh_qp_delta; |
| IN_RANGE_OR_RETURN(shdr->slice_qp_y, -sps->qp_bd_offset, 63); |
| } |
| if (pps->pps_slice_chroma_qp_offsets_present_flag) { |
| READ_SE_OR_RETURN(&shdr->sh_cb_qp_offset); |
| READ_SE_OR_RETURN(&shdr->sh_cr_qp_offset); |
| if (sps->sps_joint_cbcr_enabled_flag) { |
| READ_SE_OR_RETURN(&shdr->sh_joint_cbcr_qp_offset); |
| } |
| IN_RANGE_OR_RETURN(shdr->sh_cb_qp_offset, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_cr_qp_offset, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_joint_cbcr_qp_offset, -12, 12); |
| } |
| IN_RANGE_OR_RETURN(pps->pps_cb_qp_offset + shdr->sh_cb_qp_offset, -12, 12); |
| IN_RANGE_OR_RETURN(pps->pps_cr_qp_offset + shdr->sh_cr_qp_offset, -12, 12); |
| IN_RANGE_OR_RETURN( |
| pps->pps_joint_cbcr_qp_offset_value + shdr->sh_joint_cbcr_qp_offset, -12, |
| 12); |
| if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_cu_chroma_qp_offset_enabled_flag); |
| } |
| |
| if (sps->sps_sao_enabled_flag && !pps->pps_sao_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_sao_luma_used_flag); |
| if (sps->sps_chroma_format_idc != 0) { |
| READ_BOOL_OR_RETURN(&shdr->sh_sao_chroma_used_flag); |
| } else { |
| shdr->sh_sao_chroma_used_flag = ph->ph_sao_chroma_enabled_flag; |
| } |
| } else { |
| shdr->sh_sao_luma_used_flag = ph->ph_sao_luma_enabled_flag; |
| shdr->sh_sao_chroma_used_flag = ph->ph_sao_chroma_enabled_flag; |
| } |
| |
| if (pps->pps_deblocking_filter_override_enabled_flag && |
| !pps->pps_dbf_info_in_ph_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_deblocking_params_present_flag); |
| } |
| |
| // Load default chroma/luma beta/tc offsets from PH. |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| shdr->sh_luma_beta_offset_div2 = ph->ph_luma_beta_offset_div2; |
| shdr->sh_luma_tc_offset_div2 = ph->ph_luma_tc_offset_div2; |
| shdr->sh_cb_beta_offset_div2 = ph->ph_cb_beta_offset_div2; |
| shdr->sh_cb_tc_offset_div2 = ph->ph_cb_tc_offset_div2; |
| shdr->sh_cr_beta_offset_div2 = ph->ph_cr_beta_offset_div2; |
| shdr->sh_cr_tc_offset_div2 = ph->ph_cr_tc_offset_div2; |
| } |
| if (shdr->sh_deblocking_params_present_flag) { |
| if (!pps->pps_deblocking_filter_disabled_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_deblocking_filter_disabled_flag); |
| } |
| if (!shdr->sh_deblocking_filter_disabled_flag) { |
| READ_SE_OR_RETURN(&shdr->sh_luma_beta_offset_div2); |
| READ_SE_OR_RETURN(&shdr->sh_luma_tc_offset_div2); |
| IN_RANGE_OR_RETURN(shdr->sh_luma_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_luma_tc_offset_div2, -12, 12); |
| if (pps->pps_chroma_tool_offsets_present_flag) { |
| READ_SE_OR_RETURN(&shdr->sh_cb_beta_offset_div2); |
| READ_SE_OR_RETURN(&shdr->sh_cb_tc_offset_div2); |
| READ_SE_OR_RETURN(&shdr->sh_cr_beta_offset_div2); |
| READ_SE_OR_RETURN(&shdr->sh_cr_tc_offset_div2); |
| IN_RANGE_OR_RETURN(shdr->sh_cb_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_cb_tc_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_cr_beta_offset_div2, -12, 12); |
| IN_RANGE_OR_RETURN(shdr->sh_cr_tc_offset_div2, -12, 12); |
| } else { |
| shdr->sh_cb_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cb_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| shdr->sh_cr_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cr_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| } |
| } else { |
| if (!pps->pps_chroma_tool_offsets_present_flag) { |
| shdr->sh_cb_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cb_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| shdr->sh_cr_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cr_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| } |
| } |
| } else { |
| if (!pps->pps_deblocking_filter_disabled_flag || |
| !shdr->sh_deblocking_params_present_flag) { |
| shdr->sh_deblocking_filter_disabled_flag = |
| ph->ph_deblocking_filter_disabled_flag; |
| } |
| if (!pps->pps_chroma_tool_offsets_present_flag) { |
| shdr->sh_cb_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cb_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| shdr->sh_cr_beta_offset_div2 = shdr->sh_luma_beta_offset_div2; |
| shdr->sh_cr_tc_offset_div2 = shdr->sh_luma_tc_offset_div2; |
| } |
| } |
| |
| if (sps->sps_dep_quant_enabled_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_dep_quant_used_flag); |
| } |
| if (sps->sps_sign_data_hiding_enabled_flag && !shdr->sh_dep_quant_used_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_sign_data_hiding_used_flag); |
| } |
| if (sps->sps_transform_skip_enabled_flag && !shdr->sh_dep_quant_used_flag && |
| !shdr->sh_sign_data_hiding_used_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_ts_residual_coding_disabled_flag); |
| } |
| if (!shdr->sh_ts_residual_coding_disabled_flag && |
| sps->sps_range_extension.sps_ts_residual_coding_rice_present_in_sh_flag) { |
| READ_BITS_OR_RETURN(3, &shdr->sh_ts_residual_coding_rice_idx_minus1); |
| } |
| if (sps->sps_range_extension.sps_reverse_last_sig_coeff_enabled_flag) { |
| READ_BOOL_OR_RETURN(&shdr->sh_reverse_last_sig_coeff_flag); |
| } |
| if (pps->pps_slice_header_extension_present_flag) { |
| READ_UE_OR_RETURN(&shdr->sh_slice_header_extension_length); |
| IN_RANGE_OR_RETURN(shdr->sh_slice_header_extension_length, 0, 256); |
| for (int i = 0; i < shdr->sh_slice_header_extension_length; i++) { |
| SKIP_BITS_OR_RETURN(8); |
| } |
| } |
| |
| // Equation 113 & 141 |
| int num_entry_points = 0; |
| if (sps->sps_entry_point_offsets_present_flag) { |
| if (pps->pps_rect_slice_flag) { |
| int width_in_tiles = 0, slice_idx = shdr->sh_slice_address; |
| for (int i = 0; i < curr_subpic_idx; i++) { |
| slice_idx += pps->num_slices_in_subpic[i]; |
| } |
| width_in_tiles = pps->pps_slice_width_in_tiles_minus1[slice_idx] + 1; |
| int height = sps->sps_entropy_coding_sync_enabled_flag |
| ? pps->slice_height_in_ctus[slice_idx] |
| : pps->pps_slice_height_in_tiles_minus1[slice_idx] + 1; |
| num_entry_points = width_in_tiles * height; |
| } else { |
| int tile_idx = 0, tile_y = 0, height = 0; |
| for (tile_idx = shdr->sh_slice_address; |
| tile_idx <= |
| shdr->sh_slice_address + shdr->sh_num_tiles_in_slice_minus1; |
| tile_idx++) { |
| tile_y = tile_idx / pps->num_tile_rows; |
| height = pps->pps_tile_row_height_minus1[tile_y] + 1; |
| num_entry_points += |
| sps->sps_entropy_coding_sync_enabled_flag ? height : 1; |
| } |
| } |
| |
| num_entry_points--; |
| if (num_entry_points > 0) { |
| shdr->sh_entry_point_offset_minus1.resize(num_entry_points); |
| READ_UE_OR_RETURN(&shdr->sh_entry_offset_len_minus1); |
| IN_RANGE_OR_RETURN(shdr->sh_entry_offset_len_minus1, 0, 31); |
| for (int i = 0; i < num_entry_points; i++) { |
| if (shdr->sh_entry_offset_len_minus1 == 31) { |
| int entry_offset_high16 = 0, entry_offset_low16 = 0; |
| READ_BITS_OR_RETURN(16, &entry_offset_high16); |
| READ_BITS_OR_RETURN(16, &entry_offset_low16); |
| shdr->sh_entry_point_offset_minus1[i] = |
| (entry_offset_high16 << 16) + entry_offset_low16; |
| } else { |
| READ_BITS_OR_RETURN(shdr->sh_entry_offset_len_minus1 + 1, |
| &shdr->sh_entry_point_offset_minus1[i]); |
| } |
| } |
| } |
| } |
| |
| BYTE_ALIGNMENT(); |
| shdr->header_emulation_prevention_bytes = |
| br_.NumEmulationPreventionBytesRead(); |
| shdr->header_size = shdr->nalu_size - |
| shdr->header_emulation_prevention_bytes - |
| br_.NumBitsLeft() / 8; |
| return kOk; |
| } |
| |
| const H266VPS* H266Parser::GetVPS(int vps_id) const { |
| auto it = active_vps_.find(vps_id); |
| if (it == active_vps_.end()) { |
| DVLOG(1) << "Requested a nonexistent VPS id " << vps_id; |
| return nullptr; |
| } |
| return it->second.get(); |
| } |
| |
| const H266SPS* H266Parser::GetSPS(int sps_id) const { |
| auto it = active_sps_.find(sps_id); |
| if (it == active_sps_.end()) { |
| DVLOG(1) << "Requested a nonexistent SPS id " << sps_id; |
| return nullptr; |
| } |
| |
| return it->second.get(); |
| } |
| |
| const H266PPS* H266Parser::GetPPS(int pps_id) const { |
| auto it = active_pps_.find(pps_id); |
| if (it == active_pps_.end()) { |
| DVLOG(1) << "Requested a nonexistent PPS id " << pps_id; |
| return nullptr; |
| } |
| |
| return it->second.get(); |
| } |
| |
| const H266APS* H266Parser::GetAPS(const H266APS::ParamType& type, |
| int aps_id) const { |
| switch (type) { |
| case H266APS::ParamType::kAlf: { |
| auto it = active_alf_aps_.find(aps_id); |
| if (it == active_alf_aps_.end()) { |
| DVLOG(1) << "Requested a nonexistent ALF APS id " << aps_id; |
| return nullptr; |
| } |
| return it->second.get(); |
| } |
| case H266APS::ParamType::kLmcs: { |
| auto it = active_lmcs_aps_.find(aps_id); |
| if (it == active_lmcs_aps_.end()) { |
| DVLOG(1) << "Requested a nonexistent LMCS APS id " << aps_id; |
| return nullptr; |
| } |
| return it->second.get(); |
| } |
| case H266APS::ParamType::kScalingList: { |
| auto it = active_scaling_list_aps_.find(aps_id); |
| if (it == active_scaling_list_aps_.end()) { |
| DVLOG(1) << "Requested a nonexistent ScalingData APS id " << aps_id; |
| return nullptr; |
| } |
| return it->second.get(); |
| } |
| } |
| } |
| |
| } // namespace media |