Skip to main content

mp4/
types.rs

1use serde::Serialize;
2use std::borrow::Cow;
3use std::convert::TryFrom;
4use std::fmt;
5
6use crate::mp4box::*;
7use crate::*;
8
9pub use bytes::Bytes;
10pub use num_rational::Ratio;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
13pub struct FixedPointU8(Ratio<u16>);
14
15impl FixedPointU8 {
16    pub fn new(val: u8) -> Self {
17        Self(Ratio::new_raw(val as u16 * 0x100, 0x100))
18    }
19
20    pub fn new_raw(val: u16) -> Self {
21        Self(Ratio::new_raw(val, 0x100))
22    }
23
24    pub fn value(&self) -> u8 {
25        self.0.to_integer() as u8
26    }
27
28    pub fn raw_value(&self) -> u16 {
29        *self.0.numer()
30    }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
34pub struct FixedPointI8(Ratio<i16>);
35
36impl FixedPointI8 {
37    pub fn new(val: i8) -> Self {
38        Self(Ratio::new_raw(val as i16 * 0x100, 0x100))
39    }
40
41    pub fn new_raw(val: i16) -> Self {
42        Self(Ratio::new_raw(val, 0x100))
43    }
44
45    pub fn value(&self) -> i8 {
46        self.0.to_integer() as i8
47    }
48
49    pub fn raw_value(&self) -> i16 {
50        *self.0.numer()
51    }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
55pub struct FixedPointU16(Ratio<u32>);
56
57impl FixedPointU16 {
58    pub fn new(val: u16) -> Self {
59        Self(Ratio::new_raw(val as u32 * 0x10000, 0x10000))
60    }
61
62    pub fn new_raw(val: u32) -> Self {
63        Self(Ratio::new_raw(val, 0x10000))
64    }
65
66    pub fn value(&self) -> u16 {
67        self.0.to_integer() as u16
68    }
69
70    pub fn raw_value(&self) -> u32 {
71        *self.0.numer()
72    }
73}
74
75impl fmt::Debug for BoxType {
76    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77        let fourcc: FourCC = From::from(*self);
78        write!(f, "{fourcc}")
79    }
80}
81
82impl fmt::Display for BoxType {
83    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84        let fourcc: FourCC = From::from(*self);
85        write!(f, "{fourcc}")
86    }
87}
88
89#[derive(Default, PartialEq, Eq, Clone, Copy, Serialize)]
90pub struct FourCC {
91    pub value: [u8; 4],
92}
93
94impl std::str::FromStr for FourCC {
95    type Err = Error;
96
97    fn from_str(s: &str) -> Result<Self> {
98        if let [a, b, c, d] = s.as_bytes() {
99            Ok(Self {
100                value: [*a, *b, *c, *d],
101            })
102        } else {
103            Err(Error::InvalidData("expected exactly four bytes in string"))
104        }
105    }
106}
107
108impl From<u32> for FourCC {
109    fn from(number: u32) -> Self {
110        FourCC {
111            value: number.to_be_bytes(),
112        }
113    }
114}
115
116impl From<FourCC> for u32 {
117    fn from(fourcc: FourCC) -> u32 {
118        (&fourcc).into()
119    }
120}
121
122impl From<&FourCC> for u32 {
123    fn from(fourcc: &FourCC) -> u32 {
124        u32::from_be_bytes(fourcc.value)
125    }
126}
127
128impl From<[u8; 4]> for FourCC {
129    fn from(value: [u8; 4]) -> FourCC {
130        FourCC { value }
131    }
132}
133
134impl From<BoxType> for FourCC {
135    fn from(t: BoxType) -> FourCC {
136        let box_num: u32 = Into::into(t);
137        From::from(box_num)
138    }
139}
140
141impl fmt::Debug for FourCC {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        let code: u32 = self.into();
144        let string = String::from_utf8_lossy(&self.value[..]);
145        write!(f, "{string} / {code:#010X}")
146    }
147}
148
149impl fmt::Display for FourCC {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        write!(f, "{}", String::from_utf8_lossy(&self.value[..]))
152    }
153}
154
155const DISPLAY_TYPE_VIDEO: &str = "Video";
156const DISPLAY_TYPE_AUDIO: &str = "Audio";
157const DISPLAY_TYPE_SUBTITLE: &str = "Subtitle";
158
159const HANDLER_TYPE_VIDEO: &str = "vide";
160const HANDLER_TYPE_VIDEO_FOURCC: [u8; 4] = [b'v', b'i', b'd', b'e'];
161
162const HANDLER_TYPE_AUDIO: &str = "soun";
163const HANDLER_TYPE_AUDIO_FOURCC: [u8; 4] = [b's', b'o', b'u', b'n'];
164
165const HANDLER_TYPE_SUBTITLE: &str = "sbtl";
166const HANDLER_TYPE_SUBTITLE_FOURCC: [u8; 4] = [b's', b'b', b't', b'l'];
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub enum TrackType {
170    Video,
171    Audio,
172    Subtitle,
173}
174
175impl fmt::Display for TrackType {
176    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
177        let s = match self {
178            TrackType::Video => DISPLAY_TYPE_VIDEO,
179            TrackType::Audio => DISPLAY_TYPE_AUDIO,
180            TrackType::Subtitle => DISPLAY_TYPE_SUBTITLE,
181        };
182        write!(f, "{s}")
183    }
184}
185
186impl TryFrom<&str> for TrackType {
187    type Error = Error;
188    fn try_from(handler: &str) -> Result<TrackType> {
189        match handler {
190            HANDLER_TYPE_VIDEO => Ok(TrackType::Video),
191            HANDLER_TYPE_AUDIO => Ok(TrackType::Audio),
192            HANDLER_TYPE_SUBTITLE => Ok(TrackType::Subtitle),
193            _ => Err(Error::InvalidData("unsupported handler type")),
194        }
195    }
196}
197
198impl TryFrom<&FourCC> for TrackType {
199    type Error = Error;
200    fn try_from(fourcc: &FourCC) -> Result<TrackType> {
201        match fourcc.value {
202            HANDLER_TYPE_VIDEO_FOURCC => Ok(TrackType::Video),
203            HANDLER_TYPE_AUDIO_FOURCC => Ok(TrackType::Audio),
204            HANDLER_TYPE_SUBTITLE_FOURCC => Ok(TrackType::Subtitle),
205            _ => Err(Error::InvalidData("unsupported handler type")),
206        }
207    }
208}
209
210impl From<TrackType> for FourCC {
211    fn from(t: TrackType) -> FourCC {
212        match t {
213            TrackType::Video => HANDLER_TYPE_VIDEO_FOURCC.into(),
214            TrackType::Audio => HANDLER_TYPE_AUDIO_FOURCC.into(),
215            TrackType::Subtitle => HANDLER_TYPE_SUBTITLE_FOURCC.into(),
216        }
217    }
218}
219
220const MEDIA_TYPE_H264: &str = "h264";
221const MEDIA_TYPE_H265: &str = "h265";
222const MEDIA_TYPE_VP9: &str = "vp9";
223const MEDIA_TYPE_AAC: &str = "aac";
224const MEDIA_TYPE_TTXT: &str = "ttxt";
225
226#[derive(Debug, Clone, Copy, PartialEq, Eq)]
227pub enum MediaType {
228    H264,
229    H265,
230    VP9,
231    AAC,
232    TTXT,
233}
234
235impl fmt::Display for MediaType {
236    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237        let s: &str = self.into();
238        write!(f, "{s}")
239    }
240}
241
242impl TryFrom<&str> for MediaType {
243    type Error = Error;
244    fn try_from(media: &str) -> Result<MediaType> {
245        match media {
246            MEDIA_TYPE_H264 => Ok(MediaType::H264),
247            MEDIA_TYPE_H265 => Ok(MediaType::H265),
248            MEDIA_TYPE_VP9 => Ok(MediaType::VP9),
249            MEDIA_TYPE_AAC => Ok(MediaType::AAC),
250            MEDIA_TYPE_TTXT => Ok(MediaType::TTXT),
251            _ => Err(Error::InvalidData("unsupported media type")),
252        }
253    }
254}
255
256impl From<MediaType> for &str {
257    fn from(t: MediaType) -> &'static str {
258        match t {
259            MediaType::H264 => MEDIA_TYPE_H264,
260            MediaType::H265 => MEDIA_TYPE_H265,
261            MediaType::VP9 => MEDIA_TYPE_VP9,
262            MediaType::AAC => MEDIA_TYPE_AAC,
263            MediaType::TTXT => MEDIA_TYPE_TTXT,
264        }
265    }
266}
267
268impl From<&MediaType> for &str {
269    fn from(t: &MediaType) -> &'static str {
270        match t {
271            MediaType::H264 => MEDIA_TYPE_H264,
272            MediaType::H265 => MEDIA_TYPE_H265,
273            MediaType::VP9 => MEDIA_TYPE_VP9,
274            MediaType::AAC => MEDIA_TYPE_AAC,
275            MediaType::TTXT => MEDIA_TYPE_TTXT,
276        }
277    }
278}
279
280#[derive(Debug, PartialEq, Eq, Clone, Copy)]
281pub enum AvcProfile {
282    AvcConstrainedBaseline, // 66 with constraint set 1
283    AvcBaseline,            // 66,
284    AvcMain,                // 77,
285    AvcExtended,            // 88,
286    AvcHigh,                // 100
287                            // TODO Progressive High Profile, Constrained High Profile, ...
288}
289
290impl TryFrom<(u8, u8)> for AvcProfile {
291    type Error = Error;
292    fn try_from(value: (u8, u8)) -> Result<AvcProfile> {
293        let profile = value.0;
294        let constraint_set1_flag = (value.1 & 0x40) >> 7;
295        match (profile, constraint_set1_flag) {
296            (66, 1) => Ok(AvcProfile::AvcConstrainedBaseline),
297            (66, 0) => Ok(AvcProfile::AvcBaseline),
298            (77, _) => Ok(AvcProfile::AvcMain),
299            (88, _) => Ok(AvcProfile::AvcExtended),
300            (100, _) => Ok(AvcProfile::AvcHigh),
301            _ => Err(Error::InvalidData("unsupported avc profile")),
302        }
303    }
304}
305
306impl fmt::Display for AvcProfile {
307    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308        let profile = match self {
309            AvcProfile::AvcConstrainedBaseline => "Constrained Baseline",
310            AvcProfile::AvcBaseline => "Baseline",
311            AvcProfile::AvcMain => "Main",
312            AvcProfile::AvcExtended => "Extended",
313            AvcProfile::AvcHigh => "High",
314        };
315        write!(f, "{profile}")
316    }
317}
318
319#[derive(Debug, PartialEq, Eq, Clone, Copy)]
320pub enum AudioObjectType {
321    AacMain = 1,                                       // AAC Main Profile
322    AacLowComplexity = 2,                              // AAC Low Complexity
323    AacScalableSampleRate = 3,                         // AAC Scalable Sample Rate
324    AacLongTermPrediction = 4,                         // AAC Long Term Predictor
325    SpectralBandReplication = 5,                       // Spectral band Replication
326    AACScalable = 6,                                   // AAC Scalable
327    TwinVQ = 7,                                        // Twin VQ
328    CodeExcitedLinearPrediction = 8,                   // CELP
329    HarmonicVectorExcitationCoding = 9,                // HVXC
330    TextToSpeechtInterface = 12,                       // TTSI
331    MainSynthetic = 13,                                // Main Synthetic
332    WavetableSynthesis = 14,                           // Wavetable Synthesis
333    GeneralMIDI = 15,                                  // General MIDI
334    AlgorithmicSynthesis = 16,                         // Algorithmic Synthesis
335    ErrorResilientAacLowComplexity = 17,               // ER AAC LC
336    ErrorResilientAacLongTermPrediction = 19,          // ER AAC LTP
337    ErrorResilientAacScalable = 20,                    // ER AAC Scalable
338    ErrorResilientAacTwinVQ = 21,                      // ER AAC TwinVQ
339    ErrorResilientAacBitSlicedArithmeticCoding = 22,   // ER Bit Sliced Arithmetic Coding
340    ErrorResilientAacLowDelay = 23,                    // ER AAC Low Delay
341    ErrorResilientCodeExcitedLinearPrediction = 24,    // ER CELP
342    ErrorResilientHarmonicVectorExcitationCoding = 25, // ER HVXC
343    ErrorResilientHarmonicIndividualLinesNoise = 26,   // ER HILN
344    ErrorResilientParametric = 27,                     // ER Parametric
345    SinuSoidalCoding = 28,                             // SSC
346    ParametricStereo = 29,                             // PS
347    MpegSurround = 30,                                 // MPEG Surround
348    MpegLayer1 = 32,                                   // MPEG Layer 1
349    MpegLayer2 = 33,                                   // MPEG Layer 2
350    MpegLayer3 = 34,                                   // MPEG Layer 3
351    DirectStreamTransfer = 35,                         // DST Direct Stream Transfer
352    AudioLosslessCoding = 36,                          // ALS Audio Lossless Coding
353    ScalableLosslessCoding = 37,                       // SLC Scalable Lossless Coding
354    ScalableLosslessCodingNoneCore = 38,               // SLC non-core
355    ErrorResilientAacEnhancedLowDelay = 39,            // ER AAC ELD
356    SymbolicMusicRepresentationSimple = 40,            // SMR Simple
357    SymbolicMusicRepresentationMain = 41,              // SMR Main
358    UnifiedSpeechAudioCoding = 42,                     // USAC
359    SpatialAudioObjectCoding = 43,                     // SAOC
360    LowDelayMpegSurround = 44,                         // LD MPEG Surround
361    SpatialAudioObjectCodingDialogueEnhancement = 45,  // SAOC-DE
362    AudioSync = 46,                                    // Audio Sync
363}
364
365impl TryFrom<u8> for AudioObjectType {
366    type Error = Error;
367    fn try_from(value: u8) -> Result<AudioObjectType> {
368        match value {
369            1 => Ok(AudioObjectType::AacMain),
370            2 => Ok(AudioObjectType::AacLowComplexity),
371            3 => Ok(AudioObjectType::AacScalableSampleRate),
372            4 => Ok(AudioObjectType::AacLongTermPrediction),
373            5 => Ok(AudioObjectType::SpectralBandReplication),
374            6 => Ok(AudioObjectType::AACScalable),
375            7 => Ok(AudioObjectType::TwinVQ),
376            8 => Ok(AudioObjectType::CodeExcitedLinearPrediction),
377            9 => Ok(AudioObjectType::HarmonicVectorExcitationCoding),
378            12 => Ok(AudioObjectType::TextToSpeechtInterface),
379            13 => Ok(AudioObjectType::MainSynthetic),
380            14 => Ok(AudioObjectType::WavetableSynthesis),
381            15 => Ok(AudioObjectType::GeneralMIDI),
382            16 => Ok(AudioObjectType::AlgorithmicSynthesis),
383            17 => Ok(AudioObjectType::ErrorResilientAacLowComplexity),
384            19 => Ok(AudioObjectType::ErrorResilientAacLongTermPrediction),
385            20 => Ok(AudioObjectType::ErrorResilientAacScalable),
386            21 => Ok(AudioObjectType::ErrorResilientAacTwinVQ),
387            22 => Ok(AudioObjectType::ErrorResilientAacBitSlicedArithmeticCoding),
388            23 => Ok(AudioObjectType::ErrorResilientAacLowDelay),
389            24 => Ok(AudioObjectType::ErrorResilientCodeExcitedLinearPrediction),
390            25 => Ok(AudioObjectType::ErrorResilientHarmonicVectorExcitationCoding),
391            26 => Ok(AudioObjectType::ErrorResilientHarmonicIndividualLinesNoise),
392            27 => Ok(AudioObjectType::ErrorResilientParametric),
393            28 => Ok(AudioObjectType::SinuSoidalCoding),
394            29 => Ok(AudioObjectType::ParametricStereo),
395            30 => Ok(AudioObjectType::MpegSurround),
396            32 => Ok(AudioObjectType::MpegLayer1),
397            33 => Ok(AudioObjectType::MpegLayer2),
398            34 => Ok(AudioObjectType::MpegLayer3),
399            35 => Ok(AudioObjectType::DirectStreamTransfer),
400            36 => Ok(AudioObjectType::AudioLosslessCoding),
401            37 => Ok(AudioObjectType::ScalableLosslessCoding),
402            38 => Ok(AudioObjectType::ScalableLosslessCodingNoneCore),
403            39 => Ok(AudioObjectType::ErrorResilientAacEnhancedLowDelay),
404            40 => Ok(AudioObjectType::SymbolicMusicRepresentationSimple),
405            41 => Ok(AudioObjectType::SymbolicMusicRepresentationMain),
406            42 => Ok(AudioObjectType::UnifiedSpeechAudioCoding),
407            43 => Ok(AudioObjectType::SpatialAudioObjectCoding),
408            44 => Ok(AudioObjectType::LowDelayMpegSurround),
409            45 => Ok(AudioObjectType::SpatialAudioObjectCodingDialogueEnhancement),
410            46 => Ok(AudioObjectType::AudioSync),
411            _ => Err(Error::InvalidData("invalid audio object type")),
412        }
413    }
414}
415
416impl fmt::Display for AudioObjectType {
417    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418        let type_str = match self {
419            AudioObjectType::AacMain => "AAC Main",
420            AudioObjectType::AacLowComplexity => "LC",
421            AudioObjectType::AacScalableSampleRate => "SSR",
422            AudioObjectType::AacLongTermPrediction => "LTP",
423            AudioObjectType::SpectralBandReplication => "SBR",
424            AudioObjectType::AACScalable => "Scalable",
425            AudioObjectType::TwinVQ => "TwinVQ",
426            AudioObjectType::CodeExcitedLinearPrediction => "CELP",
427            AudioObjectType::HarmonicVectorExcitationCoding => "HVXC",
428            AudioObjectType::TextToSpeechtInterface => "TTSI",
429            AudioObjectType::MainSynthetic => "Main Synthetic",
430            AudioObjectType::WavetableSynthesis => "Wavetable Synthesis",
431            AudioObjectType::GeneralMIDI => "General MIDI",
432            AudioObjectType::AlgorithmicSynthesis => "Algorithmic Synthesis",
433            AudioObjectType::ErrorResilientAacLowComplexity => "ER AAC LC",
434            AudioObjectType::ErrorResilientAacLongTermPrediction => "ER AAC LTP",
435            AudioObjectType::ErrorResilientAacScalable => "ER AAC scalable",
436            AudioObjectType::ErrorResilientAacTwinVQ => "ER AAC TwinVQ",
437            AudioObjectType::ErrorResilientAacBitSlicedArithmeticCoding => "ER AAC BSAC",
438            AudioObjectType::ErrorResilientAacLowDelay => "ER AAC LD",
439            AudioObjectType::ErrorResilientCodeExcitedLinearPrediction => "ER CELP",
440            AudioObjectType::ErrorResilientHarmonicVectorExcitationCoding => "ER HVXC",
441            AudioObjectType::ErrorResilientHarmonicIndividualLinesNoise => "ER HILN",
442            AudioObjectType::ErrorResilientParametric => "ER Parametric",
443            AudioObjectType::SinuSoidalCoding => "SSC",
444            AudioObjectType::ParametricStereo => "Parametric Stereo",
445            AudioObjectType::MpegSurround => "MPEG surround",
446            AudioObjectType::MpegLayer1 => "MPEG Layer 1",
447            AudioObjectType::MpegLayer2 => "MPEG Layer 2",
448            AudioObjectType::MpegLayer3 => "MPEG Layer 3",
449            AudioObjectType::DirectStreamTransfer => "DST",
450            AudioObjectType::AudioLosslessCoding => "ALS",
451            AudioObjectType::ScalableLosslessCoding => "SLS",
452            AudioObjectType::ScalableLosslessCodingNoneCore => "SLS Non-core",
453            AudioObjectType::ErrorResilientAacEnhancedLowDelay => "ER AAC ELD",
454            AudioObjectType::SymbolicMusicRepresentationSimple => "SMR Simple",
455            AudioObjectType::SymbolicMusicRepresentationMain => "SMR Main",
456            AudioObjectType::UnifiedSpeechAudioCoding => "USAC",
457            AudioObjectType::SpatialAudioObjectCoding => "SAOC",
458            AudioObjectType::LowDelayMpegSurround => "LD MPEG Surround",
459            AudioObjectType::SpatialAudioObjectCodingDialogueEnhancement => "SAOC-DE",
460            AudioObjectType::AudioSync => "Audio Sync",
461        };
462        write!(f, "{type_str}")
463    }
464}
465
466#[derive(Debug, PartialEq, Eq, Clone, Copy)]
467pub enum SampleFreqIndex {
468    Freq96000 = 0x0,
469    Freq88200 = 0x1,
470    Freq64000 = 0x2,
471    Freq48000 = 0x3,
472    Freq44100 = 0x4,
473    Freq32000 = 0x5,
474    Freq24000 = 0x6,
475    Freq22050 = 0x7,
476    Freq16000 = 0x8,
477    Freq12000 = 0x9,
478    Freq11025 = 0xa,
479    Freq8000 = 0xb,
480    Freq7350 = 0xc,
481}
482
483impl TryFrom<u8> for SampleFreqIndex {
484    type Error = Error;
485    fn try_from(value: u8) -> Result<SampleFreqIndex> {
486        match value {
487            0x0 => Ok(SampleFreqIndex::Freq96000),
488            0x1 => Ok(SampleFreqIndex::Freq88200),
489            0x2 => Ok(SampleFreqIndex::Freq64000),
490            0x3 => Ok(SampleFreqIndex::Freq48000),
491            0x4 => Ok(SampleFreqIndex::Freq44100),
492            0x5 => Ok(SampleFreqIndex::Freq32000),
493            0x6 => Ok(SampleFreqIndex::Freq24000),
494            0x7 => Ok(SampleFreqIndex::Freq22050),
495            0x8 => Ok(SampleFreqIndex::Freq16000),
496            0x9 => Ok(SampleFreqIndex::Freq12000),
497            0xa => Ok(SampleFreqIndex::Freq11025),
498            0xb => Ok(SampleFreqIndex::Freq8000),
499            0xc => Ok(SampleFreqIndex::Freq7350),
500            _ => Err(Error::InvalidData("invalid sampling frequency index")),
501        }
502    }
503}
504
505impl SampleFreqIndex {
506    pub fn freq(&self) -> u32 {
507        match *self {
508            SampleFreqIndex::Freq96000 => 96000,
509            SampleFreqIndex::Freq88200 => 88200,
510            SampleFreqIndex::Freq64000 => 64000,
511            SampleFreqIndex::Freq48000 => 48000,
512            SampleFreqIndex::Freq44100 => 44100,
513            SampleFreqIndex::Freq32000 => 32000,
514            SampleFreqIndex::Freq24000 => 24000,
515            SampleFreqIndex::Freq22050 => 22050,
516            SampleFreqIndex::Freq16000 => 16000,
517            SampleFreqIndex::Freq12000 => 12000,
518            SampleFreqIndex::Freq11025 => 11025,
519            SampleFreqIndex::Freq8000 => 8000,
520            SampleFreqIndex::Freq7350 => 7350,
521        }
522    }
523}
524
525#[derive(Debug, PartialEq, Eq, Clone, Copy)]
526pub enum ChannelConfig {
527    Mono = 0x1,
528    Stereo = 0x2,
529    Three = 0x3,
530    Four = 0x4,
531    Five = 0x5,
532    FiveOne = 0x6,
533    SevenOne = 0x7,
534}
535
536impl TryFrom<u8> for ChannelConfig {
537    type Error = Error;
538    fn try_from(value: u8) -> Result<ChannelConfig> {
539        match value {
540            0x1 => Ok(ChannelConfig::Mono),
541            0x2 => Ok(ChannelConfig::Stereo),
542            0x3 => Ok(ChannelConfig::Three),
543            0x4 => Ok(ChannelConfig::Four),
544            0x5 => Ok(ChannelConfig::Five),
545            0x6 => Ok(ChannelConfig::FiveOne),
546            0x7 => Ok(ChannelConfig::SevenOne),
547            _ => Err(Error::InvalidData("invalid channel configuration")),
548        }
549    }
550}
551
552impl fmt::Display for ChannelConfig {
553    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554        let s = match self {
555            ChannelConfig::Mono => "mono",
556            ChannelConfig::Stereo => "stereo",
557            ChannelConfig::Three => "three",
558            ChannelConfig::Four => "four",
559            ChannelConfig::Five => "five",
560            ChannelConfig::FiveOne => "five.one",
561            ChannelConfig::SevenOne => "seven.one",
562        };
563        write!(f, "{s}")
564    }
565}
566
567#[derive(Debug, PartialEq, Eq, Clone, Default)]
568pub struct AvcConfig {
569    pub width: u16,
570    pub height: u16,
571    pub seq_param_set: Vec<u8>,
572    pub pic_param_set: Vec<u8>,
573}
574
575#[derive(Debug, PartialEq, Eq, Clone, Default)]
576pub struct HevcConfig {
577    pub width: u16,
578    pub height: u16,
579}
580
581#[derive(Debug, PartialEq, Eq, Clone, Default)]
582pub struct Vp9Config {
583    pub width: u16,
584    pub height: u16,
585}
586
587#[derive(Debug, PartialEq, Eq, Clone)]
588pub struct AacConfig {
589    pub bitrate: u32,
590    pub profile: AudioObjectType,
591    pub freq_index: SampleFreqIndex,
592    pub chan_conf: ChannelConfig,
593}
594
595impl Default for AacConfig {
596    fn default() -> Self {
597        Self {
598            bitrate: 0,
599            profile: AudioObjectType::AacLowComplexity,
600            freq_index: SampleFreqIndex::Freq48000,
601            chan_conf: ChannelConfig::Stereo,
602        }
603    }
604}
605
606#[derive(Debug, PartialEq, Eq, Clone, Default)]
607pub struct TtxtConfig {}
608
609#[derive(Debug, PartialEq, Eq, Clone)]
610pub enum MediaConfig {
611    AvcConfig(AvcConfig),
612    HevcConfig(HevcConfig),
613    Vp9Config(Vp9Config),
614    AacConfig(AacConfig),
615    TtxtConfig(TtxtConfig),
616}
617
618#[derive(Debug)]
619pub struct Mp4Sample {
620    pub start_time: u64,
621    pub duration: u32,
622    pub rendering_offset: i32,
623    pub is_sync: bool,
624    pub bytes: Bytes,
625}
626
627impl PartialEq for Mp4Sample {
628    fn eq(&self, other: &Self) -> bool {
629        self.start_time == other.start_time
630            && self.duration == other.duration
631            && self.rendering_offset == other.rendering_offset
632            && self.is_sync == other.is_sync
633            && self.bytes.len() == other.bytes.len() // XXX for easy check
634    }
635}
636
637impl fmt::Display for Mp4Sample {
638    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
639        write!(
640            f,
641            "start_time {}, duration {}, rendering_offset {}, is_sync {}, length {}",
642            self.start_time,
643            self.duration,
644            self.rendering_offset,
645            self.is_sync,
646            self.bytes.len()
647        )
648    }
649}
650
651pub fn creation_time(creation_time: u64) -> u64 {
652    // convert from MP4 epoch (1904-01-01) to Unix epoch (1970-01-01)
653    if creation_time >= 2082844800 {
654        creation_time - 2082844800
655    } else {
656        creation_time
657    }
658}
659
660#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
661pub enum DataType {
662    Binary = 0x000000,
663    Text = 0x000001,
664    Image = 0x00000D,
665    TempoCpil = 0x000015,
666}
667
668#[allow(clippy::derivable_impls)]
669impl std::default::Default for DataType {
670    fn default() -> Self {
671        DataType::Binary
672    }
673}
674
675impl TryFrom<u32> for DataType {
676    type Error = Error;
677    fn try_from(value: u32) -> Result<DataType> {
678        match value {
679            0x000000 => Ok(DataType::Binary),
680            0x000001 => Ok(DataType::Text),
681            0x00000D => Ok(DataType::Image),
682            0x000015 => Ok(DataType::TempoCpil),
683            _ => Err(Error::InvalidData("invalid data type")),
684        }
685    }
686}
687
688#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
689pub enum MetadataKey {
690    Title,
691    Year,
692    Poster,
693    Summary,
694}
695
696pub trait Metadata<'a> {
697    /// The video's title
698    fn title(&self) -> Option<Cow<str>>;
699    /// The video's release year
700    fn year(&self) -> Option<u32>;
701    /// The video's poster (cover art)
702    fn poster(&self) -> Option<&[u8]>;
703    /// The video's summary
704    fn summary(&self) -> Option<Cow<str>>;
705}
706
707impl<'a, T: Metadata<'a>> Metadata<'a> for &'a T {
708    fn title(&self) -> Option<Cow<str>> {
709        (**self).title()
710    }
711
712    fn year(&self) -> Option<u32> {
713        (**self).year()
714    }
715
716    fn poster(&self) -> Option<&[u8]> {
717        (**self).poster()
718    }
719
720    fn summary(&self) -> Option<Cow<str>> {
721        (**self).summary()
722    }
723}
724
725impl<'a, T: Metadata<'a>> Metadata<'a> for Option<T> {
726    fn title(&self) -> Option<Cow<str>> {
727        self.as_ref().and_then(|t| t.title())
728    }
729
730    fn year(&self) -> Option<u32> {
731        self.as_ref().and_then(|t| t.year())
732    }
733
734    fn poster(&self) -> Option<&[u8]> {
735        self.as_ref().and_then(|t| t.poster())
736    }
737
738    fn summary(&self) -> Option<Cow<str>> {
739        self.as_ref().and_then(|t| t.summary())
740    }
741}