Skip to main content

mp4_atom/moov/trak/mdia/minf/stbl/stsd/
mod.rs

1mod ac3;
2mod amr;
3mod audio;
4mod av01;
5mod btrt;
6mod camm;
7mod ccst;
8mod chnl;
9mod colr;
10mod eac3;
11mod evte;
12mod fiel;
13mod flac;
14mod ftab;
15mod h264;
16mod hevc;
17mod jpeg;
18mod mebx;
19mod metadata;
20mod mett;
21mod metx;
22mod mp3;
23mod mp4a;
24mod opus;
25mod pasp;
26mod pcm;
27mod plaintext;
28mod spatial;
29mod st3d;
30mod sv3d;
31mod taic;
32mod tx3g;
33mod uncv;
34mod urim;
35mod vexu;
36mod visual;
37mod vp9;
38mod wvtt;
39
40pub use ac3::*;
41pub use amr::*;
42pub use audio::*;
43pub use av01::*;
44pub use btrt::*;
45pub use camm::*;
46pub use ccst::*;
47pub use chnl::*;
48pub use colr::*;
49pub use eac3::*;
50pub use evte::*;
51pub use fiel::*;
52pub use flac::*;
53pub use ftab::*;
54pub use h264::*;
55pub use hevc::*;
56pub use jpeg::*;
57pub use mebx::*;
58pub use metadata::*;
59pub use mett::*;
60pub use metx::*;
61pub use mp3::*;
62pub use mp4a::*;
63pub use opus::*;
64pub use pasp::*;
65pub use pcm::*;
66pub use plaintext::*;
67pub use spatial::*;
68pub use st3d::*;
69pub use sv3d::*;
70pub use taic::*;
71pub use tx3g::*;
72pub use uncv::*;
73pub use urim::*;
74pub use vexu::*;
75pub use visual::*;
76pub use vp9::*;
77pub use wvtt::*;
78
79use crate::*;
80use derive_more::From;
81
82#[derive(Debug, Clone, PartialEq, Eq, Default)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
84pub struct Stsd {
85    pub codecs: Vec<Codec>,
86}
87
88/// Called a "sample entry" in the ISOBMFF specification.
89#[derive(Debug, Clone, PartialEq, Eq, From)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91#[non_exhaustive]
92pub enum Codec {
93    // H264
94    Avc1(Avc1),
95
96    // H264: SPS/PPS may also be inline
97    Avc3(Avc3),
98
99    // Photo - JPEG (QuickTime Motion JPEG)
100    Jpeg(Jpeg),
101
102    // HEVC: SPS/PPS/VPS is inline
103    Hev1(Hev1),
104
105    // HEVC: SPS/PPS/VPS is in a separate atom
106    Hvc1(Hvc1),
107
108    // VP8
109    Vp08(Vp08),
110
111    // VP9
112    Vp09(Vp09),
113
114    // AV1
115    Av01(Av01),
116
117    // AAC
118    Mp4a(Mp4a),
119
120    // MP3
121    Mp3(Mp3),
122
123    // Text
124    Tx3g(Tx3g),
125
126    // Opus
127    Opus(Opus),
128
129    // Uncompressed video
130    Uncv(Uncv),
131
132    // FLAC audio
133    Flac(Flac),
134
135    // AC-3 audio
136    Ac3(Ac3),
137
138    // EAC-3 audio
139    Eac3(Eac3),
140
141    // Uncompressed audio
142    // ipcm and fpcm are from 23003-5.
143    Ipcm(Ipcm),
144    Fpcm(Fpcm),
145    // sowt / twos and in24 / in32 / fl32 / fl64 / lpcm are Quicktime (QTFF-2001).
146    // s16l seems to be something that VLC produced at some point.
147    Sowt(Sowt),
148    Twos(Twos),
149    Lpcm(Lpcm),
150    In24(In24),
151    In32(In32),
152    Fl32(Fl32),
153    Fl64(Fl64),
154    S16l(S16l),
155
156    // WebVTT, ISO/IEC 14496-30
157    Wvtt(Wvtt),
158
159    // 3GPP Narrowband audio (3GPP TS 26.244 or ETSI TS 126 244)
160    Samr(Samr),
161
162    // Text-based timed metadata
163    Mett(Mett),
164
165    // XML-based timed metadata
166    Metx(Metx),
167
168    // URI-based timed metadata
169    Urim(Urim),
170
171    // Camera motion metadata (gyroscope/accelerometer), used by Google devices
172    Camm(Camm),
173
174    // CMAF/DASH Event Message track, carrying `Emsg` boxes as samples
175    // (ISO/IEC 23001-18).
176    Evte(Evte),
177
178    // Structured/"boxed" timed metadata, QuickTime "Metadata Media"
179    Mebx(Mebx),
180
181    // Unknown
182    Unknown(FourCC, Vec<u8>),
183}
184
185impl Codec {
186    /// A video track's sample entry fields (frame size, ...);
187    /// `None` for any other codec.
188    pub fn visual(&self) -> Option<&Visual> {
189        Some(match self {
190            Self::Avc1(avc1) => &avc1.visual,
191            Self::Avc3(avc3) => &avc3.visual,
192            Self::Jpeg(jpeg) => &jpeg.visual,
193            Self::Hev1(hev1) => &hev1.visual,
194            Self::Hvc1(hvc1) => &hvc1.visual,
195            Self::Vp08(vp08) => &vp08.visual,
196            Self::Vp09(vp09) => &vp09.visual,
197            Self::Av01(av01) => &av01.visual,
198            Self::Uncv(uncv) => &uncv.visual,
199            _ => return None,
200        })
201    }
202
203    /// An audio track's sample entry fields (sample rate, channel count, ...);
204    /// `None` for any other codec.
205    pub fn audio(&self) -> Option<&Audio> {
206        Some(match self {
207            Self::Mp4a(mp4a) => &mp4a.audio,
208            Self::Mp3(mp3) => &mp3.audio,
209            Self::Opus(opus) => &opus.audio,
210            Self::Flac(flac) => &flac.audio,
211            Self::Ac3(ac3) => &ac3.audio,
212            Self::Eac3(eac3) => &eac3.audio,
213            Self::Ipcm(pcm) => &pcm.audio,
214            Self::Fpcm(pcm) => &pcm.audio,
215            Self::Sowt(pcm) => &pcm.audio,
216            Self::Twos(pcm) => &pcm.audio,
217            Self::Lpcm(pcm) => &pcm.audio,
218            Self::In24(pcm) => &pcm.audio,
219            Self::In32(pcm) => &pcm.audio,
220            Self::Fl32(pcm) => &pcm.audio,
221            Self::Fl64(pcm) => &pcm.audio,
222            Self::S16l(pcm) => &pcm.audio,
223            _ => return None,
224        })
225    }
226
227    /// A timed metadata track's sample entry fields (data reference index);
228    /// `None` for any other codec.
229    pub fn metadata(&self) -> Option<&MetaData> {
230        Some(match self {
231            Self::Mett(mett) => &mett.metadata,
232            Self::Metx(metx) => &metx.metadata,
233            Self::Urim(urim) => &urim.metadata,
234            Self::Camm(camm) => &camm.metadata,
235            Self::Evte(evte) => &evte.metadata,
236            Self::Mebx(mebx) => &mebx.metadata,
237            _ => return None,
238        })
239    }
240}
241
242impl Decode for Codec {
243    fn decode<B: Buf>(buf: &mut B) -> Result<Self> {
244        let atom = Any::decode(buf)?;
245        Ok(match atom {
246            Any::Avc1(atom) => atom.into(),
247            Any::Avc3(atom) => atom.into(),
248            Any::Jpeg(atom) => atom.into(),
249            Any::Hev1(atom) => atom.into(),
250            Any::Hvc1(atom) => atom.into(),
251            Any::Vp08(atom) => atom.into(),
252            Any::Vp09(atom) => atom.into(),
253            Any::Mp4a(atom) => atom.into(),
254            Any::Mp3(atom) => atom.into(),
255            Any::Tx3g(atom) => atom.into(),
256            Any::Av01(atom) => atom.into(),
257            Any::Opus(atom) => atom.into(),
258            Any::Uncv(atom) => atom.into(),
259            Any::Flac(atom) => atom.into(),
260            Any::Ac3(atom) => atom.into(),
261            Any::Eac3(atom) => atom.into(),
262            Any::Ipcm(atom) => atom.into(),
263            Any::Fpcm(atom) => atom.into(),
264            Any::Sowt(atom) => atom.into(),
265            Any::Twos(atom) => atom.into(),
266            Any::Lpcm(atom) => atom.into(),
267            Any::In24(atom) => atom.into(),
268            Any::In32(atom) => atom.into(),
269            Any::Fl32(atom) => atom.into(),
270            Any::Fl64(atom) => atom.into(),
271            Any::S16l(atom) => atom.into(),
272            Any::Wvtt(atom) => atom.into(),
273            Any::Samr(atom) => atom.into(),
274            Any::Mett(atom) => atom.into(),
275            Any::Metx(atom) => atom.into(),
276            Any::Urim(atom) => atom.into(),
277            Any::Camm(atom) => atom.into(),
278            Any::Evte(atom) => atom.into(),
279            Any::Mebx(atom) => atom.into(),
280            Any::Unknown(four_cc, body) => Self::Unknown(four_cc, body),
281            unknown => {
282                crate::decode_unknown(&unknown, Stsd::KIND)?;
283
284                // The atom kind is known elsewhere in the hierarchy, but is not a supported
285                // sample entry. Re-encode its body so the unknown entry remains a valid box.
286                let kind = unknown.kind();
287                let mut encoded = Vec::new();
288                unknown.encode(&mut encoded)?;
289                Self::Unknown(kind, encoded.split_off(8))
290            }
291        })
292    }
293}
294
295impl Encode for Codec {
296    fn encode<B: BufMut>(&self, buf: &mut B) -> Result<()> {
297        match self {
298            Self::Unknown(..) => Err(Error::UnknownCodec),
299            Self::Avc1(atom) => atom.encode(buf),
300            Self::Avc3(atom) => atom.encode(buf),
301            Self::Jpeg(atom) => atom.encode(buf),
302            Self::Hev1(atom) => atom.encode(buf),
303            Self::Hvc1(atom) => atom.encode(buf),
304            Self::Vp08(atom) => atom.encode(buf),
305            Self::Vp09(atom) => atom.encode(buf),
306            Self::Mp4a(atom) => atom.encode(buf),
307            Self::Mp3(atom) => atom.encode(buf),
308            Self::Tx3g(atom) => atom.encode(buf),
309            Self::Av01(atom) => atom.encode(buf),
310            Self::Opus(atom) => atom.encode(buf),
311            Self::Uncv(atom) => atom.encode(buf),
312            Self::Flac(atom) => atom.encode(buf),
313            Self::Ac3(atom) => atom.encode(buf),
314            Self::Eac3(atom) => atom.encode(buf),
315            Self::Ipcm(atom) => atom.encode(buf),
316            Self::Fpcm(atom) => atom.encode(buf),
317            Self::Sowt(atom) => atom.encode(buf),
318            Self::Twos(atom) => atom.encode(buf),
319            Self::Lpcm(atom) => atom.encode(buf),
320            Self::In24(atom) => atom.encode(buf),
321            Self::In32(atom) => atom.encode(buf),
322            Self::Fl32(atom) => atom.encode(buf),
323            Self::Fl64(atom) => atom.encode(buf),
324            Self::S16l(atom) => atom.encode(buf),
325            Self::Wvtt(atom) => atom.encode(buf),
326            Self::Samr(atom) => atom.encode(buf),
327            Self::Mett(atom) => atom.encode(buf),
328            Self::Metx(atom) => atom.encode(buf),
329            Self::Urim(atom) => atom.encode(buf),
330            Self::Camm(atom) => atom.encode(buf),
331            Self::Evte(atom) => atom.encode(buf),
332            Self::Mebx(atom) => atom.encode(buf),
333        }
334    }
335}
336
337impl AtomExt for Stsd {
338    type Ext = ();
339
340    const KIND_EXT: FourCC = FourCC::new(b"stsd");
341
342    fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
343        let codec_count = u32::decode(buf)?;
344        let mut codecs = Vec::new();
345
346        for _ in 0..codec_count {
347            let codec = Codec::decode(buf)?;
348            codecs.push(codec);
349        }
350
351        Ok(Stsd { codecs })
352    }
353
354    fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
355        (self.codecs.len() as u32).encode(buf)?;
356        for codec in &self.codecs {
357            codec.encode(buf)?;
358        }
359
360        Ok(())
361    }
362}
363
364#[cfg(test)]
365mod tests {
366    use super::*;
367
368    #[test]
369    fn test_codec_visual() {
370        let visual = Visual {
371            width: 640,
372            height: 480,
373            ..Default::default()
374        };
375        let codec = Codec::from(Jpeg {
376            visual: visual.clone(),
377            ..Default::default()
378        });
379        assert_eq!(codec.visual(), Some(&visual));
380        assert_eq!(codec.audio(), None);
381        assert_eq!(codec.metadata(), None);
382    }
383
384    #[test]
385    fn test_codec_audio() {
386        let audio = Audio {
387            data_reference_index: 1,
388            channel_count: 2,
389            sample_size: 16,
390            sample_rate: 44100.into(),
391        };
392        let codec = Codec::from(Mp3 {
393            audio: audio.clone(),
394        });
395        assert_eq!(codec.audio(), Some(&audio));
396        assert_eq!(codec.visual(), None);
397    }
398
399    #[test]
400    fn test_codec_metadata() {
401        let metadata = MetaData {
402            data_reference_index: 3,
403        };
404        let codec = Codec::from(Camm {
405            metadata: metadata.clone(),
406        });
407        assert_eq!(codec.metadata(), Some(&metadata));
408        assert_eq!(codec.visual(), None);
409        assert_eq!(codec.audio(), None);
410    }
411
412    #[test]
413    fn test_codec_neither() {
414        for codec in [
415            Codec::from(Tx3g::default()),
416            Codec::Unknown(FourCC::new(b"dvh9"), vec![]),
417        ] {
418            assert_eq!(codec.visual(), None);
419            assert_eq!(codec.audio(), None);
420            assert_eq!(codec.metadata(), None);
421        }
422    }
423
424    #[cfg(not(feature = "strict"))]
425    mod not_strict {
426        use super::*;
427
428        #[test]
429        fn unknown_codec_parses() {
430            let input = b"\0\0\0\x1cstsd\0\0\0\0\0\0\0\x01\0\0\0\x0cdvh9\x01\x02\x03\x04";
431            let mut buf = input.as_slice();
432
433            let stsd = Stsd::decode(&mut buf).unwrap();
434            assert_eq!(
435                stsd.codecs,
436                vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])]
437            );
438        }
439
440        #[test]
441        fn unknown_codec_not_emitted() {
442            let stsd = Stsd {
443                codecs: vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])],
444            };
445            assert_eq!(
446                stsd.codecs,
447                vec![Codec::Unknown(FourCC::new(b"dvh9"), vec![1, 2, 3, 4])]
448            );
449            let mut output = Vec::new();
450            assert!(matches!(
451                stsd.encode(&mut output),
452                Err(crate::Error::UnknownCodec)
453            ));
454        }
455    }
456}