use super::rbsp::{unescape_rbsp, BitReader};
use super::sps::{skip_scaling_list, SpsSummary};
pub(super) fn parse_pps(pps: &[u8], sps_context: &[SpsSummary]) -> Result<(u32, usize), String> {
let rbsp = unescape_rbsp(&pps[1..]);
let mut r = BitReader::new(&rbsp);
let pps_id = r.ue()?;
if pps_id > 255 {
return Err(format!("pic_parameter_set_id {pps_id} exceeds 255"));
}
let sps_id = r.ue()?;
if sps_id > 31 {
return Err(format!("seq_parameter_set_id {sps_id} exceeds 31"));
}
let (bound_index, sps) = sps_context
.iter()
.enumerate()
.rev()
.find(|(_, s)| s.sps_id == sps_id)
.ok_or_else(|| {
format!("references seq_parameter_set_id {sps_id}, which no preceding SPS in the configuration carries")
})?;
r.bits(1)?; r.bits(1)?; let num_slice_groups_minus1 = r.ue()?;
if num_slice_groups_minus1 > 7 {
return Err(format!(
"num_slice_groups_minus1 {num_slice_groups_minus1} exceeds 7"
));
}
if num_slice_groups_minus1 > 0 {
check_slice_group_map(&mut r, num_slice_groups_minus1, sps)?;
}
let num_ref_idx_l0 = r.ue()?;
let num_ref_idx_l1 = r.ue()?;
if num_ref_idx_l0 > 31 || num_ref_idx_l1 > 31 {
return Err(format!(
"num_ref_idx_l0/l1_default_active_minus1 {num_ref_idx_l0}/{num_ref_idx_l1} \
exceeds 31"
));
}
r.bits(1)?; let weighted_bipred_idc = r.bits(2)?;
if weighted_bipred_idc > 2 {
return Err(format!(
"weighted_bipred_idc {weighted_bipred_idc} (must be <= 2)"
));
}
let pic_init_qp_minus26 = r.se()?;
let qp_floor = -(26 + 6 * (sps.bit_depth_luma as i64 - 8));
if !(qp_floor..=25).contains(&pic_init_qp_minus26) {
return Err(format!(
"pic_init_qp_minus26 {pic_init_qp_minus26} outside [{qp_floor}, 25] \
(the referenced SPS codes {}-bit luma)",
sps.bit_depth_luma
));
}
let pic_init_qs_minus26 = r.se()?;
if !(-26..=25).contains(&pic_init_qs_minus26) {
return Err(format!(
"pic_init_qs_minus26 {pic_init_qs_minus26} outside [-26, 25]"
));
}
let chroma_qp_index_offset = r.se()?;
if !(-12..=12).contains(&chroma_qp_index_offset) {
return Err(format!(
"chroma_qp_index_offset {chroma_qp_index_offset} outside [-12, 12]"
));
}
r.bits(1)?; r.bits(1)?; r.bits(1)?; if r.more_rbsp_data() {
let transform_8x8_mode_flag = r.bits(1)? == 1;
if r.bits(1)? == 1 {
let lists = 6
+ if transform_8x8_mode_flag {
if sps.chroma_format_idc != 3 {
2
} else {
6
}
} else {
0
};
for i in 0..lists {
if r.bits(1)? == 1 {
skip_scaling_list(&mut r, if i < 6 { 16 } else { 64 })?;
}
}
}
let second_chroma_qp_index_offset = r.se()?;
if !(-12..=12).contains(&second_chroma_qp_index_offset) {
return Err(format!(
"second_chroma_qp_index_offset {second_chroma_qp_index_offset} \
outside [-12, 12]"
));
}
}
r.finish_rbsp()?;
Ok((pps_id, bound_index))
}
fn check_slice_group_map(
r: &mut BitReader,
num_slice_groups_minus1: u32,
sps: &SpsSummary,
) -> Result<(), String> {
let pic_size_in_map_units =
sps.pic_width_in_mbs as u64 * sps.pic_height_in_map_units as u64;
let map_type = r.ue()?;
match map_type {
0 => {
for _ in 0..=num_slice_groups_minus1 {
let run_length_minus1 = r.ue()?;
if run_length_minus1 as u64 >= pic_size_in_map_units {
return Err(format!(
"slice-group run_length_minus1 {run_length_minus1} reaches past \
the {pic_size_in_map_units} map units of the referenced SPS"
));
}
}
}
1 => {}
2 => {
for _ in 0..num_slice_groups_minus1 {
let top_left = r.ue()?;
let bottom_right = r.ue()?;
if bottom_right as u64 >= pic_size_in_map_units {
return Err(format!(
"slice-group bottom_right {bottom_right} is outside the \
{pic_size_in_map_units} map units of the referenced SPS"
));
}
let width = sps.pic_width_in_mbs;
if top_left > bottom_right || top_left % width > bottom_right % width {
return Err(format!(
"slice-group rectangle {top_left}..{bottom_right} is inverted \
(7.4.2.2 orders both corners, by map unit and by column)"
));
}
}
}
3..=5 => {
if num_slice_groups_minus1 != 1 {
return Err(format!(
"slice_group_map_type {map_type} requires exactly two slice groups \
(num_slice_groups_minus1 is {num_slice_groups_minus1})"
));
}
r.bits(1)?; let change_rate_minus1 = r.ue()?;
if change_rate_minus1 as u64 >= pic_size_in_map_units {
return Err(format!(
"slice_group_change_rate_minus1 {change_rate_minus1} reaches past \
the {pic_size_in_map_units} map units of the referenced SPS"
));
}
}
6 => {
let pic_size_in_map_units_minus1 = r.ue()?;
if pic_size_in_map_units_minus1 as u64 + 1 != pic_size_in_map_units {
return Err(format!(
"slice-group table declares {} map units but the referenced SPS \
codes {pic_size_in_map_units}",
pic_size_in_map_units_minus1 as u64 + 1
));
}
let width = 32 - num_slice_groups_minus1.leading_zeros();
for _ in 0..=pic_size_in_map_units_minus1 {
let slice_group_id = r.bits(width)?;
if slice_group_id > num_slice_groups_minus1 {
return Err(format!(
"slice_group_id {slice_group_id} exceeds \
num_slice_groups_minus1 {num_slice_groups_minus1}"
));
}
}
}
other => return Err(format!("slice_group_map_type {other} (must be <= 6)")),
}
Ok(())
}