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}