use crate::DecodeError;
use mediaway_sw::h264::BitReader;
use super::pps::Pps;
use super::sps::Sps;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct SliceHeader {
pub(super) first_mb_in_slice: u32,
pub(super) slice_type: u8,
pub(super) pic_parameter_set_id: u32,
pub(super) frame_num: u32,
pub(super) pic_order_cnt_lsb: u32,
pub(super) slice_qp_delta: i32,
pub(super) disable_deblocking_filter_idc: u8,
pub(super) slice_alpha_c0_offset_div2: i32,
pub(super) slice_beta_offset_div2: i32,
pub(super) bits_consumed: usize,
}
impl SliceHeader {
pub(super) fn parse(
rbsp: &[u8],
nal_ref_idc: u8,
sps: &Sps,
pps: &Pps,
) -> Result<Self, DecodeError> {
let mut r = BitReader::new(rbsp);
let map_err = |_| DecodeError::InvalidInput;
let first_mb_in_slice = r.read_ue().map_err(map_err)?;
if first_mb_in_slice != 0 {
return Err(DecodeError::Unsupported);
}
let slice_type_raw = r.read_ue().map_err(map_err)?;
let slice_type = u8::try_from(slice_type_raw % 5).unwrap_or(u8::MAX);
if slice_type != 2 {
return Err(DecodeError::Unsupported);
}
let pic_parameter_set_id = r.read_ue().map_err(map_err)?;
let frame_num_bits = sps.log2_max_frame_num_minus4 + 4;
let frame_num = r.read_bits(frame_num_bits).map_err(map_err)?;
let _idr_pic_id = r.read_ue().map_err(map_err)?;
let poc_lsb_bits = sps.log2_max_pic_order_cnt_lsb_minus4 + 4;
let pic_order_cnt_lsb = r.read_bits(poc_lsb_bits).map_err(map_err)?;
if pps.pic_order_present_flag {
let _delta_pic_order_cnt_bottom = r.read_se().map_err(map_err)?;
}
if pps.redundant_pic_cnt_present_flag {
let redundant_pic_cnt = r.read_ue().map_err(map_err)?;
if redundant_pic_cnt != 0 {
return Err(DecodeError::Unsupported);
}
}
if nal_ref_idc != 0 {
let _no_output_of_prior_pics_flag = r.read_bit().map_err(map_err)?;
let _long_term_reference_flag = r.read_bit().map_err(map_err)?;
}
let slice_qp_delta = r.read_se().map_err(map_err)?;
let (disable_deblocking_filter_idc, slice_alpha_c0_offset_div2, slice_beta_offset_div2) =
if pps.deblocking_filter_control_present_flag {
let idc_raw = r.read_ue().map_err(map_err)?;
let idc = u8::try_from(idc_raw).map_err(|_| DecodeError::InvalidInput)?;
if idc == 1 {
(idc, 0, 0)
} else {
let alpha = r.read_se().map_err(map_err)?;
let beta = r.read_se().map_err(map_err)?;
(idc, alpha, beta)
}
} else {
(0u8, 0i32, 0i32)
};
let bits_consumed = r.bits_read();
Ok(Self {
first_mb_in_slice,
slice_type,
pic_parameter_set_id,
frame_num,
pic_order_cnt_lsb,
slice_qp_delta,
disable_deblocking_filter_idc,
slice_alpha_c0_offset_div2,
slice_beta_offset_div2,
bits_consumed,
})
}
}
#[cfg(test)]
#[path = "slice_tests.rs"]
mod tests;