h264_reader/nal/sei/
buffering_period.rs

1use super::SeiMessage;
2use crate::nal::sei::HeaderType;
3use crate::nal::sps;
4use crate::rbsp::BitRead;
5use crate::rbsp::BitReaderError;
6use crate::Context;
7
8#[derive(Debug)]
9pub enum BufferingPeriodError {
10    ReaderError(BitReaderError),
11    UndefinedSeqParamSetId(sps::SeqParamSetId),
12    InvalidSeqParamSetId(sps::SeqParamSetIdError),
13}
14impl From<BitReaderError> for BufferingPeriodError {
15    fn from(e: BitReaderError) -> Self {
16        BufferingPeriodError::ReaderError(e)
17    }
18}
19impl From<sps::SeqParamSetIdError> for BufferingPeriodError {
20    fn from(e: sps::SeqParamSetIdError) -> Self {
21        BufferingPeriodError::InvalidSeqParamSetId(e)
22    }
23}
24
25#[derive(Debug, Eq, PartialEq)]
26struct InitialCpbRemoval {
27    initial_cpb_removal_delay: u32,
28    initial_cpb_removal_delay_offset: u32,
29}
30
31fn read_cpb_removal_delay_list<R: BitRead>(
32    r: &mut R,
33    count: usize,
34    length: u32,
35) -> Result<Vec<InitialCpbRemoval>, BitReaderError> {
36    let mut res = vec![];
37    for _ in 0..count {
38        res.push(InitialCpbRemoval {
39            initial_cpb_removal_delay: r.read(length, "initial_cpb_removal_delay")?,
40            initial_cpb_removal_delay_offset: r.read(length, "initial_cpb_removal_delay_offset")?,
41        });
42    }
43    Ok(res)
44}
45
46#[derive(Debug, Eq, PartialEq)]
47pub struct BufferingPeriod {
48    nal_hrd_bp: Option<Vec<InitialCpbRemoval>>,
49    vcl_hrd_bp: Option<Vec<InitialCpbRemoval>>,
50}
51impl BufferingPeriod {
52    pub fn read(
53        ctx: &Context,
54        msg: &SeiMessage<'_>,
55    ) -> Result<BufferingPeriod, BufferingPeriodError> {
56        assert_eq!(msg.payload_type, HeaderType::BufferingPeriod);
57        let mut r = crate::rbsp::BitReader::new(msg.payload);
58        let seq_parameter_set_id =
59            sps::SeqParamSetId::from_u32(r.read_ue("seq_parameter_set_id")?)?;
60        let sps = ctx
61            .sps_by_id(seq_parameter_set_id)
62            .ok_or_else(|| BufferingPeriodError::UndefinedSeqParamSetId(seq_parameter_set_id))?;
63        let vui = sps.vui_parameters.as_ref();
64        let mut read = |p: &sps::HrdParameters| {
65            read_cpb_removal_delay_list(
66                &mut r,
67                p.cpb_specs.len(),
68                u32::from(p.initial_cpb_removal_delay_length_minus1) + 1,
69            )
70        };
71        let nal_hrd_bp = vui
72            .and_then(|v| v.nal_hrd_parameters.as_ref())
73            .map(&mut read)
74            .transpose()?;
75        let vcl_hrd_bp = vui
76            .and_then(|v| v.vcl_hrd_parameters.as_ref())
77            .map(&mut read)
78            .transpose()?;
79        r.finish_sei_payload()?;
80        Ok(BufferingPeriod {
81            nal_hrd_bp,
82            vcl_hrd_bp,
83        })
84    }
85}
86
87#[cfg(test)]
88mod test {
89    use hex_literal::hex;
90
91    use crate::rbsp;
92
93    use super::*;
94
95    #[test]
96    fn parse() {
97        // https://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_14496-4_2004_Amd_6_2005_Bitstreams/
98        // This example taken from CVSEFDFT3_Sony_E.zip.
99        let mut ctx = Context::default();
100        let sps_rbsp = hex!(
101            "
102            4d 60 15 8d 8d 28 58 9d 08 00 00 0f a0 00 07 53
103            07 00 00 00 92 7c 00 00 12 4f 80 fb dc 18 00 00
104            0f 42 40 00 07 a1 20 7d ee 07 c6 0c 62 60
105        "
106        );
107        ctx.put_seq_param_set(
108            sps::SeqParameterSet::from_bits(rbsp::BitReader::new(&sps_rbsp[..])).unwrap(),
109        );
110
111        let msg = SeiMessage {
112            payload_type: HeaderType::BufferingPeriod,
113            payload: &hex!("d7 e4 00 00 57 e4 00 00 40")[..],
114        };
115        assert_eq!(
116            BufferingPeriod::read(&ctx, &msg).unwrap(),
117            BufferingPeriod {
118                nal_hrd_bp: Some(vec![InitialCpbRemoval {
119                    initial_cpb_removal_delay: 45_000,
120                    initial_cpb_removal_delay_offset: 0,
121                },]),
122                vcl_hrd_bp: Some(vec![InitialCpbRemoval {
123                    initial_cpb_removal_delay: 45_000,
124                    initial_cpb_removal_delay_offset: 0,
125                },]),
126            }
127        );
128    }
129}