isobmff/boxes/
track_time.rs

1use std::fmt::Debug;
2use std::io;
3
4use fixed::FixedI32;
5use fixed::types::extra::U16;
6use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize, ZeroCopyReader};
7
8use crate::{BoxHeader, FullBoxHeader, IsoBox, IsoSized};
9
10/// Time to sample box
11///
12/// ISO/IEC 14496-12 - 8.6.1.2
13#[derive(IsoBox, Debug, PartialEq, Eq, Default)]
14#[iso_box(box_type = b"stts", crate_path = crate)]
15pub struct TimeToSampleBox {
16    /// The full box header.
17    pub full_header: FullBoxHeader,
18    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
19    pub entry_count: u32,
20    /// `sample_count` and `sample_delta`.
21    #[iso_box(repeated)]
22    pub entries: Vec<TimeToSampleBoxEntry>,
23}
24
25/// Entry in the [`TimeToSampleBox`].
26#[derive(Debug, PartialEq, Eq)]
27pub struct TimeToSampleBoxEntry {
28    /// An integer that counts the number of consecutive samples that have the given duration.
29    pub sample_count: u32,
30    /// An integer that gives the difference between the decoding timestamp of the next
31    /// sample and this one, in the time-scale of the media.
32    pub sample_delta: u32,
33}
34
35impl<'a> Deserialize<'a> for TimeToSampleBoxEntry {
36    fn deserialize<R>(mut reader: R) -> io::Result<Self>
37    where
38        R: ZeroCopyReader<'a>,
39    {
40        Ok(Self {
41            sample_count: u32::deserialize(&mut reader)?,
42            sample_delta: u32::deserialize(&mut reader)?,
43        })
44    }
45}
46
47impl Serialize for TimeToSampleBoxEntry {
48    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
49    where
50        W: std::io::Write,
51    {
52        self.sample_count.serialize(&mut writer)?;
53        self.sample_delta.serialize(&mut writer)?;
54        Ok(())
55    }
56}
57
58impl IsoSized for TimeToSampleBoxEntry {
59    fn size(&self) -> usize {
60        self.sample_count.size() + self.sample_delta.size()
61    }
62}
63
64/// Composition time to sample box
65///
66/// ISO/IEC 14496-12 - 8.6.1.3
67#[derive(IsoBox, PartialEq, Eq)]
68#[iso_box(box_type = b"ctts", skip_impl(deserialize_seed, serialize), crate_path = crate)]
69pub struct CompositionOffsetBox {
70    /// The full box header.
71    pub full_header: FullBoxHeader,
72    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
73    pub entry_count: u32,
74    /// `sample_count` and `sample_offset`.
75    #[iso_box(repeated)]
76    pub entries: Vec<CompositionOffsetBoxEntry>,
77}
78
79impl<'a> DeserializeSeed<'a, BoxHeader> for CompositionOffsetBox {
80    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
81    where
82        R: ZeroCopyReader<'a>,
83    {
84        let full_header = FullBoxHeader::deserialize(&mut reader)?;
85        let entry_count = u32::deserialize(&mut reader)?;
86
87        let mut entries = Vec::new();
88        if full_header.version == 0 || full_header.version == 1 {
89            for _ in 0..entry_count {
90                entries.push(CompositionOffsetBoxEntry::deserialize_seed(&mut reader, full_header.version)?);
91            }
92        }
93
94        Ok(Self {
95            full_header,
96            entry_count,
97            entries,
98        })
99    }
100}
101
102impl Serialize for CompositionOffsetBox {
103    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
104    where
105        W: std::io::Write,
106    {
107        self.serialize_box_header(&mut writer)?;
108        self.full_header.serialize(&mut writer)?;
109        self.entry_count.serialize(&mut writer)?;
110
111        for entry in &self.entries {
112            entry.serialize(&mut writer, self)?;
113        }
114
115        Ok(())
116    }
117}
118
119impl Debug for CompositionOffsetBox {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        f.debug_struct("CompositionOffsetBox")
122            .field("full_header", &self.full_header)
123            .field("entry_count", &self.entry_count)
124            .field("entries.len", &self.entries.len())
125            .finish()
126    }
127}
128
129/// Entry in the [`CompositionOffsetBox`].
130#[derive(Debug, PartialEq, Eq)]
131pub struct CompositionOffsetBoxEntry {
132    /// An integer that counts the number of consecutive samples that have the given offset.
133    pub sample_count: u32,
134    /// An integer that gives the offset between CT and DT, such that `CT[n] = DT[n] + sample_offset[n]`.
135    pub sample_offset: i64,
136}
137
138impl<'a> DeserializeSeed<'a, u8> for CompositionOffsetBoxEntry {
139    fn deserialize_seed<R>(mut reader: R, seed: u8) -> io::Result<Self>
140    where
141        R: ZeroCopyReader<'a>,
142    {
143        Ok(Self {
144            sample_count: u32::deserialize(&mut reader)?,
145            sample_offset: if seed == 0 {
146                u32::deserialize(&mut reader)? as i64
147            } else if seed == 1 {
148                i32::deserialize(&mut reader)? as i64
149            } else {
150                return Err(io::Error::new(
151                    io::ErrorKind::InvalidData,
152                    "cannot be called with version > 1",
153                ));
154            },
155        })
156    }
157}
158
159impl CompositionOffsetBoxEntry {
160    fn serialize<W>(&self, mut writer: W, parent: &CompositionOffsetBox) -> io::Result<()>
161    where
162        W: std::io::Write,
163    {
164        self.sample_count.serialize(&mut writer)?;
165        if parent.full_header.version == 0 {
166            (self.sample_offset as u32).serialize(&mut writer)?;
167        } else if parent.full_header.version == 1 {
168            (self.sample_offset as i32).serialize(&mut writer)?;
169        }
170        Ok(())
171    }
172}
173
174impl IsoSized for CompositionOffsetBoxEntry {
175    fn size(&self) -> usize {
176        self.sample_count.size() + 4
177    }
178}
179
180/// Composition to decode box
181///
182/// ISO/IEC 14496-12 - 8.6.1.4
183#[derive(IsoBox, Debug, PartialEq, Eq)]
184#[iso_box(box_type = b"cslg", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
185pub struct CompositionToDecodeBox {
186    /// The full box header.
187    pub full_header: FullBoxHeader,
188    /// If this value is added to the composition timestamps (as calculated by the CTS
189    /// offsets from the DTS), then for all samples, their CTS is guaranteed to be greater than or equal
190    /// to their DTS, and the buffer model implied by the indicated profile/level will be honoured; if
191    /// `leastDecodeToDisplayDelta` is positive or zero, this field can be 0; otherwise it should be at least
192    /// (`-leastDecodeToDisplayDelta`)
193    pub composition_to_dt_shift: i64,
194    /// The smallest composition offset in the CompositionOffsetBox in this track.
195    pub least_decode_to_display_delta: i64,
196    /// The largest composition offset in the CompositionOffsetBox in this track.
197    pub greatest_decode_to_display_delta: i64,
198    /// The smallest computed composition timestamp (CTS) for any sample in the media of this track.
199    pub composition_start_time: i64,
200    /// The composition timestamp plus the composition duration, of the sample with the
201    /// largest computed composition timestamp (CTS) in the media of this track; if this field takes the
202    /// value 0, the composition end time is unknown.
203    pub composition_end_time: i64,
204}
205
206impl<'a> DeserializeSeed<'a, BoxHeader> for CompositionToDecodeBox {
207    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
208    where
209        R: ZeroCopyReader<'a>,
210    {
211        let full_header = FullBoxHeader::deserialize(&mut reader)?;
212
213        let composition_to_dt_shift = if full_header.version == 0 {
214            i32::deserialize(&mut reader)? as i64
215        } else {
216            i64::deserialize(&mut reader)?
217        };
218        let least_decode_to_display_delta = if full_header.version == 0 {
219            i32::deserialize(&mut reader)? as i64
220        } else {
221            i64::deserialize(&mut reader)?
222        };
223        let greatest_decode_to_display_delta = if full_header.version == 0 {
224            i32::deserialize(&mut reader)? as i64
225        } else {
226            i64::deserialize(&mut reader)?
227        };
228        let composition_start_time = if full_header.version == 0 {
229            i32::deserialize(&mut reader)? as i64
230        } else {
231            i64::deserialize(&mut reader)?
232        };
233        let composition_end_time = if full_header.version == 0 {
234            i32::deserialize(&mut reader)? as i64
235        } else {
236            i64::deserialize(&mut reader)?
237        };
238
239        Ok(Self {
240            full_header,
241            composition_to_dt_shift,
242            least_decode_to_display_delta,
243            greatest_decode_to_display_delta,
244            composition_start_time,
245            composition_end_time,
246        })
247    }
248}
249
250impl Serialize for CompositionToDecodeBox {
251    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
252    where
253        W: std::io::Write,
254    {
255        self.serialize_box_header(&mut writer)?;
256        self.full_header.serialize(&mut writer)?;
257        if self.full_header.version == 0 {
258            (self.composition_to_dt_shift as i32).serialize(&mut writer)?;
259            (self.least_decode_to_display_delta as i32).serialize(&mut writer)?;
260            (self.greatest_decode_to_display_delta as i32).serialize(&mut writer)?;
261            (self.composition_start_time as i32).serialize(&mut writer)?;
262            (self.composition_end_time as i32).serialize(&mut writer)?;
263        } else {
264            self.composition_to_dt_shift.serialize(&mut writer)?;
265            self.least_decode_to_display_delta.serialize(&mut writer)?;
266            self.greatest_decode_to_display_delta.serialize(&mut writer)?;
267            self.composition_start_time.serialize(&mut writer)?;
268            self.composition_end_time.serialize(&mut writer)?;
269        }
270        Ok(())
271    }
272}
273
274impl IsoSized for CompositionToDecodeBox {
275    fn size(&self) -> usize {
276        let mut size = self.full_header.size();
277        if self.full_header.version == 0 {
278            size += 4 + 4 + 4 + 4 + 4;
279        } else {
280            size += 8 + 8 + 8 + 8 + 8;
281        }
282
283        Self::add_header_size(size)
284    }
285}
286
287/// Sync sample box
288///
289/// ISO/IEC 14496-12 - 8.6.2
290#[derive(IsoBox, Debug, PartialEq, Eq)]
291#[iso_box(box_type = b"stss", crate_path = crate)]
292pub struct SyncSampleBox {
293    /// The full box header.
294    pub full_header: FullBoxHeader,
295    /// An integer that gives the number of entries in the [`sample_number`](Self::sample_number) vec.
296    /// If `entry_count` is zero, there are no sync samples within the stream and the
297    /// [`sample_number`](Self::sample_number) vec is empty.
298    pub entry_count: u32,
299    /// Gives, for each sync sample in the stream, its sample number.
300    #[iso_box(repeated)]
301    pub sample_number: Vec<u32>,
302}
303
304/// Shadow sync sample box
305///
306/// ISO/IEC 14496-12 - 8.6.3.2
307#[derive(IsoBox, Debug, PartialEq, Eq)]
308#[iso_box(box_type = b"stsh", crate_path = crate)]
309pub struct ShadowSyncSampleBox {
310    /// The full box header.
311    pub full_header: FullBoxHeader,
312    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
313    pub entry_count: u32,
314    /// `shadowed_sample_number` and `sync_sample_number`.
315    #[iso_box(repeated)]
316    pub entries: Vec<ShadowSyncSampleBoxEntry>,
317}
318
319/// Entry in the [`ShadowSyncSampleBox`].
320#[derive(Debug, PartialEq, Eq)]
321pub struct ShadowSyncSampleBoxEntry {
322    /// Gives the number of a sample for which there is an alternative sync sample.
323    pub shadowed_sample_number: u32,
324    /// Gives the number of the alternative sync sample.
325    pub sync_sample_number: u32,
326}
327
328impl<'a> Deserialize<'a> for ShadowSyncSampleBoxEntry {
329    fn deserialize<R>(mut reader: R) -> io::Result<Self>
330    where
331        R: ZeroCopyReader<'a>,
332    {
333        Ok(Self {
334            shadowed_sample_number: u32::deserialize(&mut reader)?,
335            sync_sample_number: u32::deserialize(&mut reader)?,
336        })
337    }
338}
339
340impl Serialize for ShadowSyncSampleBoxEntry {
341    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
342    where
343        W: std::io::Write,
344    {
345        self.shadowed_sample_number.serialize(&mut writer)?;
346        self.sync_sample_number.serialize(&mut writer)?;
347        Ok(())
348    }
349}
350
351impl IsoSized for ShadowSyncSampleBoxEntry {
352    fn size(&self) -> usize {
353        self.shadowed_sample_number.size() + self.sync_sample_number.size()
354    }
355}
356
357/// Independent and disposable samples box
358///
359/// ISO/IEC 14496-12 - 8.6.4
360#[derive(IsoBox, Debug, PartialEq, Eq)]
361#[iso_box(box_type = b"sdtp", crate_path = crate)]
362pub struct SampleDependencyTypeBox {
363    /// The full box header.
364    pub full_header: FullBoxHeader,
365    /// `is_leading`, `sample_depends_on`, `sample_is_depended_on`, and `sample_has_redundancy`.
366    #[iso_box(from = "u8", repeated)]
367    pub entries: Vec<SampleDependencyTypeBoxEntry>,
368}
369
370/// Entry in the [`SampleDependencyTypeBox`].
371#[derive(Debug, PartialEq, Eq, Clone, Copy)]
372pub struct SampleDependencyTypeBoxEntry {
373    /// - `0`: The leading nature of this sample is unknown;
374    /// - `1`: This sample is a leading sample that has a dependency before the referenced I-picture (and is
375    ///   therefore not decodable);
376    /// - `2`: This sample is not a leading sample;
377    /// - `3`: This sample is a leading sample that has no dependency before the referenced I-picture (and is
378    ///   therefore decodable);
379    pub is_leading: u8,
380    /// - `0`: The dependency of this sample is unknown;
381    /// - `1`: This sample does depend on others (not an I picture);
382    /// - `2`: This sample does not depend on others (I picture);
383    /// - `3`: Reserved;
384    pub sample_depends_on: u8,
385    /// - `0`: The dependency of other samples on this sample is unknown;
386    /// - `1`: Other samples may depend on this one (not disposable);
387    /// - `2`: No other sample depends on this one (disposable);
388    /// - `3`: Reserved;
389    pub sample_is_depended_on: u8,
390    /// - `0`: It is unknown whether there is redundant coding in this sample;
391    /// - `1`: There is redundant coding in this sample;
392    /// - `2`: There is no redundant coding in this sample;
393    /// - `3`: Reserved;
394    pub sample_has_redundancy: u8,
395}
396
397impl From<u8> for SampleDependencyTypeBoxEntry {
398    fn from(value: u8) -> Self {
399        Self {
400            is_leading: (value >> 6) & 0b11,
401            sample_depends_on: (value >> 4) & 0b11,
402            sample_is_depended_on: (value >> 2) & 0b11,
403            sample_has_redundancy: value & 0b11,
404        }
405    }
406}
407
408impl From<SampleDependencyTypeBoxEntry> for u8 {
409    fn from(val: SampleDependencyTypeBoxEntry) -> Self {
410        ((val.is_leading & 0b11) << 6)
411            | ((val.sample_depends_on & 0b11) << 4)
412            | ((val.sample_is_depended_on & 0b11) << 2)
413            | (val.sample_has_redundancy & 0b11)
414    }
415}
416
417impl IsoSized for SampleDependencyTypeBoxEntry {
418    fn size(&self) -> usize {
419        1
420    }
421}
422
423/// Edit box
424///
425/// ISO/IEC 14496-12 - 8.6.5
426#[derive(IsoBox, Debug, PartialEq, Eq)]
427#[iso_box(box_type = b"edts", crate_path = crate)]
428pub struct EditBox {
429    /// The contained [`EditListBox`]. (optional)
430    #[iso_box(nested_box(collect))]
431    pub elst: Option<EditListBox>,
432}
433
434/// Edit list box
435///
436/// ISO/IEC 14496-12 - 8.6.6
437#[derive(IsoBox, Debug, PartialEq, Eq)]
438#[iso_box(box_type = b"elst", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
439pub struct EditListBox {
440    /// The full box header.
441    pub full_header: FullBoxHeader,
442    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
443    pub entry_count: u32,
444    /// `edit_duration`, `media_time`, and `media_rate`.
445    #[iso_box(repeated)]
446    pub entries: Vec<EditListBoxEntry>,
447}
448
449impl<'a> DeserializeSeed<'a, BoxHeader> for EditListBox {
450    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
451    where
452        R: ZeroCopyReader<'a>,
453    {
454        let full_header = FullBoxHeader::deserialize(&mut reader)?;
455
456        let entry_count = u32::deserialize(&mut reader)?;
457
458        let mut entries = Vec::with_capacity(entry_count as usize);
459        for _ in 0..entry_count {
460            entries.push(EditListBoxEntry::deserialize_seed(&mut reader, full_header.version)?);
461        }
462
463        Ok(Self {
464            full_header,
465            entry_count,
466            entries,
467        })
468    }
469}
470
471impl Serialize for EditListBox {
472    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
473    where
474        W: std::io::Write,
475    {
476        self.serialize_box_header(&mut writer)?;
477        self.full_header.serialize(&mut writer)?;
478        self.entry_count.serialize(&mut writer)?;
479
480        for entry in &self.entries {
481            entry.serialize(&mut writer, self.full_header.version)?;
482        }
483
484        Ok(())
485    }
486}
487
488impl IsoSized for EditListBox {
489    fn size(&self) -> usize {
490        let mut size = 0;
491        size += self.full_header.size();
492        size += self.entry_count.size();
493        size += self
494            .entries
495            .iter()
496            .map(|entry| entry.size(self.full_header.version))
497            .sum::<usize>();
498
499        Self::add_header_size(size)
500    }
501}
502
503/// Entry in the [`EditListBox`].
504#[derive(Debug, PartialEq, Eq)]
505pub struct EditListBoxEntry {
506    /// An integer that specifies the duration of this edit in units of the timescale in the
507    /// [`MovieHeaderBox`](super::MovieHeaderBox).
508    pub edit_duration: u64,
509    /// An integer containing the starting time within the media of this edit entry (in media time
510    /// scale units, in composition time). If this field is set to –1, it is an empty edit. The last edit in a track
511    /// shall never be an empty edit. Any difference between the duration in the [`MovieHeaderBox`](super::MovieHeaderBox),
512    /// and the track’s duration is expressed as an implicit empty edit at the end.
513    pub media_time: i64,
514    /// Specifies the relative rate at which to play the media corresponding to this edit entry. If
515    /// this value is 0, then the edit is specifying a 'dwell': the media at media-time is presented for the
516    /// edit_duration. The normal value, indicating normal-speed forward play, is 1.0.
517    pub media_rate: FixedI32<U16>,
518}
519
520impl<'a> DeserializeSeed<'a, u8> for EditListBoxEntry {
521    fn deserialize_seed<R>(mut reader: R, seed: u8) -> io::Result<Self>
522    where
523        R: ZeroCopyReader<'a>,
524    {
525        let edit_duration = if seed == 1 {
526            u64::deserialize(&mut reader)?
527        } else {
528            u32::deserialize(&mut reader)? as u64
529        };
530        let media_time = if seed == 1 {
531            i64::deserialize(&mut reader)?
532        } else {
533            i32::deserialize(&mut reader)? as i64
534        };
535        let media_rate = FixedI32::from_bits(i32::deserialize(&mut reader)?);
536
537        Ok(Self {
538            edit_duration,
539            media_time,
540            media_rate,
541        })
542    }
543}
544
545impl EditListBoxEntry {
546    fn serialize<W>(&self, mut writer: W, version: u8) -> io::Result<()>
547    where
548        W: std::io::Write,
549    {
550        if version == 1 {
551            self.edit_duration.serialize(&mut writer)?;
552            self.media_time.serialize(&mut writer)?;
553        } else {
554            (self.edit_duration as u32).serialize(&mut writer)?;
555            (self.media_time as i32).serialize(&mut writer)?;
556        }
557        self.media_rate.to_bits().serialize(&mut writer)?;
558
559        Ok(())
560    }
561}
562
563impl EditListBoxEntry {
564    /// Returns the size of this entry in bytes, depending on the version.
565    pub fn size(&self, version: u8) -> usize {
566        let mut size = 0;
567        if version == 1 {
568            size += 8 + 8;
569        } else {
570            size += 4 + 4;
571        }
572        size + 2 + 2
573    }
574}