VVC parser implementation: Picture header parser.
This enables VVC picture header parsing. Picture header structure in VVC may exist in a PH_NUT if it is shared by multiple slices, or in slice header when the PU contains only 1 slice. Bug: 1417910 Change-Id: Iea13def3b4026a519aa85e47a5bc7a9ccc07e17f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4514157 Reviewed-by: Dan Sanders <sandersd@chromium.org> Commit-Queue: Jianlin Qiu <jianlin.qiu@intel.com> Cr-Commit-Position: refs/heads/main@{#1144529}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
25551950c2
commit
0c24d52f72
@ -196,6 +196,24 @@ EncoderApp --CTUSize=128 -c sample_scaling_list.cfg -f 8 \
|
||||
Please be noted sample_scaling_list.cfg is the file with the same name from VTM
|
||||
sample configure.
|
||||
|
||||
#### bbb_rpl_in_ph_nut.vvc
|
||||
VVC stream generated with VTM that is used to verify parsing of complex picture
|
||||
header structure in a separate PH NALU.
|
||||
Created with VTM and ffmpeg:
|
||||
```
|
||||
ffmpeg -i bbb-320x240-2video-2audio.mp4 bbb.y4m
|
||||
ffmpeg -i bbb.y4m -vf scale=1920x1080 bbb_1920x1080.yuv
|
||||
EncoderApp -f 5 --EnablePicPartitioning=1 --CTUSize=128 \
|
||||
--TileColumnWidthArray=5,5,5 --TileRowHeightArray=3,3 --RasterScanSlices=0 \
|
||||
--RectSliceFixedWidth=0 --RectSliceFixedHeight=0 \
|
||||
--RectSlicePositions=0,19,30,34,45,64,75,79,90,109,120,124,5,24,35,39,50,69,\
|
||||
80,84,95,114,125,129,10,29,40,44,55,74,85,89,100,119,130,134 \
|
||||
--SliceLevelRpl=0 --SliceLevelDblk=0 --SliceLevelSao=0 --SliceLevelAlf=0 \
|
||||
--SliceLevelDeltaQp=0 --ALF=1 --JointCbCr=1 --SAO=1 --WeightedPredP=1 \
|
||||
--WeightedPredB=1 --WeightedPredMethod=4 --CCALF=1 \
|
||||
--VirtualBoundariesPresentInSPSFlag=0 --SliceLevelWeightedPrediction=0
|
||||
```
|
||||
|
||||
### AV1
|
||||
|
||||
Unless noted otherwise, the codec string is `av01.0.04M.08` for 8-bit files,
|
||||
|
BIN
media/test/data/bbb_rpl_in_ph_nut.vvc
Normal file
BIN
media/test/data/bbb_rpl_in_ph_nut.vvc
Normal file
Binary file not shown.
@ -41,6 +41,7 @@ data/bbb_360p.vvc
|
||||
data/bbb_9tiles.vvc
|
||||
data/bbb_9tiles_18slices.vvc
|
||||
data/bbb_chroma_qp_offset_lists.vvc
|
||||
data/bbb_rpl_in_ph_nut.vvc
|
||||
data/bbb_scaling_lists.vvc
|
||||
data/bear-1280x720-a_frag-cenc-key_rotation.mp4
|
||||
data/bear-1280x720-a_frag-cenc.mp4
|
||||
|
@ -38,6 +38,7 @@
|
||||
//media/test/data/bbb_9tiles.vvc
|
||||
//media/test/data/bbb_9tiles_18slices.vvc
|
||||
//media/test/data/bbb_chroma_qp_offset_lists.vvc
|
||||
//media/test/data/bbb_rpl_in_ph_nut.vvc
|
||||
//media/test/data/bbb_scaling_lists.vvc
|
||||
//media/test/data/bear-1280x720-a_frag-cenc-key_rotation.mp4
|
||||
//media/test/data/bear-1280x720-a_frag-cenc.mp4
|
||||
|
@ -108,6 +108,14 @@ H266LmcsData::H266LmcsData() {
|
||||
memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
|
||||
}
|
||||
|
||||
H266PredWeightTable::H266PredWeightTable() {
|
||||
memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
|
||||
}
|
||||
|
||||
H266PictureHeader::H266PictureHeader() {
|
||||
memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
|
||||
}
|
||||
|
||||
H266Parser::H266Parser() = default;
|
||||
|
||||
H266Parser::~H266Parser() = default;
|
||||
@ -2350,9 +2358,12 @@ H266Parser::Result H266Parser::ParsePPS(const H266NALU& nalu, int* pps_id) {
|
||||
}
|
||||
READ_BOOL_OR_RETURN(&pps->pps_rpl1_idx_present_flag);
|
||||
READ_BOOL_OR_RETURN(&pps->pps_weighted_pred_flag);
|
||||
if (!sps->sps_weighted_pred_flag) {
|
||||
TRUE_OR_RETURN(!pps->pps_weighted_pred_flag);
|
||||
}
|
||||
READ_BOOL_OR_RETURN(&pps->pps_weighted_bipred_flag);
|
||||
if (pps->pps_weighted_pred_flag) {
|
||||
TRUE_OR_RETURN(pps->pps_weighted_bipred_flag == 0);
|
||||
if (!sps->sps_weighted_bipred_flag) {
|
||||
TRUE_OR_RETURN(!pps->pps_weighted_bipred_flag);
|
||||
}
|
||||
READ_BOOL_OR_RETURN(&pps->pps_ref_wraparound_enabled_flag);
|
||||
if (sps->sps_ref_pic_resampling_enabled_flag == 0 ||
|
||||
@ -2887,6 +2898,752 @@ H266Parser::Result H266Parser::ParseAPS(const H266NALU& nalu,
|
||||
return kOk;
|
||||
}
|
||||
|
||||
// 7.3.9 & 7.4.10
|
||||
H266Parser::Result H266Parser::ParseRefPicLists(
|
||||
const H266SPS& sps,
|
||||
const H266PPS& pps,
|
||||
H266RefPicLists* ref_pic_lists) {
|
||||
DCHECK(ref_pic_lists);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (sps.sps_num_ref_pic_lists[i] > 0 &&
|
||||
(i == 0 || (i == 1 && pps.pps_rpl1_idx_present_flag))) {
|
||||
READ_BOOL_OR_RETURN(&ref_pic_lists->rpl_sps_flag[i]);
|
||||
} else {
|
||||
if (sps.sps_num_ref_pic_lists[i] == 0) {
|
||||
ref_pic_lists->rpl_sps_flag[i] = 0;
|
||||
} else if (sps.sps_num_ref_pic_lists[i] > 0) {
|
||||
if (pps.pps_rpl1_idx_present_flag == 0 && i == 1) {
|
||||
ref_pic_lists->rpl_sps_flag[i] = ref_pic_lists->rpl_sps_flag[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ref_pic_lists->rpl_sps_flag[i]) {
|
||||
if (sps.sps_num_ref_pic_lists[i] > 1 &&
|
||||
(i == 0 || (i == 1 && pps.pps_rpl1_idx_present_flag))) {
|
||||
READ_BITS_OR_RETURN(base::bits::Log2Ceiling(static_cast<uint32_t>(
|
||||
sps.sps_num_ref_pic_lists[i])),
|
||||
&ref_pic_lists->rpl_idx[i]);
|
||||
IN_RANGE_OR_RETURN(ref_pic_lists->rpl_idx[i], 0,
|
||||
sps.sps_num_ref_pic_lists[i] - 1);
|
||||
} else {
|
||||
if (sps.sps_num_ref_pic_lists[i] == 1) {
|
||||
ref_pic_lists->rpl_idx[i] = 0;
|
||||
}
|
||||
if (i == 1 && pps.pps_rpl1_idx_present_flag == 0 &&
|
||||
sps.sps_num_ref_pic_lists[1] > 1) {
|
||||
ref_pic_lists->rpl_idx[i] = ref_pic_lists->rpl_idx[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ParseRefPicListStruct(i, sps.sps_num_ref_pic_lists[i], sps,
|
||||
&ref_pic_lists->rpl_ref_lists[i]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < ref_pic_lists->rpl_ref_lists[i].num_ltrp_entries; j++) {
|
||||
if (ref_pic_lists->rpl_ref_lists[i].ltrp_in_header_flag) {
|
||||
READ_BITS_OR_RETURN(sps.sps_log2_max_pic_order_cnt_lsb_minus4 + 4,
|
||||
&ref_pic_lists->poc_lsb_lt[i][j]);
|
||||
// Currently we do not use PocLsbLt[i][j], so equation 147 is not
|
||||
// handled.
|
||||
}
|
||||
READ_BOOL_OR_RETURN(
|
||||
&ref_pic_lists->delta_poc_msb_cycle_present_flag[i][j]);
|
||||
if (ref_pic_lists->delta_poc_msb_cycle_present_flag[i][j]) {
|
||||
READ_UE_OR_RETURN(&ref_pic_lists->delta_poc_msb_cycle_lt[i][j]);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ref_pic_lists->delta_poc_msb_cycle_lt[i][j], 0,
|
||||
std::pow(2, 32 - sps.sps_log2_max_pic_order_cnt_lsb_minus4 - 4));
|
||||
} else {
|
||||
ref_pic_lists->delta_poc_msb_cycle_lt[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Equation 146
|
||||
ref_pic_lists->rpls_idx[i] = ref_pic_lists->rpl_sps_flag[i]
|
||||
? ref_pic_lists->rpl_idx[i]
|
||||
: sps.sps_num_ref_pic_lists[i];
|
||||
}
|
||||
|
||||
return kOk;
|
||||
}
|
||||
|
||||
H266Parser::Result H266Parser::ParsePredWeightTable(
|
||||
const H266SPS& sps,
|
||||
const H266PPS& pps,
|
||||
const H266RefPicLists& ref_pic_lists,
|
||||
int num_ref_idx_active[2],
|
||||
H266PredWeightTable* pred_weight_table) {
|
||||
// 7.3.8
|
||||
READ_UE_OR_RETURN(&pred_weight_table->luma_log2_weight_denom);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->luma_log2_weight_denom, 0, 7);
|
||||
if (sps.sps_chroma_format_idc != 0) {
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_log2_weight_denom);
|
||||
} else {
|
||||
pred_weight_table->delta_chroma_log2_weight_denom = 0;
|
||||
}
|
||||
pred_weight_table->chroma_log2_weight_denom =
|
||||
pred_weight_table->luma_log2_weight_denom +
|
||||
pred_weight_table->delta_chroma_log2_weight_denom;
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->chroma_log2_weight_denom, 0, 7);
|
||||
|
||||
if (pps.pps_wp_info_in_ph_flag) {
|
||||
READ_UE_OR_RETURN(&pred_weight_table->num_l0_weights);
|
||||
IN_RANGE_OR_RETURN(
|
||||
pred_weight_table->num_l0_weights, 0,
|
||||
std::min(15, ref_pic_lists.rpl_ref_lists[0].num_ref_entries));
|
||||
pred_weight_table->num_weights_l0 = pred_weight_table->num_l0_weights;
|
||||
} else {
|
||||
pred_weight_table->num_weights_l0 = num_ref_idx_active[0];
|
||||
}
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l0; i++) {
|
||||
READ_BOOL_OR_RETURN(&pred_weight_table->luma_weight_l0_flag[i]);
|
||||
}
|
||||
if (sps.sps_chroma_format_idc != 0) {
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l0; i++) {
|
||||
READ_BOOL_OR_RETURN(&pred_weight_table->chroma_weight_l0_flag[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l0; i++) {
|
||||
if (pred_weight_table->luma_weight_l0_flag[i]) {
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l0[i]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l0[i], -128, 127);
|
||||
READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l0[i]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l0[i], -128, 127);
|
||||
} else {
|
||||
pred_weight_table->delta_luma_weight_l0[i] = 0;
|
||||
pred_weight_table->luma_offset_l0[i] = 0;
|
||||
}
|
||||
if (pred_weight_table->chroma_weight_l0_flag[i]) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l0[i][j]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l0[i][j],
|
||||
-128, 127);
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l0[i][j]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l0[i][j],
|
||||
-4 * 128, 4 * 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pps.pps_weighted_bipred_flag && pps.pps_wp_info_in_ph_flag &&
|
||||
ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) {
|
||||
READ_UE_OR_RETURN(&pred_weight_table->num_l1_weights);
|
||||
IN_RANGE_OR_RETURN(
|
||||
pred_weight_table->num_l1_weights, 0,
|
||||
std::min(15, ref_pic_lists.rpl_ref_lists[1].num_ref_entries));
|
||||
}
|
||||
// Equation 145
|
||||
if (!pps.pps_weighted_bipred_flag ||
|
||||
(pps.pps_wp_info_in_ph_flag &&
|
||||
ref_pic_lists.rpl_ref_lists[1].num_ref_entries == 0)) {
|
||||
pred_weight_table->num_weights_l1 = 0;
|
||||
} else if (pps.pps_wp_info_in_ph_flag) {
|
||||
pred_weight_table->num_weights_l1 = pred_weight_table->num_l1_weights;
|
||||
} else {
|
||||
pred_weight_table->num_weights_l1 = num_ref_idx_active[1];
|
||||
}
|
||||
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l1; i++) {
|
||||
READ_BOOL_OR_RETURN(&pred_weight_table->luma_weight_l0_flag[i]);
|
||||
}
|
||||
if (sps.sps_chroma_format_idc != 0) {
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l1; i++) {
|
||||
READ_BOOL_OR_RETURN(&pred_weight_table->chroma_weight_l1_flag[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < pred_weight_table->num_weights_l1; i++) {
|
||||
if (pred_weight_table->luma_weight_l1_flag[i]) {
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_luma_weight_l1[i]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_luma_weight_l1[i], -128, 127);
|
||||
READ_SE_OR_RETURN(&pred_weight_table->luma_offset_l1[i]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->luma_offset_l1[i], -128, 127);
|
||||
} else {
|
||||
pred_weight_table->delta_luma_weight_l1[i] = 0;
|
||||
pred_weight_table->luma_offset_l1[i] = 0;
|
||||
}
|
||||
if (pred_weight_table->chroma_weight_l1_flag[i]) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_weight_l1[i][j]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_weight_l1[i][j],
|
||||
-128, 127);
|
||||
READ_SE_OR_RETURN(&pred_weight_table->delta_chroma_offset_l1[i][j]);
|
||||
IN_RANGE_OR_RETURN(pred_weight_table->delta_chroma_offset_l1[i][j],
|
||||
-4 * 128, 4 * 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kOk;
|
||||
}
|
||||
|
||||
H266Parser::Result H266Parser::ParsePHNut(const H266NALU& nalu,
|
||||
H266PictureHeader* ph) {
|
||||
DCHECK(ph);
|
||||
memset(reinterpret_cast<void*>(ph), 0, sizeof(H266PictureHeader));
|
||||
|
||||
if (nalu.nal_unit_type != H266NALU::kPH) {
|
||||
DVLOG(1) << "Not a picture header NALU.";
|
||||
return kIgnored;
|
||||
}
|
||||
|
||||
ph->nal_unit_type = nalu.nal_unit_type;
|
||||
return ParsePictureHeaderStructure(nalu, ph);
|
||||
}
|
||||
|
||||
H266Parser::Result H266Parser::ParsePHInSlice(const H266NALU& nalu,
|
||||
H266PictureHeader* ph) {
|
||||
DCHECK(ph);
|
||||
memset(reinterpret_cast<void*>(ph), 0, sizeof(H266PictureHeader));
|
||||
|
||||
if (!(nalu.nal_unit_type >= H266NALU::kTrail &&
|
||||
nalu.nal_unit_type <= H266NALU::kReservedIRAP11)) {
|
||||
DVLOG(1) << "Embedded picture header structure must be in slice.";
|
||||
return kInvalidStream;
|
||||
}
|
||||
|
||||
// The nalu type of slice that current picture header is embedded into.
|
||||
ph->nal_unit_type = nalu.nal_unit_type;
|
||||
return ParsePictureHeaderStructure(nalu, ph);
|
||||
}
|
||||
|
||||
// 7.3.2.8 Picture header structure
|
||||
// May be in separate PH_NUT or included in slice header. They convey
|
||||
// information for a particular picture including but not limited to:
|
||||
// 1. Indication of IRAP/GDR, and if inter-intra slices are allowed.
|
||||
// 2. LSB and MSB of POC, coding partitioning.
|
||||
// 3. Picture level collocated info and tool switches.
|
||||
// 4. RPLs, deblocking/QP info, etc.
|
||||
// Be noted for each picture there needs to be exactly one PH associated
|
||||
// with it.
|
||||
H266Parser::Result H266Parser::ParsePictureHeaderStructure(
|
||||
const H266NALU& nalu,
|
||||
H266PictureHeader* ph) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_gdr_or_irap_pic_flag);
|
||||
READ_BOOL_OR_RETURN(&ph->ph_non_ref_pic_flag);
|
||||
if (ph->ph_gdr_or_irap_pic_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_gdr_pic_flag);
|
||||
} else {
|
||||
ph->ph_gdr_pic_flag = 0;
|
||||
}
|
||||
READ_BOOL_OR_RETURN(&ph->ph_inter_slice_allowed_flag);
|
||||
|
||||
if (ph->ph_inter_slice_allowed_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_intra_slice_allowed_flag);
|
||||
} else {
|
||||
ph->ph_intra_slice_allowed_flag = 1;
|
||||
}
|
||||
|
||||
READ_UE_OR_RETURN(&ph->ph_pic_parameter_set_id);
|
||||
IN_RANGE_OR_RETURN(ph->ph_pic_parameter_set_id, 0, 63);
|
||||
|
||||
const H266PPS* pps = GetPPS(ph->ph_pic_parameter_set_id);
|
||||
if (!pps) {
|
||||
DVLOG(1) << "Invalid PPS in picture header.";
|
||||
return kInvalidStream;
|
||||
}
|
||||
|
||||
const H266SPS* sps = GetSPS(pps->pps_seq_parameter_set_id);
|
||||
if (!sps) {
|
||||
DVLOG(1) << "Failed to find SPS for current PPS.";
|
||||
return kInvalidStream;
|
||||
}
|
||||
const H266VPS* vps = GetVPS(sps->sps_video_parameter_set_id);
|
||||
if (!vps) {
|
||||
DVLOG(1) << "VPS for current SPS is not found.";
|
||||
return kInvalidStream;
|
||||
}
|
||||
|
||||
if (ph->ph_gdr_or_irap_pic_flag && !ph->ph_gdr_pic_flag) {
|
||||
int general_layer_idx = vps->GetGeneralLayerIdx(nalu.nuh_layer_id);
|
||||
if (general_layer_idx > 0 & general_layer_idx < kMaxLayers &&
|
||||
vps->vps_independent_layer_flag[general_layer_idx]) {
|
||||
TRUE_OR_RETURN(!ph->ph_inter_slice_allowed_flag);
|
||||
}
|
||||
}
|
||||
|
||||
// Late validation of ph_gdr_pic_flag as pps id is fetched after
|
||||
// ph_gdr_pic_flag.
|
||||
if (sps->sps_gdr_enabled_flag == 0) {
|
||||
TRUE_OR_RETURN(ph->ph_gdr_pic_flag == 0);
|
||||
}
|
||||
|
||||
READ_BITS_OR_RETURN(sps->sps_log2_max_pic_order_cnt_lsb_minus4 + 4,
|
||||
&ph->ph_pic_order_cnt_lsb);
|
||||
IN_RANGE_OR_RETURN(ph->ph_pic_order_cnt_lsb, 0,
|
||||
sps->max_pic_order_cnt_lsb - 1);
|
||||
if (ph->ph_gdr_pic_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_recovery_poc_cnt);
|
||||
IN_RANGE_OR_RETURN(ph->ph_recovery_poc_cnt, 0,
|
||||
sps->max_pic_order_cnt_lsb - 1);
|
||||
}
|
||||
|
||||
if (sps->num_extra_ph_bits > 0) {
|
||||
SKIP_BITS_OR_RETURN(sps->num_extra_ph_bits);
|
||||
}
|
||||
|
||||
if (sps->sps_poc_msb_cycle_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_poc_msb_cycle_present_flag);
|
||||
if (ph->ph_poc_msb_cycle_present_flag) {
|
||||
READ_BITS_OR_RETURN(sps->sps_poc_msb_cycle_len_minus1 + 1,
|
||||
&ph->ph_poc_msb_cycle_val);
|
||||
}
|
||||
}
|
||||
|
||||
// PH alf info.
|
||||
if (sps->sps_alf_enabled_flag && pps->pps_alf_info_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_alf_enabled_flag);
|
||||
if (ph->ph_alf_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_num_alf_aps_ids_luma);
|
||||
for (int i = 0; i < ph->ph_num_alf_aps_ids_luma; i++) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_alf_aps_id_luma[i]);
|
||||
}
|
||||
if (sps->sps_chroma_format_idc != 0) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_alf_cb_enabled_flag);
|
||||
READ_BOOL_OR_RETURN(&ph->ph_alf_cr_enabled_flag);
|
||||
} else {
|
||||
ph->ph_alf_cb_enabled_flag = ph->ph_alf_cr_enabled_flag = 0;
|
||||
}
|
||||
if (ph->ph_alf_cb_enabled_flag || ph->ph_alf_cr_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_alf_aps_id_chroma);
|
||||
}
|
||||
if (sps->sps_ccalf_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_alf_cc_cb_enabled_flag);
|
||||
if (ph->ph_alf_cc_cb_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_alf_cc_cb_aps_id);
|
||||
}
|
||||
READ_BOOL_OR_RETURN(&ph->ph_alf_cc_cr_enabled_flag);
|
||||
if (ph->ph_alf_cc_cr_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_alf_cc_cr_aps_id);
|
||||
}
|
||||
} else {
|
||||
ph->ph_alf_cc_cb_enabled_flag = 0;
|
||||
ph->ph_alf_cc_cr_enabled_flag = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ph->ph_alf_enabled_flag = 0;
|
||||
ph->ph_alf_cb_enabled_flag = ph->ph_alf_cr_enabled_flag = 0;
|
||||
ph->ph_alf_cc_cb_enabled_flag = 0;
|
||||
ph->ph_alf_cc_cr_enabled_flag = 0;
|
||||
}
|
||||
|
||||
if (sps->sps_lmcs_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_lmcs_enabled_flag);
|
||||
if (ph->ph_lmcs_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(2, &ph->ph_lmcs_aps_id);
|
||||
if (sps->sps_chroma_format_idc != 0) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_chroma_residual_scale_flag);
|
||||
} else {
|
||||
ph->ph_chroma_residual_scale_flag = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ph->ph_lmcs_enabled_flag = 0;
|
||||
ph->ph_chroma_residual_scale_flag = 0;
|
||||
}
|
||||
|
||||
if (sps->sps_explicit_scaling_list_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_explicit_scaling_list_enabled_flag);
|
||||
if (ph->ph_explicit_scaling_list_enabled_flag) {
|
||||
READ_BITS_OR_RETURN(3, &ph->ph_scaling_list_aps_id);
|
||||
}
|
||||
} else {
|
||||
ph->ph_explicit_scaling_list_enabled_flag = 0;
|
||||
}
|
||||
|
||||
if (sps->sps_virtual_boundaries_enabled_flag &&
|
||||
!sps->sps_virtual_boundaries_present_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_virtual_boundaries_present_flag);
|
||||
// Equation 77.
|
||||
ph->virtual_boundaries_present_flag = 0;
|
||||
if (sps->sps_virtual_boundaries_enabled_flag) {
|
||||
ph->virtual_boundaries_present_flag =
|
||||
sps->sps_virtual_boundaries_present_flag ||
|
||||
ph->ph_virtual_boundaries_present_flag;
|
||||
}
|
||||
if (ph->ph_virtual_boundaries_present_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_num_ver_virtual_boundaries);
|
||||
IN_RANGE_OR_RETURN(ph->ph_num_ver_virtual_boundaries, 0,
|
||||
(pps->pps_pic_width_in_luma_samples <= 8) ? 0 : 3);
|
||||
for (int i = 0; i < ph->ph_num_ver_virtual_boundaries; i++) {
|
||||
READ_UE_OR_RETURN(&ph->ph_virtual_boundary_pos_x_minus1[i]);
|
||||
IN_RANGE_OR_RETURN(ph->ph_virtual_boundary_pos_x_minus1[i], 0,
|
||||
(pps->pps_pic_width_in_luma_samples + 7 / 8) - 2);
|
||||
}
|
||||
|
||||
READ_UE_OR_RETURN(&ph->ph_num_hor_virtual_boundaries);
|
||||
IN_RANGE_OR_RETURN(ph->ph_num_hor_virtual_boundaries, 0,
|
||||
(pps->pps_pic_height_in_luma_samples <= 8) ? 0 : 3);
|
||||
for (int i = 0; i < ph->ph_num_hor_virtual_boundaries; i++) {
|
||||
READ_UE_OR_RETURN(&ph->ph_virtual_boundary_pos_y_minus1[i]);
|
||||
IN_RANGE_OR_RETURN(ph->ph_virtual_boundary_pos_y_minus1[i], 0,
|
||||
(pps->pps_pic_height_in_luma_samples + 7 / 8) - 2);
|
||||
}
|
||||
} else {
|
||||
ph->ph_num_ver_virtual_boundaries = 0;
|
||||
}
|
||||
} else {
|
||||
ph->ph_virtual_boundaries_present_flag = 0;
|
||||
ph->ph_num_ver_virtual_boundaries = 0;
|
||||
}
|
||||
|
||||
if (pps->pps_output_flag_present_flag && !ph->ph_non_ref_pic_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_pic_output_flag);
|
||||
} else {
|
||||
ph->ph_pic_output_flag = 1;
|
||||
}
|
||||
|
||||
if (pps->pps_rpl_info_in_ph_flag) {
|
||||
ParseRefPicLists(*sps, *pps, &ph->ref_pic_lists);
|
||||
}
|
||||
|
||||
if (sps->sps_partition_constraints_override_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_partition_constraints_override_flag);
|
||||
} else {
|
||||
ph->ph_partition_constraints_override_flag = 0;
|
||||
}
|
||||
|
||||
if (ph->ph_intra_slice_allowed_flag) {
|
||||
if (ph->ph_partition_constraints_override_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y);
|
||||
// Equation 82
|
||||
ph->min_qt_log2_size_intra_y =
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma +
|
||||
sps->min_cb_log2_size_y;
|
||||
|
||||
READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_intra_slice_luma);
|
||||
IN_RANGE_OR_RETURN(ph->ph_max_mtt_hierarchy_depth_intra_slice_luma, 0,
|
||||
2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y));
|
||||
|
||||
if (ph->ph_max_mtt_hierarchy_depth_intra_slice_luma != 0) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma);
|
||||
IN_RANGE_OR_RETURN(ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma, 0,
|
||||
(sps->sps_qtbtt_dual_tree_intra_flag
|
||||
? std::min(6, sps->ctb_log2_size_y)
|
||||
: sps->ctb_log2_size_y) -
|
||||
ph->min_qt_log2_size_intra_y);
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_y);
|
||||
} else {
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma =
|
||||
sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma;
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma =
|
||||
sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma;
|
||||
}
|
||||
|
||||
if (sps->sps_qtbtt_dual_tree_intra_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y);
|
||||
READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma, 0,
|
||||
2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y));
|
||||
|
||||
// Equation 83
|
||||
ph->min_qt_log2_size_intra_c =
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma +
|
||||
sps->min_cb_log2_size_y;
|
||||
|
||||
if (ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_c);
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_intra_c);
|
||||
} else {
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma;
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma;
|
||||
}
|
||||
} else {
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma;
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma;
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma =
|
||||
sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma;
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma =
|
||||
sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma;
|
||||
}
|
||||
} else {
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_luma =
|
||||
sps->sps_log2_diff_min_qt_min_cb_intra_slice_luma;
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_luma =
|
||||
sps->sps_max_mtt_hierarchy_depth_intra_slice_luma;
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_luma =
|
||||
sps->sps_log2_diff_max_bt_min_qt_intra_slice_luma;
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_luma =
|
||||
sps->sps_log2_diff_max_tt_min_qt_intra_slice_luma;
|
||||
ph->ph_log2_diff_max_bt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_bt_min_qt_intra_slice_chroma;
|
||||
ph->ph_log2_diff_max_tt_min_qt_intra_slice_chroma =
|
||||
sps->sps_log2_diff_max_tt_min_qt_intra_slice_chroma;
|
||||
ph->ph_log2_diff_min_qt_min_cb_intra_slice_chroma =
|
||||
sps->sps_log2_diff_min_qt_min_cb_intra_slice_chroma;
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_chroma =
|
||||
sps->sps_max_mtt_hierarchy_depth_intra_slice_chroma;
|
||||
}
|
||||
if (pps->pps_cu_qp_delta_enabled_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_cu_qp_delta_subdiv_intra_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_cu_qp_delta_subdiv_intra_slice, 0,
|
||||
2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_intra_y +
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_luma));
|
||||
} else {
|
||||
ph->ph_cu_qp_delta_subdiv_intra_slice = 0;
|
||||
}
|
||||
if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_cu_chroma_qp_offset_subdiv_intra_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_cu_chroma_qp_offset_subdiv_intra_slice, 0,
|
||||
2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_intra_y +
|
||||
ph->ph_max_mtt_hierarchy_depth_intra_slice_luma));
|
||||
} else {
|
||||
ph->ph_cu_chroma_qp_offset_subdiv_intra_slice = 0;
|
||||
}
|
||||
} // ph_intra_slice_allowed_flag
|
||||
|
||||
if (ph->ph_inter_slice_allowed_flag) { // Syntax parsing till before
|
||||
// ph_qp_delta
|
||||
if (ph->ph_partition_constraints_override_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_min_qt_min_cb_inter_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_min_qt_min_cb_inter_slice, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - sps->min_cb_log2_size_y);
|
||||
// Equation 84
|
||||
ph->min_qt_log2_size_inter_y =
|
||||
ph->ph_log2_diff_min_qt_min_cb_inter_slice + sps->min_cb_log2_size_y;
|
||||
|
||||
READ_UE_OR_RETURN(&ph->ph_max_mtt_hierarchy_depth_inter_slice);
|
||||
IN_RANGE_OR_RETURN(ph->ph_max_mtt_hierarchy_depth_inter_slice, 0,
|
||||
2 * (sps->ctb_log2_size_y - sps->min_cb_log2_size_y));
|
||||
|
||||
if (ph->ph_max_mtt_hierarchy_depth_inter_slice != 0) {
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_bt_min_qt_inter_slice);
|
||||
IN_RANGE_OR_RETURN(ph->ph_log2_diff_max_bt_min_qt_inter_slice, 0,
|
||||
sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y);
|
||||
READ_UE_OR_RETURN(&ph->ph_log2_diff_max_tt_min_qt_inter_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_log2_diff_max_tt_min_qt_inter_slice, 0,
|
||||
std::min(6, sps->ctb_log2_size_y) - ph->min_qt_log2_size_inter_y);
|
||||
} else {
|
||||
ph->ph_log2_diff_max_bt_min_qt_inter_slice =
|
||||
sps->sps_log2_diff_max_bt_min_qt_inter_slice;
|
||||
ph->ph_log2_diff_max_tt_min_qt_inter_slice =
|
||||
sps->sps_log2_diff_max_tt_min_qt_inter_slice;
|
||||
}
|
||||
} else {
|
||||
ph->ph_log2_diff_min_qt_min_cb_inter_slice =
|
||||
sps->sps_log2_diff_max_bt_min_qt_inter_slice;
|
||||
ph->ph_max_mtt_hierarchy_depth_inter_slice =
|
||||
sps->sps_max_mtt_hierarchy_depth_inter_slice;
|
||||
ph->ph_log2_diff_max_bt_min_qt_inter_slice =
|
||||
sps->sps_log2_diff_max_bt_min_qt_inter_slice;
|
||||
ph->ph_log2_diff_max_tt_min_qt_inter_slice =
|
||||
sps->sps_log2_diff_max_tt_min_qt_inter_slice;
|
||||
}
|
||||
|
||||
if (pps->pps_cu_qp_delta_enabled_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_cu_qp_delta_subdiv_inter_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_cu_qp_delta_subdiv_inter_slice, 0,
|
||||
2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y +
|
||||
ph->ph_max_mtt_hierarchy_depth_inter_slice));
|
||||
} else {
|
||||
ph->ph_cu_qp_delta_subdiv_inter_slice = 0;
|
||||
}
|
||||
|
||||
if (pps->pps_cu_chroma_qp_offset_list_enabled_flag) {
|
||||
READ_UE_OR_RETURN(&ph->ph_cu_chroma_qp_offset_subdiv_inter_slice);
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_cu_chroma_qp_offset_subdiv_inter_slice, 0,
|
||||
2 * (sps->ctb_log2_size_y - ph->min_qt_log2_size_inter_y +
|
||||
ph->ph_max_mtt_hierarchy_depth_inter_slice));
|
||||
} else {
|
||||
ph->ph_cu_chroma_qp_offset_subdiv_inter_slice = 0;
|
||||
}
|
||||
|
||||
if (sps->sps_temporal_mvp_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_temporal_mvp_enabled_flag);
|
||||
|
||||
if (ph->ph_temporal_mvp_enabled_flag && pps->pps_rpl_info_in_ph_flag) {
|
||||
if (ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_collocated_from_l0_flag);
|
||||
} else {
|
||||
ph->ph_collocated_from_l0_flag = 1;
|
||||
}
|
||||
|
||||
if ((ph->ph_collocated_from_l0_flag &&
|
||||
ph->ref_pic_lists.rpl_ref_lists[0].num_ref_entries > 1) ||
|
||||
(!ph->ph_collocated_from_l0_flag &&
|
||||
ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 1)) {
|
||||
READ_UE_OR_RETURN(&ph->ph_collocated_ref_idx);
|
||||
if (ph->ph_collocated_from_l0_flag) {
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_collocated_ref_idx, 0,
|
||||
ph->ref_pic_lists.rpl_ref_lists[0].num_ref_entries - 1);
|
||||
} else {
|
||||
IN_RANGE_OR_RETURN(
|
||||
ph->ph_collocated_ref_idx, 0,
|
||||
ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries - 1);
|
||||
}
|
||||
} else {
|
||||
ph->ph_collocated_ref_idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sps->sps_mmvd_fullpel_only_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_mmvd_fullpel_only_flag);
|
||||
} else {
|
||||
ph->ph_mmvd_fullpel_only_flag = 0;
|
||||
}
|
||||
|
||||
bool presence_flag = 0;
|
||||
if (!pps->pps_rpl_info_in_ph_flag) {
|
||||
presence_flag = 1;
|
||||
} else if (ph->ref_pic_lists.rpl_ref_lists[1].num_ref_entries > 0) {
|
||||
presence_flag = 1;
|
||||
}
|
||||
if (presence_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_mvd_l1_zero_flag);
|
||||
if (sps->sps_bdof_control_present_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_bdof_disabled_flag);
|
||||
} else {
|
||||
ph->ph_bdof_disabled_flag = 1 - sps->sps_bdof_enabled_flag;
|
||||
}
|
||||
if (sps->sps_dmvr_control_present_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_dmvr_disabled_flag);
|
||||
} else {
|
||||
ph->ph_dmvr_disabled_flag = 1 - sps->sps_dmvr_enabled_flag;
|
||||
}
|
||||
} else {
|
||||
ph->ph_mvd_l1_zero_flag = 1;
|
||||
ph->ph_bdof_disabled_flag = 1;
|
||||
}
|
||||
|
||||
if (sps->sps_prof_control_present_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_prof_disabled_flag);
|
||||
} else {
|
||||
if (sps->sps_affine_prof_enabled_flag) {
|
||||
ph->ph_prof_disabled_flag = 0;
|
||||
} else {
|
||||
ph->ph_prof_disabled_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pps->pps_weighted_pred_flag || pps->pps_weighted_bipred_flag) &&
|
||||
pps->pps_wp_info_in_ph_flag) {
|
||||
int num_active_ref_idx[2] = {0, 0};
|
||||
ParsePredWeightTable(*sps, *pps, ph->ref_pic_lists, num_active_ref_idx,
|
||||
&ph->pred_weight_table);
|
||||
}
|
||||
} // ph_inter_slice_allowed_flag
|
||||
|
||||
if (pps->pps_qp_delta_info_in_ph_flag) {
|
||||
READ_SE_OR_RETURN(&ph->ph_qp_delta);
|
||||
// Equation 86
|
||||
ph->slice_qp_y = 26 + pps->pps_init_qp_minus26 + ph->ph_qp_delta;
|
||||
IN_RANGE_OR_RETURN(ph->slice_qp_y, -sps->qp_bd_offset, 63);
|
||||
}
|
||||
|
||||
if (sps->sps_joint_cbcr_enabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_joint_cbcr_sign_flag);
|
||||
}
|
||||
|
||||
if (sps->sps_sao_enabled_flag && pps->pps_sao_info_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_sao_luma_enabled_flag);
|
||||
if (sps->sps_chroma_format_idc != 0) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_sao_chroma_enabled_flag);
|
||||
} else {
|
||||
ph->ph_sao_chroma_enabled_flag = 0;
|
||||
}
|
||||
} else {
|
||||
ph->ph_sao_luma_enabled_flag = 0;
|
||||
ph->ph_sao_chroma_enabled_flag = 0;
|
||||
}
|
||||
|
||||
if (pps->pps_dbf_info_in_ph_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_deblocking_params_present_flag);
|
||||
if (ph->ph_deblocking_params_present_flag) {
|
||||
if (!pps->pps_deblocking_filter_disabled_flag) {
|
||||
READ_BOOL_OR_RETURN(&ph->ph_deblocking_filter_disabled_flag);
|
||||
} else {
|
||||
if (pps->pps_deblocking_filter_disabled_flag &&
|
||||
ph->ph_deblocking_params_present_flag) {
|
||||
ph->ph_deblocking_filter_disabled_flag = 0;
|
||||
} else {
|
||||
ph->ph_deblocking_filter_disabled_flag =
|
||||
pps->pps_deblocking_filter_disabled_flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ph->ph_deblocking_filter_disabled_flag) {
|
||||
READ_SE_OR_RETURN(&ph->ph_luma_beta_offset_div2);
|
||||
READ_SE_OR_RETURN(&ph->ph_luma_tc_offset_div2);
|
||||
IN_RANGE_OR_RETURN(ph->ph_luma_beta_offset_div2, -12, 12);
|
||||
IN_RANGE_OR_RETURN(ph->ph_luma_tc_offset_div2, -12, 12);
|
||||
|
||||
if (pps->pps_chroma_tool_offsets_present_flag) {
|
||||
READ_SE_OR_RETURN(&ph->ph_cb_beta_offset_div2);
|
||||
READ_SE_OR_RETURN(&ph->ph_cb_tc_offset_div2);
|
||||
READ_SE_OR_RETURN(&ph->ph_cr_beta_offset_div2);
|
||||
READ_SE_OR_RETURN(&ph->ph_cr_tc_offset_div2);
|
||||
IN_RANGE_OR_RETURN(ph->ph_cb_beta_offset_div2, -12, 12);
|
||||
IN_RANGE_OR_RETURN(ph->ph_cb_tc_offset_div2, -12, 12);
|
||||
IN_RANGE_OR_RETURN(ph->ph_cr_beta_offset_div2, -12, 12);
|
||||
IN_RANGE_OR_RETURN(ph->ph_cr_tc_offset_div2, -12, 12);
|
||||
} else {
|
||||
if (pps->pps_chroma_tool_offsets_present_flag) {
|
||||
ph->ph_cb_beta_offset_div2 = pps->pps_cb_beta_offset_div2;
|
||||
ph->ph_cb_tc_offset_div2 = pps->pps_cb_tc_offset_div2;
|
||||
ph->ph_cr_beta_offset_div2 = pps->pps_cr_beta_offset_div2;
|
||||
ph->ph_cr_tc_offset_div2 = pps->pps_cr_tc_offset_div2;
|
||||
} else {
|
||||
ph->ph_cb_beta_offset_div2 = ph->ph_luma_beta_offset_div2;
|
||||
ph->ph_cb_tc_offset_div2 = ph->ph_luma_tc_offset_div2;
|
||||
ph->ph_cr_beta_offset_div2 = ph->ph_luma_beta_offset_div2;
|
||||
ph->ph_cr_tc_offset_div2 = ph->ph_luma_tc_offset_div2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ph->ph_luma_beta_offset_div2 = pps->pps_luma_beta_offset_div2;
|
||||
ph->ph_luma_tc_offset_div2 = pps->pps_luma_tc_offset_div2;
|
||||
if (pps->pps_chroma_tool_offsets_present_flag) {
|
||||
ph->ph_cb_beta_offset_div2 = pps->pps_cb_beta_offset_div2;
|
||||
ph->ph_cb_tc_offset_div2 = pps->pps_cb_tc_offset_div2;
|
||||
ph->ph_cr_beta_offset_div2 = pps->pps_cr_beta_offset_div2;
|
||||
ph->ph_cr_tc_offset_div2 = pps->pps_cr_tc_offset_div2;
|
||||
} else {
|
||||
ph->ph_cb_beta_offset_div2 = ph->ph_luma_beta_offset_div2;
|
||||
ph->ph_cb_tc_offset_div2 = ph->ph_luma_tc_offset_div2;
|
||||
ph->ph_cr_beta_offset_div2 = ph->ph_luma_beta_offset_div2;
|
||||
ph->ph_cr_tc_offset_div2 = ph->ph_luma_tc_offset_div2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ph->ph_deblocking_params_present_flag = 0;
|
||||
}
|
||||
|
||||
// We stop here and do not parse ph extension when
|
||||
// pps_picture_header_extension_present_flag is 1.
|
||||
|
||||
return kOk;
|
||||
}
|
||||
|
||||
const H266VPS* H266Parser::GetVPS(int vps_id) const {
|
||||
auto it = active_vps_.find(vps_id);
|
||||
if (it == active_vps_.end()) {
|
||||
|
@ -714,6 +714,126 @@ struct MEDIA_EXPORT H266APS {
|
||||
std::variant<H266AlfData, H266LmcsData, H266ScalingListData> data;
|
||||
};
|
||||
|
||||
// 7.3.8. PredWeightTable could exist in picture header or slice header.
|
||||
struct MEDIA_EXPORT H266PredWeightTable {
|
||||
H266PredWeightTable();
|
||||
|
||||
// Syntax elements.
|
||||
int luma_log2_weight_denom;
|
||||
int delta_chroma_log2_weight_denom;
|
||||
int num_l0_weights;
|
||||
bool luma_weight_l0_flag[15];
|
||||
bool chroma_weight_l0_flag[15];
|
||||
int delta_luma_weight_l0[15];
|
||||
int luma_offset_l0[15];
|
||||
int delta_chroma_weight_l0[2][15];
|
||||
int delta_chroma_offset_l0[2][15];
|
||||
int num_l1_weights;
|
||||
bool luma_weight_l1_flag[15];
|
||||
bool chroma_weight_l1_flag[15];
|
||||
int delta_luma_weight_l1[15];
|
||||
int luma_offset_l1[15];
|
||||
int delta_chroma_weight_l1[2][15];
|
||||
int delta_chroma_offset_l1[2][15];
|
||||
|
||||
// Calculated values.
|
||||
int chroma_log2_weight_denom;
|
||||
int num_weights_l0;
|
||||
int num_weights_l1;
|
||||
};
|
||||
|
||||
// 7.3.2.8
|
||||
struct MEDIA_EXPORT H266PictureHeader {
|
||||
H266PictureHeader();
|
||||
|
||||
// Implies whether the picture header structure
|
||||
// is within PH_NUT or slice header.
|
||||
int nal_unit_type;
|
||||
|
||||
// Syntax elements.
|
||||
bool ph_gdr_or_irap_pic_flag;
|
||||
bool ph_non_ref_pic_flag;
|
||||
bool ph_gdr_pic_flag;
|
||||
bool ph_inter_slice_allowed_flag;
|
||||
bool ph_intra_slice_allowed_flag;
|
||||
int ph_pic_parameter_set_id;
|
||||
int ph_pic_order_cnt_lsb;
|
||||
int ph_recovery_poc_cnt;
|
||||
bool ph_poc_msb_cycle_present_flag;
|
||||
int ph_poc_msb_cycle_val;
|
||||
bool ph_alf_enabled_flag;
|
||||
int ph_num_alf_aps_ids_luma;
|
||||
int ph_alf_aps_id_luma[7];
|
||||
bool ph_alf_cb_enabled_flag;
|
||||
bool ph_alf_cr_enabled_flag;
|
||||
int ph_alf_aps_id_chroma;
|
||||
bool ph_alf_cc_cb_enabled_flag;
|
||||
int ph_alf_cc_cb_aps_id;
|
||||
bool ph_alf_cc_cr_enabled_flag;
|
||||
int ph_alf_cc_cr_aps_id;
|
||||
bool ph_lmcs_enabled_flag;
|
||||
int ph_lmcs_aps_id;
|
||||
bool ph_chroma_residual_scale_flag;
|
||||
bool ph_explicit_scaling_list_enabled_flag;
|
||||
int ph_scaling_list_aps_id;
|
||||
bool ph_virtual_boundaries_present_flag;
|
||||
int ph_num_ver_virtual_boundaries;
|
||||
int ph_virtual_boundary_pos_x_minus1[3];
|
||||
int ph_num_hor_virtual_boundaries;
|
||||
int ph_virtual_boundary_pos_y_minus1[3];
|
||||
bool ph_pic_output_flag;
|
||||
H266RefPicLists ref_pic_lists;
|
||||
bool ph_partition_constraints_override_flag;
|
||||
int ph_log2_diff_min_qt_min_cb_intra_slice_luma;
|
||||
int ph_max_mtt_hierarchy_depth_intra_slice_luma;
|
||||
int ph_log2_diff_max_bt_min_qt_intra_slice_luma;
|
||||
int ph_log2_diff_max_tt_min_qt_intra_slice_luma;
|
||||
int ph_log2_diff_min_qt_min_cb_intra_slice_chroma;
|
||||
int ph_max_mtt_hierarchy_depth_intra_slice_chroma;
|
||||
int ph_log2_diff_max_bt_min_qt_intra_slice_chroma;
|
||||
int ph_log2_diff_max_tt_min_qt_intra_slice_chroma;
|
||||
int ph_cu_qp_delta_subdiv_intra_slice;
|
||||
int ph_cu_chroma_qp_offset_subdiv_intra_slice;
|
||||
int ph_log2_diff_min_qt_min_cb_inter_slice;
|
||||
int ph_max_mtt_hierarchy_depth_inter_slice;
|
||||
int ph_log2_diff_max_bt_min_qt_inter_slice;
|
||||
int ph_log2_diff_max_tt_min_qt_inter_slice;
|
||||
int ph_cu_qp_delta_subdiv_inter_slice;
|
||||
int ph_cu_chroma_qp_offset_subdiv_inter_slice;
|
||||
bool ph_temporal_mvp_enabled_flag;
|
||||
bool ph_collocated_from_l0_flag;
|
||||
int ph_collocated_ref_idx;
|
||||
bool ph_mmvd_fullpel_only_flag;
|
||||
bool ph_mvd_l1_zero_flag;
|
||||
bool ph_bdof_disabled_flag;
|
||||
bool ph_dmvr_disabled_flag;
|
||||
bool ph_prof_disabled_flag;
|
||||
H266PredWeightTable pred_weight_table;
|
||||
int ph_qp_delta;
|
||||
bool ph_joint_cbcr_sign_flag;
|
||||
bool ph_sao_luma_enabled_flag;
|
||||
bool ph_sao_chroma_enabled_flag;
|
||||
bool ph_deblocking_params_present_flag;
|
||||
bool ph_deblocking_filter_disabled_flag;
|
||||
int ph_luma_beta_offset_div2;
|
||||
int ph_luma_tc_offset_div2;
|
||||
int ph_cb_beta_offset_div2;
|
||||
int ph_cb_tc_offset_div2;
|
||||
int ph_cr_beta_offset_div2;
|
||||
int ph_cr_tc_offset_div2;
|
||||
int ph_extension_length;
|
||||
// Skip any possible extension bytes.
|
||||
|
||||
// Calculated values.
|
||||
bool virtual_boundaries_present_flag;
|
||||
int num_ver_virtual_boundaries;
|
||||
int num_hor_virtual_boundaries;
|
||||
int min_qt_log2_size_intra_y;
|
||||
int min_qt_log2_size_intra_c;
|
||||
int min_qt_log2_size_inter_y;
|
||||
int slice_qp_y;
|
||||
};
|
||||
|
||||
// Class to parse an Annex-B H.266 stream.
|
||||
class MEDIA_EXPORT H266Parser : public H266NaluParser {
|
||||
public:
|
||||
@ -752,6 +872,10 @@ class MEDIA_EXPORT H266Parser : public H266NaluParser {
|
||||
// |*aps_id| and |*type| as parameter.
|
||||
Result ParseAPS(const H266NALU& nalu, int* pps_id, H266APS::ParamType* type);
|
||||
|
||||
// Parse a picture header(PH) NALU and return the parsed structure
|
||||
// in |*ph|.
|
||||
Result ParsePHNut(const H266NALU& nalu, H266PictureHeader* ph);
|
||||
|
||||
// Return a pointer to VPS with given |vps_id| or
|
||||
// null if not present.
|
||||
const H266VPS* GetVPS(int vps_id) const;
|
||||
@ -800,6 +924,24 @@ class MEDIA_EXPORT H266Parser : public H266NaluParser {
|
||||
const H266SPS& sps,
|
||||
H266VUIParameters* vui);
|
||||
|
||||
Result ParseRefPicLists(const H266SPS& sps,
|
||||
const H266PPS& pps,
|
||||
H266RefPicLists* ref_pic_lists);
|
||||
|
||||
Result ParsePredWeightTable(const H266SPS& sps,
|
||||
const H266PPS& pps,
|
||||
const H266RefPicLists& ref_pic_lists,
|
||||
int num_ref_idx_active[2],
|
||||
H266PredWeightTable* pred_weight_table);
|
||||
|
||||
// Called when picture header structure is in slice header.
|
||||
Result ParsePHInSlice(const H266NALU& nalu, H266PictureHeader* ph);
|
||||
|
||||
// Shared picture header structure parser for PH structure in PH_NUT and slice
|
||||
// header.
|
||||
Result ParsePictureHeaderStructure(const H266NALU& nalu,
|
||||
H266PictureHeader* ph);
|
||||
|
||||
// VPSes/SPSes/PPSes stored for future reference.
|
||||
base::flat_map<int, std::unique_ptr<H266VPS>> active_vps_;
|
||||
base::flat_map<int, std::unique_ptr<H266SPS>> active_sps_;
|
||||
|
@ -20,6 +20,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
// found.
|
||||
while (true) {
|
||||
media::H266NALU nalu;
|
||||
media::H266PictureHeader ph;
|
||||
media::H266Parser::Result res = parser.AdvanceToNextNALU(&nalu);
|
||||
if (res != media::H266Parser::kOk) {
|
||||
break;
|
||||
@ -44,6 +45,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
int aps_id;
|
||||
res = parser.ParseAPS(nalu, &aps_id, &aps_type);
|
||||
break;
|
||||
case media::H266NALU::kPH:
|
||||
res = parser.ParsePHNut(nalu, &ph);
|
||||
break;
|
||||
// TODO(crbugs.com/1417910): Other NALU types will be checked.
|
||||
default:
|
||||
// Skip other NALU types
|
||||
|
@ -61,6 +61,7 @@ TEST_F(H266ParserTest, RawVvcStreamFileParsingShouldSucceed) {
|
||||
int num_parsed_nalus = 0;
|
||||
while (true) {
|
||||
H266NALU nalu;
|
||||
H266PictureHeader ph;
|
||||
H266Parser::Result res = parser_.AdvanceToNextNALU(&nalu);
|
||||
if (res == H266Parser::kEndOfStream) {
|
||||
DVLOG(1) << "Number of successfully parsed NALUs before EOS: "
|
||||
@ -94,6 +95,9 @@ TEST_F(H266ParserTest, RawVvcStreamFileParsingShouldSucceed) {
|
||||
res = parser_.ParseAPS(nalu, &aps_id, &aps_type);
|
||||
EXPECT_TRUE(!!parser_.GetAPS(aps_type, aps_id));
|
||||
break;
|
||||
case H266NALU::kPH:
|
||||
res = parser_.ParsePHNut(nalu, &ph);
|
||||
break;
|
||||
// TODO(crbugs.com/1417910): add more NALU types.
|
||||
default:
|
||||
break;
|
||||
@ -1190,4 +1194,168 @@ TEST_F(H266ParserTest, ParseAPSShouldConstructCorrectLmcsData) {
|
||||
EXPECT_TRUE(!nonexisting_aps);
|
||||
}
|
||||
|
||||
// Verify parsing of simple PH_NUT.
|
||||
TEST_F(H266ParserTest, ParseSimplePHNutShouldSucceed) {
|
||||
LoadParserFile("bbb_9tiles_18slices.vvc");
|
||||
H266NALU target_nalu;
|
||||
int sps_id;
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kSPS));
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParseSPS(target_nalu, &sps_id));
|
||||
// Parsing of the SPS should generate fake VPS with vps_id = 0;
|
||||
const H266VPS* vps = parser_.GetVPS(0);
|
||||
EXPECT_TRUE(!!vps);
|
||||
const H266SPS* sps = parser_.GetSPS(sps_id);
|
||||
EXPECT_TRUE(!!sps);
|
||||
int pps_id;
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPPS));
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePPS(target_nalu, &pps_id));
|
||||
const H266PPS* pps = parser_.GetPPS(pps_id);
|
||||
EXPECT_TRUE(!!pps);
|
||||
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPH));
|
||||
H266PictureHeader ph;
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePHNut(target_nalu, &ph));
|
||||
EXPECT_TRUE(ph.ph_gdr_or_irap_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_non_ref_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_gdr_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_inter_slice_allowed_flag);
|
||||
EXPECT_EQ(ph.ph_pic_parameter_set_id, 0);
|
||||
EXPECT_EQ(ph.ph_pic_order_cnt_lsb, 0);
|
||||
EXPECT_FALSE(ph.ph_lmcs_enabled_flag);
|
||||
EXPECT_FALSE(ph.ph_partition_constraints_override_flag);
|
||||
EXPECT_FALSE(ph.ph_joint_cbcr_sign_flag);
|
||||
}
|
||||
|
||||
// Verify parsing of complex PH_NUT in which the RPL, deblocking filter,
|
||||
// SAO, ALF and etc are coded, instead of placing them in slice header(not
|
||||
// even in the picture header structure of slice header, which will be covered
|
||||
// by slice header parsing tests.).
|
||||
TEST_F(H266ParserTest, ParseComplexPHNutShouldSucceed) {
|
||||
LoadParserFile("bbb_rpl_in_ph_nut.vvc");
|
||||
H266NALU target_nalu;
|
||||
int sps_id;
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kSPS));
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParseSPS(target_nalu, &sps_id));
|
||||
// Parsing of the SPS should generate fake VPS with vps_id = 0;
|
||||
const H266VPS* vps = parser_.GetVPS(0);
|
||||
EXPECT_TRUE(!!vps);
|
||||
const H266SPS* sps = parser_.GetSPS(sps_id);
|
||||
EXPECT_TRUE(!!sps);
|
||||
int pps_id;
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPPS));
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePPS(target_nalu, &pps_id));
|
||||
const H266PPS* pps = parser_.GetPPS(pps_id);
|
||||
EXPECT_TRUE(!!pps);
|
||||
|
||||
// Parse the first PH_NUT which is for slices of the IDR_N_LP frame.
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPH));
|
||||
H266PictureHeader ph;
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePHNut(target_nalu, &ph));
|
||||
EXPECT_TRUE(ph.ph_gdr_or_irap_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_non_ref_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_gdr_pic_flag);
|
||||
EXPECT_FALSE(ph.ph_inter_slice_allowed_flag);
|
||||
EXPECT_EQ(ph.ph_pic_parameter_set_id, 0);
|
||||
EXPECT_EQ(ph.ph_pic_order_cnt_lsb, 0);
|
||||
EXPECT_FALSE(ph.ph_alf_enabled_flag);
|
||||
EXPECT_FALSE(ph.ph_lmcs_enabled_flag);
|
||||
// For this test clip, RPL 0 in ref_pic_lists() is based on one of
|
||||
// ref_pic_struct(0, rplsIdx), where rplsIdx is indicated by rpl_idx[0].
|
||||
EXPECT_EQ(sps->sps_num_ref_pic_lists[0], 20);
|
||||
EXPECT_FALSE(sps->sps_rpl1_same_as_rpl0_flag);
|
||||
EXPECT_FALSE(pps->pps_rpl1_idx_present_flag);
|
||||
EXPECT_TRUE(ph.ref_pic_lists.rpl_sps_flag[0]);
|
||||
EXPECT_EQ(ph.ref_pic_lists.rpl_idx[0], 0);
|
||||
// rpl_sps_flag[1] & rpl_idx[1] is not present in PH, but they are inferred to
|
||||
// be equal to rpl_sps_flag[0] since sps_num_ref_pic_lists[i] is non-zero.
|
||||
EXPECT_EQ(sps->sps_num_ref_pic_lists[1], 20);
|
||||
EXPECT_EQ(ph.ref_pic_lists.rpl_sps_flag[1], ph.ref_pic_lists.rpl_sps_flag[0]);
|
||||
EXPECT_EQ(ph.ref_pic_lists.rpl_idx[1], ph.ref_pic_lists.rpl_idx[0]);
|
||||
|
||||
EXPECT_FALSE(ph.ph_partition_constraints_override_flag);
|
||||
EXPECT_EQ(ph.ph_qp_delta, -5);
|
||||
EXPECT_FALSE(ph.ph_joint_cbcr_sign_flag);
|
||||
EXPECT_TRUE(ph.ph_sao_luma_enabled_flag);
|
||||
EXPECT_TRUE(ph.ph_sao_chroma_enabled_flag);
|
||||
|
||||
// Parse the second PH_NUT which is for slices of first STSA frame.
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPH));
|
||||
H266PictureHeader ph2;
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePHNut(target_nalu, &ph2));
|
||||
EXPECT_FALSE(ph2.ph_gdr_or_irap_pic_flag);
|
||||
EXPECT_FALSE(ph2.ph_non_ref_pic_flag);
|
||||
EXPECT_TRUE(ph2.ph_inter_slice_allowed_flag);
|
||||
EXPECT_FALSE(ph2.ph_intra_slice_allowed_flag);
|
||||
EXPECT_EQ(ph2.ph_pic_parameter_set_id, 0);
|
||||
EXPECT_EQ(ph2.ph_pic_order_cnt_lsb, 4);
|
||||
// RPL 0/1 is signalled in PH, since rpl_sps_flag[1] is inferred to be
|
||||
// equal to rpl_sps_flag[0], which is 0 here.
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_sps_flag[0], 0);
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_sps_flag[1],
|
||||
ph2.ref_pic_lists.rpl_sps_flag[0]);
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_ref_lists[0].num_ref_entries, 1);
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_ref_lists[0].abs_delta_poc_st[0], 3);
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_ref_lists[1].num_ref_entries, 1);
|
||||
EXPECT_EQ(ph2.ref_pic_lists.rpl_ref_lists[1].abs_delta_poc_st[0], 3);
|
||||
|
||||
EXPECT_TRUE(ph2.ph_temporal_mvp_enabled_flag);
|
||||
EXPECT_FALSE(ph2.ph_collocated_from_l0_flag);
|
||||
|
||||
// Verify the weighted prediction table.
|
||||
EXPECT_EQ(ph2.pred_weight_table.luma_log2_weight_denom, 0);
|
||||
EXPECT_EQ(ph2.pred_weight_table.delta_chroma_log2_weight_denom, 0);
|
||||
EXPECT_EQ(ph2.pred_weight_table.num_l0_weights, 1);
|
||||
EXPECT_FALSE(ph2.pred_weight_table.luma_weight_l0_flag[0]);
|
||||
EXPECT_FALSE(ph2.pred_weight_table.chroma_weight_l0_flag[0]);
|
||||
EXPECT_EQ(ph2.pred_weight_table.num_l1_weights, 1);
|
||||
EXPECT_FALSE(ph2.pred_weight_table.luma_weight_l1_flag[0]);
|
||||
EXPECT_FALSE(ph2.pred_weight_table.chroma_weight_l1_flag[0]);
|
||||
|
||||
// Verify other misc syntax elements.
|
||||
EXPECT_EQ(ph2.ph_qp_delta, 4);
|
||||
EXPECT_FALSE(ph2.ph_joint_cbcr_sign_flag);
|
||||
EXPECT_TRUE(ph2.ph_sao_chroma_enabled_flag);
|
||||
EXPECT_TRUE(ph2.ph_sao_chroma_enabled_flag);
|
||||
|
||||
// Parse till the end of the stream for the last PH_NUT.
|
||||
H266PictureHeader last_ph;
|
||||
while (ParseNalusUntilNut(&target_nalu, H266NALU::kPH)) {
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParsePHNut(target_nalu, &last_ph));
|
||||
}
|
||||
EXPECT_EQ(last_ph.ph_pic_order_cnt_lsb, 3);
|
||||
EXPECT_EQ(last_ph.ref_pic_lists.rpl_ref_lists[0].num_ref_entries, 2);
|
||||
EXPECT_EQ(last_ph.ref_pic_lists.rpl_ref_lists[0].abs_delta_poc_st[0], 0);
|
||||
EXPECT_EQ(last_ph.ref_pic_lists.rpl_ref_lists[0].abs_delta_poc_st[1], 2);
|
||||
EXPECT_EQ(last_ph.ref_pic_lists.rpl_ref_lists[1].abs_delta_poc_st[0], 0);
|
||||
EXPECT_EQ(last_ph.ref_pic_lists.rpl_ref_lists[1].abs_delta_poc_st[1], 2);
|
||||
EXPECT_EQ(last_ph.pred_weight_table.luma_log2_weight_denom, 0);
|
||||
EXPECT_EQ(last_ph.pred_weight_table.delta_chroma_log2_weight_denom, 0);
|
||||
EXPECT_EQ(last_ph.pred_weight_table.num_l0_weights, 2);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.luma_weight_l0_flag[0]);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.luma_weight_l0_flag[1]);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.chroma_weight_l0_flag[0]);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.chroma_weight_l0_flag[1]);
|
||||
EXPECT_EQ(last_ph.pred_weight_table.num_l1_weights, 2);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.luma_weight_l1_flag[0]);
|
||||
EXPECT_FALSE(last_ph.pred_weight_table.chroma_weight_l1_flag[0]);
|
||||
EXPECT_EQ(last_ph.ph_qp_delta, 7);
|
||||
}
|
||||
|
||||
TEST_F(H266ParserTest, ParsePHNutWithoutParsingPPSShouldFail) {
|
||||
LoadParserFile("bbb_9tiles_18slices.vvc");
|
||||
H266NALU target_nalu;
|
||||
int sps_id;
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kSPS));
|
||||
EXPECT_EQ(H266Parser::kOk, parser_.ParseSPS(target_nalu, &sps_id));
|
||||
// Parsing of the SPS should generate fake VPS with vps_id = 0;
|
||||
const H266VPS* vps = parser_.GetVPS(0);
|
||||
EXPECT_TRUE(!!vps);
|
||||
const H266SPS* sps = parser_.GetSPS(sps_id);
|
||||
EXPECT_TRUE(!!sps);
|
||||
|
||||
EXPECT_TRUE(ParseNalusUntilNut(&target_nalu, H266NALU::kPH));
|
||||
H266PictureHeader ph;
|
||||
EXPECT_EQ(H266Parser::kInvalidStream, parser_.ParsePHNut(target_nalu, &ph));
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
Reference in New Issue
Block a user