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