Skip to main content

mp4_atom/mfra/
mod.rs

1mod mfro;
2mod tfra;
3
4pub use mfro::*;
5pub use tfra::*;
6
7use crate::*;
8
9/// MovieFragmentRandomAccessBox (`mfra`).
10///
11/// See ISO/IEC 14496-12:2022 section 8.8.9
12#[derive(Debug, Clone, PartialEq, Eq, Default)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct Mfra {
15    pub tfra: Vec<Tfra>,
16    pub mfro: Mfro,
17}
18
19// We can't use the normal nested macro here, because we need mfro to be written last
20impl Atom for Mfra {
21    const KIND: FourCC = FourCC::new(b"mfra");
22
23    fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
24        let mut mfro = None;
25        let mut tfra = Vec::new();
26
27        while let Some(atom) = Any::decode_maybe(buf)? {
28            match atom {
29                Any::Mfro(atom) => {
30                    if mfro.is_some() {
31                        return Err(Error::DuplicateBox(Mfro::KIND));
32                    }
33                    mfro = Some(atom);
34                }
35                Any::Tfra(atom) => {
36                    tfra.push(atom);
37                }
38                Any::Skip(atom) => tracing::debug!(size = atom.zeroed.size, "skipping skip box"),
39                Any::Free(atom) => tracing::debug!(size = atom.zeroed.size, "skipping free box"),
40                unknown => Self::decode_unknown(&unknown)?,
41            }
42        }
43        skip_trailing_padding(buf);
44
45        Ok(Self {
46            mfro: mfro.ok_or(Error::MissingBox(Mfro::KIND))?,
47            tfra,
48        })
49    }
50
51    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
52        self.tfra.iter().try_for_each(|x| x.encode(buf))?;
53        self.mfro.encode(buf)
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    // From MPEG File Format Conformance suite: fragment_random_access-2.mp4
62    const ENCODED_MFRA: &[u8] = &[
63        0x00, 0x00, 0x00, 0xa9, 0x6d, 0x66, 0x72, 0x61, 0x00, 0x00, 0x00, 0x91, 0x74, 0x66, 0x72,
64        0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65        0x00, 0x0b, 0x00, 0x06, 0xdd, 0xd0, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x01, 0x01, 0x00, 0x08,
66        0x3d, 0x60, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x02, 0x01, 0x00, 0x09, 0x9c, 0xf0, 0x00, 0x00,
67        0xeb, 0x1b, 0x01, 0x03, 0x01, 0x00, 0x0a, 0xfc, 0x80, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x04,
68        0x01, 0x00, 0x0c, 0x5c, 0x10, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x05, 0x01, 0x00, 0x0d, 0xbb,
69        0xa0, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x01, 0x01, 0x00, 0x0f, 0x1b, 0x30, 0x00, 0x01, 0xdc,
70        0xa3, 0x01, 0x02, 0x01, 0x00, 0x10, 0x7a, 0xc0, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x03, 0x01,
71        0x00, 0x11, 0xda, 0x50, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x04, 0x01, 0x00, 0x13, 0x39, 0xe0,
72        0x00, 0x01, 0xdc, 0xa3, 0x01, 0x05, 0x01, 0x00, 0x14, 0x99, 0x70, 0x00, 0x02, 0xc4, 0x33,
73        0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x66, 0x72, 0x6f, 0x00, 0x00, 0x00, 0x00,
74        0x00, 0x00, 0x00, 0xa9,
75    ];
76
77    fn get_reference_mfra() -> Mfra {
78        Mfra {
79            tfra: vec![Tfra {
80                track_id: 1,
81                entries: vec![
82                    FragmentInfo {
83                        time: 450000,
84                        moof_offset: 60187,
85                        traf_number: 1,
86                        trun_number: 1,
87                        sample_delta: 1,
88                    },
89                    FragmentInfo {
90                        time: 540000,
91                        moof_offset: 60187,
92                        traf_number: 1,
93                        trun_number: 2,
94                        sample_delta: 1,
95                    },
96                    FragmentInfo {
97                        time: 630000,
98                        moof_offset: 60187,
99                        traf_number: 1,
100                        trun_number: 3,
101                        sample_delta: 1,
102                    },
103                    FragmentInfo {
104                        time: 720000,
105                        moof_offset: 60187,
106                        traf_number: 1,
107                        trun_number: 4,
108                        sample_delta: 1,
109                    },
110                    FragmentInfo {
111                        time: 810000,
112                        moof_offset: 60187,
113                        traf_number: 1,
114                        trun_number: 5,
115                        sample_delta: 1,
116                    },
117                    FragmentInfo {
118                        time: 900000,
119                        moof_offset: 122019,
120                        traf_number: 1,
121                        trun_number: 1,
122                        sample_delta: 1,
123                    },
124                    FragmentInfo {
125                        time: 990000,
126                        moof_offset: 122019,
127                        traf_number: 1,
128                        trun_number: 2,
129                        sample_delta: 1,
130                    },
131                    FragmentInfo {
132                        time: 1080000,
133                        moof_offset: 122019,
134                        traf_number: 1,
135                        trun_number: 3,
136                        sample_delta: 1,
137                    },
138                    FragmentInfo {
139                        time: 1170000,
140                        moof_offset: 122019,
141                        traf_number: 1,
142                        trun_number: 4,
143                        sample_delta: 1,
144                    },
145                    FragmentInfo {
146                        time: 1260000,
147                        moof_offset: 122019,
148                        traf_number: 1,
149                        trun_number: 5,
150                        sample_delta: 1,
151                    },
152                    FragmentInfo {
153                        time: 1350000,
154                        moof_offset: 181299,
155                        traf_number: 1,
156                        trun_number: 1,
157                        sample_delta: 1,
158                    },
159                ],
160            }],
161            mfro: Mfro { parent_size: 169 },
162        }
163    }
164
165    #[test]
166    fn test_mfra_decode() {
167        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_MFRA);
168        let mfra = Mfra::decode(buf).expect("failed to decode mfra");
169        assert_eq!(mfra, get_reference_mfra());
170    }
171
172    #[test]
173    fn test_mfra_encode() {
174        let mfra = get_reference_mfra();
175        let mut buf = Vec::new();
176        mfra.encode(&mut buf).unwrap();
177        assert_eq!(buf, ENCODED_MFRA);
178    }
179}