mirror of https://code.videolan.org/videolan/vlc
Merge branch 'rust-for-vlc.tick' into 'master'
rust: add abstraction for vlc_tick_t and date_t See merge request videolan/vlc!3983
This commit is contained in:
commit
d13ad79084
|
@ -1,5 +1,7 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"vlcrs-messages",
|
||||
"vlcrs-tick",
|
||||
"vlcrs-sys-generator"
|
||||
]
|
||||
|
|
|
@ -62,7 +62,11 @@ impl BindingsGenerator {
|
|||
.raw_line("#![allow(non_snake_case)]")
|
||||
// Since we are generating the input header content at runtime,
|
||||
// specify wrapper.h as a fake name.
|
||||
.header_contents("wrapper.h", &header_contents);
|
||||
.header_contents("wrapper.h", &header_contents)
|
||||
// And since the generated wrappers should be target-independent,
|
||||
// we cannot have layout tests, since they are by definition
|
||||
// target-dependent.
|
||||
.layout_tests(false);
|
||||
|
||||
// Apply "user" configurations, ie allowlist_function, allowlist_type, ...
|
||||
// So that they can pit-point what they want.
|
||||
|
@ -94,4 +98,11 @@ fn main() {
|
|||
non_exhaustive: true,
|
||||
})
|
||||
});
|
||||
bindings_gen.generate_bindings_for("vlcrs-tick", &["vlc_tick.h"], |builder| {
|
||||
builder
|
||||
.allowlist_function("date_Increment")
|
||||
.allowlist_function("date_Decrement")
|
||||
.allowlist_type("date_t")
|
||||
.allowlist_type("vlc_tick_t")
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "vlcrs-tick"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
license = "LGPL-2.1-or-later"
|
||||
|
||||
[dependencies]
|
|
@ -0,0 +1,250 @@
|
|||
//! VLC Tick and Date abstractions.
|
||||
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
ops::{Add, Sub},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod sys;
|
||||
use sys::*;
|
||||
|
||||
/// The VLC clock fequency
|
||||
pub const CLOCK_FREQ: u64 = 1_000_000u64;
|
||||
|
||||
/// High precision date or time interval
|
||||
///
|
||||
/// Store a high precision date or time interval. The maximum precision is the
|
||||
/// microsecond, and a 64 bits integer is used to avoid overflows (maximum
|
||||
/// time interval is then 292271 years, which should be long enough for any
|
||||
/// video). Dates are stored as microseconds since a common date (usually the
|
||||
/// epoch).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use vlcrs_tick::{Tick, Seconds};
|
||||
/// let two_seconds = Seconds::from(2.0f32);
|
||||
/// let ticks = Tick::from(two_seconds);
|
||||
/// assert_eq!(two_seconds, ticks.into());
|
||||
/// ```
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug, Default)]
|
||||
#[doc(alias = "vlc_tick_t")]
|
||||
pub struct Tick(pub(crate) vlc_tick_t);
|
||||
|
||||
impl Tick {
|
||||
/// Maximum of a Tick
|
||||
pub const MIN: Tick = Tick(vlc_tick_t::MIN);
|
||||
|
||||
/// Maximum of a Tick
|
||||
pub const MAX: Tick = Tick(vlc_tick_t::MAX);
|
||||
|
||||
/// Samples to tick
|
||||
///
|
||||
/// ```
|
||||
/// # use vlcrs_tick::{Tick, Seconds};
|
||||
/// let fith_two_seconds = Tick::from_samples(520, 10);
|
||||
/// # let secs = Tick::from(Seconds::from(52));
|
||||
/// # assert_eq!(fith_two_seconds, secs);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn from_samples(samples: u64, rate: u32) -> Tick {
|
||||
let rate = rate as u64;
|
||||
let quot = samples.wrapping_div(rate);
|
||||
let rem = samples.wrapping_rem(rate);
|
||||
|
||||
let ticks_rem = CLOCK_FREQ.wrapping_mul(rem).wrapping_div(rate);
|
||||
let ticks = CLOCK_FREQ.wrapping_mul(quot);
|
||||
|
||||
debug_assert!(ticks < (i64::MAX as u64 - ticks_rem));
|
||||
Tick(ticks.wrapping_add(ticks_rem) as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Tick {
|
||||
type Output = Tick;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Tick(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Tick {
|
||||
type Output = Tick;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Tick(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Tick {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let ticks = if self.0.is_negative() {
|
||||
f.write_str("-")?;
|
||||
(-self.0) as u64
|
||||
} else {
|
||||
self.0 as u64
|
||||
};
|
||||
|
||||
let total_seconds = ticks / CLOCK_FREQ;
|
||||
let seconds = total_seconds % 60;
|
||||
let total_minutes = total_seconds / 60;
|
||||
let minutes = total_minutes % 60;
|
||||
let total_hours = total_minutes / 60;
|
||||
|
||||
if total_hours > 0 {
|
||||
f.write_fmt(format_args!("{total_hours}:{minutes:02}:{seconds:02}"))
|
||||
} else {
|
||||
f.write_fmt(format_args!("{minutes:02}:{seconds:02}"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// interal macro to create the From and Into impls for the givens unit-of-time
|
||||
macro_rules! tu_impls {
|
||||
($name:ident, $mul:literal, $(($t:ty, $i:ty)),+) => {
|
||||
$(
|
||||
impl From<$t> for $name {
|
||||
#[inline]
|
||||
fn from(a: $t) -> $name {
|
||||
$name(a as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name> for $t {
|
||||
#[inline]
|
||||
fn from(a: $name) -> $t {
|
||||
a.0 as _
|
||||
}
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
// internal macro to create a unit-of-time and it's impls
|
||||
macro_rules! tu {
|
||||
($name:ident, $mul:literal) => {
|
||||
#[doc = concat!("A ", stringify!($name), " unit-of-time")]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct $name(i64);
|
||||
|
||||
impl From<$name> for Tick {
|
||||
#[inline]
|
||||
fn from(a: $name) -> Tick {
|
||||
Tick(if CLOCK_FREQ >= $mul {
|
||||
((CLOCK_FREQ / $mul) as i64 * a.0) as _
|
||||
} else {
|
||||
((a.0 as i64 * CLOCK_FREQ as i64) / $mul as i64) as _
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Tick> for $name {
|
||||
#[inline]
|
||||
fn from(a: Tick) -> $name {
|
||||
$name(((a.0 as i64 / CLOCK_FREQ as i64) * $mul as i64) as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for $name {
|
||||
type Output = $name;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
$name(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for $name {
|
||||
type Output = $name;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
$name(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
tu_impls!(
|
||||
$name,
|
||||
$mul,
|
||||
(i8, i64),
|
||||
(i16, i64),
|
||||
(i32, i64),
|
||||
(i64, i64),
|
||||
(u8, u64),
|
||||
(u16, u64),
|
||||
(u32, u64),
|
||||
(u64, u64),
|
||||
(f32, f64),
|
||||
(f64, f64)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
tu!(Nanoseconds, 1_000_000_000u64);
|
||||
tu!(Microseconds, 1_000_000u64);
|
||||
tu!(Milliseconds, 1_000u64);
|
||||
tu!(Seconds, 1u64);
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[doc(alias = "date_t")]
|
||||
#[repr(transparent)]
|
||||
pub struct Date(date_t);
|
||||
|
||||
impl Date {
|
||||
/// New date from `num` and `den`
|
||||
#[doc(alias = "date_Init")]
|
||||
#[inline]
|
||||
pub fn new(num: u32, den: u32) -> Date {
|
||||
Date(date_t {
|
||||
date: 0,
|
||||
i_divider_num: num,
|
||||
i_divider_den: den,
|
||||
i_remainder: 0,
|
||||
})
|
||||
}
|
||||
|
||||
/// Change with `num` and `den`
|
||||
#[doc(alias = "date_Change")]
|
||||
#[inline]
|
||||
pub fn change(&mut self, num: u32, den: u32) {
|
||||
self.0.i_remainder = self.0.i_remainder * num / self.0.i_divider_num;
|
||||
self.0.i_divider_num = num;
|
||||
self.0.i_divider_den = den;
|
||||
}
|
||||
|
||||
/// Increment the date by `count` and return the timestamp
|
||||
#[doc(alias = "date_Increment")]
|
||||
#[inline]
|
||||
pub fn increment(&mut self, count: u32) -> Tick {
|
||||
// SAFETY: The pointer points to a valid date_t
|
||||
Tick(unsafe { date_Increment(&mut self.0 as *mut _, count) })
|
||||
}
|
||||
|
||||
/// Decrement the date by `count` and return the timestamp
|
||||
#[doc(alias = "date_Decrement")]
|
||||
#[inline]
|
||||
pub fn decrement(&mut self, count: u32) -> Tick {
|
||||
// SAFETY: The pointer points to a valid date_t
|
||||
Tick(unsafe { date_Decrement(&mut self.0 as *mut _, count) })
|
||||
}
|
||||
|
||||
/// Assign a tick to this date
|
||||
#[doc(alias = "date_Set")]
|
||||
#[inline]
|
||||
pub fn set(&mut self, tick: Tick) {
|
||||
// KEEP in sync with `date_Set`
|
||||
self.0.i_remainder = 0;
|
||||
self.0.date = tick.0;
|
||||
}
|
||||
|
||||
/// Retrieve the tick from this date
|
||||
#[doc(alias = "date_Get")]
|
||||
#[inline]
|
||||
pub fn get(&self) -> Tick {
|
||||
// KEEP in sync with `date_Get`
|
||||
Tick(self.0.date)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* automatically generated by rust-bindgen 0.66.1 */
|
||||
|
||||
#![allow(rustdoc::bare_urls)]
|
||||
#![allow(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
#[doc = " High precision date or time interval\n\n Store a high precision date or time interval. The maximum precision is the\n microsecond, and a 64 bits integer is used to avoid overflows (maximum\n time interval is then 292271 years, which should be long enough for any\n video). Dates are stored as microseconds since a common date (usually the\n epoch). Note that date and time intervals can be manipulated using regular\n arithmetic operators, and that no special functions are required."]
|
||||
pub type vlc_tick_t = i64;
|
||||
#[doc = " \\defgroup date Timestamps, error-free\n These functions support generating timestamps without long term rounding\n errors due to sample rate conversions.\n \\ingroup input\n @{\n/\n/**\n Timestamps without long-term rounding errors"]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct date_t {
|
||||
pub date: vlc_tick_t,
|
||||
pub i_divider_num: u32,
|
||||
pub i_divider_den: u32,
|
||||
pub i_remainder: u32,
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Increments a date.\n\n Moves the date_t timestamp forward by a given number of samples.\n\n \\param date date to move forward\n \\param count number of samples\n \\return timestamp value after incrementing"]
|
||||
pub fn date_Increment(date: *mut date_t, count: u32) -> vlc_tick_t;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Decrements a date.\n\n Moves the date_t timestamp backward by a given number of samples.\n\n \\param date date to move backward\n \\param count number of samples\n \\return date value"]
|
||||
pub fn date_Decrement(date: *mut date_t, count: u32) -> vlc_tick_t;
|
||||
}
|
Loading…
Reference in New Issue