blob: 30c6284d7d599ff702d2d271e2ac4c0feb454ef1 [file] [log] [blame]
// 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);
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));
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);
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
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]);
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++) {
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++) {
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++) {
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