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 } + if TrunBox::FLAG_SAMPLE_SIZE & flags > 0 { size_of::<u32>() } else { 0 } + if TrunBox::FLAG_SAMPLE_FLAGS & flags > 0 { size_of::<u32>() } else { 0 } + if TrunBox::FLAG_SAMPLE_CTS & flags > 0 { size_of::<u32>() } else { 0 }; 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}