mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-06-02 13:29:50 +00:00
Properly convert the f64 framerate to a fraction
This commit is contained in:
parent
f9cd9e128d
commit
cc183ea92e
|
@ -26,6 +26,7 @@ use error::*;
|
|||
use rsdemuxer::*;
|
||||
use buffer::*;
|
||||
use adapter::*;
|
||||
use utils;
|
||||
|
||||
const AUDIO_STREAM_ID: u32 = 0;
|
||||
const VIDEO_STREAM_ID: u32 = 1;
|
||||
|
@ -354,9 +355,10 @@ impl Metadata {
|
|||
("height", &flavors::ScriptDataValue::Number(height)) => {
|
||||
metadata.video_height = Some(height as u32);
|
||||
}
|
||||
("framerate", &flavors::ScriptDataValue::Number(framerate)) => {
|
||||
// FIXME: Convert properly to a fraction
|
||||
metadata.video_framerate = Some((framerate as u32, 1));
|
||||
("framerate", &flavors::ScriptDataValue::Number(framerate)) if framerate >= 0.0 => {
|
||||
if let Some((n, d)) = utils::f64_to_fraction(framerate) {
|
||||
metadata.video_framerate = Some((n as u32, d as u32));
|
||||
}
|
||||
}
|
||||
("AspectRatioX", &flavors::ScriptDataValue::Number(par_x)) => {
|
||||
par_n = Some(par_x as u32);
|
||||
|
|
111
src/utils.rs
111
src/utils.rs
|
@ -18,6 +18,7 @@
|
|||
//
|
||||
use libc::c_char;
|
||||
use std::ffi::CString;
|
||||
use std::i32;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
|
@ -51,3 +52,113 @@ impl GBoolean {
|
|||
pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) {
|
||||
let _ = CString::from_raw(ptr);
|
||||
}
|
||||
|
||||
pub fn f64_to_fraction(val: f64) -> Option<(i32, i32)> {
|
||||
// Continued fractions algorithm
|
||||
// http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac
|
||||
|
||||
let negative = val < 0.0;
|
||||
|
||||
let mut q = val.abs();
|
||||
let mut n0 = 0;
|
||||
let mut d0 = 1;
|
||||
let mut n1 = 1;
|
||||
let mut d1 = 0;
|
||||
|
||||
const MAX_ITERATIONS: usize = 30;
|
||||
const MAX_ERROR: f64 = 1.0e-20;
|
||||
// 1/EPSILON > i32::MAX
|
||||
const EPSILON: f64 = 1.0e-10;
|
||||
|
||||
// Overflow
|
||||
if q > i32::MAX as f64 {
|
||||
return None;
|
||||
}
|
||||
|
||||
for _ in 0..MAX_ITERATIONS {
|
||||
let a = q as u32;
|
||||
let f = q - (a as f64);
|
||||
|
||||
// Prevent overflow
|
||||
if a != 0 &&
|
||||
(n1 > (i32::MAX as u32) / a || d1 > (i32::MAX as u32) / a ||
|
||||
a * n1 > (i32::MAX as u32) - n0 || a * d1 > (i32::MAX as u32) - d0) {
|
||||
break;
|
||||
}
|
||||
|
||||
let n = a * n1 + n0;
|
||||
let d = a * d1 + d0;
|
||||
|
||||
n0 = n1;
|
||||
d0 = d1;
|
||||
n1 = n;
|
||||
d1 = d;
|
||||
|
||||
// Prevent division by ~0
|
||||
if f < EPSILON {
|
||||
break;
|
||||
}
|
||||
let r = 1.0 / f;
|
||||
|
||||
// Simplify fraction. Doing so here instead of at the end
|
||||
// allows us to get closer to the target value without overflows
|
||||
let g = gcd(n1, d1);
|
||||
if g != 0 {
|
||||
n1 /= g;
|
||||
d1 /= g;
|
||||
}
|
||||
|
||||
// Close enough?
|
||||
if ((n as f64) / (d as f64) - val).abs() < MAX_ERROR {
|
||||
break;
|
||||
}
|
||||
|
||||
q = r;
|
||||
}
|
||||
|
||||
// Guaranteed by the overflow check
|
||||
assert!(n1 <= i32::MAX as u32);
|
||||
assert!(d1 <= i32::MAX as u32);
|
||||
|
||||
// Overflow
|
||||
if d1 == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Make negative again if needed
|
||||
if negative {
|
||||
Some((-(n1 as i32), d1 as i32))
|
||||
} else {
|
||||
Some((n1 as i32, d1 as i32))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gcd(mut a: u32, mut b: u32) -> u32 {
|
||||
// Euclid's algorithm
|
||||
while b != 0 {
|
||||
let tmp = a;
|
||||
a = b;
|
||||
b = tmp % b;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gcd() {
|
||||
assert_eq!(gcd(2 * 2 * 2 * 2, 2 * 2 * 2 * 3), 2 * 2 * 2);
|
||||
assert_eq!(gcd(2 * 3 * 5 * 5 * 7, 2 * 5 * 7), 2 * 5 * 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64_to_fraction() {
|
||||
assert_eq!(f64_to_fraction(2.0), Some((2, 1)));
|
||||
assert_eq!(f64_to_fraction(2.5), Some((5, 2)));
|
||||
assert_eq!(f64_to_fraction(0.127659574), Some((29013539, 227272723)));
|
||||
assert_eq!(f64_to_fraction(29.97), Some((2997, 100)));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue