scuffle_h264/sps/
timing_info.rs1use std::io;
2use std::num::NonZeroU32;
3
4use byteorder::{BigEndian, ReadBytesExt};
5use scuffle_bytes_util::{BitReader, BitWriter};
6
7#[derive(Debug, Clone, PartialEq)]
15pub struct TimingInfo {
16 pub num_units_in_tick: NonZeroU32,
27
28 pub time_scale: NonZeroU32,
39}
40
41impl TimingInfo {
42 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 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 pub fn bitsize(&self) -> u64 {
67 64
68 }
69
70 pub fn bytesize(&self) -> u64 {
72 8
73 }
74
75 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 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 let mut reader = BitReader::new_from_slice(&mut data);
100 let timing_info = TimingInfo::parse(&mut reader).unwrap();
101
102 let mut buf = Vec::new();
104 let mut writer2 = BitWriter::new(&mut buf);
105
106 timing_info.build(&mut writer2).unwrap();
108 writer2.finish().unwrap();
109
110 assert_eq!(buf, data);
111
112 let mut reader2 = BitReader::new_from_slice(buf);
115 let rebuilt_timing_info = TimingInfo::parse(&mut reader2).unwrap();
116
117 assert_eq!(rebuilt_timing_info.bitsize(), timing_info.bitsize());
119 assert_eq!(rebuilt_timing_info.bytesize(), timing_info.bytesize());
120 }
121}