Skip to main content

oximedia_proxy/generate/
settings.rs

1//! Proxy generation settings and configuration.
2
3use serde::{Deserialize, Serialize};
4
5/// Proxy generation settings.
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct ProxyGenerationSettings {
8    /// Target resolution as a scale factor (0.25, 0.5, 1.0).
9    pub scale_factor: f32,
10
11    /// Target codec name (e.g., "h264", "vp9").
12    pub codec: String,
13
14    /// Target bitrate in bits per second.
15    pub bitrate: u64,
16
17    /// Audio codec name (e.g., "aac", "opus").
18    pub audio_codec: String,
19
20    /// Audio bitrate in bits per second.
21    pub audio_bitrate: u64,
22
23    /// Frame rate preservation mode.
24    pub preserve_frame_rate: bool,
25
26    /// Timecode preservation mode.
27    pub preserve_timecode: bool,
28
29    /// Metadata preservation mode.
30    pub preserve_metadata: bool,
31
32    /// Container format (e.g., "mp4", "mov").
33    pub container: String,
34
35    /// Use hardware acceleration if available.
36    pub use_hw_accel: bool,
37
38    /// Number of encoding threads (0 = auto).
39    pub threads: u32,
40
41    /// Quality preset name (e.g., "fast", "medium", "slow").
42    pub quality_preset: String,
43}
44
45impl Default for ProxyGenerationSettings {
46    fn default() -> Self {
47        Self {
48            scale_factor: 0.25, // Quarter resolution by default
49            codec: "h264".to_string(),
50            bitrate: 5_000_000, // 5 Mbps
51            audio_codec: "aac".to_string(),
52            audio_bitrate: 128_000, // 128 kbps
53            preserve_frame_rate: true,
54            preserve_timecode: true,
55            preserve_metadata: true,
56            container: "mp4".to_string(),
57            use_hw_accel: true,
58            threads: 0, // Auto
59            quality_preset: "medium".to_string(),
60        }
61    }
62}
63
64impl ProxyGenerationSettings {
65    /// Create settings for quarter resolution H.264 proxy.
66    #[must_use]
67    pub fn quarter_res_h264() -> Self {
68        Self {
69            scale_factor: 0.25,
70            codec: "h264".to_string(),
71            bitrate: 2_000_000,
72            ..Self::default()
73        }
74    }
75
76    /// Create settings for half resolution H.264 proxy.
77    #[must_use]
78    pub fn half_res_h264() -> Self {
79        Self {
80            scale_factor: 0.5,
81            codec: "h264".to_string(),
82            bitrate: 5_000_000,
83            ..Self::default()
84        }
85    }
86
87    /// Create settings for full resolution H.264 proxy.
88    #[must_use]
89    pub fn full_res_h264() -> Self {
90        Self {
91            scale_factor: 1.0,
92            codec: "h264".to_string(),
93            bitrate: 10_000_000,
94            ..Self::default()
95        }
96    }
97
98    /// Create settings for quarter resolution VP9 proxy.
99    #[must_use]
100    pub fn quarter_res_vp9() -> Self {
101        Self {
102            scale_factor: 0.25,
103            codec: "vp9".to_string(),
104            bitrate: 1_500_000,
105            audio_codec: "opus".to_string(),
106            container: "webm".to_string(),
107            ..Self::default()
108        }
109    }
110
111    /// Set the scale factor.
112    #[must_use]
113    pub fn with_scale_factor(mut self, scale_factor: f32) -> Self {
114        self.scale_factor = scale_factor;
115        self
116    }
117
118    /// Set the codec.
119    #[must_use]
120    pub fn with_codec(mut self, codec: impl Into<String>) -> Self {
121        self.codec = codec.into();
122        self
123    }
124
125    /// Set the bitrate.
126    #[must_use]
127    pub fn with_bitrate(mut self, bitrate: u64) -> Self {
128        self.bitrate = bitrate;
129        self
130    }
131
132    /// Set the container format.
133    #[must_use]
134    pub fn with_container(mut self, container: impl Into<String>) -> Self {
135        self.container = container.into();
136        self
137    }
138
139    /// Set hardware acceleration.
140    #[must_use]
141    pub fn with_hw_accel(mut self, enable: bool) -> Self {
142        self.use_hw_accel = enable;
143        self
144    }
145
146    /// Validate the settings.
147    pub fn validate(&self) -> crate::Result<()> {
148        if self.scale_factor <= 0.0 || self.scale_factor > 1.0 {
149            return Err(crate::ProxyError::InvalidInput(
150                "Scale factor must be between 0.0 and 1.0".to_string(),
151            ));
152        }
153
154        if self.bitrate == 0 {
155            return Err(crate::ProxyError::InvalidInput(
156                "Bitrate must be greater than 0".to_string(),
157            ));
158        }
159
160        if self.codec.is_empty() {
161            return Err(crate::ProxyError::InvalidInput(
162                "Codec must be specified".to_string(),
163            ));
164        }
165
166        Ok(())
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn test_default_settings() {
176        let settings = ProxyGenerationSettings::default();
177        assert_eq!(settings.scale_factor, 0.25);
178        assert_eq!(settings.codec, "h264");
179        assert_eq!(settings.bitrate, 5_000_000);
180    }
181
182    #[test]
183    fn test_quarter_res_preset() {
184        let settings = ProxyGenerationSettings::quarter_res_h264();
185        assert_eq!(settings.scale_factor, 0.25);
186        assert_eq!(settings.bitrate, 2_000_000);
187    }
188
189    #[test]
190    fn test_half_res_preset() {
191        let settings = ProxyGenerationSettings::half_res_h264();
192        assert_eq!(settings.scale_factor, 0.5);
193        assert_eq!(settings.bitrate, 5_000_000);
194    }
195
196    #[test]
197    fn test_builder_pattern() {
198        let settings = ProxyGenerationSettings::default()
199            .with_scale_factor(0.5)
200            .with_codec("vp9")
201            .with_bitrate(8_000_000);
202
203        assert_eq!(settings.scale_factor, 0.5);
204        assert_eq!(settings.codec, "vp9");
205        assert_eq!(settings.bitrate, 8_000_000);
206    }
207
208    #[test]
209    fn test_validation() {
210        let mut settings = ProxyGenerationSettings::default();
211        assert!(settings.validate().is_ok());
212
213        settings.scale_factor = 0.0;
214        assert!(settings.validate().is_err());
215
216        settings.scale_factor = 0.5;
217        settings.bitrate = 0;
218        assert!(settings.validate().is_err());
219    }
220}