isobmff/boxes/
track_data_layout.rs

1use std::fmt::Debug;
2use std::{io, iter};
3
4use scuffle_bytes_util::zero_copy::{Deserialize, DeserializeSeed, Serialize, U24Be, ZeroCopyReader};
5use scuffle_bytes_util::{BytesCow, IoResultExt};
6
7use crate::{BoxHeader, FullBoxHeader, IsoBox, IsoSized, UnknownBox, Utf8String};
8
9/// Data information box
10///
11/// ISO/IEC 14496-12 - 8.7.1
12#[derive(IsoBox, Debug, PartialEq, Eq, Default)]
13#[iso_box(box_type = b"dinf", crate_path = crate)]
14pub struct DataInformationBox<'a> {
15    /// The contained [`DataReferenceBox`]. (mandatory)
16    #[iso_box(nested_box)]
17    pub dref: DataReferenceBox<'a>,
18}
19
20/// Data entry url box
21///
22/// ISO/IEC 14496-12 - 8.7.2
23#[derive(IsoBox, Debug, PartialEq, Eq, Default)]
24#[iso_box(box_type = b"url ", skip_impl(deserialize_seed, serialize), crate_path = crate)]
25pub struct DataEntryUrlBox {
26    /// The full box header.
27    pub full_header: FullBoxHeader,
28    /// A URL, and is required in a URL entry and optional in a URN entry, where it gives a location
29    /// to find the resource with the given name. The URL type should be of a service that delivers a file
30    /// (e.g. URLs of type file, http, ftp etc.), and which services ideally also permit random access. Relative
31    /// URLs are permissible and are relative to the file that contains this data reference.
32    ///
33    /// The official spec says that this field is mandatory but there are files that don't have it (e.g. `assets/avc_aac.mp4`).
34    pub location: Option<Utf8String>,
35}
36
37impl<'a> DeserializeSeed<'a, BoxHeader> for DataEntryUrlBox {
38    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
39    where
40        R: ZeroCopyReader<'a>,
41    {
42        let full_header = FullBoxHeader::deserialize(&mut reader)?;
43        let location = Utf8String::deserialize(&mut reader).eof_to_none()?;
44
45        Ok(Self { full_header, location })
46    }
47}
48
49impl Serialize for DataEntryUrlBox {
50    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
51    where
52        W: std::io::Write,
53    {
54        self.serialize_box_header(&mut writer)?;
55        self.full_header.serialize(&mut writer)?;
56        if let Some(location) = &self.location {
57            location.serialize(&mut writer)?;
58        }
59
60        Ok(())
61    }
62}
63
64/// Data entry urn box
65///
66/// ISO/IEC 14496-12 - 8.7.2
67#[derive(IsoBox, Debug, PartialEq, Eq)]
68#[iso_box(box_type = b"urn ", skip_impl(deserialize_seed, serialize), crate_path = crate)]
69pub struct DataEntryUrnBox {
70    /// The full box header.
71    pub full_header: FullBoxHeader,
72    /// A URN.
73    pub name: Utf8String,
74    /// A URL, and is required in a URL entry and optional in a URN entry, where it gives a location
75    /// to find the resource with the given name. The URL type should be of a service that delivers a file
76    /// (e.g. URLs of type file, http, ftp etc.), and which services ideally also permit random access. Relative
77    /// URLs are permissible and are relative to the file that contains this data reference.
78    pub location: Option<Utf8String>,
79}
80
81impl<'a> DeserializeSeed<'a, BoxHeader> for DataEntryUrnBox {
82    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
83    where
84        R: ZeroCopyReader<'a>,
85    {
86        let full_header = FullBoxHeader::deserialize(&mut reader)?;
87        let name = Utf8String::deserialize(&mut reader)?;
88        let location = Utf8String::deserialize(&mut reader).eof_to_none()?;
89
90        Ok(Self {
91            full_header,
92            name,
93            location,
94        })
95    }
96}
97
98impl Serialize for DataEntryUrnBox {
99    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
100    where
101        W: std::io::Write,
102    {
103        self.serialize_box_header(&mut writer)?;
104        self.full_header.serialize(&mut writer)?;
105        self.name.serialize(&mut writer)?;
106        if let Some(location) = &self.location {
107            location.serialize(&mut writer)?;
108        }
109
110        Ok(())
111    }
112}
113
114/// Data entry imda box
115///
116/// ISO/IEC 14496-12 - 8.7.2
117#[derive(IsoBox, Debug, PartialEq, Eq)]
118#[iso_box(box_type = b"imdt", crate_path = crate)]
119pub struct DataEntryImdaBox {
120    /// The full box header.
121    pub full_header: FullBoxHeader,
122    /// Identifies the [`IdentifiedMediaDataBox`](super::IdentifiedMediaDataBox) containing the
123    /// media data accessed through the `data_reference_index` corresponding to this [`DataEntryImdaBox`].
124    /// The referred [`IdentifiedMediaDataBox`](super::IdentifiedMediaDataBox) contains `imda_identifier`
125    /// that is equal to `imda_ref_identifier`.
126    pub imda_ref_identifier: u32,
127}
128
129/// Data entry sequence number imda box
130///
131/// ISO/IEC 14496-12 - 8.7.2
132#[derive(IsoBox, Debug, PartialEq, Eq)]
133#[iso_box(box_type = b"snim", crate_path = crate)]
134pub struct DataEntrySeqNumImdaBox {
135    /// The full box header.
136    pub full_header: FullBoxHeader,
137}
138
139/// Data reference box
140///
141/// ISO/IEC 14496-12 - 8.7.2
142#[derive(IsoBox, Debug, PartialEq, Eq)]
143#[iso_box(box_type = b"dref", crate_path = crate)]
144pub struct DataReferenceBox<'a> {
145    /// The full box header.
146    pub full_header: FullBoxHeader,
147    /// An integer that counts the sub boxes.
148    pub entry_count: u32,
149    /// Data entry URL boxes.
150    #[iso_box(nested_box(collect))]
151    pub url: Vec<DataEntryUrlBox>,
152    /// Data entry URN boxes.
153    #[iso_box(nested_box(collect))]
154    pub urn: Vec<DataEntryUrnBox>,
155    /// Data entry IMDA boxes.
156    #[iso_box(nested_box(collect))]
157    pub imda: Vec<DataEntryImdaBox>,
158    /// Data entry sequence number IMDA boxes.
159    #[iso_box(nested_box(collect))]
160    pub snim: Vec<DataEntrySeqNumImdaBox>,
161    /// Any other unknown boxes.
162    #[iso_box(nested_box(collect_unknown))]
163    pub unknown_boxes: Vec<UnknownBox<'a>>,
164}
165
166impl Default for DataReferenceBox<'_> {
167    fn default() -> Self {
168        Self {
169            full_header: FullBoxHeader::default(),
170            entry_count: 1,
171            url: vec![DataEntryUrlBox::default()],
172            urn: vec![],
173            imda: vec![],
174            snim: vec![],
175            unknown_boxes: vec![],
176        }
177    }
178}
179
180/// Sample size box
181///
182/// ISO/IEC 14496-12 - 8.7.3.2
183#[derive(IsoBox, PartialEq, Eq, Default)]
184#[iso_box(box_type = b"stsz", crate_path = crate)]
185pub struct SampleSizeBox {
186    /// The full box header.
187    pub full_header: FullBoxHeader,
188    /// An integer specifying the default sample size. If all the samples are the same size, this field
189    /// contains that size value. If this field is set to 0, then the samples have different sizes, and those sizes
190    /// are stored in the sample size table. If this field is not 0, it specifies the constant sample size, and no
191    /// array follows.
192    pub sample_size: u32,
193    /// An integer that gives the number of samples in the track; if sample-size is 0, then it is
194    /// also the number of entries in the [`entry_size`](SampleSizeBox::entry_size) vec.
195    pub sample_count: u32,
196    /// Integers specifying the size of a sample, indexed by its number.
197    #[iso_box(repeated)]
198    pub entry_size: Vec<u32>,
199}
200
201impl Debug for SampleSizeBox {
202    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203        f.debug_struct("SampleSizeBox")
204            .field("full_header", &self.full_header)
205            .field("sample_size", &self.sample_size)
206            .field("sample_count", &self.sample_count)
207            .field("entry_size.len", &self.entry_size.len())
208            .finish()
209    }
210}
211
212/// Compact sample size box
213///
214/// ISO/IEC 14496-12 - 8.7.3.3
215#[derive(IsoBox, Debug, PartialEq, Eq)]
216#[iso_box(box_type = b"stz2", crate_path = crate)]
217pub struct CompactSampleSizeBox<'a> {
218    /// The full box header.
219    pub full_header: FullBoxHeader,
220    /// Reserved 24 bits, must be 0.
221    pub reserved: U24Be,
222    /// An integer specifying the size in bits of the entries in the following table; it shall take the
223    /// value 4, 8 or 16. If the value 4 is used, then each byte contains two values: `entry[i]<<4 + entry[i+1]`;
224    /// if the sizes do not fill an integral number of bytes, the last byte is padded with zeros.
225    pub field_size: u8,
226    /// An integer that gives the number of entries in the [`entry_size`](Self::entry_size) vec.
227    pub sample_count: u32,
228    /// Integers specifying the size of a sample, indexed by its number.
229    pub entry_size: BytesCow<'a>,
230}
231
232/// Sample to chunk box
233///
234/// ISO/IEC 14496-12 - 8.7.4
235#[derive(IsoBox, PartialEq, Eq, Default)]
236#[iso_box(box_type = b"stsc", crate_path = crate)]
237pub struct SampleToChunkBox {
238    /// The full box header.
239    pub full_header: FullBoxHeader,
240    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
241    pub entry_count: u32,
242    /// `first_chunk`, `samples_per_chunk` and `sample_description_index`.
243    #[iso_box(repeated)]
244    pub entries: Vec<SampleToChunkBoxEntry>,
245}
246
247impl Debug for SampleToChunkBox {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        f.debug_struct("SampleToChunkBox")
250            .field("full_header", &self.full_header)
251            .field("entry_count", &self.entry_count)
252            .field("entries.len", &self.entries.len())
253            .finish()
254    }
255}
256
257/// Entry in [`SampleToChunkBox`].
258#[derive(Debug, PartialEq, Eq)]
259pub struct SampleToChunkBoxEntry {
260    /// An integer that gives the index of the first chunk in this run of chunks that share the
261    /// same samples-per-chunk and sample-description-index; the index of the first chunk in a track has
262    /// the value 1 (the `first_chunk` field in the first record of this box has the value 1, identifying that the
263    /// first sample maps to the first chunk).
264    pub first_chunk: u32,
265    /// An integer that gives the number of samples in each of these chunks.
266    pub samples_per_chunk: u32,
267    /// An integer that gives the index of the sample entry that describes
268    /// the samples in this chunk. The index ranges from 1 to the number of sample entries in the
269    /// [`SampleDescriptionBox`](super::SampleDescriptionBox).
270    pub sample_description_index: u32,
271}
272
273impl<'a> Deserialize<'a> for SampleToChunkBoxEntry {
274    fn deserialize<R>(mut reader: R) -> io::Result<Self>
275    where
276        R: ZeroCopyReader<'a>,
277    {
278        Ok(Self {
279            first_chunk: u32::deserialize(&mut reader)?,
280            samples_per_chunk: u32::deserialize(&mut reader)?,
281            sample_description_index: u32::deserialize(&mut reader)?,
282        })
283    }
284}
285
286impl Serialize for SampleToChunkBoxEntry {
287    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
288    where
289        W: std::io::Write,
290    {
291        self.first_chunk.serialize(&mut writer)?;
292        self.samples_per_chunk.serialize(&mut writer)?;
293        self.sample_description_index.serialize(&mut writer)?;
294        Ok(())
295    }
296}
297
298impl IsoSized for SampleToChunkBoxEntry {
299    fn size(&self) -> usize {
300        4 + 4 + 4 // 3 u32s
301    }
302}
303
304/// Chunk offset box
305///
306/// ISO/IEC 14496-12 - 8.7.5
307#[derive(IsoBox, PartialEq, Eq, Default)]
308#[iso_box(box_type = b"stco", crate_path = crate)]
309pub struct ChunkOffsetBox {
310    /// The full box header.
311    pub full_header: FullBoxHeader,
312    /// An integer that gives the number of entries in the [`chunk_offset`](Self::chunk_offset) vec.
313    pub entry_count: u32,
314    /// Integers that give the offset of the start of a chunk. If the referenced
315    /// data reference entry is [`DataEntryImdaBox`] or [`DataEntrySeqNumImdaBox`],
316    /// the value of `chunk_offset` is relative to the first byte of the payload of the
317    /// [`IdentifiedMediaDataBox`](super::IdentifiedMediaDataBox) corresponding to the data reference entry.
318    /// Otherwise, the value of `chunk_offset` is relative to the start of the containing media file.
319    #[iso_box(repeated)]
320    pub chunk_offset: Vec<u32>,
321}
322
323impl Debug for ChunkOffsetBox {
324    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
325        f.debug_struct("ChunkOffsetBox")
326            .field("full_header", &self.full_header)
327            .field("entry_count", &self.entry_count)
328            .field("chunk_offset.len", &self.chunk_offset.len())
329            .finish()
330    }
331}
332
333/// Chunk large offset box
334///
335/// ISO/IEC 14496-12 - 8.7.5
336#[derive(IsoBox, Debug, PartialEq, Eq)]
337#[iso_box(box_type = b"co64", crate_path = crate)]
338pub struct ChunkLargeOffsetBox {
339    /// The full box header.
340    pub full_header: FullBoxHeader,
341    /// An integer that gives the number of entries in the [`chunk_offset`](Self::chunk_offset) vec.
342    pub entry_count: u32,
343    /// Integers that give the offset of the start of a chunk. If the referenced
344    /// data reference entry is [`DataEntryImdaBox`] or [`DataEntrySeqNumImdaBox`],
345    /// the value of `chunk_offset` is relative to the first byte of the payload of the
346    /// [`IdentifiedMediaDataBox`](super::IdentifiedMediaDataBox) corresponding to the data reference entry.
347    /// Otherwise, the value of `chunk_offset` is relative to the start of the containing media file.
348    #[iso_box(repeated)]
349    pub chunk_offset: Vec<u64>,
350}
351
352/// Padding bits box
353///
354/// ISO/IEC 14496-12 - 8.7.6
355#[derive(IsoBox, PartialEq, Eq)]
356#[iso_box(box_type = b"padb", crate_path = crate)]
357pub struct PaddingBitsBox {
358    /// The full box header.
359    pub full_header: FullBoxHeader,
360    /// Counts the number of samples in the track; it should match the count in other tables.
361    pub sample_count: u32,
362    /// `pad1` and `pad2`
363    #[iso_box(from = "u8", repeated)]
364    pub entry: Vec<PaddingBitsBoxEntry>,
365}
366
367impl Debug for PaddingBitsBox {
368    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369        f.debug_struct("PaddingBitsBox")
370            .field("full_header", &self.full_header)
371            .field("sample_count", &self.sample_count)
372            .field("entry.len", &self.entry.len())
373            .finish()
374    }
375}
376
377/// Entry in [`PaddingBitsBox`].
378#[derive(Debug, PartialEq, Eq, Clone, Copy)]
379pub struct PaddingBitsBoxEntry {
380    /// A value from 0 to 7, indicating the number of padding bits at the end of sample `(i*2)+1`.
381    pub pad1: u8,
382    /// A value from 0 to 7, indicating the number of padding bits at the end of sample `(i*2)+2`.
383    pub pad2: u8,
384}
385
386impl From<u8> for PaddingBitsBoxEntry {
387    fn from(value: u8) -> Self {
388        // 0xxx 0xxx
389        Self {
390            pad1: (value >> 4) & 0b0111,
391            pad2: value & 0b0111,
392        }
393    }
394}
395
396impl From<PaddingBitsBoxEntry> for u8 {
397    fn from(value: PaddingBitsBoxEntry) -> Self {
398        (value.pad1 << 4) | value.pad2
399    }
400}
401
402impl IsoSized for PaddingBitsBoxEntry {
403    fn size(&self) -> usize {
404        1
405    }
406}
407
408/// Sub-sample information box
409///
410/// ISO/IEC 14496-12 - 8.7.7
411#[derive(IsoBox, Debug, PartialEq, Eq)]
412#[iso_box(box_type = b"subs", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
413pub struct SubSampleInformationBox {
414    /// The full box header.
415    pub full_header: FullBoxHeader,
416    /// An integer that gives the number of entries in the [`entries`](Self::entries) vec.
417    pub entry_count: u32,
418    /// `sample_delta`, `subsample_count` and subsample information.
419    pub entries: Vec<SubSampleInformationBoxEntry>,
420}
421
422impl<'a> DeserializeSeed<'a, BoxHeader> for SubSampleInformationBox {
423    fn deserialize_seed<R>(mut reader: R, seed: BoxHeader) -> io::Result<Self>
424    where
425        R: ZeroCopyReader<'a>,
426    {
427        let full_header = FullBoxHeader::deserialize(&mut reader)?;
428
429        let entry_count = u32::deserialize(&mut reader)?;
430
431        let entries = {
432            if let Some(payload_size) = seed.size.size() {
433                let mut payload_reader = reader.take(payload_size);
434                iter::from_fn(|| {
435                    SubSampleInformationBoxEntry::deserialize_seed(&mut payload_reader, full_header.version)
436                        .eof_to_none()
437                        .transpose()
438                })
439                .collect::<Result<Vec<SubSampleInformationBoxEntry>, io::Error>>()?
440            } else {
441                iter::from_fn(|| {
442                    SubSampleInformationBoxEntry::deserialize_seed(&mut reader, full_header.version)
443                        .eof_to_none()
444                        .transpose()
445                })
446                .collect::<Result<Vec<SubSampleInformationBoxEntry>, io::Error>>()?
447            }
448        };
449
450        Ok(Self {
451            full_header,
452            entry_count,
453            entries,
454        })
455    }
456}
457
458impl Serialize for SubSampleInformationBox {
459    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
460    where
461        W: std::io::Write,
462    {
463        self.serialize_box_header(&mut writer)?;
464        self.full_header.serialize(&mut writer)?;
465        self.entry_count.serialize(&mut writer)?;
466
467        for entry in &self.entries {
468            entry.serialize(&mut writer, self.full_header.version)?;
469        }
470
471        Ok(())
472    }
473}
474
475impl IsoSized for SubSampleInformationBox {
476    fn size(&self) -> usize {
477        let mut size = 0;
478        size += self.full_header.size();
479        size += 4;
480        size += self.entries.iter().map(|e| e.size(self.full_header.version)).sum::<usize>();
481
482        Self::add_header_size(size)
483    }
484}
485
486/// Entry in [`SubSampleInformationBox`].
487#[derive(Debug, PartialEq, Eq)]
488pub struct SubSampleInformationBoxEntry {
489    /// An integer that indicates the sample having sub‐sample structure. It is coded as the
490    /// difference, in decoding order, between the desired sample number, and the sample number
491    /// indicated in the previous entry. If the current entry is the first entry in the track, the value
492    /// indicates the sample number of the first sample having sub-sample information, that is, the value
493    /// is the difference between the sample number and zero (0). If the current entry is the first entry
494    /// in a track fragment with preceding non-empty track fragments, the value indicates the difference
495    /// between the sample number of the first sample having sub-sample information and the sample
496    /// number of the last sample in the previous track fragment. If the current entry is the first entry in
497    /// a track fragment without any preceding track fragments, the value indicates the sample number
498    /// of the first sample having sub-sample information, that is, the value is the difference between the
499    /// sample number and zero (0). This implies that the `sample_delta` for the first entry describing the
500    /// first sample in the track or in the track fragment is always 1.
501    pub sample_delta: u32,
502    /// An integer that specifies the number of sub-sample for the current sample. If there
503    /// is no sub-sample structure, then this field takes the value 0.
504    pub subsample_count: u16,
505    /// `subsample_size`, `subsample_priority`, `discardable` and `codec_specific_parameters`.
506    pub subsample_info: Vec<SubSampleInformationBoxEntrySubSample>,
507}
508
509impl<'a> DeserializeSeed<'a, u8> for SubSampleInformationBoxEntry {
510    fn deserialize_seed<R: ZeroCopyReader<'a>>(mut reader: R, seed: u8) -> io::Result<Self> {
511        let sample_delta = u32::deserialize(&mut reader)?;
512        let subsample_count = u16::deserialize(&mut reader)?;
513
514        let mut subsample_info = Vec::with_capacity(subsample_count as usize);
515        for _ in 0..subsample_count {
516            subsample_info.push(SubSampleInformationBoxEntrySubSample::deserialize_seed(&mut reader, seed)?);
517        }
518
519        Ok(Self {
520            sample_delta,
521            subsample_count,
522            subsample_info,
523        })
524    }
525}
526
527impl SubSampleInformationBoxEntry {
528    fn serialize<W>(&self, mut writer: W, version: u8) -> io::Result<()>
529    where
530        W: std::io::Write,
531    {
532        self.sample_delta.serialize(&mut writer)?;
533
534        self.subsample_count.serialize(&mut writer)?;
535        for subsample in &self.subsample_info {
536            subsample.serialize(&mut writer, version)?;
537        }
538
539        Ok(())
540    }
541}
542
543impl SubSampleInformationBoxEntry {
544    /// Returns the size of this entry in bytes, depending on the version.
545    pub fn size(&self, version: u8) -> usize {
546        4 + 2 + self.subsample_info.iter().map(|s| s.size(version)).sum::<usize>()
547    }
548}
549
550/// Sub-sample information in a [`SubSampleInformationBoxEntry`].
551#[derive(Debug, PartialEq, Eq)]
552pub struct SubSampleInformationBoxEntrySubSample {
553    /// An integer that specifies the size, in bytes, of the current sub-sample.
554    pub subsample_size: u32,
555    /// An integer specifying the degradation priority for each sub-sample. Higher
556    /// values of subsample_priority, indicate sub-samples which are important to, and have a greater
557    /// impact on, the decoded quality.
558    pub subsample_priority: u8,
559    /// Equal to 0 means that the sub-sample is required to decode the current sample, while
560    /// equal to 1 means the sub-sample is not required to decode the current sample but may be used
561    /// for enhancements, e.g., the sub-sample consists of supplemental enhancement information (SEI)
562    /// messages.
563    pub discardable: u8,
564    /// Defined by the codec in use. If no such definition is available, this field
565    /// shall be set to 0.
566    pub codec_specific_parameters: u32,
567}
568
569impl<'a> DeserializeSeed<'a, u8> for SubSampleInformationBoxEntrySubSample {
570    fn deserialize_seed<R>(mut reader: R, seed: u8) -> io::Result<Self>
571    where
572        R: ZeroCopyReader<'a>,
573    {
574        let subsample_size = if seed == 1 {
575            u32::deserialize(&mut reader)?
576        } else {
577            u16::deserialize(&mut reader)? as u32
578        };
579        let subsample_priority = u8::deserialize(&mut reader)?;
580        let discardable = u8::deserialize(&mut reader)?;
581        let codec_specific_parameters = u32::deserialize(&mut reader)?;
582
583        Ok(Self {
584            subsample_size,
585            subsample_priority,
586            discardable,
587            codec_specific_parameters,
588        })
589    }
590}
591
592impl SubSampleInformationBoxEntrySubSample {
593    fn serialize<W>(&self, mut writer: W, version: u8) -> io::Result<()>
594    where
595        W: std::io::Write,
596    {
597        if version == 1 {
598            self.subsample_size.serialize(&mut writer)?;
599        } else {
600            (self.subsample_size as u16).serialize(&mut writer)?;
601        }
602        self.subsample_priority.serialize(&mut writer)?;
603        self.discardable.serialize(&mut writer)?;
604        self.codec_specific_parameters.serialize(&mut writer)?;
605
606        Ok(())
607    }
608}
609
610impl SubSampleInformationBoxEntrySubSample {
611    /// Returns the size of this entry in bytes, depending on the version.
612    pub fn size(&self, version: u8) -> usize {
613        if version == 1 { 4 + 1 + 1 + 4 } else { 2 + 1 + 1 + 4 }
614    }
615}
616
617/// Sample auxiliary information sizes box
618///
619/// ISO/IEC 14496-12 - 8.7.8
620#[derive(IsoBox, Debug, PartialEq, Eq)]
621#[iso_box(box_type = b"saiz", skip_impl(deserialize_seed, serialize), crate_path = crate)]
622pub struct SampleAuxiliaryInformationSizesBox<'a> {
623    /// The full box header.
624    pub full_header: FullBoxHeader,
625    /// An integer that identifies the type of the sample auxiliary information. At most one
626    /// occurrence of this box with the same values for `aux_info_type` and `aux_info_type_parameter` shall
627    /// exist in the containing box.
628    pub aux_info_type: Option<u32>,
629    /// Identifies the "stream" of auxiliary information having the same value of
630    /// `aux_info_type` and associated to the same track. The semantics of `aux_info_type_parameter` are
631    /// determined by the value of `aux_info_type`.
632    pub aux_info_type_parameter: Option<u32>,
633    /// An integer specifying the sample auxiliary information size for the case
634    /// where all the indicated samples have the same sample auxiliary information size. If the size varies
635    /// then this field shall be zero.
636    pub default_sample_info_size: u8,
637    /// An integer that gives the number of samples for which a size is defined.
638    ///
639    /// For a [`SampleAuxiliaryInformationSizesBox`] appearing in the [`SampleTableBox`](super::SampleTableBox)
640    /// this shall be the same as, or less than, the `sample_count` within the [`SampleSizeBox`] or [`CompactSampleSizeBox`].
641    ///
642    /// For a [`SampleAuxiliaryInformationSizesBox`] appearing in a [`TrackFragmentBox`](super::TrackFragmentBox) this
643    /// shall be the same as, or less than, the sum of the `sample_count` entries within the
644    /// [`TrackRunBox`](super::TrackRunBox)es of the track fragment.
645    ///
646    /// If this is less than the number of samples, then auxiliary information is supplied for the initial samples, and the
647    /// remaining samples have no associated auxiliary information.
648    pub sample_count: u32,
649    /// Gives the size of the sample auxiliary information in bytes. This may be zero to
650    /// indicate samples with no associated auxiliary information.
651    ///
652    /// If set, length is [`sample_count`](Self::sample_count).
653    pub sample_info_size: Option<BytesCow<'a>>,
654}
655
656impl<'a> DeserializeSeed<'a, BoxHeader> for SampleAuxiliaryInformationSizesBox<'a> {
657    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
658    where
659        R: ZeroCopyReader<'a>,
660    {
661        let full_header = FullBoxHeader::deserialize(&mut reader)?;
662
663        let aux_info_type = if (*full_header.flags & 0b1) == 1 {
664            Some(u32::deserialize(&mut reader)?)
665        } else {
666            None
667        };
668        let aux_info_type_parameter = if (*full_header.flags & 0b1) == 1 {
669            Some(u32::deserialize(&mut reader)?)
670        } else {
671            None
672        };
673
674        let default_sample_info_size = u8::deserialize(&mut reader)?;
675        let sample_count = u32::deserialize(&mut reader)?;
676
677        let sample_info_size = if default_sample_info_size == 0 {
678            Some(reader.try_read(sample_count as usize)?)
679        } else {
680            None
681        };
682
683        Ok(Self {
684            full_header,
685            aux_info_type,
686            aux_info_type_parameter,
687            default_sample_info_size,
688            sample_count,
689            sample_info_size,
690        })
691    }
692}
693
694impl Serialize for SampleAuxiliaryInformationSizesBox<'_> {
695    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
696    where
697        W: std::io::Write,
698    {
699        self.serialize_box_header(&mut writer)?;
700        self.full_header.serialize(&mut writer)?;
701
702        if (*self.full_header.flags & 0b1) == 1 {
703            self.aux_info_type
704                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "aux_info_type is required"))?
705                .serialize(&mut writer)?;
706            self.aux_info_type_parameter
707                .ok_or(io::Error::new(
708                    io::ErrorKind::InvalidData,
709                    "aux_info_type_parameter is required",
710                ))?
711                .serialize(&mut writer)?;
712        }
713
714        self.default_sample_info_size.serialize(&mut writer)?;
715        self.sample_count.serialize(&mut writer)?;
716        if self.default_sample_info_size == 0 {
717            self.sample_info_size
718                .as_ref()
719                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "sample_info_size is required"))?
720                .serialize(&mut writer)?;
721        }
722
723        Ok(())
724    }
725}
726
727/// Sample auxiliary information offsets box
728///
729/// ISO/IEC 14496-12 - 8.7.9
730#[derive(IsoBox, Debug, PartialEq, Eq)]
731#[iso_box(box_type = b"saio", skip_impl(deserialize_seed, serialize, sized), crate_path = crate)]
732pub struct SampleAuxiliaryInformationOffsetsBox {
733    /// The full box header.
734    pub full_header: FullBoxHeader,
735    /// An integer that identifies the type of the sample auxiliary information. At most one
736    /// occurrence of this box with the same values for `aux_info_type` and `aux_info_type_parameter` shall
737    /// exist in the containing box.
738    pub aux_info_type: Option<u32>,
739    /// Identifies the "stream" of auxiliary information having the same value of
740    /// `aux_info_type` and associated to the same track. The semantics of `aux_info_type_parameter` are
741    /// determined by the value of `aux_info_type`.
742    pub aux_info_type_parameter: Option<u32>,
743    /// Gives the number of entries in the following table.
744    ///
745    /// For a [`SampleAuxiliaryInformationOffsetsBox`] appearing in a [`SampleTableBox`](super::SampleTableBox),
746    /// this shall be equal to one or to the value of the `entry_count`
747    /// field in the [`ChunkOffsetBox`] or [`ChunkLargeOffsetBox`].
748    ///
749    /// For a [`SampleAuxiliaryInformationOffsetsBox`] appearing in a [`TrackFragmentBox`](super::TrackFragmentBox),
750    /// this shall be equal to one or to the number of TrackRunBoxes in the [`TrackFragmentBox`](super::TrackFragmentBox).
751    pub entry_count: u32,
752    /// Gives the position in the file of the Sample Auxiliary Information for each Chunk or Track
753    /// Fragment Run. If `entry_count` is one, then the Sample Auxiliary Information for all Chunks or Runs
754    /// is contiguous in the file in chunk or run order. When in the [`SampleTableBox`](super::SampleTableBox),
755    /// the offsets are relative to the same base offset as derived for the respective samples through the
756    /// `data_reference_index` of the sample entry referenced by the samples.
757    /// In a [`TrackFragmentBox`](super::TrackFragmentBox), this value is relative to the base offset established by the
758    /// [`TrackFragmentHeaderBox`](super::TrackFragmentHeaderBox) in the same track fragment (see 8.8.14).
759    pub offset: Vec<u64>,
760}
761
762impl<'a> DeserializeSeed<'a, BoxHeader> for SampleAuxiliaryInformationOffsetsBox {
763    fn deserialize_seed<R>(mut reader: R, _seed: BoxHeader) -> io::Result<Self>
764    where
765        R: ZeroCopyReader<'a>,
766    {
767        let full_header = FullBoxHeader::deserialize(&mut reader)?;
768
769        let aux_info_type = if (*full_header.flags & 0b1) == 1 {
770            Some(u32::deserialize(&mut reader)?)
771        } else {
772            None
773        };
774        let aux_info_type_parameter = if (*full_header.flags & 0b1) == 1 {
775            Some(u32::deserialize(&mut reader)?)
776        } else {
777            None
778        };
779
780        let entry_count = u32::deserialize(&mut reader)?;
781
782        let offset = if full_header.version == 0 {
783            (0..entry_count)
784                .map(|_| u32::deserialize(&mut reader).map(|v| v as u64))
785                .collect::<Result<Vec<u64>, io::Error>>()?
786        } else {
787            (0..entry_count)
788                .map(|_| u64::deserialize(&mut reader))
789                .collect::<Result<Vec<u64>, io::Error>>()?
790        };
791
792        Ok(Self {
793            full_header,
794            aux_info_type,
795            aux_info_type_parameter,
796            entry_count,
797            offset,
798        })
799    }
800}
801
802impl Serialize for SampleAuxiliaryInformationOffsetsBox {
803    fn serialize<W>(&self, mut writer: W) -> io::Result<()>
804    where
805        W: std::io::Write,
806    {
807        self.serialize_box_header(&mut writer)?;
808        self.full_header.serialize(&mut writer)?;
809
810        if (*self.full_header.flags & 0b1) == 1 {
811            self.aux_info_type
812                .ok_or(io::Error::new(io::ErrorKind::InvalidData, "aux_info_type is required"))?
813                .serialize(&mut writer)?;
814            self.aux_info_type_parameter
815                .ok_or(io::Error::new(
816                    io::ErrorKind::InvalidData,
817                    "aux_info_type_parameter is required",
818                ))?
819                .serialize(&mut writer)?;
820        }
821
822        self.entry_count.serialize(&mut writer)?;
823        for entry in &self.offset {
824            if self.full_header.version == 0 {
825                (*entry as u32).serialize(&mut writer)?;
826            } else {
827                entry.serialize(&mut writer)?;
828            }
829        }
830
831        Ok(())
832    }
833}
834
835impl IsoSized for SampleAuxiliaryInformationOffsetsBox {
836    fn size(&self) -> usize {
837        let mut size = self.full_header.size();
838        if (*self.full_header.flags & 0b1) == 1 {
839            size += 4; // aux_info_type
840            size += 4; // aux_info_type_parameter
841        }
842        size += 4; // entry_count
843        size += if self.full_header.version == 0 {
844            4 * self.offset.len() // u32
845        } else {
846            8 * self.offset.len() // u64
847        };
848
849        Self::add_header_size(size)
850    }
851}