Skip to main content

talw_timecode/
framerate.rs

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}