scuffle_h264/sps/
timing_info.rs

1use std::io;
2use std::num::NonZeroU32;
3
4use byteorder::{BigEndian, ReadBytesExt};
5use scuffle_bytes_util::{BitReader, BitWriter};
6
7/// `TimingInfo` contains the fields that are set when `timing_info_present_flag == 1`.
8///
9/// This contains the following fields: `num_units_in_tick` and `time_scale`.
10///
11/// ISO/IEC-14496-10-2022 - E.2.1
12///
13/// Refer to the direct fields for more information.
14#[derive(Debug, Clone, PartialEq)]
15pub struct TimingInfo {
16    /// The `num_units_in_tick` is the smallest unit used to measure time.
17    ///
18    /// It is used alongside `time_scale` to compute the `frame_rate` as follows:
19    ///
20    /// `frame_rate = time_scale / (2 * num_units_in_tick)`
21    ///
22    /// It must be greater than 0, therefore, it is a `NonZeroU32`.
23    /// If it is 0, it will fail to parse.
24    ///
25    /// ISO/IEC-14496-10-2022 - E.2.1
26    pub num_units_in_tick: NonZeroU32,
27
28    /// The `time_scale` is the number of time units that pass in 1 second (hz).
29    ///
30    /// It is used alongside `num_units_in_tick` to compute the `frame_rate` as follows:
31    ///
32    /// `frame_rate = time_scale / (2 * num_units_in_tick)`
33    ///
34    /// It must be greater than 0, therefore, it is a `NonZeroU32`.
35    /// If it is 0, it will fail to parse.
36    ///
37    /// ISO/IEC-14496-10-2022 - E.2.1
38    pub time_scale: NonZeroU32,
39}
40
41impl TimingInfo {
42    /// Parses the fields defined when the `timing_info_present_flag == 1` from a bitstream.
43    /// Returns a `TimingInfo` struct.
44    pub fn parse<T: io::Read>(reader: &mut BitReader<T>) -> io::Result<Self> {
45        let num_units_in_tick = NonZeroU32::new(reader.read_u32::<BigEndian>()?)
46            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "num_units_in_tick cannot be 0"))?;
47
48        let time_scale = NonZeroU32::new(reader.read_u32::<BigEndian>()?)
49            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "time_scale cannot be 0"))?;
50
51        Ok(TimingInfo {
52            num_units_in_tick,
53            time_scale,
54        })
55    }
56
57    /// Builds the TimingInfo struct into a byte stream.
58    /// Returns a built byte stream.
59    pub fn build<T: io::Write>(&self, writer: &mut BitWriter<T>) -> io::Result<()> {
60        writer.write_bits(self.num_units_in_tick.get() as u64, 32)?;
61        writer.write_bits(self.time_scale.get() as u64, 32)?;
62        Ok(())
63    }
64
65    /// Returns the total bits of the TimingInfo struct. It is always 64 bits (8 bytes).
66    pub fn bitsize(&self) -> u64 {
67        64
68    }
69
70    /// Returns the total bytes of the TimingInfo struct. It is always 8 bytes (64 bits).
71    pub fn bytesize(&self) -> u64 {
72        8
73    }
74
75    /// Returns the frame rate of the TimingInfo struct.
76    pub fn frame_rate(&self) -> f64 {
77        self.time_scale.get() as f64 / (2.0 * self.num_units_in_tick.get() as f64)
78    }
79}
80
81#[cfg(test)]
82#[cfg_attr(all(test, coverage_nightly), coverage(off))]
83mod tests {
84    use scuffle_bytes_util::{BitReader, BitWriter};
85
86    use crate::sps::TimingInfo;
87
88    #[test]
89    fn test_build_size_timing_info() {
90        // create bitstream for timing_info
91        let mut data = Vec::new();
92        let mut writer = BitWriter::new(&mut data);
93
94        writer.write_bits(1234, 32).unwrap();
95        writer.write_bits(321, 32).unwrap();
96        writer.finish().unwrap();
97
98        // parse bitstream
99        let mut reader = BitReader::new_from_slice(&mut data);
100        let timing_info = TimingInfo::parse(&mut reader).unwrap();
101
102        // create a writer for the builder
103        let mut buf = Vec::new();
104        let mut writer2 = BitWriter::new(&mut buf);
105
106        // build from the example result
107        timing_info.build(&mut writer2).unwrap();
108        writer2.finish().unwrap();
109
110        assert_eq!(buf, data);
111
112        // now we re-parse so we can compare the bit sizes.
113        // create a reader for the parser
114        let mut reader2 = BitReader::new_from_slice(buf);
115        let rebuilt_timing_info = TimingInfo::parse(&mut reader2).unwrap();
116
117        // now we can check the size:
118        assert_eq!(rebuilt_timing_info.bitsize(), timing_info.bitsize());
119        assert_eq!(rebuilt_timing_info.bytesize(), timing_info.bytesize());
120    }
121}