flowly_mp4/mp4box/
trun.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 TrunBox {
10    pub version: u8,
11    pub flags: u32,
12    pub sample_count: u32,
13    pub data_offset: Option<i32>,
14    pub first_sample_flags: Option<u32>,
15
16    #[serde(skip_serializing)]
17    pub sample_durations: Vec<u32>,
18
19    #[serde(skip_serializing)]
20    pub sample_sizes: Vec<u32>,
21
22    #[serde(skip_serializing)]
23    pub sample_flags: Vec<u32>,
24
25    #[serde(skip_serializing)]
26    pub sample_cts: Vec<u32>,
27}
28
29impl TrunBox {
30    pub const FLAG_DATA_OFFSET: u32 = 0x01;
31    pub const FLAG_FIRST_SAMPLE_FLAGS: u32 = 0x04;
32    pub const FLAG_SAMPLE_DURATION: u32 = 0x100;
33    pub const FLAG_SAMPLE_SIZE: u32 = 0x200;
34    pub const FLAG_SAMPLE_FLAGS: u32 = 0x400;
35    pub const FLAG_SAMPLE_CTS: u32 = 0x800;
36
37    pub fn get_type(&self) -> BoxType {
38        BoxType::TrunBox
39    }
40
41    pub fn get_size(&self) -> u64 {
42        let mut sum = HEADER_SIZE + HEADER_EXT_SIZE + 4;
43        if TrunBox::FLAG_DATA_OFFSET & self.flags > 0 {
44            sum += 4;
45        }
46        if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 {
47            sum += 4;
48        }
49        if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 {
50            sum += 4 * self.sample_count as u64;
51        }
52        if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 {
53            sum += 4 * self.sample_count as u64;
54        }
55        if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 {
56            sum += 4 * self.sample_count as u64;
57        }
58        if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 {
59            sum += 4 * self.sample_count as u64;
60        }
61        sum
62    }
63}
64
65impl Mp4Box for TrunBox {
66    const TYPE: BoxType = BoxType::TrunBox;
67
68    fn box_size(&self) -> u64 {
69        self.get_size()
70    }
71
72    fn to_json(&self) -> Result<String, Error> {
73        Ok(serde_json::to_string(&self).unwrap())
74    }
75
76    fn summary(&self) -> Result<String, Error> {
77        let s = format!("sample_size={}", self.sample_count);
78        Ok(s)
79    }
80}
81
82impl BlockReader for TrunBox {
83    fn read_block<'a>(reader: &mut impl Reader<'a>) -> Result<Self, Error> {
84        let (version, flags) = read_box_header_ext(reader);
85
86        let sample_size = if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 { size_of::<u32>() } else { 0 } // sample_duration
87            + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { size_of::<u32>() } else { 0 } // sample_size
88            + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { size_of::<u32>() } else { 0 } // sample_flags
89            + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { size_of::<u32>() } else { 0 }; // sample_composition_time_offset
90
91        let sample_count = reader.get_u32();
92
93        let data_offset = if TrunBox::FLAG_DATA_OFFSET & flags > 0 {
94            Some(reader.try_get_i32()?)
95        } else {
96            None
97        };
98
99        let first_sample_flags = if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & flags > 0 {
100            Some(reader.try_get_u32()?)
101        } else {
102            None
103        };
104
105        let mut sample_durations = Vec::new();
106        let mut sample_sizes = Vec::new();
107        let mut sample_flags = Vec::new();
108        let mut sample_cts = Vec::new();
109
110        if sample_count as usize * sample_size > reader.remaining() {
111            return Err(Error::InvalidData(
112                "trun sample_count indicates more values than could fit in the box",
113            ));
114        }
115
116        if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 {
117            sample_durations.reserve(sample_count as usize);
118        }
119
120        if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 {
121            sample_sizes.reserve(sample_count as usize);
122        }
123
124        if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 {
125            sample_flags.reserve(sample_count as usize);
126        }
127
128        if TrunBox::FLAG_SAMPLE_CTS & flags > 0 {
129            sample_cts.reserve(sample_count as usize);
130        }
131
132        for _ in 0..sample_count {
133            if TrunBox::FLAG_SAMPLE_DURATION & flags > 0 {
134                let duration = reader.get_u32();
135                sample_durations.push(duration);
136            }
137
138            if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 {
139                let sample_size = reader.get_u32();
140                sample_sizes.push(sample_size);
141            }
142
143            if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 {
144                let sample_flag = reader.get_u32();
145                sample_flags.push(sample_flag);
146            }
147
148            if TrunBox::FLAG_SAMPLE_CTS & flags > 0 {
149                let cts = reader.get_u32();
150                sample_cts.push(cts);
151            }
152        }
153
154        Ok(TrunBox {
155            version,
156            flags,
157            sample_count,
158            data_offset,
159            first_sample_flags,
160            sample_durations,
161            sample_sizes,
162            sample_flags,
163            sample_cts,
164        })
165    }
166
167    fn size_hint() -> usize {
168        8
169    }
170}
171
172impl<W: Write> WriteBox<&mut W> for TrunBox {
173    fn write_box(&self, writer: &mut W) -> Result<u64, Error> {
174        let size = self.box_size();
175        BoxHeader::new(Self::TYPE, size).write(writer)?;
176
177        write_box_header_ext(writer, self.version, self.flags)?;
178
179        writer.write_u32::<BigEndian>(self.sample_count)?;
180        if let Some(v) = self.data_offset {
181            writer.write_i32::<BigEndian>(v)?;
182        }
183        if let Some(v) = self.first_sample_flags {
184            writer.write_u32::<BigEndian>(v)?;
185        }
186        if self.sample_count != self.sample_sizes.len() as u32 {
187            return Err(Error::InvalidData("sample count out of sync"));
188        }
189        for i in 0..self.sample_count as usize {
190            if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 {
191                writer.write_u32::<BigEndian>(self.sample_durations[i])?;
192            }
193            if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 {
194                writer.write_u32::<BigEndian>(self.sample_sizes[i])?;
195            }
196            if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 {
197                writer.write_u32::<BigEndian>(self.sample_flags[i])?;
198            }
199            if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 {
200                writer.write_u32::<BigEndian>(self.sample_cts[i])?;
201            }
202        }
203
204        Ok(size)
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211    use crate::mp4box::BoxHeader;
212
213    #[tokio::test]
214    async fn test_trun_same_size() {
215        let src_box = TrunBox {
216            version: 0,
217            flags: 0,
218            data_offset: None,
219            sample_count: 0,
220            sample_sizes: vec![],
221            sample_flags: vec![],
222            first_sample_flags: None,
223            sample_durations: vec![],
224            sample_cts: vec![],
225        };
226        let mut buf = Vec::new();
227        src_box.write_box(&mut buf).unwrap();
228        assert_eq!(buf.len(), src_box.box_size() as usize);
229
230        let mut reader = buf.as_slice();
231        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
232        assert_eq!(header.kind, BoxType::TrunBox);
233        assert_eq!(src_box.box_size(), header.size);
234
235        let dst_box = TrunBox::read_block(&mut reader).unwrap();
236        assert_eq!(src_box, dst_box);
237    }
238
239    #[tokio::test]
240    async fn test_trun_many_sizes() {
241        let src_box = TrunBox {
242            version: 0,
243            flags: TrunBox::FLAG_SAMPLE_DURATION
244                | TrunBox::FLAG_SAMPLE_SIZE
245                | TrunBox::FLAG_SAMPLE_FLAGS
246                | TrunBox::FLAG_SAMPLE_CTS,
247            data_offset: None,
248            sample_count: 9,
249            sample_sizes: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
250            sample_flags: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
251            first_sample_flags: None,
252            sample_durations: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
253            sample_cts: vec![1165, 11, 11, 8545, 10126, 10866, 9643, 9351, 7730],
254        };
255        let mut buf = Vec::new();
256        src_box.write_box(&mut buf).unwrap();
257        assert_eq!(buf.len(), src_box.box_size() as usize);
258
259        let mut reader = buf.as_slice();
260        let header = BoxHeader::read(&mut reader, &mut 0).await.unwrap().unwrap();
261        assert_eq!(header.kind, BoxType::TrunBox);
262        assert_eq!(src_box.box_size(), header.size);
263
264        let dst_box = TrunBox::read_block(&mut reader).unwrap();
265        assert_eq!(src_box, dst_box);
266    }
267}