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) => mfro.insert_once(atom)?,
30                Any::Tfra(atom) => {
31                    tfra.push(atom);
32                }
33                Any::Skip(atom) => tracing::debug!(size = atom.zeroed.size, "skipping skip box"),
34                Any::Free(atom) => tracing::debug!(size = atom.zeroed.size, "skipping free box"),
35                unknown => Self::decode_unknown(&unknown)?,
36            }
37        }
38        skip_trailing_padding(buf);
39
40        Ok(Self {
41            mfro: mfro.ok_or(Error::MissingBox(Mfro::KIND))?,
42            tfra,
43        })
44    }
45
46    fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
47        self.tfra.iter().try_for_each(|x| x.encode(buf))?;
48        self.mfro.encode(buf)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    // From MPEG File Format Conformance suite: fragment_random_access-2.mp4
57    const ENCODED_MFRA: &[u8] = &[
58        0x00, 0x00, 0x00, 0xa9, 0x6d, 0x66, 0x72, 0x61, 0x00, 0x00, 0x00, 0x91, 0x74, 0x66, 0x72,
59        0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60        0x00, 0x0b, 0x00, 0x06, 0xdd, 0xd0, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x01, 0x01, 0x00, 0x08,
61        0x3d, 0x60, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x02, 0x01, 0x00, 0x09, 0x9c, 0xf0, 0x00, 0x00,
62        0xeb, 0x1b, 0x01, 0x03, 0x01, 0x00, 0x0a, 0xfc, 0x80, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x04,
63        0x01, 0x00, 0x0c, 0x5c, 0x10, 0x00, 0x00, 0xeb, 0x1b, 0x01, 0x05, 0x01, 0x00, 0x0d, 0xbb,
64        0xa0, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x01, 0x01, 0x00, 0x0f, 0x1b, 0x30, 0x00, 0x01, 0xdc,
65        0xa3, 0x01, 0x02, 0x01, 0x00, 0x10, 0x7a, 0xc0, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x03, 0x01,
66        0x00, 0x11, 0xda, 0x50, 0x00, 0x01, 0xdc, 0xa3, 0x01, 0x04, 0x01, 0x00, 0x13, 0x39, 0xe0,
67        0x00, 0x01, 0xdc, 0xa3, 0x01, 0x05, 0x01, 0x00, 0x14, 0x99, 0x70, 0x00, 0x02, 0xc4, 0x33,
68        0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x10, 0x6d, 0x66, 0x72, 0x6f, 0x00, 0x00, 0x00, 0x00,
69        0x00, 0x00, 0x00, 0xa9,
70    ];
71
72    fn get_reference_mfra() -> Mfra {
73        Mfra {
74            tfra: vec![Tfra {
75                track_id: 1,
76                entries: vec![
77                    FragmentInfo {
78                        time: 450000,
79                        moof_offset: 60187,
80                        traf_number: 1,
81                        trun_number: 1,
82                        sample_delta: 1,
83                    },
84                    FragmentInfo {
85                        time: 540000,
86                        moof_offset: 60187,
87                        traf_number: 1,
88                        trun_number: 2,
89                        sample_delta: 1,
90                    },
91                    FragmentInfo {
92                        time: 630000,
93                        moof_offset: 60187,
94                        traf_number: 1,
95                        trun_number: 3,
96                        sample_delta: 1,
97                    },
98                    FragmentInfo {
99                        time: 720000,
100                        moof_offset: 60187,
101                        traf_number: 1,
102                        trun_number: 4,
103                        sample_delta: 1,
104                    },
105                    FragmentInfo {
106                        time: 810000,
107                        moof_offset: 60187,
108                        traf_number: 1,
109                        trun_number: 5,
110                        sample_delta: 1,
111                    },
112                    FragmentInfo {
113                        time: 900000,
114                        moof_offset: 122019,
115                        traf_number: 1,
116                        trun_number: 1,
117                        sample_delta: 1,
118                    },
119                    FragmentInfo {
120                        time: 990000,
121                        moof_offset: 122019,
122                        traf_number: 1,
123                        trun_number: 2,
124                        sample_delta: 1,
125                    },
126                    FragmentInfo {
127                        time: 1080000,
128                        moof_offset: 122019,
129                        traf_number: 1,
130                        trun_number: 3,
131                        sample_delta: 1,
132                    },
133                    FragmentInfo {
134                        time: 1170000,
135                        moof_offset: 122019,
136                        traf_number: 1,
137                        trun_number: 4,
138                        sample_delta: 1,
139                    },
140                    FragmentInfo {
141                        time: 1260000,
142                        moof_offset: 122019,
143                        traf_number: 1,
144                        trun_number: 5,
145                        sample_delta: 1,
146                    },
147                    FragmentInfo {
148                        time: 1350000,
149                        moof_offset: 181299,
150                        traf_number: 1,
151                        trun_number: 1,
152                        sample_delta: 1,
153                    },
154                ],
155            }],
156            mfro: Mfro { parent_size: 169 },
157        }
158    }
159
160    #[test]
161    fn test_mfra_decode() {
162        let buf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_MFRA);
163        let mfra = Mfra::decode(buf).expect("failed to decode mfra");
164        assert_eq!(mfra, get_reference_mfra());
165    }
166
167    #[test]
168    fn test_mfra_encode() {
169        let mfra = get_reference_mfra();
170        let mut buf = Vec::new();
171        mfra.encode(&mut buf).unwrap();
172        assert_eq!(buf, ENCODED_MFRA);
173    }
174}