frame_rate/
lib.rs

1pub use num_rational::Ratio;
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub enum FrameRate {
6  _24_00,
7  _25_00,
8  _30_00,
9  _50_00,
10  _60_00,
11  _120_00,
12  _23_97,
13  _24_97,
14  _29_97,
15  _59_94,
16  FrCustom(Ratio<u32>),
17}
18
19impl FrameRate {
20  pub fn new(num: u32, den: u32) -> Self {
21    Ratio::new(num, den).into()
22  }
23}
24
25impl From<&FrameRate> for f64 {
26  fn from(frame_rate: &FrameRate) -> Self {
27    let ratio: Ratio<u32> = (*frame_rate).into();
28    *ratio.numer() as f64 / *ratio.denom() as f64
29  }
30}
31
32impl From<FrameRate> for Ratio<u32> {
33  fn from(frame_rate: FrameRate) -> Self {
34    match frame_rate {
35      FrameRate::_24_00 => Self::from_integer(24),
36      FrameRate::_25_00 => Self::from_integer(25),
37      FrameRate::_30_00 => Self::from_integer(30),
38      FrameRate::_50_00 => Self::from_integer(50),
39      FrameRate::_60_00 => Self::from_integer(60),
40      FrameRate::_120_00 => Self::from_integer(120),
41      FrameRate::_23_97 => Self::new(24000, 1001),
42      FrameRate::_24_97 => Self::new(25000, 1001),
43      FrameRate::_29_97 => Self::new(30000, 1001),
44      FrameRate::_59_94 => Self::new(60000, 1001),
45      FrameRate::FrCustom(rational) => rational,
46    }
47  }
48}
49
50impl From<Ratio<u32>> for FrameRate {
51  fn from(rational: Ratio<u32>) -> Self {
52    match (rational.numer(), rational.denom()) {
53      (24, 1) => Self::_24_00,
54      (25, 1) => Self::_25_00,
55      (30, 1) => Self::_30_00,
56      (50, 1) => Self::_50_00,
57      (60, 1) => Self::_60_00,
58      (120, 1) => Self::_120_00,
59      (24000, 1001) => Self::_23_97,
60      (25000, 1001) => Self::_24_97,
61      (30000, 1001) => Self::_29_97,
62      (60000, 1001) => Self::_59_94,
63      _ => Self::FrCustom(rational),
64    }
65  }
66}
67
68#[derive(Serialize, Deserialize)]
69struct SerializeRational {
70  num: u32,
71  den: u32,
72}
73
74impl From<Ratio<u32>> for SerializeRational {
75  fn from(rational: Ratio<u32>) -> Self {
76    Self {
77      num: *rational.numer(),
78      den: *rational.denom(),
79    }
80  }
81}
82
83impl From<SerializeRational> for Ratio<u32> {
84  fn from(serialize_rational: SerializeRational) -> Self {
85    Self::new(serialize_rational.num, serialize_rational.den)
86  }
87}
88
89impl Serialize for FrameRate {
90  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91  where
92    S: Serializer,
93  {
94    SerializeRational::from(Ratio::<u32>::from(*self)).serialize(serializer)
95  }
96}
97
98impl<'de> Deserialize<'de> for FrameRate {
99  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
100  where
101    D: Deserializer<'de>,
102  {
103    Ok(Self::from(Ratio::<u32>::from(
104      SerializeRational::deserialize(deserializer)?,
105    )))
106  }
107}
108
109#[cfg(test)]
110mod tests {
111  use super::*;
112
113  #[test]
114  fn rational_from_frame_rate() {
115    assert_eq!(Ratio::from(FrameRate::_24_00), Ratio::from_integer(24));
116    assert_eq!(Ratio::from(FrameRate::_25_00), Ratio::from_integer(25));
117    assert_eq!(Ratio::from(FrameRate::_30_00), Ratio::from_integer(30));
118    assert_eq!(Ratio::from(FrameRate::_50_00), Ratio::from_integer(50));
119    assert_eq!(Ratio::from(FrameRate::_60_00), Ratio::from_integer(60));
120    assert_eq!(Ratio::from(FrameRate::_120_00), Ratio::from_integer(120));
121    assert_eq!(Ratio::from(FrameRate::_23_97), Ratio::new(24000, 1001));
122    assert_eq!(Ratio::from(FrameRate::_24_97), Ratio::new(25000, 1001));
123    assert_eq!(Ratio::from(FrameRate::_29_97), Ratio::new(30000, 1001));
124    assert_eq!(Ratio::from(FrameRate::_59_94), Ratio::new(60000, 1001));
125    let rational_2_3 = Ratio::new(2, 3);
126    let rational_6_9 = Ratio::new(6, 9);
127    assert_eq!(Ratio::from(FrameRate::FrCustom(rational_2_3)), rational_2_3);
128    assert_eq!(Ratio::from(FrameRate::FrCustom(rational_6_9)), rational_2_3);
129  }
130
131  #[test]
132  fn frame_rate_from_rational() {
133    assert_eq!(FrameRate::from(Ratio::from_integer(24)), FrameRate::_24_00);
134    assert_eq!(FrameRate::from(Ratio::from_integer(25)), FrameRate::_25_00);
135    assert_eq!(FrameRate::from(Ratio::from_integer(30)), FrameRate::_30_00);
136    assert_eq!(FrameRate::from(Ratio::from_integer(50)), FrameRate::_50_00);
137    assert_eq!(FrameRate::from(Ratio::from_integer(60)), FrameRate::_60_00);
138    assert_eq!(
139      FrameRate::from(Ratio::from_integer(120)),
140      FrameRate::_120_00
141    );
142    assert_eq!(FrameRate::from(Ratio::new(24000, 1001)), FrameRate::_23_97);
143    assert_eq!(FrameRate::from(Ratio::new(25000, 1001)), FrameRate::_24_97);
144    assert_eq!(FrameRate::from(Ratio::new(30000, 1001)), FrameRate::_29_97);
145    assert_eq!(FrameRate::from(Ratio::new(60000, 1001)), FrameRate::_59_94);
146    let rational_2_3 = Ratio::new(2, 3);
147    let rational_6_9 = Ratio::new(6, 9);
148    assert_eq!(
149      FrameRate::from(rational_2_3),
150      FrameRate::FrCustom(rational_2_3)
151    );
152    assert_eq!(
153      FrameRate::from(rational_2_3),
154      FrameRate::FrCustom(rational_6_9)
155    );
156    assert_eq!(FrameRate::from(Ratio::new(200, 4)), FrameRate::_50_00);
157  }
158
159  #[test]
160  fn serialize() {
161    assert_eq!(
162      serde_json::to_value(FrameRate::_24_00).unwrap(),
163      serde_json::json!({
164        "num": 24,
165        "den": 1
166      })
167    );
168    assert_eq!(
169      serde_json::to_value(FrameRate::_25_00).unwrap(),
170      serde_json::json!({
171        "num": 25,
172        "den": 1
173      })
174    );
175    assert_eq!(
176      serde_json::to_value(FrameRate::_30_00).unwrap(),
177      serde_json::json!({
178        "num": 30,
179        "den": 1
180      })
181    );
182    assert_eq!(
183      serde_json::to_value(FrameRate::_50_00).unwrap(),
184      serde_json::json!({
185        "num": 50,
186        "den": 1
187      })
188    );
189    assert_eq!(
190      serde_json::to_value(FrameRate::_60_00).unwrap(),
191      serde_json::json!({
192        "num": 60,
193        "den": 1
194      })
195    );
196    assert_eq!(
197      serde_json::to_value(FrameRate::_120_00).unwrap(),
198      serde_json::json!({
199        "num": 120,
200        "den": 1
201      })
202    );
203    assert_eq!(
204      serde_json::to_value(FrameRate::_23_97).unwrap(),
205      serde_json::json!({
206        "num": 24000,
207        "den": 1001
208      })
209    );
210    assert_eq!(
211      serde_json::to_value(FrameRate::_24_97).unwrap(),
212      serde_json::json!({
213        "num": 25000,
214        "den": 1001
215      })
216    );
217    assert_eq!(
218      serde_json::to_value(FrameRate::_29_97).unwrap(),
219      serde_json::json!({
220        "num": 30000,
221        "den": 1001
222      })
223    );
224    assert_eq!(
225      serde_json::to_value(FrameRate::_59_94).unwrap(),
226      serde_json::json!({
227        "num": 60000,
228        "den": 1001
229      })
230    );
231    assert_eq!(
232      serde_json::to_value(FrameRate::FrCustom(Ratio::new(2, 3))).unwrap(),
233      serde_json::json!({
234        "num": 2,
235        "den": 3
236      })
237    );
238    assert_eq!(
239      serde_json::to_value(FrameRate::FrCustom(Ratio::new(6, 9))).unwrap(),
240      serde_json::json!({
241        "num": 2,
242        "den": 3
243      })
244    );
245  }
246
247  #[test]
248  fn deserialize() {
249    assert_eq!(
250      serde_json::from_value::<FrameRate>(serde_json::json!({
251        "num": 24,
252        "den": 1
253      }))
254      .unwrap(),
255      FrameRate::_24_00
256    );
257    assert_eq!(
258      serde_json::from_value::<FrameRate>(serde_json::json!({
259        "num": 25,
260        "den": 1
261      }))
262      .unwrap(),
263      FrameRate::_25_00
264    );
265    assert_eq!(
266      serde_json::from_value::<FrameRate>(serde_json::json!({
267        "num": 30,
268        "den": 1
269      }))
270      .unwrap(),
271      FrameRate::_30_00
272    );
273    assert_eq!(
274      serde_json::from_value::<FrameRate>(serde_json::json!({
275        "num": 50,
276        "den": 1
277      }))
278      .unwrap(),
279      FrameRate::_50_00
280    );
281    assert_eq!(
282      serde_json::from_value::<FrameRate>(serde_json::json!({
283        "num": 60,
284        "den": 1
285      }))
286      .unwrap(),
287      FrameRate::_60_00
288    );
289    assert_eq!(
290      serde_json::from_value::<FrameRate>(serde_json::json!({
291        "num": 120,
292        "den": 1
293      }))
294      .unwrap(),
295      FrameRate::_120_00
296    );
297    assert_eq!(
298      serde_json::from_value::<FrameRate>(serde_json::json!({
299        "num": 24000,
300        "den": 1001
301      }))
302      .unwrap(),
303      FrameRate::_23_97
304    );
305    assert_eq!(
306      serde_json::from_value::<FrameRate>(serde_json::json!({
307        "num": 25000,
308        "den": 1001
309      }))
310      .unwrap(),
311      FrameRate::_24_97
312    );
313    assert_eq!(
314      serde_json::from_value::<FrameRate>(serde_json::json!({
315        "num": 30000,
316        "den": 1001
317      }))
318      .unwrap(),
319      FrameRate::_29_97
320    );
321    assert_eq!(
322      serde_json::from_value::<FrameRate>(serde_json::json!({
323        "num": 60000,
324        "den": 1001
325      }))
326      .unwrap(),
327      FrameRate::_59_94
328    );
329    assert_eq!(
330      serde_json::from_value::<FrameRate>(serde_json::json!({
331        "num": 2,
332        "den": 3
333      }))
334      .unwrap(),
335      FrameRate::FrCustom(Ratio::new(2, 3))
336    );
337    assert_eq!(
338      serde_json::from_value::<FrameRate>(serde_json::json!({
339        "num": 6,
340        "den": 9
341      }))
342      .unwrap(),
343      FrameRate::FrCustom(Ratio::new(2, 3))
344    );
345    assert_eq!(
346      serde_json::from_value::<FrameRate>(serde_json::json!({
347        "num": 200,
348        "den": 4
349      }))
350      .unwrap(),
351      FrameRate::_50_00
352    );
353  }
354}