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