use super::bitstream::BitReader;
use crate::CodecError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PictureFormat {
Forbidden,
SubQcif,
Qcif,
Cif,
FourCif,
SixteenCif,
Reserved,
Extended,
}
impl PictureFormat {
#[must_use]
pub const fn dimensions(&self) -> Option<(u32, u32)> {
match self {
Self::SubQcif => Some((128, 96)),
Self::Qcif => Some((176, 144)),
Self::Cif => Some((352, 288)),
Self::FourCif => Some((704, 576)),
Self::SixteenCif => Some((1408, 1152)),
Self::Forbidden | Self::Reserved | Self::Extended => None,
}
}
#[must_use]
pub const fn from_code(code: u8) -> Self {
match code {
0 => Self::Forbidden,
1 => Self::SubQcif,
2 => Self::Qcif,
3 => Self::Cif,
4 => Self::FourCif,
5 => Self::SixteenCif,
6 => Self::Reserved,
7 => Self::Extended,
_ => Self::Forbidden,
}
}
#[must_use]
pub const fn to_code(&self) -> u8 {
match self {
Self::Forbidden => 0,
Self::SubQcif => 1,
Self::Qcif => 2,
Self::Cif => 3,
Self::FourCif => 4,
Self::SixteenCif => 5,
Self::Reserved => 6,
Self::Extended => 7,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PictureCodingType {
Intra,
Inter,
}
#[derive(Clone, Debug)]
pub struct PictureHeader {
pub temporal_reference: u8,
pub picture_type: PictureCodingType,
pub source_format: PictureFormat,
pub width: Option<u32>,
pub height: Option<u32>,
pub quantizer: u8,
pub umv_mode: bool,
pub sac_mode: bool,
pub ap_mode: bool,
pub pb_frames_mode: bool,
pub cpm_enabled: bool,
pub psbi: Option<u8>,
pub tss_mode: bool,
}
impl PictureHeader {
pub fn parse(reader: &mut BitReader<'_>) -> Result<Self, CodecError> {
let psc = reader.read_bits(22)?;
if psc != 0x20 {
return Err(CodecError::InvalidData(format!(
"Invalid picture start code: 0x{psc:06X}"
)));
}
let temporal_reference = reader.read_bits(8)? as u8;
let marker = reader.read_bit()?;
if !marker {
return Err(CodecError::InvalidData("PTYPE marker bit not set".into()));
}
let split_screen = reader.read_bit()?;
if split_screen {
return Err(CodecError::InvalidData("Split screen not supported".into()));
}
let _doc_camera = reader.read_bit()?;
let _freeze_picture = reader.read_bit()?;
let source_format_code = reader.read_bits(3)? as u8;
let source_format = PictureFormat::from_code(source_format_code);
let picture_type = if reader.read_bit()? {
PictureCodingType::Inter
} else {
PictureCodingType::Intra
};
let umv_mode = reader.read_bit()?;
let sac_mode = reader.read_bit()?;
let ap_mode = reader.read_bit()?;
let pb_frames_mode = reader.read_bit()?;
let marker2 = reader.read_bit()?;
if marker2 {
return Err(CodecError::InvalidData(
"PTYPE reserved bit not zero".into(),
));
}
let (width, height) = if source_format == PictureFormat::Extended {
let _uui = reader.read_bits(3)?;
let _extended_source_format = reader.read_bits(3)?;
let custom_pcf = reader.read_bit()?;
let (w, h) = if custom_pcf {
let _par = reader.read_bits(4)?;
let pw = reader.read_bits(9)?;
let width = (pw + 1) * 4;
let _marker = reader.read_bit()?;
let ph = reader.read_bits(9)?;
let height = ph * 4;
(Some(width), Some(height))
} else {
(None, None)
};
(w, h)
} else {
(None, None)
};
let cpm_enabled = reader.read_bit()?;
let psbi = if cpm_enabled {
Some(reader.read_bits(2)? as u8)
} else {
None
};
let tss_mode = false;
let quantizer = reader.read_bits(5)? as u8;
if quantizer == 0 {
return Err(CodecError::InvalidData("Invalid quantizer value: 0".into()));
}
loop {
let pei = reader.read_bit()?;
if !pei {
break;
}
let _pspare = reader.read_bits(8)?;
}
Ok(Self {
temporal_reference,
picture_type,
source_format,
width,
height,
quantizer,
umv_mode,
sac_mode,
ap_mode,
pb_frames_mode,
cpm_enabled,
psbi,
tss_mode,
})
}
pub fn dimensions(&self) -> Result<(u32, u32), CodecError> {
if let (Some(w), Some(h)) = (self.width, self.height) {
return Ok((w, h));
}
self.source_format
.dimensions()
.ok_or_else(|| CodecError::InvalidData("Invalid source format".into()))
}
#[must_use]
pub const fn is_intra(&self) -> bool {
matches!(self.picture_type, PictureCodingType::Intra)
}
#[must_use]
pub const fn is_inter(&self) -> bool {
matches!(self.picture_type, PictureCodingType::Inter)
}
}
#[derive(Clone, Debug)]
pub struct GobHeader {
pub gob_number: u8,
pub gob_frame_id: u8,
pub quantizer: u8,
}
impl GobHeader {
pub fn parse(reader: &mut BitReader<'_>) -> Result<Self, CodecError> {
let gbsc = reader.read_bits(17)?;
if gbsc != 0x01 {
return Err(CodecError::InvalidData(format!(
"Invalid GOB start code: 0x{gbsc:05X}"
)));
}
let gob_number = reader.read_bits(5)? as u8;
let gob_frame_id = reader.read_bits(2)? as u8;
let quantizer = reader.read_bits(5)? as u8;
Ok(Self {
gob_number,
gob_frame_id,
quantizer,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MacroblockType {
Inter,
InterQ,
Inter4V,
Intra,
IntraQ,
Skipped,
}
impl MacroblockType {
#[must_use]
pub const fn is_intra(&self) -> bool {
matches!(self, Self::Intra | Self::IntraQ)
}
#[must_use]
pub const fn is_inter(&self) -> bool {
matches!(self, Self::Inter | Self::InterQ | Self::Inter4V)
}
#[must_use]
pub const fn has_quant(&self) -> bool {
matches!(self, Self::InterQ | Self::IntraQ)
}
#[must_use]
pub const fn has_4mv(&self) -> bool {
matches!(self, Self::Inter4V)
}
}
#[derive(Clone, Debug)]
pub struct MacroblockHeader {
pub mb_type: MacroblockType,
pub cbpc: u8,
pub cbpy: u8,
pub dquant: Option<i8>,
pub mvd_x: Option<i16>,
pub mvd_y: Option<i16>,
pub mvd_additional: Option<[(i16, i16); 4]>,
}
impl MacroblockHeader {
#[must_use]
pub const fn new(mb_type: MacroblockType) -> Self {
Self {
mb_type,
cbpc: 0,
cbpy: 0,
dquant: None,
mvd_x: None,
mvd_y: None,
mvd_additional: None,
}
}
#[must_use]
pub const fn cbp(&self) -> u8 {
(self.cbpy << 2) | self.cbpc
}
#[must_use]
pub const fn is_block_coded(&self, block_idx: usize) -> bool {
if block_idx > 5 {
return false;
}
let cbp = self.cbp();
((cbp >> (5 - block_idx)) & 1) != 0
}
}
#[derive(Clone, Copy, Debug)]
pub struct EndOfSequence;
impl EndOfSequence {
pub fn parse(reader: &mut BitReader<'_>) -> Result<Self, CodecError> {
let eos = reader.read_bits(22)?;
if eos != 0x1F {
return Err(CodecError::InvalidData(format!(
"Invalid EOS code: 0x{eos:06X}"
)));
}
Ok(Self)
}
}
#[derive(Clone, Debug)]
pub struct SliceHeader {
pub mb_address: u16,
pub quantizer: u8,
}
impl SliceHeader {
pub fn parse(reader: &mut BitReader<'_>) -> Result<Self, CodecError> {
let ssc = reader.read_bits(17)?;
if ssc != 0x01 {
return Err(CodecError::InvalidData(format!(
"Invalid slice start code: 0x{ssc:05X}"
)));
}
let mb_address = reader.read_bits(9)? as u16;
let quantizer = reader.read_bits(5)? as u8;
Ok(Self {
mb_address,
quantizer,
})
}
}
#[derive(Clone, Debug)]
pub struct ReferencePictureSelection {
pub temporal_reference: u8,
pub picture_number: u16,
}
#[derive(Clone, Debug, Default)]
pub struct AdvancedModes {
pub umv: bool,
pub sac: bool,
pub ap: bool,
pub pb_frames: bool,
pub deblocking: bool,
pub slice_structured: bool,
pub rps: bool,
pub isd: bool,
pub aiv: bool,
pub mq: bool,
}
impl AdvancedModes {
#[must_use]
pub const fn is_advanced(&self) -> bool {
self.umv
|| self.sac
|| self.ap
|| self.pb_frames
|| self.deblocking
|| self.slice_structured
|| self.rps
|| self.isd
|| self.aiv
|| self.mq
}
}