Skip to main content

ff_encode/shared/
container.rs

1//! Container format definitions.
2
3/// Output container format for encoding.
4///
5/// The container format is usually auto-detected from the file extension,
6/// but can be explicitly specified if needed.
7///
8/// Named `OutputContainer` (rather than `Container`) to avoid confusion with
9/// `ff_format::ContainerInfo`, which describes a container *read* from a probed file.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[non_exhaustive]
12pub enum OutputContainer {
13    /// MP4 / `QuickTime`
14    Mp4,
15
16    /// Fragmented MP4 — CMAF-compatible streaming container.
17    ///
18    /// Uses the same `mp4` `FFmpeg` muxer as [`OutputContainer::Mp4`] but with
19    /// `movflags=+frag_keyframe+empty_moov+default_base_moof` applied before
20    /// writing the header. Required for HTTP Live Streaming fMP4 segments
21    /// (CMAF) and MPEG-DASH.
22    FMp4,
23
24    /// `WebM`
25    WebM,
26
27    /// Matroska
28    Mkv,
29
30    /// AVI
31    Avi,
32
33    /// MOV
34    Mov,
35
36    /// FLAC (lossless audio container)
37    Flac,
38
39    /// OGG (audio container for Vorbis/Opus)
40    Ogg,
41}
42
43impl OutputContainer {
44    /// Get `FFmpeg` format name.
45    #[must_use]
46    pub const fn as_str(self) -> &'static str {
47        match self {
48            Self::Mp4 | Self::FMp4 => "mp4",
49            Self::WebM => "webm",
50            Self::Mkv => "matroska",
51            Self::Avi => "avi",
52            Self::Mov => "mov",
53            Self::Flac => "flac",
54            Self::Ogg => "ogg",
55        }
56    }
57
58    /// Get default file extension.
59    #[must_use]
60    pub const fn default_extension(self) -> &'static str {
61        match self {
62            Self::Mp4 | Self::FMp4 => "mp4",
63            Self::WebM => "webm",
64            Self::Mkv => "mkv",
65            Self::Avi => "avi",
66            Self::Mov => "mov",
67            Self::Flac => "flac",
68            Self::Ogg => "ogg",
69        }
70    }
71
72    /// Returns `true` if this container is fragmented MP4.
73    ///
74    /// When `true`, the encoder applies
75    /// `movflags=+frag_keyframe+empty_moov+default_base_moof` before writing
76    /// the file header, enabling CMAF-compatible streaming output.
77    #[must_use]
78    pub const fn is_fragmented(self) -> bool {
79        matches!(self, Self::FMp4)
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_container_as_str() {
89        assert_eq!(OutputContainer::Mp4.as_str(), "mp4");
90        assert_eq!(OutputContainer::WebM.as_str(), "webm");
91        assert_eq!(OutputContainer::Mkv.as_str(), "matroska");
92    }
93
94    #[test]
95    fn test_container_extension() {
96        assert_eq!(OutputContainer::Mp4.default_extension(), "mp4");
97        assert_eq!(OutputContainer::WebM.default_extension(), "webm");
98        assert_eq!(OutputContainer::Mkv.default_extension(), "mkv");
99        assert_eq!(OutputContainer::Flac.default_extension(), "flac");
100        assert_eq!(OutputContainer::Ogg.default_extension(), "ogg");
101    }
102
103    #[test]
104    fn flac_as_str_should_return_flac() {
105        assert_eq!(OutputContainer::Flac.as_str(), "flac");
106    }
107
108    #[test]
109    fn ogg_as_str_should_return_ogg() {
110        assert_eq!(OutputContainer::Ogg.as_str(), "ogg");
111    }
112
113    #[test]
114    fn fmp4_as_str_should_return_mp4() {
115        assert_eq!(OutputContainer::FMp4.as_str(), "mp4");
116    }
117
118    #[test]
119    fn fmp4_extension_should_return_mp4() {
120        assert_eq!(OutputContainer::FMp4.default_extension(), "mp4");
121    }
122
123    #[test]
124    fn fmp4_is_fragmented_should_return_true() {
125        assert!(OutputContainer::FMp4.is_fragmented());
126        assert!(!OutputContainer::Mp4.is_fragmented());
127        assert!(!OutputContainer::Mkv.is_fragmented());
128    }
129}