use crate::nal::{parse_nal_header_extension, Nal, NalHeaderError, NalHeaderExtension};
use crate::rbsp::{BitRead, BitReaderError};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrefixNalUnit {
pub header_extension: NalHeaderExtension,
pub ref_base_pic: Option<PrefixNalUnitRef>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrefixNalUnitRef {
pub store_ref_base_pic_flag: bool,
pub dec_ref_base_pic_marking: Option<DecRefBasePicMarking>,
pub additional_prefix_nal_unit_extension_flag: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DecRefBasePicMarking {
pub operations: Vec<DecRefBasePicMarkingOp>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DecRefBasePicMarkingOp {
ShortTermUnusedForRef {
difference_of_base_pic_nums_minus1: u32,
},
LongTermUnusedForRef { long_term_base_pic_num: u32 },
}
#[derive(Debug)]
pub enum PrefixNalUnitError {
RbspError(BitReaderError),
IoError(std::io::Error),
HeaderError(NalHeaderError),
InvalidMemoryManagementBaseControlOperation(u32),
}
impl From<BitReaderError> for PrefixNalUnitError {
fn from(e: BitReaderError) -> Self {
PrefixNalUnitError::RbspError(e)
}
}
impl From<NalHeaderError> for PrefixNalUnitError {
fn from(e: NalHeaderError) -> Self {
PrefixNalUnitError::HeaderError(e)
}
}
impl From<std::io::Error> for PrefixNalUnitError {
fn from(e: std::io::Error) -> Self {
PrefixNalUnitError::IoError(e)
}
}
impl PrefixNalUnit {
pub fn from_nal<N: Nal>(nal: &N) -> Result<PrefixNalUnit, PrefixNalUnitError> {
let header = nal.header()?;
let (header_extension, rbsp_reader) = parse_nal_header_extension(nal)?;
let mut r = crate::rbsp::BitReader::new(rbsp_reader);
let ref_base_pic = match &header_extension {
NalHeaderExtension::Svc(_) => {
if header.nal_ref_idc() != 0 {
let store_ref_base_pic_flag = r.read_bit("store_ref_base_pic_flag")?;
let dec_ref_base_pic_marking = if store_ref_base_pic_flag {
Some(read_dec_ref_base_pic_marking(&mut r)?)
} else {
None
};
let additional_prefix_nal_unit_extension_flag =
r.read_bit("additional_prefix_nal_unit_extension_flag")?;
Some(PrefixNalUnitRef {
store_ref_base_pic_flag,
dec_ref_base_pic_marking,
additional_prefix_nal_unit_extension_flag,
})
} else {
None
}
}
NalHeaderExtension::Mvc(_) => {
None
}
};
Ok(PrefixNalUnit {
header_extension,
ref_base_pic,
})
}
}
fn read_dec_ref_base_pic_marking<R: BitRead>(
r: &mut R,
) -> Result<DecRefBasePicMarking, PrefixNalUnitError> {
let mut operations = Vec::new();
loop {
let op = r.read_ue("memory_management_base_control_operation")?;
match op {
0 => break,
1 => {
let difference_of_base_pic_nums_minus1 =
r.read_ue("difference_of_base_pic_nums_minus1")?;
operations.push(DecRefBasePicMarkingOp::ShortTermUnusedForRef {
difference_of_base_pic_nums_minus1,
});
}
2 => {
let long_term_base_pic_num = r.read_ue("long_term_base_pic_num")?;
operations.push(DecRefBasePicMarkingOp::LongTermUnusedForRef {
long_term_base_pic_num,
});
}
_ => {
return Err(PrefixNalUnitError::InvalidMemoryManagementBaseControlOperation(op));
}
}
}
Ok(DecRefBasePicMarking { operations })
}
#[cfg(test)]
mod test {
use super::*;
use crate::nal::RefNal;
#[test]
fn parse_prefix_nal_mvc_no_ref() {
let data: &[u8] = &[
0x0E, 0b0100_0000, 0x00, 0b0100_0011, ];
let nal = RefNal::new(data, &[], true);
let prefix = PrefixNalUnit::from_nal(&nal).unwrap();
match prefix.header_extension {
NalHeaderExtension::Mvc(mvc) => {
assert!(mvc.non_idr_flag());
assert_eq!(mvc.view_id(), 1);
assert!(mvc.inter_view_flag());
}
_ => panic!("expected MVC extension"),
}
assert!(prefix.ref_base_pic.is_none());
}
#[test]
fn parse_prefix_nal_mvc_with_ref() {
let data: &[u8] = &[
0x6E, 0x00, 0x00, 0b0000_0001, ];
let nal = RefNal::new(data, &[], true);
let prefix = PrefixNalUnit::from_nal(&nal).unwrap();
assert!(prefix.ref_base_pic.is_none());
}
#[test]
fn parse_prefix_nal_svc_no_ref() {
let data: &[u8] = &[
0x0E, 0x80, 0x00, 0x03, ];
let nal = RefNal::new(data, &[], true);
let prefix = PrefixNalUnit::from_nal(&nal).unwrap();
match prefix.header_extension {
NalHeaderExtension::Svc(svc) => {
assert!(!svc.idr_flag());
assert_eq!(svc.priority_id(), 0);
}
_ => panic!("expected SVC extension"),
}
assert!(prefix.ref_base_pic.is_none());
}
#[test]
fn parse_prefix_nal_svc_with_ref_no_marking() {
let data: &[u8] = &[
0x6E, 0x80, 0x00, 0x03, 0b0010_0000,
];
let nal = RefNal::new(data, &[], true);
let prefix = PrefixNalUnit::from_nal(&nal).unwrap();
let ref_base = prefix.ref_base_pic.unwrap();
assert!(!ref_base.store_ref_base_pic_flag);
assert!(ref_base.dec_ref_base_pic_marking.is_none());
assert!(!ref_base.additional_prefix_nal_unit_extension_flag);
}
#[test]
fn parse_prefix_nal_svc_with_marking() {
let data: &[u8] = &[
0x4E, 0x80, 0x00, 0x03, 0b1010_1101,
0b0000_0000, ];
let nal = RefNal::new(data, &[], true);
let prefix = PrefixNalUnit::from_nal(&nal).unwrap();
let ref_base = prefix.ref_base_pic.unwrap();
assert!(ref_base.store_ref_base_pic_flag);
assert!(!ref_base.additional_prefix_nal_unit_extension_flag);
let marking = ref_base.dec_ref_base_pic_marking.unwrap();
assert_eq!(marking.operations.len(), 1);
match &marking.operations[0] {
DecRefBasePicMarkingOp::ShortTermUnusedForRef {
difference_of_base_pic_nums_minus1,
} => {
assert_eq!(*difference_of_base_pic_nums_minus1, 0);
}
_ => panic!("expected ShortTermUnusedForRef"),
}
}
}