Skip to main content

h264_reader/nal/
aud.rs

1//! Parser for `access_unit_delimiter_rbsp()` (NAL type 9, spec 7.3.2.4).
2
3use crate::rbsp::BitRead;
4use std::fmt;
5
6/// Indicates which slice types may be present in the primary coded picture
7/// of the access unit (Table 7-5).
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum PrimaryPicType {
10    /// I slices only
11    I = 0,
12    /// I, P slices
13    IP = 1,
14    /// I, P, B slices
15    IPB = 2,
16    /// SI slices only
17    SI = 3,
18    /// SI, SP slices
19    SISP = 4,
20    /// I, SI slices
21    ISI = 5,
22    /// I, SI, P, SP slices
23    ISIPSP = 6,
24    /// I, SI, P, SP, B slices
25    ISIPSPB = 7,
26}
27
28/// Error returned when a `primary_pic_type` value is out of range.
29#[derive(Debug)]
30pub struct PrimaryPicTypeError(pub u8);
31
32impl fmt::Display for PrimaryPicTypeError {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        write!(f, "invalid primary_pic_type value: {}", self.0)
35    }
36}
37
38impl PrimaryPicType {
39    pub fn from_id(id: u8) -> Result<PrimaryPicType, PrimaryPicTypeError> {
40        match id {
41            0 => Ok(PrimaryPicType::I),
42            1 => Ok(PrimaryPicType::IP),
43            2 => Ok(PrimaryPicType::IPB),
44            3 => Ok(PrimaryPicType::SI),
45            4 => Ok(PrimaryPicType::SISP),
46            5 => Ok(PrimaryPicType::ISI),
47            6 => Ok(PrimaryPicType::ISIPSP),
48            7 => Ok(PrimaryPicType::ISIPSPB),
49            _ => Err(PrimaryPicTypeError(id)),
50        }
51    }
52
53    pub fn id(self) -> u8 {
54        self as u8
55    }
56}
57
58/// Parsed `access_unit_delimiter_rbsp()` (NAL unit type 9).
59#[derive(Clone, Debug, PartialEq, Eq)]
60pub struct AccessUnitDelimiter {
61    pub primary_pic_type: PrimaryPicType,
62}
63
64impl AccessUnitDelimiter {
65    pub fn from_bits<R: BitRead>(mut r: R) -> Result<AccessUnitDelimiter, AudError> {
66        let val: u8 = r.read::<3, _>("primary_pic_type")?;
67        let primary_pic_type =
68            PrimaryPicType::from_id(val).map_err(AudError::InvalidPrimaryPicType)?;
69        r.finish_rbsp()?;
70        Ok(AccessUnitDelimiter { primary_pic_type })
71    }
72}
73
74/// Error type for AUD parsing.
75#[derive(Debug)]
76pub enum AudError {
77    InvalidPrimaryPicType(PrimaryPicTypeError),
78    RbspError(crate::rbsp::BitReaderError),
79}
80
81impl From<crate::rbsp::BitReaderError> for AudError {
82    fn from(e: crate::rbsp::BitReaderError) -> Self {
83        AudError::RbspError(e)
84    }
85}
86
87impl fmt::Display for AudError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            AudError::InvalidPrimaryPicType(e) => write!(f, "{}", e),
91            AudError::RbspError(e) => write!(f, "{:?}", e),
92        }
93    }
94}
95
96#[cfg(test)]
97mod test {
98    use super::*;
99    use crate::rbsp::BitReader;
100
101    #[test]
102    fn parse_all_pic_types() {
103        for id in 0u8..=7 {
104            // primary_pic_type(3 bits) + rbsp_stop_one_bit(1) + padding(4 zeros)
105            let byte = (id << 5) | 0x10;
106            let data = [byte];
107            let aud = AccessUnitDelimiter::from_bits(BitReader::new(&data[..])).unwrap();
108            assert_eq!(aud.primary_pic_type.id(), id);
109        }
110    }
111
112    #[test]
113    fn parse_ipb() {
114        // primary_pic_type=2 (IPB): 010 1 0000 = 0x50
115        let data = [0x50u8];
116        let aud = AccessUnitDelimiter::from_bits(BitReader::new(&data[..])).unwrap();
117        assert_eq!(aud.primary_pic_type, PrimaryPicType::IPB);
118    }
119}