1use std::ffi::c_void;
4use std::fmt;
5
6#[repr(C)]
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub struct CMTime {
28 pub value: i64,
29 pub timescale: i32,
30 pub flags: u32,
31 pub epoch: i64,
32}
33
34impl std::hash::Hash for CMTime {
35 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
36 self.value.hash(state);
37 self.timescale.hash(state);
38 self.flags.hash(state);
39 self.epoch.hash(state);
40 }
41}
42
43#[repr(C)]
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct CMSampleTimingInfo {
64 pub duration: CMTime,
65 pub presentation_time_stamp: CMTime,
66 pub decode_time_stamp: CMTime,
67}
68
69impl std::hash::Hash for CMSampleTimingInfo {
70 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
71 self.duration.hash(state);
72 self.presentation_time_stamp.hash(state);
73 self.decode_time_stamp.hash(state);
74 }
75}
76
77impl CMSampleTimingInfo {
78 #[must_use]
89 pub const fn new() -> Self {
90 Self {
91 duration: CMTime::INVALID,
92 presentation_time_stamp: CMTime::INVALID,
93 decode_time_stamp: CMTime::INVALID,
94 }
95 }
96
97 #[must_use]
99 pub const fn with_times(
100 duration: CMTime,
101 presentation_time_stamp: CMTime,
102 decode_time_stamp: CMTime,
103 ) -> Self {
104 Self {
105 duration,
106 presentation_time_stamp,
107 decode_time_stamp,
108 }
109 }
110
111 #[must_use]
113 pub const fn is_valid(&self) -> bool {
114 self.duration.is_valid()
115 && self.presentation_time_stamp.is_valid()
116 && self.decode_time_stamp.is_valid()
117 }
118
119 #[must_use]
121 pub const fn has_valid_presentation_time(&self) -> bool {
122 self.presentation_time_stamp.is_valid()
123 }
124
125 #[must_use]
127 pub const fn has_valid_decode_time(&self) -> bool {
128 self.decode_time_stamp.is_valid()
129 }
130
131 #[must_use]
133 pub const fn has_valid_duration(&self) -> bool {
134 self.duration.is_valid()
135 }
136
137 #[must_use]
139 pub fn presentation_seconds(&self) -> Option<f64> {
140 self.presentation_time_stamp.as_seconds()
141 }
142
143 #[must_use]
145 pub fn decode_seconds(&self) -> Option<f64> {
146 self.decode_time_stamp.as_seconds()
147 }
148
149 #[must_use]
151 pub fn duration_seconds(&self) -> Option<f64> {
152 self.duration.as_seconds()
153 }
154}
155
156impl Default for CMSampleTimingInfo {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162impl fmt::Display for CMSampleTimingInfo {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 write!(
165 f,
166 "CMSampleTimingInfo(pts: {}, dts: {}, duration: {})",
167 self.presentation_time_stamp, self.decode_time_stamp, self.duration
168 )
169 }
170}
171
172impl CMTime {
173 pub const ZERO: Self = Self {
174 value: 0,
175 timescale: 0,
176 flags: 1,
177 epoch: 0,
178 };
179
180 pub const INVALID: Self = Self {
181 value: 0,
182 timescale: 0,
183 flags: 0,
184 epoch: 0,
185 };
186
187 #[must_use]
188 pub const fn new(value: i64, timescale: i32) -> Self {
189 Self {
190 value,
191 timescale,
192 flags: 1,
193 epoch: 0,
194 }
195 }
196
197 #[must_use]
198 pub const fn is_valid(&self) -> bool {
199 self.flags & 0x1 != 0
200 }
201
202 #[must_use]
204 pub const fn is_zero(&self) -> bool {
205 self.value == 0 && self.is_valid()
206 }
207
208 #[must_use]
210 pub const fn is_indefinite(&self) -> bool {
211 self.flags & 0x2 != 0
212 }
213
214 #[must_use]
216 pub const fn is_positive_infinity(&self) -> bool {
217 self.flags & 0x4 != 0
218 }
219
220 #[must_use]
222 pub const fn is_negative_infinity(&self) -> bool {
223 self.flags & 0x8 != 0
224 }
225
226 #[must_use]
228 pub const fn has_been_rounded(&self) -> bool {
229 self.flags & 0x10 != 0
230 }
231
232 #[must_use]
234 pub const fn equals(&self, other: &Self) -> bool {
235 if !self.is_valid() || !other.is_valid() {
236 return false;
237 }
238 self.value == other.value && self.timescale == other.timescale
239 }
240
241 #[must_use]
243 pub const fn positive_infinity() -> Self {
244 Self {
245 value: 0,
246 timescale: 0,
247 flags: 0x5, epoch: 0,
249 }
250 }
251
252 #[must_use]
254 pub const fn negative_infinity() -> Self {
255 Self {
256 value: 0,
257 timescale: 0,
258 flags: 0x9, epoch: 0,
260 }
261 }
262
263 #[must_use]
265 pub const fn indefinite() -> Self {
266 Self {
267 value: 0,
268 timescale: 0,
269 flags: 0x3, epoch: 0,
271 }
272 }
273
274 #[must_use]
275 pub fn as_seconds(&self) -> Option<f64> {
276 if self.is_valid() && self.timescale != 0 {
277 #[allow(clippy::cast_precision_loss)]
279 Some(self.value as f64 / f64::from(self.timescale))
280 } else {
281 None
282 }
283 }
284
285 #[must_use]
289 pub fn from_seconds(seconds: f64, preferred_timescale: i32) -> Self {
290 extern "C" {
291 fn CMTimeMakeWithSeconds(seconds: f64, preferredTimescale: i32) -> CMTime;
292 }
293 unsafe { CMTimeMakeWithSeconds(seconds, preferred_timescale) }
294 }
295
296 #[must_use]
299 #[allow(clippy::should_implement_trait)]
300 pub fn add(self, other: Self) -> Self {
301 extern "C" {
302 fn CMTimeAdd(addend1: CMTime, addend2: CMTime) -> CMTime;
303 }
304 unsafe { CMTimeAdd(self, other) }
305 }
306
307 #[must_use]
309 #[allow(clippy::should_implement_trait)]
310 pub fn subtract(self, other: Self) -> Self {
311 extern "C" {
312 fn CMTimeSubtract(minuend: CMTime, subtrahend: CMTime) -> CMTime;
313 }
314 unsafe { CMTimeSubtract(self, other) }
315 }
316
317 #[must_use]
319 pub fn multiply(self, multiplier: i32) -> Self {
320 extern "C" {
321 fn CMTimeMultiply(time: CMTime, multiplier: i32) -> CMTime;
322 }
323 unsafe { CMTimeMultiply(self, multiplier) }
324 }
325
326 #[must_use]
328 pub fn multiply_by_f64(self, factor: f64) -> Self {
329 extern "C" {
330 fn CMTimeMultiplyByFloat64(time: CMTime, multiplier: f64) -> CMTime;
331 }
332 unsafe { CMTimeMultiplyByFloat64(self, factor) }
333 }
334
335 #[must_use]
339 pub fn compare(self, other: Self) -> core::cmp::Ordering {
340 extern "C" {
341 fn CMTimeCompare(time1: CMTime, time2: CMTime) -> i32;
342 }
343 let c = unsafe { CMTimeCompare(self, other) };
344 c.cmp(&0)
345 }
346
347 #[must_use]
351 pub fn convert_scale(self, new_timescale: i32) -> Self {
352 extern "C" {
353 fn CMTimeConvertScale(time: CMTime, newTimescale: i32, method: u32) -> CMTime;
354 }
355 unsafe { CMTimeConvertScale(self, new_timescale, 0) }
356 }
357}
358
359impl Default for CMTime {
360 fn default() -> Self {
361 Self::INVALID
362 }
363}
364
365impl fmt::Display for CMTime {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 if let Some(seconds) = self.as_seconds() {
368 write!(f, "{seconds:.3}s")
369 } else {
370 write!(f, "invalid")
371 }
372 }
373}
374
375pub struct CMClock {
380 ptr: *const c_void,
381}
382
383impl PartialEq for CMClock {
384 fn eq(&self, other: &Self) -> bool {
385 self.ptr == other.ptr
386 }
387}
388
389impl Eq for CMClock {}
390
391impl std::hash::Hash for CMClock {
392 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
393 self.ptr.hash(state);
394 }
395}
396
397impl CMClock {
398 #[must_use]
400 pub fn from_raw(ptr: *const c_void) -> Option<Self> {
401 if ptr.is_null() {
402 None
403 } else {
404 Some(Self { ptr })
405 }
406 }
407
408 #[allow(dead_code)]
413 pub(crate) const fn from_ptr(ptr: *const c_void) -> Self {
414 Self { ptr }
415 }
416
417 #[must_use]
419 pub const fn as_ptr(&self) -> *const c_void {
420 self.ptr
421 }
422
423 #[must_use]
428 pub const fn time(&self) -> CMTime {
429 CMTime::INVALID
432 }
433}
434
435impl Drop for CMClock {
436 fn drop(&mut self) {
437 if !self.ptr.is_null() {
438 extern "C" {
440 fn CFRelease(cf: *const c_void);
441 }
442 unsafe {
443 CFRelease(self.ptr);
444 }
445 }
446 }
447}
448
449impl Clone for CMClock {
450 fn clone(&self) -> Self {
451 if self.ptr.is_null() {
452 Self {
453 ptr: std::ptr::null(),
454 }
455 } else {
456 extern "C" {
457 fn CFRetain(cf: *const c_void) -> *const c_void;
458 }
459 unsafe {
460 Self {
461 ptr: CFRetain(self.ptr),
462 }
463 }
464 }
465 }
466}
467
468impl std::fmt::Debug for CMClock {
469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470 f.debug_struct("CMClock").field("ptr", &self.ptr).finish()
471 }
472}
473
474impl fmt::Display for CMClock {
475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476 if self.ptr.is_null() {
477 write!(f, "CMClock(null)")
478 } else {
479 write!(f, "CMClock({:p})", self.ptr)
480 }
481 }
482}
483
484unsafe impl Send for CMClock {}
486unsafe impl Sync for CMClock {}