isobmff/boxes/
general.rs

1//! File structure and general boxes defined in ISO/IEC 14496-12 - 8.1
2
3use std::fmt::Debug;
4
5use scuffle_bytes_util::BytesCow;
6use scuffle_bytes_util::zero_copy::{Deserialize, Serialize};
7
8use crate::{FullBoxHeader, IsoBox, IsoSized};
9
10/// Media data box
11///
12/// ISO/IEC 14496-12 - 8.1.1
13#[derive(IsoBox, PartialEq, Eq)]
14#[iso_box(box_type = b"mdat", crate_path = crate)]
15pub struct MediaDataBox<'a> {
16    /// The contained media data.
17    pub data: BytesCow<'a>,
18}
19
20impl<'a> MediaDataBox<'a> {
21    /// Creates a new [`MediaDataBox`] with the given data.
22    pub fn new(data: BytesCow<'a>) -> Self {
23        Self { data }
24    }
25}
26
27impl Debug for MediaDataBox<'_> {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        f.debug_struct("MediaDataBox").field("data.len", &self.data.len()).finish()
30    }
31}
32
33/// Free space box
34///
35/// ISO/IEC 14496-12 - 8.1.2
36#[derive(IsoBox, PartialEq, Eq)]
37#[iso_box(box_type = b"free", crate_path = crate)]
38pub struct FreeSpaceBox<'a> {
39    /// The contained data.
40    pub data: BytesCow<'a>,
41}
42
43impl Debug for FreeSpaceBox<'_> {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        f.debug_struct("FreeSpaceBox").field("data.len", &self.data.len()).finish()
46    }
47}
48
49/// Free space box
50///
51/// ISO/IEC 14496-12 - 8.1.2
52///
53/// This is the same as the [`FreeSpaceBox`] except the box type is `skip`.
54#[derive(IsoBox, PartialEq, Eq)]
55#[iso_box(box_type = b"skip", crate_path = crate)]
56pub struct SkipBox<'a> {
57    /// The contained data.
58    pub data: BytesCow<'a>,
59}
60
61impl Debug for SkipBox<'_> {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.debug_struct("SkipBox").field("data.len", &self.data.len()).finish()
64    }
65}
66
67/// Progressive download information box
68///
69/// ISO/IEC 14496-12 - 8.1.3
70#[derive(IsoBox, Debug, PartialEq, Eq)]
71#[iso_box(box_type = b"pdin", crate_path = crate)]
72pub struct ProgressiveDownloadInfoBox {
73    /// The full box header.
74    pub full_header: FullBoxHeader,
75    /// `rate` and `initial_delay` properties.
76    #[iso_box(repeated)]
77    pub properties: Vec<ProgressiveDownloadInfoBoxProperties>,
78}
79
80/// Properties contained in the [`ProgressiveDownloadInfoBox`].
81#[derive(Debug, PartialEq, Eq)]
82pub struct ProgressiveDownloadInfoBoxProperties {
83    /// A download rate expressed in bytes/second.
84    pub rate: u32,
85    /// Suggested delay to use when playing the file, such that if download continues at
86    /// the given rate, all data within the file will arrive in time for its use and
87    /// playback should not need to stall.
88    pub initial_delay: u32,
89}
90
91impl<'a> Deserialize<'a> for ProgressiveDownloadInfoBoxProperties {
92    fn deserialize<R>(mut reader: R) -> std::io::Result<Self>
93    where
94        R: scuffle_bytes_util::zero_copy::ZeroCopyReader<'a>,
95    {
96        let rate = u32::deserialize(&mut reader)?;
97        let initial_delay = u32::deserialize(&mut reader)?;
98
99        Ok(ProgressiveDownloadInfoBoxProperties { rate, initial_delay })
100    }
101}
102
103impl Serialize for ProgressiveDownloadInfoBoxProperties {
104    fn serialize<W>(&self, mut writer: W) -> std::io::Result<()>
105    where
106        W: std::io::Write,
107    {
108        self.rate.serialize(&mut writer)?;
109        self.initial_delay.serialize(&mut writer)?;
110        Ok(())
111    }
112}
113
114impl IsoSized for ProgressiveDownloadInfoBoxProperties {
115    fn size(&self) -> usize {
116        self.rate.size() + self.initial_delay.size()
117    }
118}
119
120/// Identified media data box
121///
122/// ISO/IEC 14496-12 - 8.1.4
123#[derive(IsoBox, PartialEq, Eq)]
124#[iso_box(box_type = b"imda", crate_path = crate)]
125pub struct IdentifiedMediaDataBox<'a> {
126    /// Shall differ from the imda_identifier values of the other
127    /// [`IdentifiedMediaDataBox`]es of the file.
128    pub imda_identifier: u32,
129    /// The contained media data.
130    pub data: BytesCow<'a>,
131}
132
133impl Debug for IdentifiedMediaDataBox<'_> {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        f.debug_struct("IdentifiedMediaDataBox")
136            .field("imda_identifier", &self.imda_identifier)
137            .field("data.len", &self.data.len())
138            .finish()
139    }
140}
141
142#[cfg(test)]
143#[cfg_attr(all(test, coverage_nightly), coverage(off))]
144mod tests {
145    use scuffle_bytes_util::zero_copy::{Deserialize, Slice};
146
147    use super::MediaDataBox;
148
149    #[test]
150    fn demux_mdat() {
151        #[rustfmt::skip]
152        let data = [
153            0x00, 0x00, 0x00, 0x0C, // size
154            b'm', b'd', b'a', b't', // type
155            0x42, 0x00, 0x42, 0x00, // data
156            0x01,
157        ];
158
159        let mdat = MediaDataBox::deserialize(Slice::from(&data[..])).unwrap();
160        assert_eq!(mdat.data.len(), 4);
161        assert_eq!(mdat.data.as_bytes()[0], 0x42);
162        assert_eq!(mdat.data.as_bytes()[1], 0x00);
163        assert_eq!(mdat.data.as_bytes()[2], 0x42);
164        assert_eq!(mdat.data.as_bytes()[3], 0x00);
165    }
166}