blob: d2f98460bda9b15a085e220757f0648c43f6dc87 [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 {
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));
}
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;
}
}
#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]);
}
}
}
}
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;
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 {
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);
READ_BOOL_OR_RETURN(&pps->pps_weighted_bipred_flag);
if (pps->pps_weighted_pred_flag) {
TRUE_OR_RETURN(pps->pps_weighted_bipred_flag == 0);
}
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;
}
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();
}
} // namespace media