isobmff/boxes/
segments.rs

1use scuffle_bytes_util::BitWriter;
2use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize, U24Be};
3
4use super::Brand;
5use crate::{BoxHeader, FullBoxHeader, IsoBox, IsoSized};
6
7/// Segment type box
8///
9/// ISO/IEC 14496-12 - 8.16.2
10#[derive(IsoBox, Debug, PartialEq, Eq)]
11#[iso_box(box_type = b"styp", crate_path = crate)]
12pub struct SegmentTypeBox {
13    /// The "best use" brand of the file which will provide the greatest compatibility.
14    #[iso_box(from = "[u8; 4]")]
15    pub major_brand: Brand,
16    /// Minor version of the major brand.
17    pub minor_version: u32,
18    /// A list of compatible brands.
19    #[iso_box(repeated, from = "[u8; 4]")]
20    pub compatible_brands: Vec<Brand>,
21}
22
23/// Segment index box
24///
25/// ISO/IEC 14496-12 - 8.16.3
26#[derive(IsoBox, Debug, PartialEq, Eq)]
27#[iso_box(box_type = b"sidx", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
28pub struct SegmentIndexBox {
29    /// The full box header.
30    pub full_header: FullBoxHeader,
31    /// Provides the stream ID for the reference stream; if this [`SegmentIndexBox`] is referenced
32    /// from a "parent" [`SegmentIndexBox`], the value of `reference_ID` shall be the same as the value of
33    /// reference_ID of the "parent" [`SegmentIndexBox`].
34    pub reference_id: u32,
35    /// Provides the timescale, in ticks per second, for the time and duration fields within this box;
36    /// it is recommended that this match the timescale of the reference stream or track; for files based on
37    /// this document, that is the timescale field of the media header box of the track.
38    pub timescale: u32,
39    /// The earliest presentation time of any content in the reference stream
40    /// in the first subsegment, in the timescale indicated in the timescale field; the earliest presentation
41    /// time is derived from media in access units, or parts of access units, that are not omitted by an edit
42    /// list (if any).
43    pub earliest_presentation_time: u64,
44    /// The distance in bytes, in the file containing media, from the anchor point, to the first
45    /// byte of the indexed material.
46    pub first_offset: u64,
47    /// Reserved 16 bits, must be set to 0.
48    pub reserved: u16,
49    /// Provides the number of [referenced items](Self::references).
50    pub reference_count: u16,
51    /// The referenced items.
52    pub references: Vec<SegmentIndexBoxReference>,
53}
54
55impl<'a> DeserializeSeed<'a, BoxHeader> for SegmentIndexBox {
56    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
57    where
58        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
59    {
60        let full_header = FullBoxHeader::deserialize(&mut reader)?;
61
62        let reference_id = u32::deserialize(&mut reader)?;
63        let timescale = u32::deserialize(&mut reader)?;
64
65        let earliest_presentation_time = if full_header.version == 0 {
66            u32::deserialize(&mut reader)? as u64
67        } else {
68            u64::deserialize(&mut reader)?
69        };
70        let first_offset = if full_header.version == 0 {
71            u32::deserialize(&mut reader)? as u64
72        } else {
73            u64::deserialize(&mut reader)?
74        };
75
76        let reserved = u16::deserialize(&mut reader)?;
77        let reference_count = u16::deserialize(&mut reader)?;
78
79        let mut references = Vec::with_capacity(reference_count as usize);
80        for _ in 0..reference_count {
81            references.push(SegmentIndexBoxReference::deserialize(&mut reader)?);
82        }
83
84        Ok(SegmentIndexBox {
85            full_header,
86            reference_id,
87            timescale,
88            earliest_presentation_time,
89            first_offset,
90            reserved,
91            reference_count,
92            references,
93        })
94    }
95}
96
97impl Serialize for SegmentIndexBox {
98    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
99    where
100        W: std::io::Write,
101    {
102        self.serialize_box_header(&mut writer)?;
103        self.full_header.serialize(&mut writer)?;
104
105        self.reference_id.serialize(&mut writer)?;
106        self.timescale.serialize(&mut writer)?;
107
108        if self.full_header.version == 0 {
109            (self.earliest_presentation_time as u32).serialize(&mut writer)?;
110            (self.first_offset as u32).serialize(&mut writer)?;
111        } else {
112            self.earliest_presentation_time.serialize(&mut writer)?;
113            self.first_offset.serialize(&mut writer)?;
114        }
115
116        self.reserved.serialize(&mut writer)?;
117        self.reference_count.serialize(&mut writer)?;
118
119        for reference in &self.references {
120            reference.serialize(&mut writer)?;
121        }
122
123        Ok(())
124    }
125}
126
127impl IsoSized for SegmentIndexBox {
128    fn size(&self) -> usize {
129        let mut size = self.full_header.size();
130        size += 4; // reference_id
131        size += 4; // timescale
132        if self.full_header.version == 0 {
133            size += 4; // earliest_presentation_time
134            size += 4; // first_offset
135        } else {
136            size += 8; // earliest_presentation_time
137            size += 8; // first_offset
138        }
139        size += 2; // reserved
140        size += 2; // reference_count
141
142        size += self.references.size();
143
144        Self::add_header_size(size)
145    }
146}
147
148/// Reference in a [`SegmentIndexBox`].
149#[derive(Debug, PartialEq, Eq)]
150pub struct SegmentIndexBoxReference {
151    /// When set to 1 indicates that the reference is to a [`SegmentIndexBox`]; otherwise the
152    /// reference is to media content (e.g., in the case of files based on this document, to a
153    /// [`MovieFragmentBox`](super::MovieFragmentBox)).
154    /// If a separate index segment is used, then entries with reference type 1 are in the index segment,
155    /// and entries with reference type 0 are in the media file.
156    pub reference_type: bool,
157    /// The distance in bytes from the first byte of the referenced item to the first byte of the
158    /// next referenced item, or in the case of the last entry, the end of the referenced material.
159    pub referenced_size: u32,
160    /// When the reference is to [`SegmentIndexBox`], this field carries the sum of the
161    /// `subsegment_duration` fields in that box; when the reference is to a subsegment, this field carries
162    /// the difference between the earliest presentation time of any access unit of the reference stream
163    /// in the next subsegment (or the first subsegment of the next segment, if this is the last subsegment
164    /// of the segment, or the end presentation time of the reference stream if this is the last subsegment
165    /// of the stream) and the earliest presentation time of any access unit of the reference stream in the
166    /// referenced subsegment; the duration is in the same units as `earliest_presentation_time`.
167    pub subsegment_duration: u32,
168    /// Indicates whether the referenced subsegments start with a SAP. For the detailed
169    /// semantics of this field in combination with other fields, see Table 6.
170    pub starts_with_sap: bool,
171    /// Indicates a SAP type as specified in Annex I, or the value 0. Other type values are reserved.
172    /// For the detailed semantics of this field in combination with other fields, see the table below.
173    pub sap_type: u8,
174    /// Indicates T_SAP of the first SAP, in decoding order, in the referenced subsegment for the
175    /// reference stream. If the referenced subsegments do not contain a SAP, `SAP_delta_time` is reserved
176    /// with the value 0; otherwise `SAP_delta_time` is the difference between the earliest presentation
177    /// time of the subsegment, and the TSAP (this difference may be zero, in the case that the subsegment
178    /// starts with a SAP).
179    pub sap_delta_time: u32,
180}
181
182impl<'a> Deserialize<'a> for SegmentIndexBoxReference {
183    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
184    where
185        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
186    {
187        let first_u32 = u32::deserialize(&mut reader)?;
188        let reference_type = (first_u32 >> 31) != 0;
189        let referenced_size = first_u32 & 0x7F_FF_FF_FF;
190
191        let subsegment_duration = u32::deserialize(&mut reader)?;
192
193        let third_u32 = u32::deserialize(&mut reader)?;
194        let starts_with_sap = (third_u32 >> 31) != 0;
195        let sap_type = ((third_u32 >> 28) & 0b111) as u8;
196        let sap_delta_time = third_u32 & 0x0F_FF_FF_FF;
197
198        Ok(SegmentIndexBoxReference {
199            reference_type,
200            referenced_size,
201            subsegment_duration,
202            starts_with_sap,
203            sap_type,
204            sap_delta_time,
205        })
206    }
207}
208
209impl Serialize for SegmentIndexBoxReference {
210    fn serialize<W>(&self, writer: W) -> std::io::Result<()>
211    where
212        W: std::io::Write,
213    {
214        let mut bit_writer = BitWriter::new(writer);
215
216        bit_writer.write_bit(self.reference_type)?;
217        bit_writer.write_bits(self.referenced_size as u64, 31)?;
218
219        self.subsegment_duration.serialize(&mut bit_writer)?;
220
221        bit_writer.write_bit(self.starts_with_sap)?;
222        bit_writer.write_bits(self.sap_type as u64, 3)?;
223        bit_writer.write_bits(self.sap_delta_time as u64, 28)?;
224
225        Ok(())
226    }
227}
228
229impl IsoSized for SegmentIndexBoxReference {
230    fn size(&self) -> usize {
231        4 + 4 + 4 // 3 u32s
232    }
233}
234
235/// Subsegment index box
236///
237/// ISO/IEC 14496-12 - 8.16.4
238#[derive(IsoBox, Debug, PartialEq, Eq)]
239#[iso_box(box_type = b"ssix", crate_path = crate)]
240pub struct SubsegmentIndexBox {
241    /// The full box header.
242    pub full_header: FullBoxHeader,
243    /// A positive integer specifying the number of subsegments for which partial
244    /// subsegment information is specified in this box. `subsegment_count` shall be equal `toreference_count`
245    /// (i.e., the number of movie fragment references) in the immediately preceding [`SegmentIndexBox`].
246    pub subsegment_count: u32,
247    /// Subsegments in this box.
248    #[iso_box(repeated)]
249    pub subsegments: Vec<SubsegmentIndexBoxSubsegment>,
250}
251
252/// Subsegment in [`SubsegmentIndexBox`].
253#[derive(Debug, PartialEq, Eq)]
254pub struct SubsegmentIndexBoxSubsegment {
255    /// Specifies the number of partial subsegment levels into which the media data is grouped.
256    /// This value shall be greater than or equal to 2.
257    pub range_count: u32,
258    /// `range_size` and `level`.
259    pub ranges: Vec<SubsegmentIndexBoxSubsegmentRange>,
260}
261
262impl<'a> Deserialize<'a> for SubsegmentIndexBoxSubsegment {
263    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
264    where
265        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
266    {
267        let range_count = u32::deserialize(&mut reader)?;
268        let mut ranges = Vec::with_capacity(range_count as usize);
269        for _ in 0..range_count {
270            ranges.push(SubsegmentIndexBoxSubsegmentRange::deserialize(&mut reader)?);
271        }
272
273        Ok(SubsegmentIndexBoxSubsegment { range_count, ranges })
274    }
275}
276
277impl Serialize for SubsegmentIndexBoxSubsegment {
278    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
279    where
280        W: std::io::Write,
281    {
282        self.range_count.serialize(&mut writer)?;
283
284        for range in &self.ranges {
285            range.serialize(&mut writer)?;
286        }
287
288        Ok(())
289    }
290}
291
292impl IsoSized for SubsegmentIndexBoxSubsegment {
293    fn size(&self) -> usize {
294        self.range_count.size() + self.ranges.size()
295    }
296}
297
298/// Subsegment range in [`SubsegmentIndexBoxSubsegment`].
299#[derive(Debug, PartialEq, Eq)]
300pub struct SubsegmentIndexBoxSubsegmentRange {
301    /// Specifies the level to which this partial subsegment is assigned.
302    pub level: u8,
303    /// Indicates the size of the partial subsegment; the value 0 may be used in the last entry to
304    /// indicate the remaining bytes of the segment, to the end of the segment.
305    pub range_size: U24Be,
306}
307
308impl<'a> Deserialize<'a> for SubsegmentIndexBoxSubsegmentRange {
309    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
310    where
311        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
312    {
313        let level = u8::deserialize(&mut reader)?;
314        let range_size = U24Be::deserialize(&mut reader)?;
315
316        Ok(SubsegmentIndexBoxSubsegmentRange { level, range_size })
317    }
318}
319
320impl Serialize for SubsegmentIndexBoxSubsegmentRange {
321    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
322    where
323        W: std::io::Write,
324    {
325        self.level.serialize(&mut writer)?;
326        self.range_size.serialize(&mut writer)?;
327        Ok(())
328    }
329}
330
331impl IsoSized for SubsegmentIndexBoxSubsegmentRange {
332    fn size(&self) -> usize {
333        self.level.size() + self.range_size.size()
334    }
335}
336
337/// Producer reference time box
338///
339/// ISO/IEC 14496-12 - 8.16.5
340#[derive(IsoBox, Debug, PartialEq, Eq)]
341#[iso_box(box_type = b"prft", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
342pub struct ProducerReferenceTimeBox {
343    /// The full box header.
344    pub full_header: FullBoxHeader,
345    /// Provides the track_ID for the reference track.
346    pub reference_track_id: u32,
347    /// Indicates a UTC time in NTP format associated to `media_time` as follows:
348    ///
349    /// - if `flags` is set to 0, the UTC time is the time at which the frame belonging to the reference track in
350    ///   the following movie fragment and whose presentation time is `media_time` was input to the encoder.
351    /// - if `flags` is set to 1, the UTC time is the time at which the frame belonging to the reference track in the
352    ///   following movie fragment and whose presentation time is `media_time` was output from the encoder.
353    /// - if `flags` is set to 2, the UTC time is the time at which the following
354    ///   [`MovieFragmentBox`](super::MovieFragmentBox) was finalized.
355    ///   `media_time` is set to the presentation of the earliest frame of the reference track in presentation
356    ///   order of the movie fragment.
357    /// - if `flags` is set to 4, the UTC time is the time at which the following [`MovieFragmentBox`](super::MovieFragmentBox)
358    ///   was written to file.
359    ///   `media_time` is set to the presentation of the earliest frame of the reference track in presentation
360    ///   order of the movie fragment.
361    /// - if `flags` is set to 8, the association between the `media_time` and UTC time is arbitrary but consistent
362    ///   between multiple occurrences of this box in the same track.
363    /// - if `flags` is set to 24 (i.e. the two bits corresponding to value 8 and 16 are set), the UTC time has a
364    ///   consistent, small (ideally zero), offset from the real-time of the experience depicted in the media at
365    ///   `media_time`.
366    pub ntp_timestamp: u64,
367    /// Expressed in the time units used for the reference track.
368    pub media_time: u64,
369}
370
371impl<'a> DeserializeSeed<'a, BoxHeader> for ProducerReferenceTimeBox {
372    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> std::io::Result<Self>
373    where
374        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
375    {
376        let full_header = FullBoxHeader::deserialize(&mut reader)?;
377
378        let reference_track_id = u32::deserialize(&mut reader)?;
379        let ntp_timestamp = u64::deserialize(&mut reader)?;
380        let media_time = if full_header.version == 0 {
381            u32::deserialize(&mut reader)? as u64
382        } else {
383            u64::deserialize(&mut reader)?
384        };
385
386        Ok(ProducerReferenceTimeBox {
387            full_header,
388            reference_track_id,
389            ntp_timestamp,
390            media_time,
391        })
392    }
393}
394
395impl Serialize for ProducerReferenceTimeBox {
396    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
397    where
398        W: std::io::Write,
399    {
400        self.serialize_box_header(&mut writer)?;
401        self.full_header.serialize(&mut writer)?;
402
403        self.reference_track_id.serialize(&mut writer)?;
404        self.ntp_timestamp.serialize(&mut writer)?;
405        if self.full_header.version == 0 {
406            (self.media_time as u32).serialize(&mut writer)?;
407        } else {
408            self.media_time.serialize(&mut writer)?;
409        }
410        Ok(())
411    }
412}
413
414impl IsoSized for ProducerReferenceTimeBox {
415    fn size(&self) -> usize {
416        let mut size = self.full_header.size();
417        size += 4; // reference_track_id
418        size += 8; // ntp_timestamp
419        if self.full_header.version == 0 {
420            size += 4; // media_time
421        } else {
422            size += 8; // media_time
423        }
424
425        Self::add_header_size(size)
426    }
427}