Skip to main content

mp4_atom/
any.rs

1use crate::*;
2
3use std::fmt;
4use std::io::Read;
5
6macro_rules! any {
7    (basic: [$($kind:ident,)* $(,)?], boxed: [$($boxed:ident,)* $(,)?]) => {
8        /// Any of the supported atoms.
9        #[derive(Clone, PartialEq)]
10        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11        #[non_exhaustive]
12        pub enum Any {
13            $($kind($kind),)*
14            $($boxed(Box<$boxed>),)*
15            Unknown(FourCC, Vec<u8>),
16        }
17
18        impl Any {
19            /// Get the kind of the atom.
20            pub fn kind(&self) -> FourCC {
21                match self {
22                    $(Any::$kind(_) => $kind::KIND,)*
23                    $(Any::$boxed(_) => $boxed::KIND,)*
24                    Any::Unknown(kind, _) => *kind,
25                }
26            }
27        }
28
29        impl Decode for Any {
30            fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
31                match Self::decode_maybe(buf)? {
32                    Some(any) => Ok(any),
33                    None => Err(Error::OutOfBounds),
34                }
35            }
36        }
37
38        impl DecodeMaybe for Any {
39            fn decode_maybe<B: Buf>(buf: &mut B) -> Result<Option<Self>> {
40                let header = match Header::decode_maybe(buf)? {
41                    Some(header) => header,
42                    None => return Ok(None),
43                };
44
45                let size = header.size.unwrap_or(buf.remaining());
46                if size > buf.remaining() {
47                    return Ok(None);
48                }
49
50                Ok(Some(Self::decode_atom(&header, buf)?))
51            }
52        }
53
54        impl Encode for Any {
55            fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
56                let start = buf.len();
57                0u32.encode(buf)?;
58                self.kind().encode(buf)?;
59
60                match self {
61                    $(Any::$kind(inner) => Atom::encode_body(inner, buf),)*
62                    $(Any::$boxed(boxed) => Atom::encode_body(boxed.as_ref(), buf),)*
63                    Any::Unknown(_, data) => data.encode(buf),
64                }?;
65
66                let size: u32 = (buf.len() - start).try_into().map_err(|_| Error::TooLarge(self.kind()))?;
67                buf.set_slice(start, &size.to_be_bytes());
68
69                Ok(())
70            }
71        }
72
73        impl DecodeAtom for Any {
74            /// Decode the atom from a header and payload.
75            fn decode_atom<B: Buf>(header: &Header, buf: &mut B) -> Result<Self> {
76                let size = header.size.unwrap_or(buf.remaining());
77                if size > buf.remaining() {
78                    return Err(Error::OutOfBounds);
79                }
80
81                let mut body = &mut buf.slice(size);
82
83                let atom = match header.kind {
84                    $(_ if header.kind == $kind::KIND => {
85                        Any::$kind(match $kind::decode_body(&mut body) {
86                            Ok(atom) => atom,
87                            Err(Error::OutOfBounds) => return Err(Error::OverDecode($kind::KIND)),
88                            Err(Error::ShortRead) => return Err(Error::UnderDecode($kind::KIND)),
89                            Err(err) => return Err(err),
90                        })
91                    },)*
92                    $(_ if header.kind == $boxed::KIND => {
93                        Any::$boxed(match $boxed::decode_body(&mut body) {
94                            Ok(atom) => Box::new(atom),
95                            Err(Error::OutOfBounds) => return Err(Error::OverDecode($boxed::KIND)),
96                            Err(Error::ShortRead) => return Err(Error::UnderDecode($boxed::KIND)),
97                            Err(err) => return Err(err),
98                        })
99                    },)*
100                    _ => {
101                        let body = Vec::decode(body)?;
102                        Any::Unknown(header.kind, body)
103                    },
104                };
105
106                if body.has_remaining() {
107                    return Err(Error::UnderDecode(header.kind));
108                }
109
110                buf.advance(size);
111
112                Ok(atom)
113            }
114        }
115
116        impl fmt::Debug for Any {
117            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118                match self {
119                    $(Any::$kind(inner) => inner.fmt(f),)*
120                    $(Any::$boxed(boxed) => boxed.fmt(f),)*
121                    Any::Unknown(kind, body) => write!(f, "Unknown {{ kind: {:?}, size: {:?}, bytes: {:?} }}", kind, body.len(), body),
122                }
123            }
124        }
125
126        $(impl From<$kind> for Any {
127            fn from(inner: $kind) -> Self {
128                Any::$kind(inner)
129            }
130        })*
131
132        $(impl From<$boxed> for Any {
133            fn from(inner: $boxed) -> Self {
134                Any::$boxed(Box::new(inner))
135            }
136        })*
137
138        $(impl TryFrom<Any> for $kind {
139            type Error = Any;
140
141            fn try_from(any: Any) -> std::result::Result<Self, Any> {
142                match any {
143                    Any::$kind(inner) => Ok(inner),
144                    _ => Err(any),
145                }
146            }
147        })*
148
149        $(impl TryFrom<Any> for $boxed {
150            type Error = Any;
151
152            fn try_from(any: Any) -> std::result::Result<Self, Any> {
153                match any {
154                    Any::$boxed(boxed) => Ok(*boxed),
155                    _ => Err(any),
156                }
157            }
158        })*
159
160        // So we can use .into() to automatically unbox
161        $(impl From<Box<$boxed>> for $boxed {
162            fn from(boxed: Box<$boxed>) -> Self {
163                *boxed
164            }
165        })*
166
167        /// A trait to help casting to/from Any.
168        /// From/TryFrom use concrete types, but if we want to use generics, then we need a trait.
169        pub trait AnyAtom: Atom {
170            fn from_any(any: Any) -> Option<Self>;
171            fn from_any_ref(any: &Any) -> Option<&Self>;
172            fn from_any_mut(any: &mut Any) -> Option<&mut Self>;
173
174            fn into_any(self) -> Any;
175        }
176
177        $(impl AnyAtom for $kind {
178            fn from_any(any: Any) -> Option<Self> {
179                match any {
180                    Any::$kind(inner) => Some(inner),
181                    _ => None,
182                }
183            }
184
185            fn from_any_ref(any: &Any) -> Option<&Self> {
186                match any {
187                    Any::$kind(inner) => Some(inner),
188                    _ => None,
189                }
190            }
191
192            fn from_any_mut(any: &mut Any) -> Option<&mut Self> {
193                match any {
194                    Any::$kind(inner) => Some(inner),
195                    _ => None,
196                }
197            }
198
199            fn into_any(self) -> Any {
200                Any::$kind(self)
201            }
202        })*
203
204        $(impl AnyAtom for $boxed {
205            fn from_any(any: Any) -> Option<Self> {
206                match any {
207                    Any::$boxed(boxed) => Some(*boxed),
208                    _ => None,
209                }
210            }
211
212            fn from_any_ref(any: &Any) -> Option<&Self> {
213                match any {
214                    Any::$boxed(boxed) => Some(boxed),
215                    _ => None,
216                }
217            }
218
219            fn from_any_mut(any: &mut Any) -> Option<&mut Self> {
220                match any {
221                    Any::$boxed(boxed) => Some(boxed),
222                    _ => None,
223                }
224            }
225
226            fn into_any(self) -> Any {
227                Any::$boxed(Box::new(self))
228            }
229        })*
230    };
231}
232
233any! {
234    basic: [
235    Ftyp,
236    Styp,
237    Meta,
238        Hdlr,
239        Pitm,
240        Iloc,
241        Iinf,
242        Iprp,
243            Ipco,
244                Auxc,
245                Clap,
246                Imir,
247                Irot,
248                Iscl,
249                Ispe,
250                Pixi,
251                Rref,
252            Ipma,
253        Iref,
254        Idat,
255        Ilst,
256            Covr,
257            Desc,
258            Tool, // "©too"
259            Name,
260            Rtng,
261            Year,
262    Moov,
263        Mvhd,
264        Ainf,
265        Udta,
266            Cprt,
267            Kind,
268            Skip,
269        // Trak, // boxed to avoid large size differences between variants
270            Tkhd,
271            Mdia,
272                Mdhd,
273                Minf,
274                    Stbl,
275                        Stsd,
276                            Avc1,
277                                Avcc,
278                                Btrt,
279                                Ccst,
280                                Colr,
281                                Pasp,
282                                Taic,
283                                Fiel,
284                            Hev1, Hvc1,
285                                Hvcc, Lhvc,
286                            Mp4a,
287                                Esds,
288                            Tx3g,
289                                Ftab,
290                            Vp08, Vp09,
291                                VpcC,
292                            Av01,
293                                Av1c,
294                            Opus,
295                                Dops,
296                            Uncv,
297                                Cmpd,
298                                UncC,
299                            Flac,
300                                Dfla,
301                            Ac3,
302                                Ac3SpecificBox,
303                            Eac3,
304                                Ec3SpecificBox,
305                            Sowt, Twos, Lpcm, Ipcm, Fpcm, In24, In32, Fl32, Fl64, S16l,
306                                PcmC,
307                                Chnl,
308                            Wvtt,
309                                VttC,
310                                Vlab,
311                            Samr,
312                                Damr,
313                        Stts,
314                        Stsc,
315                        Stsz,
316                        Stss,
317                        Stco,
318                        Co64,
319                        Cslg,
320                        Ctts,
321                        Sbgp,
322                        Sgpd,
323                        Subs,
324                        Saio,
325                        Saiz,
326                    Dinf,
327                        Dref,
328                    Hmhd,
329                    Nmhd,
330                    Smhd,
331                    Sthd,
332                    Vmhd,
333            Edts,
334                Elst,
335            Tref,
336        Mvex,
337            Mehd,
338            Trex,
339    Emsg,
340    Moof,
341        Mfhd,
342        Traf,
343            Tfhd,
344            Tfdt,
345            Trun,
346            Senc,
347    Mdat,
348    Free,
349    Sidx,
350    Prft,
351    Mfra,
352        Tfra,
353        Mfro,
354    ],
355    boxed: [
356        Trak,
357    ]
358}
359
360impl ReadFrom for Any {
361    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
362        <Option<Any> as ReadFrom>::read_from(r)?.ok_or(Error::UnexpectedEof)
363    }
364}
365
366impl ReadFrom for Option<Any> {
367    fn read_from<R: Read + ?Sized>(r: &mut R) -> Result<Self> {
368        let header = match <Option<Header> as ReadFrom>::read_from(r)? {
369            Some(header) => header,
370            None => return Ok(None),
371        };
372
373        let body = &mut header.read_body(r)?;
374        Ok(Some(Any::decode_atom(&header, body)?))
375    }
376}
377
378impl ReadAtom for Any {
379    fn read_atom<R: Read + ?Sized>(header: &Header, r: &mut R) -> Result<Self> {
380        let body = &mut header.read_body(r)?;
381        Any::decode_atom(header, body)
382    }
383}