flowly_mp4/mp4box/
stts.rs

1use byteorder::{BigEndian, WriteBytesExt};
2use serde::Serialize;
3use std::io::Write;
4use std::mem::size_of;
5
6use crate::mp4box::*;
7
8#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
9pub struct SttsBox {
10    pub version: u8,
11    pub flags: u32,
12
13    #[serde(skip_serializing)]
14    pub entries: Vec<SttsEntry>,
15}
16
17impl SttsBox {
18    pub fn get_type(&self) -> BoxType {
19        BoxType::SttsBox
20    }
21
22    pub fn get_size(&self) -> u64 {
23        HEADER_SIZE + HEADER_EXT_SIZE + 4 + (8 * self.entries.len() as u64)
24    }
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize)]
28pub struct SttsEntry {
29    pub sample_count: u32,
30    pub sample_delta: u32,
31}
32
33impl Mp4Box for SttsBox {
34    const TYPE: BoxType = BoxType::SttsBox;
35
36    fn box_size(&self) -> u64 {
37        self.get_size()
38    }
39
40    fn to_json(&self) -> Result<String, Error> {
41        Ok(serde_json::to_string(&self).unwrap())
42    }
43
44    fn summary(&self) -> Result<String, Error> {
45        let s = format!("entries={}", self.entries.len());
46        Ok(s)
47    }
48}
49
50impl BlockReader for SttsBox {
51    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
52        let (version, flags) = read_box_header_ext(reader);
53
54        let entry_size = size_of::<u32>() + size_of::<u32>(); // sample_count + sample_delta
55        let entry_count = reader.get_u32();
56
57        if entry_count as usize > reader.remaining() / entry_size {
58            return Err(Error::InvalidData(
59                "stts entry_count indicates more entries than could fit in the box",
60            ));
61        }
62
63        let mut entries = Vec::with_capacity(entry_count as usize);
64        for _i in 0..entry_count {
65            let entry = SttsEntry {
66                sample_count: reader.get_u32(),
67                sample_delta: reader.get_u32(),
68            };
69            entries.push(entry);
70        }
71
72        Ok(SttsBox {
73            version,
74            flags,
75            entries,
76        })
77    }
78
79    fn size_hint() -> usize {
80        8
81    }
82}
83
84impl<W: Write> WriteBox<&mut W> for SttsBox {
85    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
86        let size = self.box_size();
87        BoxHeader::new(Self::TYPE, size).write(writer)?;
88
89        write_box_header_ext(writer, self.version, self.flags)?;
90
91        writer.write_u32::<BigEndian>(self.entries.len() as u32)?;
92        for entry in self.entries.iter() {
93            writer.write_u32::<BigEndian>(entry.sample_count)?;
94            writer.write_u32::<BigEndian>(entry.sample_delta)?;
95        }
96
97        Ok(size)
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use crate::mp4box::BoxHeader;
105
106    #[tokio::test]
107    async fn test_stts() {
108        let src_box = SttsBox {
109            version: 0,
110            flags: 0,
111            entries: vec![
112                SttsEntry {
113                    sample_count: 29726,
114                    sample_delta: 1024,
115                },
116                SttsEntry {
117                    sample_count: 1,
118                    sample_delta: 512,
119                },
120            ],
121        };
122        let mut buf = Vec::new();
123        src_box.write_box(&mut buf).unwrap();
124        assert_eq!(buf.len(), src_box.box_size() as usize);
125
126        let mut reader = buf.as_slice();
127        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
128        assert_eq!(header.kind, BoxType::SttsBox);
129        assert_eq!(src_box.box_size(), header.size);
130
131        let dst_box = SttsBox::read_block(&mut reader).unwrap();
132        assert_eq!(src_box, dst_box);
133    }
134}