1use crate::*;
2
3ext! {
4 name: Trun,
5 versions: [0, 1],
6 flags: {
7 data_offset = 0,
8 first_sample_flags = 2,
9 sample_duration = 8,
10 sample_size = 9,
11 sample_flags = 10,
12 sample_cts = 11,
13 }
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Default)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18pub struct Trun {
19 pub data_offset: Option<i32>,
20 pub samples: TrunSamples,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30pub enum TrunSamples {
31 Inherited {
34 count: u32,
35 first_flags: Option<u32>,
36 },
37
38 Explicit(Vec<TrunEntry>),
40}
41
42impl TrunSamples {
43 pub fn len(&self) -> usize {
45 match self {
46 Self::Inherited { count, .. } => *count as usize,
47 Self::Explicit(entries) => entries.len(),
48 }
49 }
50
51 pub fn is_empty(&self) -> bool {
52 self.len() == 0
53 }
54
55 pub fn get(&self, index: usize) -> Option<TrunEntry> {
57 match self {
58 Self::Inherited { count, first_flags } => {
59 (index < *count as usize).then(|| TrunEntry {
60 flags: if index == 0 { *first_flags } else { None },
61 ..Default::default()
62 })
63 }
64 Self::Explicit(entries) => entries.get(index).copied(),
65 }
66 }
67
68 pub fn iter(&self) -> TrunSamplesIter<'_> {
70 match self {
71 Self::Inherited { count, first_flags } => TrunSamplesIter::Inherited {
72 remaining: *count,
73 first_flags: *first_flags,
74 },
75 Self::Explicit(entries) => TrunSamplesIter::Explicit(entries.iter()),
76 }
77 }
78}
79
80impl Default for TrunSamples {
81 fn default() -> Self {
82 Self::Inherited {
83 count: 0,
84 first_flags: None,
85 }
86 }
87}
88
89impl From<Vec<TrunEntry>> for TrunSamples {
90 fn from(entries: Vec<TrunEntry>) -> Self {
91 Self::Explicit(entries)
92 }
93}
94
95impl<'a> IntoIterator for &'a TrunSamples {
96 type Item = TrunEntry;
97 type IntoIter = TrunSamplesIter<'a>;
98
99 fn into_iter(self) -> Self::IntoIter {
100 self.iter()
101 }
102}
103
104#[derive(Debug, Clone)]
106pub enum TrunSamplesIter<'a> {
107 Inherited {
108 remaining: u32,
109 first_flags: Option<u32>,
110 },
111 Explicit(std::slice::Iter<'a, TrunEntry>),
112}
113
114impl Iterator for TrunSamplesIter<'_> {
115 type Item = TrunEntry;
116
117 fn next(&mut self) -> Option<TrunEntry> {
118 match self {
119 Self::Inherited {
120 remaining,
121 first_flags,
122 } => {
123 *remaining = remaining.checked_sub(1)?;
124 Some(TrunEntry {
125 flags: first_flags.take(),
126 ..Default::default()
127 })
128 }
129 Self::Explicit(entries) => entries.next().copied(),
130 }
131 }
132
133 fn nth(&mut self, n: usize) -> Option<TrunEntry> {
134 match self {
135 Self::Inherited {
136 remaining,
137 first_flags,
138 } => {
139 if n > 0 {
141 *first_flags = None;
142 *remaining = remaining.saturating_sub(n.try_into().unwrap_or(u32::MAX));
143 }
144 }
145 Self::Explicit(entries) => return entries.nth(n).copied(),
146 }
147 self.next()
148 }
149
150 fn size_hint(&self) -> (usize, Option<usize>) {
151 let len = match self {
152 Self::Inherited { remaining, .. } => *remaining as usize,
153 Self::Explicit(entries) => entries.len(),
154 };
155 (len, Some(len))
156 }
157}
158
159impl ExactSizeIterator for TrunSamplesIter<'_> {}
160
161impl Default for TrunSamplesIter<'_> {
162 fn default() -> Self {
164 Self::Inherited {
165 remaining: 0,
166 first_flags: None,
167 }
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
179#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
180pub struct TrunEntry {
181 pub duration: Option<u32>,
182 pub size: Option<u32>,
183 pub flags: Option<u32>,
184 pub cts: Option<i64>,
186}
187
188impl AtomExt for Trun {
189 const KIND_EXT: FourCC = FourCC::new(b"trun");
190
191 type Ext = TrunExt;
192
193 fn decode_body_ext<B: Buf>(buf: &mut B, ext: TrunExt) -> Result<Self> {
194 let sample_count = u32::decode(buf)?;
195 let data_offset = match ext.data_offset {
196 true => i32::decode(buf)?.into(),
197 false => None,
198 };
199
200 let mut first_sample_flags = match ext.first_sample_flags {
201 true => u32::decode(buf)?.into(),
202 false => None,
203 };
204
205 let fields = [
206 ext.sample_duration,
207 ext.sample_size,
208 ext.sample_flags,
209 ext.sample_cts,
210 ]
211 .into_iter()
212 .filter(|&field| field)
213 .count();
214
215 if fields == 0 {
218 return Ok(Trun {
219 data_offset,
220 samples: TrunSamples::Inherited {
221 count: sample_count,
222 first_flags: first_sample_flags,
223 },
224 });
225 }
226
227 let capacity = (sample_count as usize).min(buf.remaining() / (4 * fields));
229 let mut entries = Vec::with_capacity(capacity);
230
231 for _ in 0..sample_count {
232 let duration = match ext.sample_duration {
233 true => u32::decode(buf)?.into(),
234 false => None,
235 };
236 let size = match ext.sample_size {
237 true => u32::decode(buf)?.into(),
238 false => None,
239 };
240 let sample_flags = match first_sample_flags.take() {
241 Some(flags) => Some(flags),
242 None => match ext.sample_flags {
243 true => u32::decode(buf)?.into(),
244 false => None,
245 },
246 };
247 let cts = match (ext.sample_cts, ext.version) {
248 (false, _) => None,
249 (true, TrunVersion::V0) => Some(u32::decode(buf)?.into()),
250 (true, TrunVersion::V1) => Some(i32::decode(buf)?.into()),
251 };
252
253 entries.push(TrunEntry {
254 duration,
255 size,
256 flags: sample_flags,
257 cts,
258 });
259 }
260
261 Ok(Trun {
262 data_offset,
263 samples: TrunSamples::Explicit(entries),
264 })
265 }
266
267 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<TrunExt> {
268 let entries = match &self.samples {
269 TrunSamples::Inherited { count, first_flags } => {
270 let ext = TrunExt {
271 version: TrunVersion::V1,
272 data_offset: self.data_offset.is_some(),
273 first_sample_flags: first_flags.is_some(),
274 ..Default::default()
275 };
276
277 count.encode(buf)?;
278 self.data_offset.encode(buf)?;
279 first_flags.encode(buf)?;
280
281 return Ok(ext);
282 }
283 TrunSamples::Explicit(entries) => entries,
284 };
285
286 let any_flags = entries.iter().any(|s| s.flags.is_some());
287 let first_only_flags = any_flags
288 && entries.first().is_some_and(|s| s.flags.is_some())
289 && entries.iter().skip(1).all(|s| s.flags.is_none());
290
291 let sample_flags = any_flags && !first_only_flags;
294
295 let mut cts = entries.iter().filter_map(|s| s.cts);
297 let version = if cts.clone().all(|cts| i32::try_from(cts).is_ok()) {
298 TrunVersion::V1
299 } else if cts.all(|cts| u32::try_from(cts).is_ok()) {
300 TrunVersion::V0
301 } else {
302 return Err(Error::InvalidCombination(
303 "trun composition offsets fit neither i32 nor u32",
304 ));
305 };
306
307 let ext = TrunExt {
308 version,
309 data_offset: self.data_offset.is_some(),
310 first_sample_flags: first_only_flags,
311
312 sample_duration: entries.iter().any(|s| s.duration.is_some()),
317 sample_size: entries.iter().any(|s| s.size.is_some()),
318 sample_flags,
319 sample_cts: entries.iter().any(|s| s.cts.is_some()),
320 };
321
322 (entries.len() as u32).encode(buf)?;
323
324 self.data_offset.encode(buf)?;
325 if ext.first_sample_flags {
326 entries[0].flags.unwrap().encode(buf)?;
327 }
328
329 for entry in entries {
330 if ext.sample_duration {
331 Some(Some(entry.duration.unwrap_or(0))).encode(buf)?;
332 }
333 if ext.sample_size {
334 Some(Some(entry.size.unwrap_or(0))).encode(buf)?;
335 }
336 if ext.sample_flags {
337 Some(Some(entry.flags.unwrap_or(0))).encode(buf)?;
338 }
339 if ext.sample_cts {
340 let cts = entry.cts.unwrap_or(0);
342 match version {
343 TrunVersion::V0 => (cts as u32).encode(buf)?,
344 TrunVersion::V1 => (cts as i32).encode(buf)?,
345 }
346 }
347 }
348
349 Ok(ext)
350 }
351}
352
353#[cfg(test)]
354mod test {
355 use super::*;
356
357 #[test]
364 fn first_sample_flags_roundtrip() {
365 let trun = Trun {
366 data_offset: Some(100),
367 samples: TrunSamples::Explicit(vec![
368 TrunEntry {
369 duration: Some(512),
370 size: Some(1000),
371 flags: Some(0x02000000), cts: None,
373 },
374 TrunEntry {
375 duration: Some(512),
376 size: Some(200),
377 flags: None, cts: None,
379 },
380 TrunEntry {
381 duration: Some(512),
382 size: Some(200),
383 flags: None,
384 cts: None,
385 },
386 ]),
387 };
388
389 let mut buf = Vec::new();
390 trun.encode(&mut buf).expect("encode");
391
392 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
393 assert_eq!(decoded.data_offset, Some(100));
394 let decoded: Vec<_> = decoded.samples.iter().collect();
395
396 assert_eq!(decoded[0].flags, Some(0x02000000));
398 assert_eq!(decoded[1].flags, None);
400 assert_eq!(decoded[2].flags, None);
401 assert_eq!(decoded.len(), 3);
402 }
403
404 #[test]
407 fn mixed_flags_uses_per_sample() {
408 let trun = Trun {
409 data_offset: Some(100),
410 samples: TrunSamples::Explicit(vec![
411 TrunEntry {
412 duration: Some(512),
413 size: Some(1000),
414 flags: Some(0x02000000), cts: None,
416 },
417 TrunEntry {
418 duration: Some(512),
419 size: Some(200),
420 flags: Some(0x01010000), cts: None,
422 },
423 TrunEntry {
424 duration: Some(512),
425 size: Some(200),
426 flags: None, cts: None,
428 },
429 ]),
430 };
431
432 let mut buf = Vec::new();
433 trun.encode(&mut buf).expect("encode");
434
435 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
436 let decoded: Vec<_> = decoded.samples.iter().collect();
437
438 assert_eq!(decoded[0].flags, Some(0x02000000));
440 assert_eq!(decoded[1].flags, Some(0x01010000));
441 assert_eq!(decoded[2].flags, Some(0)); }
443
444 #[test]
446 fn all_flags_roundtrip() {
447 let trun = Trun {
448 data_offset: Some(100),
449 samples: TrunSamples::Explicit(vec![
450 TrunEntry {
451 duration: Some(512),
452 size: Some(1000),
453 flags: Some(0x02000000),
454 cts: None,
455 },
456 TrunEntry {
457 duration: Some(512),
458 size: Some(200),
459 flags: Some(0x01010000),
460 cts: None,
461 },
462 ]),
463 };
464
465 let mut buf = Vec::new();
466 trun.encode(&mut buf).expect("encode");
467
468 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
469 let decoded: Vec<_> = decoded.samples.iter().collect();
470
471 assert_eq!(decoded[0].flags, Some(0x02000000));
472 assert_eq!(decoded[1].flags, Some(0x01010000));
473 }
474
475 #[test]
478 fn duration_backfill_roundtrip() {
479 let trun = Trun {
480 data_offset: Some(100),
481 samples: TrunSamples::Explicit(vec![
482 TrunEntry {
483 duration: Some(512),
484 size: Some(1000),
485 flags: Some(0x02000000),
486 cts: None,
487 },
488 TrunEntry {
489 duration: None, size: Some(200),
491 flags: None,
492 cts: None,
493 },
494 ]),
495 };
496
497 let mut buf = Vec::new();
498 trun.encode(&mut buf).expect("encode");
499
500 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
501 let decoded: Vec<_> = decoded.samples.iter().collect();
502
503 assert_eq!(decoded[0].duration, Some(512));
504 assert_eq!(decoded[1].duration, Some(0));
506 }
507
508 #[test]
511 fn size_backfill_roundtrip() {
512 let trun = Trun {
513 data_offset: Some(100),
514 samples: TrunSamples::Explicit(vec![
515 TrunEntry {
516 duration: Some(512),
517 size: Some(1000),
518 flags: None,
519 cts: None,
520 },
521 TrunEntry {
522 duration: Some(512),
523 size: None, flags: None,
525 cts: None,
526 },
527 ]),
528 };
529
530 let mut buf = Vec::new();
531 trun.encode(&mut buf).expect("encode");
532
533 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
534 let decoded: Vec<_> = decoded.samples.iter().collect();
535
536 assert_eq!(decoded[0].size, Some(1000));
537 assert_eq!(decoded[1].size, Some(0));
539 }
540
541 #[test]
544 fn all_none_fields_omitted() {
545 let trun = Trun {
546 data_offset: Some(100),
547 samples: TrunSamples::Explicit(vec![
548 TrunEntry {
549 duration: None,
550 size: None,
551 flags: None,
552 cts: None,
553 },
554 TrunEntry {
555 duration: None,
556 size: None,
557 flags: None,
558 cts: None,
559 },
560 ]),
561 };
562
563 let mut buf = Vec::new();
564 trun.encode(&mut buf).expect("encode");
565
566 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
567 let decoded: Vec<_> = decoded.samples.iter().collect();
568
569 assert_eq!(decoded[0].duration, None);
570 assert_eq!(decoded[0].size, None);
571 assert_eq!(decoded[0].flags, None);
572 assert_eq!(decoded[0].cts, None);
573 }
574
575 #[test]
577 fn inherited_roundtrip() {
578 for first_flags in [None, Some(0x02000000)] {
579 let trun = Trun {
580 data_offset: Some(100),
581 samples: TrunSamples::Inherited {
582 count: u32::MAX,
583 first_flags,
584 },
585 };
586
587 let mut buf = Vec::new();
588 trun.encode(&mut buf).expect("encode");
589
590 let expected = 20 + first_flags.map_or(0, |_| 4);
592 assert_eq!(buf.len(), expected);
593
594 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
595 assert_eq!(decoded, trun);
596 assert_eq!(decoded.samples.len(), u32::MAX as usize);
597
598 let mut entries = decoded.samples.iter();
599 assert_eq!(entries.len(), u32::MAX as usize);
600 assert_eq!(
601 entries.next(),
602 Some(TrunEntry {
603 flags: first_flags,
604 ..Default::default()
605 })
606 );
607 assert_eq!(entries.next(), Some(TrunEntry::default()));
608 assert_eq!(entries.len(), u32::MAX as usize - 2);
609
610 assert_eq!(
612 entries.nth(u32::MAX as usize - 3),
613 Some(TrunEntry::default())
614 );
615 assert_eq!(entries.next(), None);
616
617 let last = u32::MAX as usize - 1;
618 assert_eq!(decoded.samples.get(0), decoded.samples.iter().next());
619 assert_eq!(decoded.samples.get(last), Some(TrunEntry::default()));
620 assert_eq!(decoded.samples.get(last + 1), None);
621 }
622 }
623
624 #[test]
626 fn explicit_without_fields_decodes_inherited() {
627 let trun = Trun {
628 data_offset: None,
629 samples: TrunSamples::Explicit(vec![
630 TrunEntry {
631 flags: Some(0x02000000),
632 ..Default::default()
633 },
634 TrunEntry::default(),
635 ]),
636 };
637
638 let mut buf = Vec::new();
639 trun.encode(&mut buf).expect("encode");
640
641 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
642 assert_eq!(
643 decoded.samples,
644 TrunSamples::Inherited {
645 count: 2,
646 first_flags: Some(0x02000000),
647 }
648 );
649 assert!(decoded.samples.iter().eq(trun.samples.iter()));
650 }
651
652 #[test]
654 fn random_access() {
655 let inherited = TrunSamples::Inherited {
656 count: 3,
657 first_flags: Some(0x02000000),
658 };
659 let explicit = TrunSamples::Explicit(vec![
660 TrunEntry {
661 size: Some(1),
662 ..Default::default()
663 },
664 TrunEntry {
665 size: Some(2),
666 ..Default::default()
667 },
668 ]);
669
670 for samples in [inherited, explicit] {
671 let all: Vec<_> = samples.iter().collect();
672 for n in 0..=all.len() {
673 assert_eq!(samples.get(n), all.get(n).copied());
674 assert_eq!(samples.iter().nth(n), all.get(n).copied());
675 }
676 }
677 }
678
679 fn cts_entries(cts: &[i64]) -> Trun {
680 Trun {
681 data_offset: None,
682 samples: cts
683 .iter()
684 .map(|&cts| TrunEntry {
685 cts: Some(cts),
686 ..Default::default()
687 })
688 .collect::<Vec<_>>()
689 .into(),
690 }
691 }
692
693 #[test]
696 fn cts_version_roundtrip() {
697 for (cts, version) in [
698 (vec![0, 1024, -512], 1),
699 (vec![0, 1 << 31, u32::MAX as i64], 0),
700 ] {
701 let trun = cts_entries(&cts);
702 let mut buf = Vec::new();
703 trun.encode(&mut buf).expect("encode");
704 assert_eq!(buf[8], version);
705
706 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
707 assert!(decoded.samples.iter().map(|e| e.cts.unwrap()).eq(cts));
708 }
709 }
710
711 #[test]
713 fn cts_version_0_is_unsigned() {
714 let mut buf = Vec::new();
715 cts_entries(&[-1]).encode(&mut buf).expect("encode");
716 assert_eq!(buf[8], 1);
717 buf[8] = 0;
718
719 let decoded = Trun::decode(&mut &buf[..]).expect("decode");
720 assert_eq!(decoded.samples.get(0).unwrap().cts, Some(u32::MAX as i64));
721 }
722
723 #[test]
724 fn cts_out_of_range_is_refused() {
725 for cts in [vec![-1, 1 << 31], vec![1 << 32], vec![i32::MIN as i64 - 1]] {
726 assert!(matches!(
727 cts_entries(&cts).encode(&mut Vec::new()),
728 Err(Error::InvalidCombination(_))
729 ));
730 }
731 }
732
733 #[test]
735 fn explicit_truncated() {
736 let mut buf = Vec::new();
737 Trun {
738 data_offset: None,
739 samples: TrunSamples::Explicit(vec![TrunEntry {
740 size: Some(1),
741 ..Default::default()
742 }]),
743 }
744 .encode(&mut buf)
745 .expect("encode");
746
747 buf[12..16].copy_from_slice(&u32::MAX.to_be_bytes());
749 assert!(Trun::decode(&mut &buf[..]).is_err());
750 }
751}