use std::io::Read;
use media_codec_bitstream::{BigEndian, BitReader};
use media_core::{invalid_data_error, not_found_error, Result};
use smallvec::SmallVec;
use crate::{
constants::{MAX_PPS_COUNT, MAX_REFS},
nal::NalUnitType,
pps::Pps,
ps::ParameterSets,
};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[repr(u8)]
pub enum SliceType {
P = 0,
B = 1,
#[default]
I = 2,
SP = 3,
SI = 4,
}
impl SliceType {
pub fn from_u8(value: u8) -> Option<Self> {
match value % 5 {
0 => Some(Self::P),
1 => Some(Self::B),
2 => Some(Self::I),
3 => Some(Self::SP),
4 => Some(Self::SI),
_ => None,
}
}
#[inline]
pub fn is_all_same_type(value: u32) -> bool {
value >= 5
}
#[inline]
pub fn is_intra(&self) -> bool {
matches!(self, Self::I | Self::SI)
}
#[inline]
pub fn is_inter(&self) -> bool {
!self.is_intra()
}
#[inline]
pub fn is_b(&self) -> bool {
matches!(self, Self::B)
}
#[inline]
pub fn is_p(&self) -> bool {
matches!(self, Self::P)
}
#[inline]
pub fn is_sp(&self) -> bool {
matches!(self, Self::SP)
}
#[inline]
pub fn is_si(&self) -> bool {
matches!(self, Self::SI)
}
#[inline]
pub fn is_switching(&self) -> bool {
matches!(self, Self::SP | Self::SI)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum PictureStructure {
#[default]
Frame,
TopField,
BottomField,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RefPicListModOp {
SubtractFromPicNum(u32),
AddToPicNum(u32),
LongTermPicNum(u32),
End,
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct RefPicListModification {
pub modification_l0: SmallVec<[RefPicListModOp; MAX_REFS << 1]>,
pub modification_l1: SmallVec<[RefPicListModOp; MAX_REFS << 1]>,
}
impl RefPicListModification {
pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>, slice_type: SliceType) -> Result<Self> {
let mut rplm = Self::default();
if !slice_type.is_intra() {
let ref_pic_list_modification_flag_l0 = reader.read_bit()?;
if ref_pic_list_modification_flag_l0 {
rplm.modification_l0.reserve(MAX_REFS);
loop {
let modification_of_pic_nums_idc = reader.read_ue()?;
let op = match modification_of_pic_nums_idc {
0 => {
let abs_diff_pic_num = reader.read_ue()? + 1;
RefPicListModOp::SubtractFromPicNum(abs_diff_pic_num)
}
1 => {
let abs_diff_pic_num = reader.read_ue()? + 1;
RefPicListModOp::AddToPicNum(abs_diff_pic_num)
}
2 => {
let long_term_pic_num = reader.read_ue()?;
RefPicListModOp::LongTermPicNum(long_term_pic_num)
}
3 => RefPicListModOp::End,
_ => return Err(invalid_data_error!("modification_of_pic_nums_idc", modification_of_pic_nums_idc)),
};
rplm.modification_l0.push(op);
if matches!(op, RefPicListModOp::End) {
break;
}
}
}
}
if slice_type.is_b() {
let ref_pic_list_modification_flag_l1 = reader.read_bit()?;
if ref_pic_list_modification_flag_l1 {
rplm.modification_l1.reserve(MAX_REFS);
loop {
let modification_of_pic_nums_idc = reader.read_ue()?;
let op = match modification_of_pic_nums_idc {
0 => {
let abs_diff_pic_num = reader.read_ue()? + 1;
RefPicListModOp::SubtractFromPicNum(abs_diff_pic_num)
}
1 => {
let abs_diff_pic_num = reader.read_ue()? + 1;
RefPicListModOp::AddToPicNum(abs_diff_pic_num)
}
2 => {
let long_term_pic_num = reader.read_ue()?;
RefPicListModOp::LongTermPicNum(long_term_pic_num)
}
3 => RefPicListModOp::End,
_ => return Err(invalid_data_error!("modification_of_pic_nums_idc", modification_of_pic_nums_idc)),
};
rplm.modification_l1.push(op);
if matches!(op, RefPicListModOp::End) {
break;
}
}
}
}
Ok(rplm)
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PredWeightTable {
pub luma_log2_weight_denom: u32,
pub chroma_log2_weight_denom: u32,
pub luma_weight_l0: SmallVec<[i32; MAX_REFS]>,
pub luma_offset_l0: SmallVec<[i32; MAX_REFS]>,
pub chroma_weight_l0: SmallVec<[[i32; 2]; MAX_REFS]>,
pub chroma_offset_l0: SmallVec<[[i32; 2]; MAX_REFS]>,
pub luma_weight_l1: SmallVec<[i32; MAX_REFS]>,
pub luma_offset_l1: SmallVec<[i32; MAX_REFS]>,
pub chroma_weight_l1: SmallVec<[[i32; 2]; MAX_REFS]>,
pub chroma_offset_l1: SmallVec<[[i32; 2]; MAX_REFS]>,
}
impl PredWeightTable {
pub fn parse<R: Read>(
reader: &mut BitReader<R, BigEndian>,
slice_type: SliceType,
num_ref_idx_l0_active: u32,
num_ref_idx_l1_active: u32,
chroma_array_type: u8,
) -> Result<Self> {
let mut pwt = Self {
luma_log2_weight_denom: reader.read_ue()?,
..Default::default()
};
if chroma_array_type != 0 {
pwt.chroma_log2_weight_denom = reader.read_ue()?;
}
let default_luma_weight = 1i32 << pwt.luma_log2_weight_denom;
let default_chroma_weight = 1i32 << pwt.chroma_log2_weight_denom;
let num_l0 = num_ref_idx_l0_active as usize;
pwt.luma_weight_l0 = SmallVec::with_capacity(num_l0);
pwt.luma_offset_l0 = SmallVec::with_capacity(num_l0);
pwt.chroma_weight_l0 = SmallVec::with_capacity(num_l0);
pwt.chroma_offset_l0 = SmallVec::with_capacity(num_l0);
for _ in 0..num_l0 {
let luma_weight_l0_flag = reader.read_bit()?;
if luma_weight_l0_flag {
pwt.luma_weight_l0.push(reader.read_se()?);
pwt.luma_offset_l0.push(reader.read_se()?);
} else {
pwt.luma_weight_l0.push(default_luma_weight);
pwt.luma_offset_l0.push(0);
}
if chroma_array_type != 0 {
let chroma_weight_l0_flag = reader.read_bit()?;
if chroma_weight_l0_flag {
let w0 = reader.read_se()?;
let o0 = reader.read_se()?;
let w1 = reader.read_se()?;
let o1 = reader.read_se()?;
pwt.chroma_weight_l0.push([w0, w1]);
pwt.chroma_offset_l0.push([o0, o1]);
} else {
pwt.chroma_weight_l0.push([default_chroma_weight, default_chroma_weight]);
pwt.chroma_offset_l0.push([0, 0]);
}
}
}
if slice_type.is_b() {
let num_l1 = num_ref_idx_l1_active as usize;
pwt.luma_weight_l1 = SmallVec::with_capacity(num_l1);
pwt.luma_offset_l1 = SmallVec::with_capacity(num_l1);
pwt.chroma_weight_l1 = SmallVec::with_capacity(num_l1);
pwt.chroma_offset_l1 = SmallVec::with_capacity(num_l1);
for _ in 0..num_l1 {
let luma_weight_l1_flag = reader.read_bit()?;
if luma_weight_l1_flag {
pwt.luma_weight_l1.push(reader.read_se()?);
pwt.luma_offset_l1.push(reader.read_se()?);
} else {
pwt.luma_weight_l1.push(default_luma_weight);
pwt.luma_offset_l1.push(0);
}
if chroma_array_type != 0 {
let chroma_weight_l1_flag = reader.read_bit()?;
if chroma_weight_l1_flag {
let w0 = reader.read_se()?;
let o0 = reader.read_se()?;
let w1 = reader.read_se()?;
let o1 = reader.read_se()?;
pwt.chroma_weight_l1.push([w0, w1]);
pwt.chroma_offset_l1.push([o0, o1]);
} else {
pwt.chroma_weight_l1.push([default_chroma_weight, default_chroma_weight]);
pwt.chroma_offset_l1.push([0, 0]);
}
}
}
}
Ok(pwt)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MemoryManagementControlOp {
End,
ShortTermUnused { difference_of_pic_nums: u32 },
LongTermUnused { long_term_pic_num: u32 },
ShortTermToLongTerm { difference_of_pic_nums: u32, long_term_frame_idx: u32 },
MaxLongTermFrameIdx { max_long_term_frame_idx: i32 },
ClearAll,
CurrentToLongTerm { long_term_frame_idx: u32 },
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct DecRefPicMarking {
pub no_output_of_prior_pics_flag: bool,
pub long_term_reference_flag: bool,
pub adaptive_ref_pic_marking_mode_flag: bool,
pub memory_management_control_operations: SmallVec<[MemoryManagementControlOp; MAX_REFS << 2]>,
}
impl DecRefPicMarking {
pub fn parse<R: Read>(reader: &mut BitReader<R, BigEndian>, is_idr: bool) -> Result<Self> {
let mut drpm = Self::default();
if is_idr {
drpm.no_output_of_prior_pics_flag = reader.read_bit()?;
drpm.long_term_reference_flag = reader.read_bit()?;
} else {
drpm.adaptive_ref_pic_marking_mode_flag = reader.read_bit()?;
if drpm.adaptive_ref_pic_marking_mode_flag {
loop {
let memory_management_control_operation = reader.read_ue()?;
let op = match memory_management_control_operation {
0 => MemoryManagementControlOp::End,
1 => {
let difference_of_pic_nums = reader.read_ue()? + 1;
MemoryManagementControlOp::ShortTermUnused {
difference_of_pic_nums,
}
}
2 => {
let long_term_pic_num = reader.read_ue()?;
MemoryManagementControlOp::LongTermUnused {
long_term_pic_num,
}
}
3 => {
let difference_of_pic_nums = reader.read_ue()? + 1;
let long_term_frame_idx = reader.read_ue()?;
MemoryManagementControlOp::ShortTermToLongTerm {
difference_of_pic_nums,
long_term_frame_idx,
}
}
4 => {
let max_long_term_frame_idx = reader.read_ue()? as i32 - 1;
MemoryManagementControlOp::MaxLongTermFrameIdx {
max_long_term_frame_idx,
}
}
5 => MemoryManagementControlOp::ClearAll,
6 => {
let long_term_frame_idx = reader.read_ue()?;
MemoryManagementControlOp::CurrentToLongTerm {
long_term_frame_idx,
}
}
_ => return Err(invalid_data_error!("memory_management_control_operation", memory_management_control_operation)),
};
drpm.memory_management_control_operations.push(op);
if matches!(op, MemoryManagementControlOp::End) {
break;
}
}
}
}
Ok(drpm)
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct SliceHeader {
pub first_mb_in_slice: u32,
pub slice_type: SliceType,
pub pic_parameter_set_id: u8,
pub colour_plane_id: u8,
pub frame_num: u32,
pub field_pic_flag: bool,
pub bottom_field_flag: bool,
pub picture_structure: PictureStructure,
pub idr_pic_id: u32,
pub pic_order_cnt_lsb: u32,
pub delta_pic_order_cnt_bottom: i32,
pub delta_pic_order_cnt_0: i32,
pub delta_pic_order_cnt_1: i32,
pub redundant_pic_cnt: u32,
pub direct_spatial_mv_pred_flag: bool,
pub num_ref_idx_active_override_flag: bool,
pub num_ref_idx_l0_active: u32,
pub num_ref_idx_l1_active: u32,
pub ref_pic_list_modification: Option<RefPicListModification>,
pub pred_weight_table: Option<PredWeightTable>,
pub dec_ref_pic_marking: Option<DecRefPicMarking>,
pub cabac_init_idc: u32,
pub slice_qp_delta: i32,
pub sp_for_switch_flag: bool,
pub slice_qs_delta: i32,
pub slice_qs: u32,
pub chroma_qp_cb: u8,
pub chroma_qp_cr: u8,
pub disable_deblocking_filter_idc: u32,
pub slice_alpha_c0_offset: i32,
pub slice_beta_offset: i32,
pub slice_group_change_cycle: u32,
}
impl SliceHeader {
pub fn parse(data: &[u8], nal_unit_type: NalUnitType, nal_ref_idc: u8, param_sets: &ParameterSets) -> Result<Self> {
let mut reader = BitReader::new(data);
Self::parse_from_bit_reader(&mut reader, nal_unit_type, nal_ref_idc, param_sets)
}
pub fn parse_from_bit_reader<R: Read>(
reader: &mut BitReader<R, BigEndian>,
nal_unit_type: NalUnitType,
nal_ref_idc: u8,
param_sets: &ParameterSets,
) -> Result<Self> {
let mut header = Self::default();
let is_idr = matches!(nal_unit_type, NalUnitType::SliceIdr);
header.first_mb_in_slice = reader.read_ue()?;
let slice_type_raw = reader.read_ue()? as u8;
header.slice_type = SliceType::from_u8(slice_type_raw).ok_or_else(|| invalid_data_error!("slice_type", slice_type_raw))?;
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));
}
header.pic_parameter_set_id = pic_parameter_set_id as u8;
let pps = param_sets.get_pps(pic_parameter_set_id).ok_or_else(|| not_found_error!("pps_id", pic_parameter_set_id))?;
let sps = param_sets.get_sps(pps.seq_parameter_set_id as u32).ok_or_else(|| not_found_error!("sps_id", pps.seq_parameter_set_id))?;
if sps.separate_colour_plane_flag {
header.colour_plane_id = reader.read::<2, u8>()?;
}
let frame_num_bits = sps.log2_max_frame_num;
header.frame_num = reader.read_var(frame_num_bits)?;
header.picture_structure = if !sps.frame_mbs_only_flag && reader.read_bit()? {
header.field_pic_flag = true;
if reader.read_bit()? {
header.bottom_field_flag = true;
PictureStructure::BottomField
} else {
PictureStructure::TopField
}
} else {
PictureStructure::Frame
};
if is_idr {
header.idr_pic_id = reader.read_ue()?;
}
if sps.pic_order_cnt_type == 0 {
let poc_lsb_bits = sps.log2_max_pic_order_cnt_lsb;
header.pic_order_cnt_lsb = reader.read_var(poc_lsb_bits)?;
if pps.bottom_field_pic_order_in_frame_present_flag && !header.field_pic_flag {
header.delta_pic_order_cnt_bottom = reader.read_se()?;
}
}
if sps.pic_order_cnt_type == 1 && !sps.delta_pic_order_always_zero_flag {
header.delta_pic_order_cnt_0 = reader.read_se()?;
if pps.bottom_field_pic_order_in_frame_present_flag && !header.field_pic_flag {
header.delta_pic_order_cnt_1 = reader.read_se()?;
}
}
if pps.redundant_pic_cnt_present_flag {
header.redundant_pic_cnt = reader.read_ue()?;
}
if header.slice_type.is_b() {
header.direct_spatial_mv_pred_flag = reader.read_bit()?;
}
if header.slice_type.is_p() || header.slice_type.is_sp() || header.slice_type.is_b() {
header.num_ref_idx_active_override_flag = reader.read_bit()?;
if header.num_ref_idx_active_override_flag {
let num_ref_idx_l0_active_minus1 = reader.read_ue()?;
if num_ref_idx_l0_active_minus1 as usize > MAX_REFS {
return Err(invalid_data_error!("num_ref_idx_l0_active_minus1", num_ref_idx_l0_active_minus1));
}
header.num_ref_idx_l0_active = num_ref_idx_l0_active_minus1 + 1;
if header.slice_type.is_b() {
let num_ref_idx_l1_active_minus1 = reader.read_ue()?;
if num_ref_idx_l1_active_minus1 as usize > MAX_REFS {
return Err(invalid_data_error!("num_ref_idx_l1_active_minus1", num_ref_idx_l1_active_minus1));
}
header.num_ref_idx_l1_active = num_ref_idx_l1_active_minus1 + 1;
}
} else {
header.num_ref_idx_l0_active = pps.num_ref_idx_l0_default_active;
header.num_ref_idx_l1_active = pps.num_ref_idx_l1_default_active;
}
}
if !header.slice_type.is_intra() {
header.ref_pic_list_modification = Some(RefPicListModification::parse(reader, header.slice_type)?);
}
let chroma_array_type = if sps.separate_colour_plane_flag {
0
} else {
sps.chroma_format as u8
};
if (pps.weighted_pred_flag && (header.slice_type.is_p() || header.slice_type.is_sp())) ||
(pps.weighted_bipred_idc == 1 && header.slice_type.is_b())
{
header.pred_weight_table = Some(PredWeightTable::parse(
reader,
header.slice_type,
header.num_ref_idx_l0_active,
header.num_ref_idx_l1_active,
chroma_array_type,
)?);
}
if nal_ref_idc != 0 {
header.dec_ref_pic_marking = Some(DecRefPicMarking::parse(reader, is_idr)?);
}
if pps.entropy_coding_mode_flag && !header.slice_type.is_intra() {
header.cabac_init_idc = reader.read_ue()?;
if header.cabac_init_idc > 2 {
return Err(invalid_data_error!("cabac_init_idc", header.cabac_init_idc));
}
}
header.slice_qp_delta = reader.read_se()?;
let qp_offset = 6 * (sps.bit_depth_luma as i32 - 8);
let slice_qp = header.slice_qp(pps);
if slice_qp < 0 || slice_qp > 51 + qp_offset {
return Err(invalid_data_error!("slice_qp_delta", header.slice_qp_delta));
}
if header.slice_type.is_sp() || header.slice_type.is_si() {
if header.slice_type.is_sp() {
header.sp_for_switch_flag = reader.read_bit()?;
}
header.slice_qs_delta = reader.read_se()?;
let slice_qs = header.slice_qs(pps);
if !(0..=51).contains(&slice_qs) {
return Err(invalid_data_error!("slice_qs_delta", header.slice_qs_delta));
}
header.slice_qs = slice_qs as u32;
}
header.chroma_qp_cb = pps.chroma_qp_tables.get_cb(slice_qp);
header.chroma_qp_cr = pps.chroma_qp_tables.get_cr(slice_qp);
if pps.deblocking_filter_control_present_flag {
header.disable_deblocking_filter_idc = reader.read_ue()?;
if header.disable_deblocking_filter_idc > 2 {
return Err(invalid_data_error!("disable_deblocking_filter_idc", header.disable_deblocking_filter_idc));
}
if header.disable_deblocking_filter_idc != 1 {
let slice_alpha_c0_offset_div2: i32 = reader.read_se()?;
let slice_beta_offset_div2: i32 = reader.read_se()?;
if !(-6..=6).contains(&slice_alpha_c0_offset_div2) {
return Err(invalid_data_error!("slice_alpha_c0_offset_div2", slice_alpha_c0_offset_div2));
}
if !(-6..=6).contains(&slice_beta_offset_div2) {
return Err(invalid_data_error!("slice_beta_offset_div2", slice_beta_offset_div2));
}
header.slice_alpha_c0_offset = slice_alpha_c0_offset_div2 * 2;
header.slice_beta_offset = slice_beta_offset_div2 * 2;
}
}
if pps.num_slice_groups > 1 {
if let Some(ref sg_params) = pps.slice_group_params {
let map_type = sg_params.slice_group_map_type as u8;
if (3..=5).contains(&map_type) {
let pic_size_in_map_units = sps.pic_width_in_mbs * sps.pic_height_in_map_units;
let slice_group_change_rate = sg_params.slice_group_change_rate;
let bits_needed = (32 - ((pic_size_in_map_units - 1) / slice_group_change_rate + 1).leading_zeros()).max(1);
header.slice_group_change_cycle = reader.read_var(bits_needed)?;
}
}
}
Ok(header)
}
#[inline]
pub fn slice_qp(&self, pps: &Pps) -> i32 {
pps.pic_init_qp + self.slice_qp_delta
}
#[inline]
pub fn slice_qs(&self, pps: &Pps) -> i32 {
pps.pic_init_qs + self.slice_qs_delta
}
#[inline]
pub fn is_first_mb_in_pic(&self) -> bool {
self.first_mb_in_slice == 0
}
#[inline]
pub fn is_field_pic(&self) -> bool {
self.field_pic_flag
}
#[inline]
pub fn is_bottom_field(&self) -> bool {
self.field_pic_flag && self.bottom_field_flag
}
#[inline]
pub fn is_top_field(&self) -> bool {
self.field_pic_flag && !self.bottom_field_flag
}
#[inline]
pub fn is_frame(&self) -> bool {
!self.field_pic_flag
}
#[inline]
pub fn alpha_c0_offset(&self) -> i32 {
self.slice_alpha_c0_offset
}
#[inline]
pub fn beta_offset(&self) -> i32 {
self.slice_beta_offset
}
#[inline]
pub fn is_deblocking_filter_disabled(&self) -> bool {
self.disable_deblocking_filter_idc == 1
}
#[inline]
pub fn deblocking_filter_crosses_slices(&self) -> bool {
self.disable_deblocking_filter_idc != 2
}
}