Skip to main content

oximedia_container/
format.rs

1//! Container format definitions.
2
3/// Supported container formats (patent-free).
4///
5/// `OxiMedia` focuses on patent-free, royalty-free container formats.
6/// The `Mp4` variant is supported only for AV1/VP9 content.
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
8pub enum ContainerFormat {
9    /// Matroska container (.mkv).
10    ///
11    /// Full-featured container supporting multiple audio/video/subtitle tracks,
12    /// chapters, attachments, and rich metadata.
13    Matroska,
14
15    /// `WebM` container (.webm).
16    ///
17    /// Matroska subset optimized for web delivery, supporting VP8/VP9/AV1 video
18    /// and Vorbis/Opus audio.
19    WebM,
20
21    /// ISOBMFF/MP4 container (.mp4, .m4a, .m4v).
22    ///
23    /// Only supported for AV1 and VP9 content to maintain patent-free status.
24    Mp4,
25
26    /// Ogg container (.ogg, .opus, .oga).
27    ///
28    /// Xiph.org container format, commonly used for Vorbis and Opus audio,
29    /// as well as Theora video.
30    Ogg,
31
32    /// WAV/RIFF container (.wav).
33    ///
34    /// Simple audio container for PCM and other uncompressed audio formats.
35    Wav,
36
37    /// FLAC native container (.flac).
38    ///
39    /// Native container for FLAC lossless audio, supporting metadata and seek tables.
40    Flac,
41
42    /// MPEG Transport Stream (.ts, .m2ts, .mts).
43    ///
44    /// Transport stream format commonly used for broadcast and streaming.
45    /// Supports multiplexed video, audio, and subtitle streams with
46    /// precise timing via Program Clock Reference (PCR).
47    /// Only patent-free codecs (AV1, VP9, VP8, Opus, FLAC) are supported.
48    MpegTs,
49
50    /// `WebVTT` subtitle format (.vtt).
51    ///
52    /// Text-based subtitle format commonly used for web video.
53    WebVtt,
54
55    /// `SubRip` subtitle format (.srt).
56    ///
57    /// Simple text-based subtitle format widely supported.
58    Srt,
59
60    /// YUV4MPEG2 container (.y4m).
61    ///
62    /// Simple uncompressed video sequence format widely used for testing
63    /// and piping raw YUV video between tools. Supports various chroma
64    /// subsampling modes (420, 422, 444, mono).
65    Y4m,
66}
67
68impl ContainerFormat {
69    /// Returns the common file extensions for this container format.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use oximedia_container::ContainerFormat;
75    ///
76    /// let exts = ContainerFormat::Matroska.file_extensions();
77    /// assert!(exts.contains(&"mkv"));
78    /// assert!(exts.contains(&"mka"));
79    /// ```
80    #[must_use]
81    pub const fn file_extensions(self) -> &'static [&'static str] {
82        match self {
83            Self::Matroska => &["mkv", "mka", "mks", "mk3d"],
84            Self::WebM => &["webm"],
85            Self::Mp4 => &["mp4", "m4a", "m4v", "mov"],
86            Self::Ogg => &["ogg", "opus", "oga", "ogv", "ogx", "spx"],
87            Self::Wav => &["wav", "wave"],
88            Self::Flac => &["flac"],
89            Self::MpegTs => &["ts", "m2ts", "mts"],
90            Self::WebVtt => &["vtt", "webvtt"],
91            Self::Srt => &["srt"],
92            Self::Y4m => &["y4m", "yuv4mpeg"],
93        }
94    }
95
96    /// Returns the primary MIME type for this container format.
97    ///
98    /// # Examples
99    ///
100    /// ```
101    /// use oximedia_container::ContainerFormat;
102    ///
103    /// assert_eq!(ContainerFormat::WebM.mime_type(), "video/webm");
104    /// assert_eq!(ContainerFormat::Ogg.mime_type(), "audio/ogg");
105    /// ```
106    #[must_use]
107    pub const fn mime_type(self) -> &'static str {
108        match self {
109            Self::Matroska => "video/x-matroska",
110            Self::WebM => "video/webm",
111            Self::Mp4 => "video/mp4",
112            Self::Ogg => "audio/ogg",
113            Self::Wav => "audio/wav",
114            Self::Flac => "audio/flac",
115            Self::MpegTs => "video/mp2t",
116            Self::WebVtt => "text/vtt",
117            Self::Srt => "application/x-subrip",
118            Self::Y4m => "video/x-raw-yuv4mpeg2",
119        }
120    }
121
122    /// Returns the format name as a human-readable string.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use oximedia_container::ContainerFormat;
128    ///
129    /// assert_eq!(ContainerFormat::Matroska.name(), "Matroska");
130    /// assert_eq!(ContainerFormat::WebM.name(), "WebM");
131    /// ```
132    #[must_use]
133    pub const fn name(self) -> &'static str {
134        match self {
135            Self::Matroska => "Matroska",
136            Self::WebM => "WebM",
137            Self::Mp4 => "MP4/ISOBMFF",
138            Self::Ogg => "Ogg",
139            Self::Wav => "WAV/RIFF",
140            Self::Flac => "FLAC",
141            Self::MpegTs => "MPEG-TS",
142            Self::WebVtt => "WebVTT",
143            Self::Srt => "SubRip",
144            Self::Y4m => "YUV4MPEG2",
145        }
146    }
147
148    /// Returns true if this format supports video streams.
149    ///
150    /// # Examples
151    ///
152    /// ```
153    /// use oximedia_container::ContainerFormat;
154    ///
155    /// assert!(ContainerFormat::Matroska.supports_video());
156    /// assert!(!ContainerFormat::Flac.supports_video());
157    /// ```
158    #[must_use]
159    pub const fn supports_video(self) -> bool {
160        match self {
161            Self::Matroska | Self::WebM | Self::Mp4 | Self::Ogg | Self::MpegTs | Self::Y4m => true,
162            Self::Wav | Self::Flac | Self::WebVtt | Self::Srt => false,
163        }
164    }
165
166    /// Returns true if this format supports audio streams.
167    #[must_use]
168    pub const fn supports_audio(self) -> bool {
169        match self {
170            Self::Matroska
171            | Self::WebM
172            | Self::Mp4
173            | Self::Ogg
174            | Self::Wav
175            | Self::Flac
176            | Self::MpegTs => true,
177            Self::WebVtt | Self::Srt | Self::Y4m => false,
178        }
179    }
180
181    /// Returns true if this format supports subtitle streams.
182    #[must_use]
183    pub const fn supports_subtitles(self) -> bool {
184        match self {
185            Self::Matroska | Self::WebM | Self::Mp4 | Self::MpegTs | Self::WebVtt | Self::Srt => {
186                true
187            }
188            Self::Ogg | Self::Wav | Self::Flac | Self::Y4m => false,
189        }
190    }
191}
192
193impl std::fmt::Display for ContainerFormat {
194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195        write!(f, "{}", self.name())
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202
203    #[test]
204    fn test_file_extensions() {
205        assert!(ContainerFormat::Matroska.file_extensions().contains(&"mkv"));
206        assert!(ContainerFormat::WebM.file_extensions().contains(&"webm"));
207        assert!(ContainerFormat::Ogg.file_extensions().contains(&"opus"));
208    }
209
210    #[test]
211    fn test_mime_types() {
212        assert_eq!(ContainerFormat::Matroska.mime_type(), "video/x-matroska");
213        assert_eq!(ContainerFormat::WebM.mime_type(), "video/webm");
214        assert_eq!(ContainerFormat::Flac.mime_type(), "audio/flac");
215    }
216
217    #[test]
218    fn test_supports_video() {
219        assert!(ContainerFormat::Matroska.supports_video());
220        assert!(ContainerFormat::WebM.supports_video());
221        assert!(!ContainerFormat::Wav.supports_video());
222        assert!(!ContainerFormat::Flac.supports_video());
223    }
224
225    #[test]
226    fn test_display() {
227        assert_eq!(format!("{}", ContainerFormat::Matroska), "Matroska");
228        assert_eq!(format!("{}", ContainerFormat::WebM), "WebM");
229    }
230}