Skip to main content

oximedia_proxy/resolution/
manager.rs

1//! Multi-resolution proxy management.
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5
6/// Multi-resolution proxy manager.
7pub struct ResolutionManager {
8    /// Map of original to resolution variants.
9    variants: HashMap<PathBuf, Vec<ProxyVariant>>,
10}
11
12impl ResolutionManager {
13    /// Create a new resolution manager.
14    #[must_use]
15    pub fn new() -> Self {
16        Self {
17            variants: HashMap::new(),
18        }
19    }
20
21    /// Add a proxy variant for an original file.
22    pub fn add_variant(&mut self, original: PathBuf, variant: ProxyVariant) {
23        self.variants
24            .entry(original)
25            .or_insert_with(Vec::new)
26            .push(variant);
27    }
28
29    /// Get all variants for an original file.
30    #[must_use]
31    pub fn get_variants(&self, original: &PathBuf) -> Option<&Vec<ProxyVariant>> {
32        self.variants.get(original)
33    }
34
35    /// Get the best variant for a target resolution.
36    #[must_use]
37    pub fn get_best_variant(
38        &self,
39        original: &PathBuf,
40        target_resolution: ProxyResolution,
41    ) -> Option<&ProxyVariant> {
42        self.variants.get(original).and_then(|variants| {
43            variants
44                .iter()
45                .find(|v| v.resolution == target_resolution)
46                .or_else(|| variants.first())
47        })
48    }
49}
50
51impl Default for ResolutionManager {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57/// Proxy resolution levels.
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub enum ProxyResolution {
60    /// Quarter resolution (25%).
61    Quarter,
62    /// Half resolution (50%).
63    Half,
64    /// Full resolution (100%).
65    Full,
66}
67
68impl ProxyResolution {
69    /// Get the scale factor for this resolution.
70    #[must_use]
71    pub const fn scale_factor(&self) -> f32 {
72        match self {
73            Self::Quarter => 0.25,
74            Self::Half => 0.5,
75            Self::Full => 1.0,
76        }
77    }
78
79    /// Get the name of this resolution.
80    #[must_use]
81    pub const fn name(&self) -> &'static str {
82        match self {
83            Self::Quarter => "Quarter",
84            Self::Half => "Half",
85            Self::Full => "Full",
86        }
87    }
88}
89
90/// A proxy variant at a specific resolution.
91#[derive(Debug, Clone)]
92pub struct ProxyVariant {
93    /// Resolution level.
94    pub resolution: ProxyResolution,
95    /// Proxy file path.
96    pub path: PathBuf,
97    /// File size in bytes.
98    pub file_size: u64,
99    /// Codec used.
100    pub codec: String,
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn test_resolution_manager() {
109        let mut manager = ResolutionManager::new();
110
111        let original = PathBuf::from("original.mov");
112        let variant = ProxyVariant {
113            resolution: ProxyResolution::Quarter,
114            path: PathBuf::from("proxy_quarter.mp4"),
115            file_size: 1000,
116            codec: "h264".to_string(),
117        };
118
119        manager.add_variant(original.clone(), variant);
120
121        let variants = manager.get_variants(&original);
122        assert!(variants.is_some());
123        assert_eq!(variants.expect("should succeed in test").len(), 1);
124    }
125
126    #[test]
127    fn test_proxy_resolution() {
128        assert_eq!(ProxyResolution::Quarter.scale_factor(), 0.25);
129        assert_eq!(ProxyResolution::Half.scale_factor(), 0.5);
130        assert_eq!(ProxyResolution::Full.scale_factor(), 1.0);
131
132        assert_eq!(ProxyResolution::Quarter.name(), "Quarter");
133    }
134}