h264_reader/nal/sei/
pic_timing.rs

1use crate::nal::sei::HeaderType;
2use crate::nal::sei::SeiMessage;
3use crate::nal::sps;
4use crate::rbsp::BitRead;
5use crate::rbsp::BitReader;
6use crate::rbsp::BitReaderError;
7
8#[derive(Debug)]
9pub enum PicTimingError {
10    RbspError(BitReaderError),
11    InvalidPicStructId(u8),
12}
13impl From<BitReaderError> for PicTimingError {
14    fn from(e: BitReaderError) -> Self {
15        PicTimingError::RbspError(e)
16    }
17}
18
19#[derive(Debug, Eq, PartialEq)]
20pub struct Delays {
21    cpb_removal_delay: u32,
22    dpb_output_delay: u32,
23}
24
25#[derive(Debug, Eq, PartialEq)]
26pub enum PicStructType {
27    Frame,
28    TopField,
29    BottomField,
30    TopFieldBottomField,
31    BottomFieldTopField,
32    TopFieldBottomFieldTopFieldRepeated,
33    BottomFieldTopFieldBottomFieldRepeated,
34    FrameDoubling,
35    FrameTripling,
36    Reserved(u8),
37}
38impl PicStructType {
39    fn from_id(id: u8) -> Result<PicStructType, PicTimingError> {
40        match id {
41            0 => Ok(PicStructType::Frame),
42            1 => Ok(PicStructType::TopField),
43            2 => Ok(PicStructType::BottomField),
44            3 => Ok(PicStructType::TopFieldBottomField),
45            4 => Ok(PicStructType::BottomFieldTopField),
46            5 => Ok(PicStructType::TopFieldBottomFieldTopFieldRepeated),
47            6 => Ok(PicStructType::BottomFieldTopFieldBottomFieldRepeated),
48            7 => Ok(PicStructType::FrameDoubling),
49            8 => Ok(PicStructType::FrameTripling),
50            9..=15 => Ok(PicStructType::Reserved(id)),
51            _ => Err(PicTimingError::InvalidPicStructId(id)),
52        }
53    }
54
55    fn num_clock_timestamps(&self) -> u8 {
56        match *self {
57            PicStructType::Frame => 1,
58            PicStructType::TopField => 1,
59            PicStructType::BottomField => 1,
60            PicStructType::TopFieldBottomField => 2,
61            PicStructType::BottomFieldTopField => 2,
62            PicStructType::TopFieldBottomFieldTopFieldRepeated => 3,
63            PicStructType::BottomFieldTopFieldBottomFieldRepeated => 3,
64            PicStructType::FrameDoubling => 2,
65            PicStructType::FrameTripling => 3,
66            PicStructType::Reserved(_) => 0,
67        }
68    }
69}
70
71#[derive(Debug, Eq, PartialEq)]
72pub enum CtType {
73    Progressive,
74    Interlaced,
75    Unknown,
76    Reserved,
77}
78impl CtType {
79    fn from_id(id: u8) -> CtType {
80        match id {
81            0 => CtType::Progressive,
82            1 => CtType::Interlaced,
83            2 => CtType::Unknown,
84            3 => CtType::Reserved,
85            _ => panic!("unexpected ct_type {}", id),
86        }
87    }
88}
89
90#[derive(Debug, Eq, PartialEq)]
91pub enum CountingType {
92    /// no dropping of `n_frames` values, and no use of `time_offset`
93    NoDroppingNoOffset,
94    /// no dropping of `n_frames` values
95    NoDropping,
96    /// dropping of individual '0' `n_frames` values
97    DroppingIndividualZero,
98    /// dropping of individual 'maxFPS - 1' `n_frames` values
99    DroppingIndividualMax,
100    /// dropping of individual '0' and '1' `n_frames` values
101    DroppingTwoLowest,
102    /// dropping of individual unspecified `n_frames` values
103    DroppingIndividual,
104    /// dropping of unspecified numbers of unspecified `n_frames` values
105    Dropping,
106    Reserved(u8),
107}
108impl CountingType {
109    fn from_id(id: u8) -> CountingType {
110        match id {
111            0 => CountingType::NoDroppingNoOffset,
112            1 => CountingType::NoDropping,
113            2 => CountingType::DroppingIndividualZero,
114            3 => CountingType::DroppingIndividualMax,
115            4 => CountingType::DroppingTwoLowest,
116            5 => CountingType::DroppingIndividual,
117            6 => CountingType::Dropping,
118            7..=31 => CountingType::Reserved(id),
119            _ => panic!("unexpected counting_type {}", id),
120        }
121    }
122}
123
124#[derive(Debug, Eq, PartialEq)]
125pub enum SecMinHour {
126    None,
127    S(u8),
128    SM(u8, u8),
129    SMH(u8, u8, u8),
130}
131impl SecMinHour {
132    pub fn seconds(&self) -> u8 {
133        match self {
134            SecMinHour::None => 0,
135            SecMinHour::S(s) => *s,
136            SecMinHour::SM(s, _) => *s,
137            SecMinHour::SMH(s, _, _) => *s,
138        }
139    }
140    pub fn minutes(&self) -> u8 {
141        match self {
142            SecMinHour::None => 0,
143            SecMinHour::S(_) => 0,
144            SecMinHour::SM(_, m) => *m,
145            SecMinHour::SMH(_, m, _) => *m,
146        }
147    }
148    pub fn hours(&self) -> u8 {
149        match self {
150            SecMinHour::None => 0,
151            SecMinHour::S(_) => 0,
152            SecMinHour::SM(_, _) => 0,
153            SecMinHour::SMH(_, _, h) => *h,
154        }
155    }
156}
157
158#[derive(Debug, Eq, PartialEq)]
159pub struct ClockTimestamp {
160    pub ct_type: CtType,
161    pub nuit_field_based_flag: bool,
162    pub counting_type: CountingType,
163    pub discontinuity_flag: bool,
164    pub cnt_dropped_flag: bool,
165    pub n_frames: u8,
166    pub smh: SecMinHour,
167    pub time_offset: Option<i32>,
168}
169impl ClockTimestamp {
170    fn read<R: BitRead>(
171        r: &mut R,
172        sps: &sps::SeqParameterSet,
173    ) -> Result<ClockTimestamp, PicTimingError> {
174        let ct_type = CtType::from_id(r.read(2, "ct_type")?);
175        let nuit_field_based_flag = r.read_bool("nuit_field_based_flag")?;
176        let counting_type = CountingType::from_id(r.read(5, "counting_type")?);
177        let full_timestamp_flag = r.read_bool("full_timestamp_flag")?;
178        let discontinuity_flag = r.read_bool("discontinuity_flag")?;
179        let cnt_dropped_flag = r.read_bool("cnt_dropped_flag")?;
180        let n_frames = r.read(8, "n_frames")?;
181        let smh = if full_timestamp_flag {
182            SecMinHour::SMH(
183                r.read(6, "seconds_value")?,
184                r.read(6, "minutes_value")?,
185                r.read(5, "hours_value")?,
186            )
187        } else if r.read_bool("seconds_flag")? {
188            let seconds = r.read(6, "seconds_value")?;
189            if r.read_bool("minutes_flag")? {
190                let minutes = r.read(6, "minutes_value")?;
191                if r.read_bool("hours_flag")? {
192                    let hours = r.read(5, "hours_value")?;
193                    SecMinHour::SMH(seconds, minutes, hours)
194                } else {
195                    SecMinHour::SM(seconds, minutes)
196                }
197            } else {
198                SecMinHour::S(seconds)
199            }
200        } else {
201            SecMinHour::None
202        };
203        let time_offset_length = if let Some(ref vui) = sps.vui_parameters {
204            if let Some(ref hrd) = vui.nal_hrd_parameters {
205                hrd.time_offset_length
206            } else if let Some(ref hrd) = vui.vcl_hrd_parameters {
207                hrd.time_offset_length
208            } else {
209                24
210            }
211        } else {
212            24
213        };
214        let time_offset = if time_offset_length == 0 {
215            None
216        } else {
217            Some(r.read(u32::from(time_offset_length), "time_offset_length")?)
218        };
219        Ok(ClockTimestamp {
220            ct_type,
221            nuit_field_based_flag,
222            counting_type,
223            discontinuity_flag,
224            cnt_dropped_flag,
225            n_frames,
226            smh,
227            time_offset,
228        })
229    }
230}
231
232#[derive(Debug, Eq, PartialEq)]
233pub struct PicStruct {
234    pub pic_struct: PicStructType,
235    pub clock_timestamps: Vec<Option<ClockTimestamp>>,
236}
237
238#[derive(Debug, Eq, PartialEq)]
239pub struct PicTiming {
240    pub delays: Option<Delays>,
241    pub pic_struct: Option<PicStruct>,
242}
243impl PicTiming {
244    /// Parses a `PicTiming` from the given SEI message.
245    /// The caller is expected to have found the correct SPS by buffering the `SeiMessage`
246    /// until after examining the following slice header.
247    pub fn read(
248        sps: &sps::SeqParameterSet,
249        msg: &SeiMessage<'_>,
250    ) -> Result<PicTiming, PicTimingError> {
251        assert_eq!(msg.payload_type, HeaderType::PicTiming);
252        let mut r = BitReader::new(msg.payload);
253        let pic_timing = PicTiming {
254            delays: Self::read_delays(&mut r, sps)?,
255            pic_struct: Self::read_pic_struct(&mut r, sps)?,
256        };
257        r.finish_sei_payload()?;
258        Ok(pic_timing)
259    }
260
261    fn read_delays<R: BitRead>(
262        r: &mut R,
263        sps: &sps::SeqParameterSet,
264    ) -> Result<Option<Delays>, PicTimingError> {
265        Ok(if let Some(ref vui_params) = sps.vui_parameters {
266            if let Some(ref hrd) = vui_params
267                .nal_hrd_parameters
268                .as_ref()
269                .or_else(|| vui_params.nal_hrd_parameters.as_ref())
270            {
271                Some(Delays {
272                    cpb_removal_delay: r.read(
273                        u32::from(hrd.cpb_removal_delay_length_minus1) + 1,
274                        "cpb_removal_delay",
275                    )?,
276                    dpb_output_delay: r.read(
277                        u32::from(hrd.dpb_output_delay_length_minus1) + 1,
278                        "dpb_output_delay",
279                    )?,
280                })
281            } else {
282                None
283            }
284        } else {
285            None
286        })
287    }
288
289    fn read_pic_struct<R: BitRead>(
290        r: &mut R,
291        sps: &sps::SeqParameterSet,
292    ) -> Result<Option<PicStruct>, PicTimingError> {
293        Ok(if let Some(ref vui_params) = sps.vui_parameters {
294            if vui_params.pic_struct_present_flag {
295                let pic_struct = PicStructType::from_id(r.read(4, "pic_struct")?)?;
296                let clock_timestamps = Self::read_clock_timestamps(r, &pic_struct, sps)?;
297
298                Some(PicStruct {
299                    pic_struct,
300                    clock_timestamps,
301                })
302            } else {
303                None
304            }
305        } else {
306            None
307        })
308    }
309
310    fn read_clock_timestamps<R: BitRead>(
311        r: &mut R,
312        pic_struct: &PicStructType,
313        sps: &sps::SeqParameterSet,
314    ) -> Result<Vec<Option<ClockTimestamp>>, PicTimingError> {
315        let mut res = Vec::new();
316        for _ in 0..pic_struct.num_clock_timestamps() {
317            res.push(if r.read_bool("clock_timestamp_flag")? {
318                Some(ClockTimestamp::read(r, sps)?)
319            } else {
320                None
321            });
322        }
323        Ok(res)
324    }
325}
326#[cfg(test)]
327mod test {
328    use crate::rbsp;
329    use hex_literal::hex;
330
331    use super::*;
332
333    #[test]
334    fn parse() {
335        // https://standards.iso.org/ittf/PubliclyAvailableStandards/ISO_IEC_14496-4_2004_Amd_6_2005_Bitstreams/
336        // This example taken from CVSEFDFT3_Sony_E.zip.
337        let sps = hex!(
338            "
339            4d 60 15 8d 8d 28 58 9d 08 00 00 0f a0 00 07 53
340            07 00 00 00 92 7c 00 00 12 4f 80 fb dc 18 00 00
341            0f 42 40 00 07 a1 20 7d ee 07 c6 0c 62 60
342        "
343        );
344        let sps = sps::SeqParameterSet::from_bits(rbsp::BitReader::new(&sps[..])).unwrap();
345        let msg = SeiMessage {
346            payload_type: HeaderType::PicTiming,
347            payload: &hex!("00 00 00 00 00 0c 72")[..],
348        };
349        let pic_timing = PicTiming::read(&sps, &msg).unwrap();
350        assert_eq!(
351            pic_timing,
352            PicTiming {
353                delays: Some(Delays {
354                    cpb_removal_delay: 0,
355                    dpb_output_delay: 12,
356                }),
357                pic_struct: Some(PicStruct {
358                    pic_struct: PicStructType::FrameDoubling,
359                    clock_timestamps: vec![None, None],
360                }),
361            }
362        );
363    }
364}