mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-05-03 00:48:44 +00:00
199 lines
4.4 KiB
Rust
199 lines
4.4 KiB
Rust
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
use libc::c_char;
|
|
use std::os::raw::c_void;
|
|
use std::ffi::CString;
|
|
use std::i32;
|
|
use num_rational::Rational32;
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum GstFlowReturn {
|
|
Ok = 0,
|
|
NotLinked = -1,
|
|
Flushing = -2,
|
|
Eos = -3,
|
|
NotNegotiated = -4,
|
|
Error = -5,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum GBoolean {
|
|
False = 0,
|
|
True = 1,
|
|
}
|
|
|
|
impl GBoolean {
|
|
pub fn from_bool(v: bool) -> GBoolean {
|
|
if v { GBoolean::True } else { GBoolean::False }
|
|
}
|
|
|
|
pub fn to_bool(&self) -> bool {
|
|
!(*self == GBoolean::False)
|
|
}
|
|
}
|
|
|
|
pub struct Element(*const c_void);
|
|
|
|
impl Element {
|
|
pub unsafe fn new(element: *const c_void) -> Element {
|
|
extern "C" {
|
|
fn gst_object_ref(object: *const c_void) -> *const c_void;
|
|
}
|
|
|
|
if element.is_null() {
|
|
panic!("NULL not allowed");
|
|
}
|
|
|
|
gst_object_ref(element);
|
|
|
|
Element(element)
|
|
}
|
|
|
|
pub unsafe fn as_ptr(&self) -> *const c_void {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
impl Drop for Element {
|
|
fn drop(&mut self) {
|
|
extern "C" {
|
|
fn gst_object_unref(object: *const c_void);
|
|
}
|
|
|
|
unsafe {
|
|
gst_object_unref(self.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Clone for Element {
|
|
fn clone(&self) -> Self {
|
|
unsafe { Element::new(self.0) }
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) {
|
|
let _ = CString::from_raw(ptr);
|
|
}
|
|
|
|
pub fn f64_to_fraction(val: f64) -> Option<Rational32> {
|
|
// 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(Rational32::new(-(n1 as i32), d1 as i32))
|
|
} else {
|
|
Some(Rational32::new(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;
|
|
}
|
|
|
|
a
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use num_rational::Rational32;
|
|
|
|
#[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(Rational32::new(2, 1)));
|
|
assert_eq!(f64_to_fraction(2.5), Some(Rational32::new(5, 2)));
|
|
assert_eq!(f64_to_fraction(0.127659574),
|
|
Some(Rational32::new(29013539, 227272723)));
|
|
assert_eq!(f64_to_fraction(29.97), Some(Rational32::new(2997, 100)));
|
|
}
|
|
}
|