use std::io::Read;
use media_codec_bitstream::{BigEndian, BitReader};
use media_core::{invalid_data_error, none_param_error, not_found_error, Result};
use smallvec::SmallVec;
use crate::{
constants::{MAX_PPS_COUNT, MAX_QP_OFFSET, MAX_REFS, MAX_SPS_COUNT, MAX_TILE_COLUMNS, MAX_TILE_ROWS, MIN_QP_OFFSET},
ps::ParameterSets,
scaling_list::ScalingListData,
sps::{ChromaFormat, Sps},
};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TileInfo {
pub num_tile_columns: u32,
pub num_tile_rows: u32,
pub uniform_spacing_flag: bool,
pub column_width: SmallVec<[u32; MAX_TILE_COLUMNS]>,
pub row_height: SmallVec<[u32; MAX_TILE_ROWS]>,
pub loop_filter_across_tiles_enabled_flag: bool,
}
impl TileInfo {
pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>) -> Result<Self> {
let num_tile_columns = reader.read_ue()? + 1;
let num_tile_rows = reader.read_ue()? + 1;
let uniform_spacing_flag = reader.read_bit()?;
let mut column_width = SmallVec::new();
let mut row_height = SmallVec::new();
if !uniform_spacing_flag {
column_width.reserve((num_tile_columns - 1) as usize);
for _ in 0..(num_tile_columns - 1) {
column_width.push(reader.read_ue()? + 1);
}
row_height.reserve((num_tile_rows - 1) as usize);
for _ in 0..(num_tile_rows - 1) {
row_height.push(reader.read_ue()? + 1);
}
}
let loop_filter_across_tiles_enabled_flag = reader.read_bit()?;
Ok(Self {
num_tile_columns,
num_tile_rows,
uniform_spacing_flag,
column_width,
row_height,
loop_filter_across_tiles_enabled_flag,
})
}
#[inline]
pub fn num_tile_columns(&self) -> u32 {
self.num_tile_columns
}
#[inline]
pub fn num_tile_rows(&self) -> u32 {
self.num_tile_rows
}
#[inline]
pub fn num_tiles(&self) -> u32 {
self.num_tile_columns() * self.num_tile_rows()
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DeblockingFilterParams {
pub deblocking_filter_override_enabled_flag: bool,
pub pps_deblocking_filter_disabled_flag: bool,
pub pps_beta_offset: i32,
pub pps_tc_offset: i32,
}
impl DeblockingFilterParams {
pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>) -> Result<Self> {
let deblocking_filter_override_enabled_flag = reader.read_bit()?;
let pps_deblocking_filter_disabled_flag = reader.read_bit()?;
let (pps_beta_offset, pps_tc_offset) = if !pps_deblocking_filter_disabled_flag {
(reader.read_se()? * 2, reader.read_se()? * 2)
} else {
(0, 0)
};
Ok(Self {
deblocking_filter_override_enabled_flag,
pps_deblocking_filter_disabled_flag,
pps_beta_offset,
pps_tc_offset,
})
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Pps {
pub pic_parameter_set_id: u8,
pub seq_parameter_set_id: u8,
pub dependent_slice_segments_enabled_flag: bool,
pub output_flag_present_flag: bool,
pub num_extra_slice_header_bits: u8,
pub sign_data_hiding_enabled_flag: bool,
pub cabac_init_present_flag: bool,
pub num_ref_idx_l0_default_active: u32,
pub num_ref_idx_l1_default_active: u32,
pub init_qp: i32,
pub constrained_intra_pred_flag: bool,
pub transform_skip_enabled_flag: bool,
pub cu_qp_delta_enabled_flag: bool,
pub diff_cu_qp_delta_depth: u32,
pub pps_cb_qp_offset: i32,
pub pps_cr_qp_offset: i32,
pub pps_slice_chroma_qp_offsets_present_flag: bool,
pub weighted_pred_flag: bool,
pub weighted_bipred_flag: bool,
pub transquant_bypass_enabled_flag: bool,
pub tiles_enabled_flag: bool,
pub entropy_coding_sync_enabled_flag: bool,
pub tile_info: Option<TileInfo>,
pub pps_loop_filter_across_slices_enabled_flag: bool,
pub deblocking_filter_control_present_flag: bool,
pub deblocking_filter_params: Option<DeblockingFilterParams>,
pub pps_scaling_list_data_present_flag: bool,
pub scaling_list_data: Option<ScalingListData>,
pub lists_modification_present_flag: bool,
pub log2_parallel_merge_level: u32,
pub slice_segment_header_extension_present_flag: bool,
pub pps_extension_present_flag: bool,
pub pps_range_extension_flag: bool,
pub pps_multilayer_extension_flag: bool,
pub pps_3d_extension_flag: bool,
pub pps_scc_extension_flag: bool,
pub pps_extension_4bits: u8,
}
impl Pps {
pub fn parse_ids(data: &[u8]) -> Result<(u8, u8)> {
let mut reader = BitReader::new(data);
Self::parse_ids_from_bit_reader(&mut reader)
}
pub fn parse_with_sps(data: &[u8], sps: &Sps) -> Result<Self> {
let mut reader = BitReader::new(data);
Self::parse_from_bit_reader(&mut reader, Some(sps), None)
}
pub fn parse_with_param_sets(data: &[u8], param_sets: &ParameterSets) -> Result<Self> {
let mut reader = BitReader::new(data);
Self::parse_from_bit_reader(&mut reader, None, Some(param_sets))
}
pub fn parse_ids_from_bit_reader<R: Read>(reader: &mut BitReader<R, BigEndian>) -> Result<(u8, u8)> {
let pic_parameter_set_id = reader.read_ue()?;
if pic_parameter_set_id as usize >= MAX_PPS_COUNT {
return Err(invalid_data_error!("pps_id", pic_parameter_set_id));
}
let pic_parameter_set_id = pic_parameter_set_id as u8;
let seq_parameter_set_id = reader.read_ue()?;
if seq_parameter_set_id as usize >= MAX_SPS_COUNT {
return Err(invalid_data_error!("sps_id", seq_parameter_set_id));
}
let seq_parameter_set_id = seq_parameter_set_id as u8;
Ok((pic_parameter_set_id, seq_parameter_set_id))
}
pub fn parse_from_bit_reader<R: Read>(
reader: &mut BitReader<R, BigEndian>,
sps: Option<&Sps>,
param_sets: Option<&ParameterSets>,
) -> Result<Self> {
let (pic_parameter_set_id, seq_parameter_set_id) = Self::parse_ids_from_bit_reader(reader)?;
let sps = if let Some(sps) = sps {
if seq_parameter_set_id != sps.seq_parameter_set_id {
return Err(invalid_data_error!("sps_id", seq_parameter_set_id));
}
sps
} else if let Some(param_sets) = param_sets {
param_sets.get_sps(seq_parameter_set_id as u32).ok_or_else(|| not_found_error!("sps_id", seq_parameter_set_id))?
} else {
return Err(none_param_error!("sps or param_sets"));
};
let dependent_slice_segments_enabled_flag = reader.read_bit()?;
let output_flag_present_flag = reader.read_bit()?;
let num_extra_slice_header_bits = reader.read::<3, u8>()?;
let sign_data_hiding_enabled_flag = reader.read_bit()?;
let cabac_init_present_flag = reader.read_bit()?;
let num_ref_idx_l0_default_active = reader.read_ue()? + 1;
if num_ref_idx_l0_default_active as usize > MAX_REFS {
return Err(invalid_data_error!("num_ref_idx_l0_default_active", num_ref_idx_l0_default_active));
}
let num_ref_idx_l1_default_active = reader.read_ue()? + 1;
if num_ref_idx_l1_default_active as usize > MAX_REFS {
return Err(invalid_data_error!("num_ref_idx_l1_default_active", num_ref_idx_l1_default_active));
}
let init_qp = reader.read_se()? + 26;
let constrained_intra_pred_flag = reader.read_bit()?;
let transform_skip_enabled_flag = reader.read_bit()?;
let cu_qp_delta_enabled_flag = reader.read_bit()?;
let diff_cu_qp_delta_depth = if cu_qp_delta_enabled_flag {
reader.read_ue()?
} else {
0
};
let pps_cb_qp_offset = reader.read_se()?;
if !(MIN_QP_OFFSET..=MAX_QP_OFFSET).contains(&pps_cb_qp_offset) {
return Err(invalid_data_error!("pps_cb_qp_offset", pps_cb_qp_offset));
}
let pps_cr_qp_offset = reader.read_se()?;
if !(MIN_QP_OFFSET..=MAX_QP_OFFSET).contains(&pps_cr_qp_offset) {
return Err(invalid_data_error!("pps_cr_qp_offset", pps_cr_qp_offset));
}
let pps_slice_chroma_qp_offsets_present_flag = reader.read_bit()?;
let weighted_pred_flag = reader.read_bit()?;
let weighted_bipred_flag = reader.read_bit()?;
let transquant_bypass_enabled_flag = reader.read_bit()?;
let tiles_enabled_flag = reader.read_bit()?;
let entropy_coding_sync_enabled_flag = reader.read_bit()?;
let tile_info = if tiles_enabled_flag {
Some(TileInfo::parse(reader)?)
} else {
None
};
let pps_loop_filter_across_slices_enabled_flag = reader.read_bit()?;
let deblocking_filter_control_present_flag = reader.read_bit()?;
let deblocking_filter_params = if deblocking_filter_control_present_flag {
Some(DeblockingFilterParams::parse(reader)?)
} else {
None
};
let pps_scaling_list_data_present_flag = reader.read_bit()?;
let scaling_list_data = if pps_scaling_list_data_present_flag {
let is_444 = sps.chroma_format == ChromaFormat::YUV444;
Some(ScalingListData::parse(reader, is_444)?)
} else {
None
};
let lists_modification_present_flag = reader.read_bit()?;
let log2_parallel_merge_level = reader.read_ue()? + 2;
let slice_segment_header_extension_present_flag = reader.read_bit()?;
let pps_extension_present_flag = reader.read_bit()?;
let (pps_range_extension_flag, pps_multilayer_extension_flag, pps_3d_extension_flag, pps_scc_extension_flag, pps_extension_4bits) =
if pps_extension_present_flag {
(reader.read_bit()?, reader.read_bit()?, reader.read_bit()?, reader.read_bit()?, reader.read::<4, u8>()?)
} else {
(false, false, false, false, 0)
};
Ok(Self {
pic_parameter_set_id,
seq_parameter_set_id,
dependent_slice_segments_enabled_flag,
output_flag_present_flag,
num_extra_slice_header_bits,
sign_data_hiding_enabled_flag,
cabac_init_present_flag,
num_ref_idx_l0_default_active,
num_ref_idx_l1_default_active,
init_qp,
constrained_intra_pred_flag,
transform_skip_enabled_flag,
cu_qp_delta_enabled_flag,
diff_cu_qp_delta_depth,
pps_cb_qp_offset,
pps_cr_qp_offset,
pps_slice_chroma_qp_offsets_present_flag,
weighted_pred_flag,
weighted_bipred_flag,
transquant_bypass_enabled_flag,
tiles_enabled_flag,
entropy_coding_sync_enabled_flag,
tile_info,
pps_loop_filter_across_slices_enabled_flag,
deblocking_filter_control_present_flag,
deblocking_filter_params,
pps_scaling_list_data_present_flag,
scaling_list_data,
lists_modification_present_flag,
log2_parallel_merge_level,
slice_segment_header_extension_present_flag,
pps_extension_present_flag,
pps_range_extension_flag,
pps_multilayer_extension_flag,
pps_3d_extension_flag,
pps_scc_extension_flag,
pps_extension_4bits,
})
}
#[inline]
pub fn number_of_reference_index_l0_default_active(&self) -> u32 {
self.num_ref_idx_l0_default_active
}
#[inline]
pub fn number_of_reference_index_l1_default_active(&self) -> u32 {
self.num_ref_idx_l1_default_active
}
#[inline]
pub fn init_qp(&self) -> i32 {
self.init_qp
}
#[inline]
pub fn log2_parallel_merge_level(&self) -> u32 {
self.log2_parallel_merge_level
}
#[inline]
pub fn has_weighted_prediction(&self) -> bool {
self.weighted_pred_flag
}
#[inline]
pub fn has_weighted_bi_prediction(&self) -> bool {
self.weighted_bipred_flag
}
#[inline]
pub fn has_tiles(&self) -> bool {
self.tiles_enabled_flag
}
#[inline]
pub fn has_wpp(&self) -> bool {
self.entropy_coding_sync_enabled_flag
}
#[inline]
pub fn has_transform_skip(&self) -> bool {
self.transform_skip_enabled_flag
}
#[inline]
pub fn has_cu_qp_delta(&self) -> bool {
self.cu_qp_delta_enabled_flag
}
#[inline]
pub fn is_deblocking_filter_disabled(&self) -> bool {
self.deblocking_filter_params.as_ref().is_some_and(|p| p.pps_deblocking_filter_disabled_flag)
}
#[inline]
pub fn cb_qp_offset(&self) -> i32 {
self.pps_cb_qp_offset
}
#[inline]
pub fn cr_qp_offset(&self) -> i32 {
self.pps_cr_qp_offset
}
#[inline]
pub fn num_tile_columns(&self) -> u32 {
self.tile_info.as_ref().map_or(1, |t| t.num_tile_columns())
}
#[inline]
pub fn num_tile_rows(&self) -> u32 {
self.tile_info.as_ref().map_or(1, |t| t.num_tile_rows())
}
#[inline]
pub fn num_tiles(&self) -> u32 {
self.tile_info.as_ref().map_or(1, |t| t.num_tiles())
}
}