ffmpeg_next/util/
rational.rs

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