Skip to main content

oximedia_transcode/
presets.rs

1//! Industry-standard presets for common transcoding scenarios.
2
3pub mod archive;
4pub mod broadcast;
5pub mod streaming;
6pub mod vimeo;
7pub mod youtube;
8
9use crate::{PresetConfig, QualityMode};
10
11/// Common preset categories.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum PresetCategory {
14    /// `YouTube` presets.
15    YouTube,
16    /// Vimeo presets.
17    Vimeo,
18    /// Broadcast/professional presets.
19    Broadcast,
20    /// Streaming (HLS/DASH) presets.
21    Streaming,
22    /// Archive/preservation presets.
23    Archive,
24    /// Social media presets.
25    SocialMedia,
26}
27
28/// Creates a basic H.264/AAC preset with specified resolution.
29#[must_use]
30pub fn h264_aac(width: u32, height: u32, video_bitrate: u64, audio_bitrate: u64) -> PresetConfig {
31    PresetConfig {
32        video_codec: Some("h264".to_string()),
33        audio_codec: Some("aac".to_string()),
34        video_bitrate: Some(video_bitrate),
35        audio_bitrate: Some(audio_bitrate),
36        width: Some(width),
37        height: Some(height),
38        frame_rate: Some((30, 1)),
39        quality_mode: Some(QualityMode::Medium),
40        container: Some("mp4".to_string()),
41        audio_channel_layout: None,
42    }
43}
44
45/// Creates a basic VP9/Opus preset with specified resolution.
46#[must_use]
47pub fn vp9_opus(width: u32, height: u32, video_bitrate: u64, audio_bitrate: u64) -> PresetConfig {
48    PresetConfig {
49        video_codec: Some("vp9".to_string()),
50        audio_codec: Some("opus".to_string()),
51        video_bitrate: Some(video_bitrate),
52        audio_bitrate: Some(audio_bitrate),
53        width: Some(width),
54        height: Some(height),
55        frame_rate: Some((30, 1)),
56        quality_mode: Some(QualityMode::Medium),
57        container: Some("webm".to_string()),
58        audio_channel_layout: None,
59    }
60}
61
62/// Creates a basic AV1/Opus preset with specified resolution.
63#[must_use]
64pub fn av1_opus(width: u32, height: u32, video_bitrate: u64, audio_bitrate: u64) -> PresetConfig {
65    PresetConfig {
66        video_codec: Some("av1".to_string()),
67        audio_codec: Some("opus".to_string()),
68        video_bitrate: Some(video_bitrate),
69        audio_bitrate: Some(audio_bitrate),
70        width: Some(width),
71        height: Some(height),
72        frame_rate: Some((30, 1)),
73        quality_mode: Some(QualityMode::High),
74        container: Some("mp4".to_string()),
75        audio_channel_layout: None,
76    }
77}
78
79/// Social media presets for Instagram, `TikTok`, Twitter, etc.
80pub mod social {
81    use super::{PresetConfig, QualityMode};
82
83    /// Instagram feed (1080x1080, square).
84    #[must_use]
85    pub fn instagram_feed() -> PresetConfig {
86        PresetConfig {
87            video_codec: Some("h264".to_string()),
88            audio_codec: Some("aac".to_string()),
89            video_bitrate: Some(3_500_000),
90            audio_bitrate: Some(128_000),
91            width: Some(1080),
92            height: Some(1080),
93            frame_rate: Some((30, 1)),
94            quality_mode: Some(QualityMode::High),
95            container: Some("mp4".to_string()),
96            audio_channel_layout: None,
97        }
98    }
99
100    /// Instagram stories (1080x1920, vertical).
101    #[must_use]
102    pub fn instagram_stories() -> PresetConfig {
103        PresetConfig {
104            video_codec: Some("h264".to_string()),
105            audio_codec: Some("aac".to_string()),
106            video_bitrate: Some(3_500_000),
107            audio_bitrate: Some(128_000),
108            width: Some(1080),
109            height: Some(1920),
110            frame_rate: Some((30, 1)),
111            quality_mode: Some(QualityMode::High),
112            container: Some("mp4".to_string()),
113            audio_channel_layout: None,
114        }
115    }
116
117    /// `TikTok` (1080x1920, vertical).
118    #[must_use]
119    pub fn tiktok() -> PresetConfig {
120        PresetConfig {
121            video_codec: Some("h264".to_string()),
122            audio_codec: Some("aac".to_string()),
123            video_bitrate: Some(4_000_000),
124            audio_bitrate: Some(128_000),
125            width: Some(1080),
126            height: Some(1920),
127            frame_rate: Some((30, 1)),
128            quality_mode: Some(QualityMode::High),
129            container: Some("mp4".to_string()),
130            audio_channel_layout: None,
131        }
132    }
133
134    /// Twitter (1280x720, landscape).
135    #[must_use]
136    pub fn twitter() -> PresetConfig {
137        PresetConfig {
138            video_codec: Some("h264".to_string()),
139            audio_codec: Some("aac".to_string()),
140            video_bitrate: Some(5_000_000),
141            audio_bitrate: Some(128_000),
142            width: Some(1280),
143            height: Some(720),
144            frame_rate: Some((30, 1)),
145            quality_mode: Some(QualityMode::High),
146            container: Some("mp4".to_string()),
147            audio_channel_layout: None,
148        }
149    }
150
151    /// Facebook (1280x720, landscape).
152    #[must_use]
153    pub fn facebook() -> PresetConfig {
154        PresetConfig {
155            video_codec: Some("h264".to_string()),
156            audio_codec: Some("aac".to_string()),
157            video_bitrate: Some(4_000_000),
158            audio_bitrate: Some(128_000),
159            width: Some(1280),
160            height: Some(720),
161            frame_rate: Some((30, 1)),
162            quality_mode: Some(QualityMode::High),
163            container: Some("mp4".to_string()),
164            audio_channel_layout: None,
165        }
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn test_h264_aac_preset() {
175        let preset = h264_aac(1920, 1080, 5_000_000, 192_000);
176        assert_eq!(preset.video_codec, Some("h264".to_string()));
177        assert_eq!(preset.audio_codec, Some("aac".to_string()));
178        assert_eq!(preset.width, Some(1920));
179        assert_eq!(preset.height, Some(1080));
180        assert_eq!(preset.video_bitrate, Some(5_000_000));
181        assert_eq!(preset.audio_bitrate, Some(192_000));
182    }
183
184    #[test]
185    fn test_vp9_opus_preset() {
186        let preset = vp9_opus(1280, 720, 2_500_000, 128_000);
187        assert_eq!(preset.video_codec, Some("vp9".to_string()));
188        assert_eq!(preset.audio_codec, Some("opus".to_string()));
189        assert_eq!(preset.container, Some("webm".to_string()));
190    }
191
192    #[test]
193    fn test_av1_opus_preset() {
194        let preset = av1_opus(1920, 1080, 4_000_000, 128_000);
195        assert_eq!(preset.video_codec, Some("av1".to_string()));
196        assert_eq!(preset.audio_codec, Some("opus".to_string()));
197        assert_eq!(preset.quality_mode, Some(QualityMode::High));
198    }
199
200    #[test]
201    fn test_social_instagram_feed() {
202        let preset = social::instagram_feed();
203        assert_eq!(preset.width, Some(1080));
204        assert_eq!(preset.height, Some(1080)); // Square
205        assert_eq!(preset.video_codec, Some("h264".to_string()));
206    }
207
208    #[test]
209    fn test_social_instagram_stories() {
210        let preset = social::instagram_stories();
211        assert_eq!(preset.width, Some(1080));
212        assert_eq!(preset.height, Some(1920)); // Vertical
213    }
214
215    #[test]
216    fn test_social_tiktok() {
217        let preset = social::tiktok();
218        assert_eq!(preset.width, Some(1080));
219        assert_eq!(preset.height, Some(1920)); // Vertical
220    }
221
222    #[test]
223    fn test_social_twitter() {
224        let preset = social::twitter();
225        assert_eq!(preset.width, Some(1280));
226        assert_eq!(preset.height, Some(720));
227    }
228}