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
286impl Default for CMTime {
287 fn default() -> Self {
288 Self::INVALID
289 }
290}
291
292impl fmt::Display for CMTime {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
294 if let Some(seconds) = self.as_seconds() {
295 write!(f, "{seconds:.3}s")
296 } else {
297 write!(f, "invalid")
298 }
299 }
300}
301
302pub struct CMClock {
307 ptr: *const c_void,
308}
309
310impl PartialEq for CMClock {
311 fn eq(&self, other: &Self) -> bool {
312 self.ptr == other.ptr
313 }
314}
315
316impl Eq for CMClock {}
317
318impl std::hash::Hash for CMClock {
319 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
320 self.ptr.hash(state);
321 }
322}
323
324impl CMClock {
325 #[must_use]
327 pub fn from_raw(ptr: *const c_void) -> Option<Self> {
328 if ptr.is_null() {
329 None
330 } else {
331 Some(Self { ptr })
332 }
333 }
334
335 #[allow(dead_code)]
340 pub(crate) const fn from_ptr(ptr: *const c_void) -> Self {
341 Self { ptr }
342 }
343
344 #[must_use]
346 pub const fn as_ptr(&self) -> *const c_void {
347 self.ptr
348 }
349
350 #[must_use]
355 pub const fn time(&self) -> CMTime {
356 CMTime::INVALID
359 }
360}
361
362impl Drop for CMClock {
363 fn drop(&mut self) {
364 if !self.ptr.is_null() {
365 extern "C" {
367 fn CFRelease(cf: *const c_void);
368 }
369 unsafe {
370 CFRelease(self.ptr);
371 }
372 }
373 }
374}
375
376impl Clone for CMClock {
377 fn clone(&self) -> Self {
378 if self.ptr.is_null() {
379 Self {
380 ptr: std::ptr::null(),
381 }
382 } else {
383 extern "C" {
384 fn CFRetain(cf: *const c_void) -> *const c_void;
385 }
386 unsafe {
387 Self {
388 ptr: CFRetain(self.ptr),
389 }
390 }
391 }
392 }
393}
394
395impl std::fmt::Debug for CMClock {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 f.debug_struct("CMClock").field("ptr", &self.ptr).finish()
398 }
399}
400
401impl fmt::Display for CMClock {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 if self.ptr.is_null() {
404 write!(f, "CMClock(null)")
405 } else {
406 write!(f, "CMClock({:p})", self.ptr)
407 }
408 }
409}
410
411unsafe impl Send for CMClock {}
413unsafe impl Sync for CMClock {}