1use std::io;
2
3use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
4use bytes::Bytes;
5
6use crate::boxes::header::{BoxHeader, FullBoxHeader};
7use crate::boxes::traits::BoxType;
8
9#[derive(Debug, Clone, PartialEq)]
10pub struct Trun {
13 pub header: FullBoxHeader,
14 pub data_offset: Option<i32>,
15 pub first_sample_flags: Option<TrunSampleFlag>,
16 pub samples: Vec<TrunSample>,
17}
18
19impl Trun {
20 pub fn new(samples: Vec<TrunSample>, first_sample_flags: Option<TrunSampleFlag>) -> Self {
21 let flags = if samples.is_empty() {
22 Self::FLAG_DATA_OFFSET
23 } else {
24 let mut flags = Self::FLAG_DATA_OFFSET;
25 if samples[0].duration.is_some() {
26 flags |= Self::FLAG_SAMPLE_DURATION;
27 }
28 if samples[0].size.is_some() {
29 flags |= Self::FLAG_SAMPLE_SIZE;
30 }
31 if samples[0].flags.is_some() {
32 flags |= Self::FLAG_SAMPLE_FLAGS;
33 }
34 if samples[0].composition_time_offset.is_some() {
35 flags |= Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET;
36 }
37 flags
38 };
39
40 let version = if samples
41 .iter()
42 .any(|s| s.composition_time_offset.is_some() && s.composition_time_offset.unwrap() < 0)
43 {
44 1
45 } else {
46 0
47 };
48
49 Self {
50 header: FullBoxHeader::new(Self::NAME, version, flags),
51 data_offset: Some(0),
52 first_sample_flags,
53 samples,
54 }
55 }
56}
57
58#[derive(Debug, Clone, PartialEq)]
59pub struct TrunSample {
60 pub duration: Option<u32>,
61 pub size: Option<u32>,
62 pub flags: Option<TrunSampleFlag>,
63 pub composition_time_offset: Option<i64>, }
65
66#[derive(Debug, Clone, PartialEq, Copy, Default)]
67pub struct TrunSampleFlag {
68 pub reserved: u8, pub is_leading: u8, pub sample_depends_on: u8, pub sample_is_depended_on: u8, pub sample_has_redundancy: u8, pub sample_padding_value: u8, pub sample_is_non_sync_sample: bool, pub sample_degradation_priority: u16, }
77
78impl TrunSampleFlag {
79 pub fn validate(&self) -> io::Result<()> {
80 if self.reserved != 0 {
81 return Err(io::Error::new(io::ErrorKind::InvalidData, "reserved bits must be 0"));
82 }
83
84 if self.is_leading > 2 {
85 return Err(io::Error::new(io::ErrorKind::InvalidData, "is_leading must be 0, 1 or 2"));
86 }
87
88 if self.sample_depends_on > 2 {
89 return Err(io::Error::new(
90 io::ErrorKind::InvalidData,
91 "sample_depends_on must be 0, 1 or 2",
92 ));
93 }
94
95 if self.sample_is_depended_on > 2 {
96 return Err(io::Error::new(
97 io::ErrorKind::InvalidData,
98 "sample_is_depended_on must be 0, 1 or 2",
99 ));
100 }
101
102 if self.sample_has_redundancy > 2 {
103 return Err(io::Error::new(
104 io::ErrorKind::InvalidData,
105 "sample_has_redundancy must be 0, 1 or 2",
106 ));
107 }
108
109 if self.sample_padding_value > 7 {
110 return Err(io::Error::new(
111 io::ErrorKind::InvalidData,
112 "sample_padding_value must be 0, 1, 2, 3, 4, 5, 6 or 7",
113 ));
114 }
115
116 Ok(())
117 }
118}
119
120impl From<u32> for TrunSampleFlag {
121 fn from(value: u32) -> Self {
122 let reserved = (value >> 28) as u8;
123 let is_leading = ((value >> 26) & 0b11) as u8;
124 let sample_depends_on = ((value >> 24) & 0b11) as u8;
125 let sample_is_depended_on = ((value >> 22) & 0b11) as u8;
126 let sample_has_redundancy = ((value >> 20) & 0b11) as u8;
127 let sample_padding_value = ((value >> 17) & 0b111) as u8;
128 let sample_is_non_sync_sample = ((value >> 16) & 0b1) != 0;
129 let sample_degradation_priority = (value & 0xFFFF) as u16;
130
131 Self {
132 reserved,
133 is_leading,
134 sample_depends_on,
135 sample_is_depended_on,
136 sample_has_redundancy,
137 sample_padding_value,
138 sample_is_non_sync_sample,
139 sample_degradation_priority,
140 }
141 }
142}
143
144impl From<TrunSampleFlag> for u32 {
145 fn from(value: TrunSampleFlag) -> Self {
146 let mut result = 0;
147
148 result |= (value.reserved as u32) << 28;
149 result |= (value.is_leading as u32) << 26;
150 result |= (value.sample_depends_on as u32) << 24;
151 result |= (value.sample_is_depended_on as u32) << 22;
152 result |= (value.sample_has_redundancy as u32) << 20;
153 result |= (value.sample_padding_value as u32) << 17;
154 result |= (value.sample_is_non_sync_sample as u32) << 16;
155 result |= value.sample_degradation_priority as u32;
156
157 result
158 }
159}
160
161impl Trun {
162 pub const FLAG_DATA_OFFSET: u32 = 0x000001;
163 pub const FLAG_FIRST_SAMPLE_FLAGS: u32 = 0x000004;
164 pub const FLAG_SAMPLE_COMPOSITION_TIME_OFFSET: u32 = 0x000800;
165 pub const FLAG_SAMPLE_DURATION: u32 = 0x000100;
166 pub const FLAG_SAMPLE_FLAGS: u32 = 0x000400;
167 pub const FLAG_SAMPLE_SIZE: u32 = 0x000200;
168}
169
170impl BoxType for Trun {
171 const NAME: [u8; 4] = *b"trun";
172
173 fn demux(header: BoxHeader, data: Bytes) -> io::Result<Self> {
174 let mut reader = io::Cursor::new(data);
175
176 let header = FullBoxHeader::demux(header, &mut reader)?;
177
178 let sample_count = reader.read_u32::<BigEndian>()?;
179
180 let data_offset = if header.flags & Self::FLAG_DATA_OFFSET != 0 {
181 Some(reader.read_i32::<BigEndian>()?)
182 } else {
183 None
184 };
185
186 let first_sample_flags = if header.flags & Self::FLAG_FIRST_SAMPLE_FLAGS != 0 {
187 Some(reader.read_u32::<BigEndian>()?.into())
188 } else {
189 None
190 };
191
192 let mut samples = Vec::with_capacity(sample_count as usize);
193 for _ in 0..sample_count {
194 let duration = if header.flags & Self::FLAG_SAMPLE_DURATION != 0 {
195 Some(reader.read_u32::<BigEndian>()?)
196 } else {
197 None
198 };
199
200 let size = if header.flags & Self::FLAG_SAMPLE_SIZE != 0 {
201 Some(reader.read_u32::<BigEndian>()?)
202 } else {
203 None
204 };
205
206 let flags = if header.flags & Self::FLAG_SAMPLE_FLAGS != 0 {
207 Some(reader.read_u32::<BigEndian>()?.into())
208 } else {
209 None
210 };
211
212 let composition_time_offset = if header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET != 0 {
213 if header.version == 1 {
214 Some(reader.read_i32::<BigEndian>()? as i64)
215 } else {
216 Some(reader.read_u32::<BigEndian>()? as i64)
217 }
218 } else {
219 None
220 };
221
222 samples.push(TrunSample {
223 duration,
224 size,
225 flags,
226 composition_time_offset,
227 });
228 }
229
230 Ok(Self {
231 header,
232 data_offset,
233 first_sample_flags,
234 samples,
235 })
236 }
237
238 fn primitive_size(&self) -> u64 {
239 self.header.size()
240 + 4 + if self.header.flags & Self::FLAG_DATA_OFFSET != 0 { 4 } else { 0 }
242 + if self.header.flags & Self::FLAG_FIRST_SAMPLE_FLAGS != 0 { 4 } else { 0 }
243 + self.samples.iter().map(|_| {
244 (if self.header.flags & Self::FLAG_SAMPLE_DURATION != 0 { 4 } else { 0 })
245 + (if self.header.flags & Self::FLAG_SAMPLE_SIZE != 0 { 4 } else { 0 })
246 + (if self.header.flags & Self::FLAG_SAMPLE_FLAGS != 0 { 4 } else { 0 })
247 + (if self.header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET != 0 {
248 4
249 } else {
250 0
251 })
252 }).sum::<u64>()
253 }
254
255 fn primitive_mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> {
256 self.header.mux(writer)?;
257
258 writer.write_u32::<BigEndian>(self.samples.len() as u32)?;
259
260 if let Some(data_offset) = self.data_offset {
261 writer.write_i32::<BigEndian>(data_offset)?;
262 }
263
264 if let Some(first_sample_flags) = self.first_sample_flags {
265 writer.write_u32::<BigEndian>(first_sample_flags.into())?;
266 }
267
268 for sample in &self.samples {
269 if let Some(duration) = sample.duration {
270 writer.write_u32::<BigEndian>(duration)?;
271 }
272
273 if let Some(size) = sample.size {
274 writer.write_u32::<BigEndian>(size)?;
275 }
276
277 if let Some(flags) = sample.flags {
278 writer.write_u32::<BigEndian>(flags.into())?;
279 }
280
281 if let Some(composition_time_offset) = sample.composition_time_offset {
282 if self.header.version == 1 {
283 writer.write_i32::<BigEndian>(composition_time_offset as i32)?;
284 } else {
285 writer.write_u32::<BigEndian>(composition_time_offset as u32)?;
286 }
287 }
288 }
289
290 Ok(())
291 }
292
293 fn validate(&self) -> io::Result<()> {
294 if self.header.version > 1 {
295 return Err(io::Error::new(io::ErrorKind::InvalidData, "trun version must be 0 or 1"));
296 }
297
298 if self.header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET == 0 && self.header.version == 1 {
299 return Err(io::Error::new(
300 io::ErrorKind::InvalidData,
301 "trun version must be 0 if sample composition time offset is not present",
302 ));
303 }
304
305 if self.header.flags & Self::FLAG_DATA_OFFSET != 0 && self.data_offset.is_none() {
306 return Err(io::Error::new(
307 io::ErrorKind::InvalidData,
308 "trun data offset is present but not set",
309 ));
310 } else if self.header.flags & Self::FLAG_DATA_OFFSET == 0 && self.data_offset.is_some() {
311 return Err(io::Error::new(
312 io::ErrorKind::InvalidData,
313 "trun data offset is not present but set",
314 ));
315 }
316
317 if self.header.flags & Self::FLAG_FIRST_SAMPLE_FLAGS != 0 && self.first_sample_flags.is_none() {
318 return Err(io::Error::new(
319 io::ErrorKind::InvalidData,
320 "trun first sample flags is present but not set",
321 ));
322 } else if self.header.flags & Self::FLAG_FIRST_SAMPLE_FLAGS == 0 && self.first_sample_flags.is_some() {
323 return Err(io::Error::new(
324 io::ErrorKind::InvalidData,
325 "trun first sample flags is not present but set",
326 ));
327 }
328
329 if self.header.flags & Self::FLAG_SAMPLE_DURATION != 0 && self.samples.iter().any(|s| s.duration.is_none()) {
330 return Err(io::Error::new(
331 io::ErrorKind::InvalidData,
332 "trun sample duration is present but not set",
333 ));
334 } else if self.header.flags & Self::FLAG_SAMPLE_DURATION == 0 && self.samples.iter().any(|s| s.duration.is_some()) {
335 return Err(io::Error::new(
336 io::ErrorKind::InvalidData,
337 "trun sample duration is not present but set",
338 ));
339 }
340
341 if self.header.flags & Self::FLAG_SAMPLE_SIZE != 0 && self.samples.iter().any(|s| s.size.is_none()) {
342 return Err(io::Error::new(
343 io::ErrorKind::InvalidData,
344 "trun sample size is present but not set",
345 ));
346 } else if self.header.flags & Self::FLAG_SAMPLE_SIZE == 0 && self.samples.iter().any(|s| s.size.is_some()) {
347 return Err(io::Error::new(
348 io::ErrorKind::InvalidData,
349 "trun sample size is not present but set",
350 ));
351 }
352
353 if self.header.flags & Self::FLAG_SAMPLE_FLAGS != 0 && self.samples.iter().any(|s| s.flags.is_none()) {
354 return Err(io::Error::new(
355 io::ErrorKind::InvalidData,
356 "trun sample flags is present but not set",
357 ));
358 } else if self.header.flags & Self::FLAG_SAMPLE_FLAGS == 0 && self.samples.iter().any(|s| s.flags.is_some()) {
359 return Err(io::Error::new(
360 io::ErrorKind::InvalidData,
361 "trun sample flags is not present but set",
362 ));
363 }
364
365 if self.header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET != 0
366 && self.samples.iter().any(|s| s.composition_time_offset.is_none())
367 {
368 return Err(io::Error::new(
369 io::ErrorKind::InvalidData,
370 "trun sample composition time offset is present but not set",
371 ));
372 } else if self.header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET == 0
373 && self.samples.iter().any(|s| s.composition_time_offset.is_some())
374 {
375 return Err(io::Error::new(
376 io::ErrorKind::InvalidData,
377 "trun sample composition time offset is not present but set",
378 ));
379 }
380
381 if self.header.flags & Self::FLAG_SAMPLE_COMPOSITION_TIME_OFFSET != 0 {
382 if self.header.version == 1
383 && self
384 .samples
385 .iter()
386 .any(|s| s.composition_time_offset.unwrap() > i32::MAX as i64)
387 {
388 return Err(io::Error::new(
389 io::ErrorKind::InvalidData,
390 "trun sample composition time offset cannot be larger than i32::MAX",
391 ));
392 } else if self.header.version == 0
393 && self
394 .samples
395 .iter()
396 .any(|s| s.composition_time_offset.unwrap() > u32::MAX as i64)
397 {
398 return Err(io::Error::new(
399 io::ErrorKind::InvalidData,
400 "trun sample composition time offset cannot be larger than u32::MAX",
401 ));
402 }
403 }
404
405 if let Some(first_sample_flags) = self.first_sample_flags {
406 first_sample_flags.validate()?;
407 }
408
409 for sample in &self.samples {
410 if let Some(flags) = sample.flags {
411 flags.validate()?;
412 }
413 }
414
415 Ok(())
416 }
417}