use std::ffi::c_void;
use std::fmt;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CMTime {
pub value: i64,
pub timescale: i32,
pub flags: u32,
pub epoch: i64,
}
impl std::hash::Hash for CMTime {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.value.hash(state);
self.timescale.hash(state);
self.flags.hash(state);
self.epoch.hash(state);
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CMSampleTimingInfo {
pub duration: CMTime,
pub presentation_time_stamp: CMTime,
pub decode_time_stamp: CMTime,
}
impl std::hash::Hash for CMSampleTimingInfo {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.duration.hash(state);
self.presentation_time_stamp.hash(state);
self.decode_time_stamp.hash(state);
}
}
impl CMSampleTimingInfo {
pub const fn new() -> Self {
Self {
duration: CMTime::INVALID,
presentation_time_stamp: CMTime::INVALID,
decode_time_stamp: CMTime::INVALID,
}
}
pub const fn with_times(
duration: CMTime,
presentation_time_stamp: CMTime,
decode_time_stamp: CMTime,
) -> Self {
Self {
duration,
presentation_time_stamp,
decode_time_stamp,
}
}
pub const fn is_valid(&self) -> bool {
self.duration.is_valid()
&& self.presentation_time_stamp.is_valid()
&& self.decode_time_stamp.is_valid()
}
pub const fn has_valid_presentation_time(&self) -> bool {
self.presentation_time_stamp.is_valid()
}
pub const fn has_valid_decode_time(&self) -> bool {
self.decode_time_stamp.is_valid()
}
pub const fn has_valid_duration(&self) -> bool {
self.duration.is_valid()
}
pub fn presentation_seconds(&self) -> Option<f64> {
self.presentation_time_stamp.as_seconds()
}
pub fn decode_seconds(&self) -> Option<f64> {
self.decode_time_stamp.as_seconds()
}
pub fn duration_seconds(&self) -> Option<f64> {
self.duration.as_seconds()
}
}
impl Default for CMSampleTimingInfo {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for CMSampleTimingInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"CMSampleTimingInfo(pts: {}, dts: {}, duration: {})",
self.presentation_time_stamp, self.decode_time_stamp, self.duration
)
}
}
impl CMTime {
pub const ZERO: Self = Self {
value: 0,
timescale: 0,
flags: 1,
epoch: 0,
};
pub const INVALID: Self = Self {
value: 0,
timescale: 0,
flags: 0,
epoch: 0,
};
pub const fn new(value: i64, timescale: i32) -> Self {
Self {
value,
timescale,
flags: 1,
epoch: 0,
}
}
pub const fn is_valid(&self) -> bool {
self.flags & 0x1 != 0
}
pub const fn is_zero(&self) -> bool {
self.value == 0 && self.is_valid()
}
pub const fn is_indefinite(&self) -> bool {
self.flags & 0x2 != 0
}
pub const fn is_positive_infinity(&self) -> bool {
self.flags & 0x4 != 0
}
pub const fn is_negative_infinity(&self) -> bool {
self.flags & 0x8 != 0
}
pub const fn has_been_rounded(&self) -> bool {
self.flags & 0x10 != 0
}
pub const fn equals(&self, other: &Self) -> bool {
if !self.is_valid() || !other.is_valid() {
return false;
}
self.value == other.value && self.timescale == other.timescale
}
pub const fn positive_infinity() -> Self {
Self {
value: 0,
timescale: 0,
flags: 0x5, epoch: 0,
}
}
pub const fn negative_infinity() -> Self {
Self {
value: 0,
timescale: 0,
flags: 0x9, epoch: 0,
}
}
pub const fn indefinite() -> Self {
Self {
value: 0,
timescale: 0,
flags: 0x3, epoch: 0,
}
}
pub fn as_seconds(&self) -> Option<f64> {
if self.is_valid() && self.timescale != 0 {
#[allow(clippy::cast_precision_loss)]
Some(self.value as f64 / f64::from(self.timescale))
} else {
None
}
}
}
impl Default for CMTime {
fn default() -> Self {
Self::INVALID
}
}
impl fmt::Display for CMTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(seconds) = self.as_seconds() {
write!(f, "{seconds:.3}s")
} else {
write!(f, "invalid")
}
}
}
pub struct CMClock {
ptr: *const c_void,
}
impl PartialEq for CMClock {
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl Eq for CMClock {}
impl std::hash::Hash for CMClock {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.ptr.hash(state);
}
}
impl CMClock {
pub fn from_raw(ptr: *const c_void) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self { ptr })
}
}
#[allow(dead_code)]
pub(crate) fn from_ptr(ptr: *const c_void) -> Self {
Self { ptr }
}
pub fn as_ptr(&self) -> *const c_void {
self.ptr
}
pub fn time(&self) -> CMTime {
CMTime::INVALID
}
}
impl Drop for CMClock {
fn drop(&mut self) {
if !self.ptr.is_null() {
extern "C" {
fn CFRelease(cf: *const c_void);
}
unsafe {
CFRelease(self.ptr);
}
}
}
}
impl Clone for CMClock {
fn clone(&self) -> Self {
if self.ptr.is_null() {
Self {
ptr: std::ptr::null(),
}
} else {
extern "C" {
fn CFRetain(cf: *const c_void) -> *const c_void;
}
unsafe {
Self {
ptr: CFRetain(self.ptr),
}
}
}
}
}
impl std::fmt::Debug for CMClock {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CMClock").field("ptr", &self.ptr).finish()
}
}
impl fmt::Display for CMClock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.ptr.is_null() {
write!(f, "CMClock(null)")
} else {
write!(f, "CMClock({:p})", self.ptr)
}
}
}
unsafe impl Send for CMClock {}
unsafe impl Sync for CMClock {}