#![cfg_attr(not(feature = "std"), no_std)]
use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Rational {
pub num: u32,
pub den: u32,
}
impl Rational {
pub const fn new(num: u32, den: u32) -> Self {
Self { num, den }
}
pub fn to_f64(self) -> f64 {
self.num as f64 / self.den as f64
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FrameRate {
Fps23_976,
Fps24,
Fps25,
Fps29_97Df,
Fps29_97Ndf,
Fps30,
Fps48,
Fps50,
Fps59_94Df,
Fps59_94Ndf,
Fps60,
}
impl FrameRate {
pub const fn rational(self) -> Rational {
match self {
Self::Fps23_976 => Rational::new(24000, 1001),
Self::Fps24 => Rational::new(24, 1),
Self::Fps25 => Rational::new(25, 1),
Self::Fps29_97Df | Self::Fps29_97Ndf => Rational::new(30000, 1001),
Self::Fps30 => Rational::new(30, 1),
Self::Fps48 => Rational::new(48, 1),
Self::Fps50 => Rational::new(50, 1),
Self::Fps59_94Df | Self::Fps59_94Ndf => Rational::new(60000, 1001),
Self::Fps60 => Rational::new(60, 1),
}
}
pub const fn nominal(self) -> u32 {
match self {
Self::Fps23_976 => 24,
Self::Fps24 => 24,
Self::Fps25 => 25,
Self::Fps29_97Df | Self::Fps29_97Ndf => 30,
Self::Fps30 => 30,
Self::Fps48 => 48,
Self::Fps50 => 50,
Self::Fps59_94Df | Self::Fps59_94Ndf => 60,
Self::Fps60 => 60,
}
}
pub const fn is_drop_frame(self) -> bool {
matches!(self, Self::Fps29_97Df | Self::Fps59_94Df)
}
pub const fn drop_count(self) -> u32 {
match self {
Self::Fps29_97Df => 2,
Self::Fps59_94Df => 4,
_ => 0,
}
}
pub fn to_f64(self) -> f64 {
self.rational().to_f64()
}
pub fn from_float(fps: f64, drop_frame: bool) -> Option<Self> {
let rounded = (fps * 100.0).round() as u32;
match (rounded, drop_frame) {
(2397, _) => Some(Self::Fps23_976),
(2400, _) => Some(Self::Fps24),
(2500, _) => Some(Self::Fps25),
(2997, true) => Some(Self::Fps29_97Df),
(2997, false) => Some(Self::Fps29_97Ndf),
(3000, _) => Some(Self::Fps30),
(4800, _) => Some(Self::Fps48),
(5000, _) => Some(Self::Fps50),
(5994, true) => Some(Self::Fps59_94Df),
(5994, false) => Some(Self::Fps59_94Ndf),
(6000, _) => Some(Self::Fps60),
_ => None,
}
}
pub const fn discriminant(self) -> u8 {
match self {
Self::Fps23_976 => 0,
Self::Fps24 => 1,
Self::Fps25 => 2,
Self::Fps29_97Df => 3,
Self::Fps29_97Ndf => 4,
Self::Fps30 => 5,
Self::Fps48 => 6,
Self::Fps50 => 7,
Self::Fps59_94Df => 8,
Self::Fps59_94Ndf => 9,
Self::Fps60 => 10,
}
}
pub fn from_discriminant(d: u8) -> Option<Self> {
match d {
0 => Some(Self::Fps23_976),
1 => Some(Self::Fps24),
2 => Some(Self::Fps25),
3 => Some(Self::Fps29_97Df),
4 => Some(Self::Fps29_97Ndf),
5 => Some(Self::Fps30),
6 => Some(Self::Fps48),
7 => Some(Self::Fps50),
8 => Some(Self::Fps59_94Df),
9 => Some(Self::Fps59_94Ndf),
10 => Some(Self::Fps60),
_ => None,
}
}
}
impl fmt::Display for FrameRate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Fps23_976 => write!(f, "23.976"),
Self::Fps24 => write!(f, "24"),
Self::Fps25 => write!(f, "25"),
Self::Fps29_97Df => write!(f, "29.97df"),
Self::Fps29_97Ndf => write!(f, "29.97"),
Self::Fps30 => write!(f, "30"),
Self::Fps48 => write!(f, "48"),
Self::Fps50 => write!(f, "50"),
Self::Fps59_94Df => write!(f, "59.94df"),
Self::Fps59_94Ndf => write!(f, "59.94"),
Self::Fps60 => write!(f, "60"),
}
}
}