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