1#![cfg_attr(not(feature = "std"), no_std)]
2
3use core::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct Rational {
7 pub num: u32,
8 pub den: u32,
9}
10
11impl Rational {
12 pub const fn new(num: u32, den: u32) -> Self {
13 Self { num, den }
14 }
15
16 pub fn to_f64(self) -> f64 {
17 self.num as f64 / self.den as f64
18 }
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum FrameRate {
23 Fps23_976,
24 Fps24,
25 Fps25,
26 Fps29_97Df,
27 Fps29_97Ndf,
28 Fps30,
29 Fps48,
30 Fps50,
31 Fps59_94Df,
32 Fps59_94Ndf,
33 Fps60,
34}
35
36impl FrameRate {
37 pub const fn rational(self) -> Rational {
38 match self {
39 Self::Fps23_976 => Rational::new(24000, 1001),
40 Self::Fps24 => Rational::new(24, 1),
41 Self::Fps25 => Rational::new(25, 1),
42 Self::Fps29_97Df | Self::Fps29_97Ndf => Rational::new(30000, 1001),
43 Self::Fps30 => Rational::new(30, 1),
44 Self::Fps48 => Rational::new(48, 1),
45 Self::Fps50 => Rational::new(50, 1),
46 Self::Fps59_94Df | Self::Fps59_94Ndf => Rational::new(60000, 1001),
47 Self::Fps60 => Rational::new(60, 1),
48 }
49 }
50
51 pub const fn nominal(self) -> u32 {
52 match self {
53 Self::Fps23_976 => 24,
54 Self::Fps24 => 24,
55 Self::Fps25 => 25,
56 Self::Fps29_97Df | Self::Fps29_97Ndf => 30,
57 Self::Fps30 => 30,
58 Self::Fps48 => 48,
59 Self::Fps50 => 50,
60 Self::Fps59_94Df | Self::Fps59_94Ndf => 60,
61 Self::Fps60 => 60,
62 }
63 }
64
65 pub const fn is_drop_frame(self) -> bool {
66 matches!(self, Self::Fps29_97Df | Self::Fps59_94Df)
67 }
68
69 pub const fn drop_count(self) -> u32 {
70 match self {
71 Self::Fps29_97Df => 2,
72 Self::Fps59_94Df => 4,
73 _ => 0,
74 }
75 }
76
77 pub fn to_f64(self) -> f64 {
78 self.rational().to_f64()
79 }
80
81 pub fn from_float(fps: f64, drop_frame: bool) -> Option<Self> {
82 let rounded = (fps * 100.0).round() as u32;
83 match (rounded, drop_frame) {
84 (2397, _) => Some(Self::Fps23_976),
85 (2400, _) => Some(Self::Fps24),
86 (2500, _) => Some(Self::Fps25),
87 (2997, true) => Some(Self::Fps29_97Df),
88 (2997, false) => Some(Self::Fps29_97Ndf),
89 (3000, _) => Some(Self::Fps30),
90 (4800, _) => Some(Self::Fps48),
91 (5000, _) => Some(Self::Fps50),
92 (5994, true) => Some(Self::Fps59_94Df),
93 (5994, false) => Some(Self::Fps59_94Ndf),
94 (6000, _) => Some(Self::Fps60),
95 _ => None,
96 }
97 }
98
99 pub const fn discriminant(self) -> u8 {
100 match self {
101 Self::Fps23_976 => 0,
102 Self::Fps24 => 1,
103 Self::Fps25 => 2,
104 Self::Fps29_97Df => 3,
105 Self::Fps29_97Ndf => 4,
106 Self::Fps30 => 5,
107 Self::Fps48 => 6,
108 Self::Fps50 => 7,
109 Self::Fps59_94Df => 8,
110 Self::Fps59_94Ndf => 9,
111 Self::Fps60 => 10,
112 }
113 }
114
115 pub fn from_discriminant(d: u8) -> Option<Self> {
116 match d {
117 0 => Some(Self::Fps23_976),
118 1 => Some(Self::Fps24),
119 2 => Some(Self::Fps25),
120 3 => Some(Self::Fps29_97Df),
121 4 => Some(Self::Fps29_97Ndf),
122 5 => Some(Self::Fps30),
123 6 => Some(Self::Fps48),
124 7 => Some(Self::Fps50),
125 8 => Some(Self::Fps59_94Df),
126 9 => Some(Self::Fps59_94Ndf),
127 10 => Some(Self::Fps60),
128 _ => None,
129 }
130 }
131}
132
133impl fmt::Display for FrameRate {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 Self::Fps23_976 => write!(f, "23.976"),
137 Self::Fps24 => write!(f, "24"),
138 Self::Fps25 => write!(f, "25"),
139 Self::Fps29_97Df => write!(f, "29.97df"),
140 Self::Fps29_97Ndf => write!(f, "29.97"),
141 Self::Fps30 => write!(f, "30"),
142 Self::Fps48 => write!(f, "48"),
143 Self::Fps50 => write!(f, "50"),
144 Self::Fps59_94Df => write!(f, "59.94df"),
145 Self::Fps59_94Ndf => write!(f, "59.94"),
146 Self::Fps60 => write!(f, "60"),
147 }
148 }
149}