playa_ffmpeg/util/
rational.rs

1use std::{
2    cmp::Ordering,
3    fmt,
4    ops::{Add, Div, Mul, Sub},
5};
6
7use crate::ffi::*;
8use libc::c_int;
9
10#[derive(Copy, Clone)]
11pub struct Rational(pub i32, pub i32);
12
13impl Rational {
14    #[inline]
15    pub fn new(numerator: i32, denominator: i32) -> Self {
16        Rational(numerator, denominator)
17    }
18
19    #[inline]
20    pub fn numerator(&self) -> i32 {
21        self.0
22    }
23
24    #[inline]
25    pub fn denominator(&self) -> i32 {
26        self.1
27    }
28
29    #[inline]
30    pub fn reduce(&self) -> Rational {
31        match self.reduce_with_limit(i32::MAX) {
32            Ok(r) => r,
33            Err(r) => r,
34        }
35    }
36
37    #[inline]
38    pub fn reduce_with_limit(&self, max: i32) -> Result<Rational, Rational> {
39        unsafe {
40            let mut dst_num: c_int = 0;
41            let mut dst_den: c_int = 0;
42
43            let exact = av_reduce(&mut dst_num, &mut dst_den, i64::from(self.numerator()), i64::from(self.denominator()), i64::from(max));
44
45            if exact == 1 { Ok(Rational(dst_num, dst_den)) } else { Err(Rational(dst_num, dst_den)) }
46        }
47    }
48
49    #[inline]
50    pub fn invert(&self) -> Rational {
51        unsafe { Rational::from(av_inv_q((*self).into())) }
52    }
53}
54
55impl From<AVRational> for Rational {
56    #[inline]
57    fn from(value: AVRational) -> Rational {
58        Rational(value.num, value.den)
59    }
60}
61
62impl From<Rational> for AVRational {
63    #[inline]
64    fn from(value: Rational) -> AVRational {
65        AVRational { num: value.0, den: value.1 }
66    }
67}
68
69impl From<f64> for Rational {
70    #[inline]
71    fn from(value: f64) -> Rational {
72        unsafe { Rational::from(av_d2q(value, c_int::MAX)) }
73    }
74}
75
76impl From<Rational> for f64 {
77    #[inline]
78    fn from(value: Rational) -> f64 {
79        unsafe { av_q2d(value.into()) }
80    }
81}
82
83impl From<Rational> for u32 {
84    #[inline]
85    fn from(value: Rational) -> u32 {
86        unsafe { av_q2intfloat(value.into()) }
87    }
88}
89
90impl From<(i32, i32)> for Rational {
91    fn from((num, den): (i32, i32)) -> Rational {
92        Rational::new(num, den)
93    }
94}
95
96impl PartialEq for Rational {
97    fn eq(&self, other: &Rational) -> bool {
98        if self.0 == other.0 && self.1 == other.1 {
99            return true;
100        }
101
102        let a = self.reduce();
103        let b = other.reduce();
104
105        if a.0 == b.0 && a.1 == b.1 {
106            return true;
107        }
108
109        false
110    }
111}
112
113impl Eq for Rational {}
114
115impl PartialOrd for Rational {
116    #[inline]
117    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
118        unsafe {
119            match av_cmp_q((*self).into(), (*other).into()) {
120                0 => Some(Ordering::Equal),
121                1 => Some(Ordering::Greater),
122                -1 => Some(Ordering::Less),
123
124                _ => None,
125            }
126        }
127    }
128}
129
130impl Add for Rational {
131    type Output = Rational;
132
133    #[inline]
134    fn add(self, other: Rational) -> Rational {
135        unsafe { Rational::from(av_add_q(self.into(), other.into())) }
136    }
137}
138
139impl Sub for Rational {
140    type Output = Rational;
141
142    #[inline]
143    fn sub(self, other: Rational) -> Rational {
144        unsafe { Rational::from(av_sub_q(self.into(), other.into())) }
145    }
146}
147
148impl Mul for Rational {
149    type Output = Rational;
150
151    #[inline]
152    fn mul(self, other: Rational) -> Rational {
153        unsafe { Rational::from(av_mul_q(self.into(), other.into())) }
154    }
155}
156
157impl Div for Rational {
158    type Output = Rational;
159
160    #[inline]
161    fn div(self, other: Rational) -> Rational {
162        unsafe { Rational::from(av_div_q(self.into(), other.into())) }
163    }
164}
165
166impl fmt::Display for Rational {
167    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
168        f.write_str(&format!("{}/{}", self.numerator(), self.denominator()))
169    }
170}
171
172impl fmt::Debug for Rational {
173    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
174        f.write_str(&format!("Rational({}/{})", self.numerator(), self.denominator()))
175    }
176}
177
178#[inline]
179pub fn nearer(q: Rational, q1: Rational, q2: Rational) -> Ordering {
180    unsafe {
181        match av_nearer_q(q.into(), q1.into(), q2.into()) {
182            1 => Ordering::Greater,
183            -1 => Ordering::Less,
184            _ => Ordering::Equal,
185        }
186    }
187}