flowly_mp4/mp4box/
stsz.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 StszBox {
10    pub version: u8,
11    pub flags: u32,
12    pub sample_size: u32,
13    pub sample_count: u32,
14
15    #[serde(skip_serializing)]
16    pub sample_sizes: Vec<u32>,
17}
18
19impl StszBox {
20    pub fn get_type(&self) -> BoxType {
21        BoxType::StszBox
22    }
23
24    pub fn get_size(&self) -> u64 {
25        HEADER_SIZE + HEADER_EXT_SIZE + 8 + (4 * self.sample_sizes.len() as u64)
26    }
27}
28
29impl Mp4Box for StszBox {
30    const TYPE: BoxType = BoxType::StszBox;
31
32    fn box_size(&self) -> u64 {
33        self.get_size()
34    }
35
36    fn to_json(&self) -> Result<String, Error> {
37        Ok(serde_json::to_string(&self).unwrap())
38    }
39
40    fn summary(&self) -> Result<String, Error> {
41        let s = format!(
42            "sample_size={} sample_count={} sample_sizes={}",
43            self.sample_size,
44            self.sample_count,
45            self.sample_sizes.len()
46        );
47        Ok(s)
48    }
49}
50
51impl BlockReader for StszBox {
52    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
53        let (version, flags) = read_box_header_ext(reader);
54
55        let sample_size = reader.get_u32();
56        let stsz_item_size = if sample_size == 0 {
57            size_of::<u32>() // entry_size
58        } else {
59            0
60        };
61        let sample_count = reader.get_u32();
62        let mut sample_sizes = Vec::new();
63        if sample_size == 0 {
64            if sample_count as usize > reader.remaining() / stsz_item_size {
65                return Err(Error::InvalidData(
66                    "stsz sample_count indicates more values than could fit in the box",
67                ));
68            }
69            sample_sizes.reserve(sample_count as usize);
70            for _ in 0..sample_count {
71                let sample_number = reader.get_u32();
72                sample_sizes.push(sample_number);
73            }
74        }
75
76        Ok(StszBox {
77            version,
78            flags,
79            sample_size,
80            sample_count,
81            sample_sizes,
82        })
83    }
84
85    fn size_hint() -> usize {
86        12
87    }
88}
89
90impl<W: Write> WriteBox<&mut W> for StszBox {
91    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
92        let size = self.box_size();
93        BoxHeader::new(Self::TYPE, size).write(writer)?;
94
95        write_box_header_ext(writer, self.version, self.flags)?;
96
97        writer.write_u32::<BigEndian>(self.sample_size)?;
98        writer.write_u32::<BigEndian>(self.sample_count)?;
99        if self.sample_size == 0 {
100            if self.sample_count != self.sample_sizes.len() as u32 {
101                return Err(Error::InvalidData("sample count out of sync"));
102            }
103            for sample_number in self.sample_sizes.iter() {
104                writer.write_u32::<BigEndian>(*sample_number)?;
105            }
106        }
107
108        Ok(size)
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115    use crate::mp4box::BoxHeader;
116
117    #[tokio::test]
118    async fn test_stsz_same_size() {
119        let src_box = StszBox {
120            version: 0,
121            flags: 0,
122            sample_size: 1165,
123            sample_count: 12,
124            sample_sizes: vec![],
125        };
126        let mut buf = Vec::new();
127        src_box.write_box(&mut buf).unwrap();
128        assert_eq!(buf.len(), src_box.box_size() as usize);
129
130        let mut reader = buf.as_slice();
131        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
132        assert_eq!(header.kind, BoxType::StszBox);
133        assert_eq!(src_box.box_size(), header.size);
134
135        let dst_box = StszBox::read_block(&mut reader).unwrap();
136        assert_eq!(src_box, dst_box);
137    }
138
139    #[tokio::test]
140    async fn test_stsz_many_sizes() {
141        let src_box = StszBox {
142            version: 0,
143            flags: 0,
144            sample_size: 0,
145            sample_count: 9,
146            sample_sizes: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
147        };
148        let mut buf = Vec::new();
149        src_box.write_box(&mut buf).unwrap();
150        assert_eq!(buf.len(), src_box.box_size() as usize);
151
152        let mut reader = buf.as_slice();
153        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
154        assert_eq!(header.kind, BoxType::StszBox);
155        assert_eq!(src_box.box_size(), header.size);
156
157        let dst_box = StszBox::read_block(&mut reader).unwrap();
158        assert_eq!(src_box, dst_box);
159    }
160}