1use std::{
2 mem,
3 ptr::{null, null_mut},
4};
5
6use block::{Block, ConcreteBlock};
7use core_foundation::{
8 base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, CFComparisonResult, CFGetTypeID, CFRetain, CFType, CFTypeID, CFTypeRef, OSStatus, TCFType},
9 declare_TCFType, impl_CFTypeDescription, impl_TCFType,
10 string::CFStringRef,
11};
12use libc::{c_void, size_t};
13
14use crate::{
15 base::{status_to_result, CMItemCount},
16 time::CMTime,
17};
18
19pub const kCMBufferQueueError_AllocationFailed: OSStatus = -12760;
20pub const kCMBufferQueueError_RequiredParameterMissing: OSStatus = -12761;
21pub const kCMBufferQueueError_InvalidCMBufferCallbacksStruct: OSStatus = -12762;
22pub const kCMBufferQueueError_EnqueueAfterEndOfData: OSStatus = -12763;
23pub const kCMBufferQueueError_QueueIsFull: OSStatus = -12764;
24pub const kCMBufferQueueError_BadTriggerDuration: OSStatus = -12765;
25pub const kCMBufferQueueError_CannotModifyQueueFromTriggerCallback: OSStatus = -12766;
26pub const kCMBufferQueueError_InvalidTriggerCondition: OSStatus = -12767;
27pub const kCMBufferQueueError_InvalidTriggerToken: OSStatus = -12768;
28pub const kCMBufferQueueError_InvalidBuffer: OSStatus = -12769;
29
30#[repr(C)]
31pub struct OpaqueCMBufferQueue(c_void);
32
33pub type CMBufferQueueRef = *mut OpaqueCMBufferQueue;
34
35pub type CMBufferRef = CFTypeRef;
36
37pub type CMBufferGetTimeCallback = extern "C" fn(buf: CMBufferRef, refcon: *mut c_void) -> CMTime;
38pub type CMBufferGetTimeHandler = *const Block<CMBufferRef, CMTime>;
39pub type CMBufferGetBooleanCallback = extern "C" fn(buf: CMBufferRef, refcon: *mut c_void) -> Boolean;
40pub type CMBufferGetBooleanHandler = *const Block<CMBufferRef, Boolean>;
41pub type CMBufferCompareCallback = extern "C" fn(buf1: CMBufferRef, buf2: CMBufferRef, refcon: *mut c_void) -> CFComparisonResult;
42pub type CMBufferCompareHandler = *const Block<(CMBufferRef, CMBufferRef), CFComparisonResult>;
43pub type CMBufferGetSizeCallback = extern "C" fn(buf: CMBufferRef, refcon: *mut c_void) -> size_t;
44pub type CMBufferGetSizeHandler = *const Block<CMBufferRef, size_t>;
45
46#[repr(C, packed(4))]
47#[derive(Clone, Copy, Debug)]
48pub struct CMBufferCallbacks {
49 pub version: u32,
50 pub refcon: Option<*mut c_void>,
51 pub getDecodeTimeStamp: CMBufferGetTimeCallback,
52 pub getPresentationTimeStamp: CMBufferGetTimeCallback,
53 pub getDuration: CMBufferGetTimeCallback,
54 pub isDataReady: CMBufferGetBooleanCallback,
55 pub compare: CMBufferCompareCallback,
56 pub dataBecameReadyNotification: CFStringRef,
57 pub getSize: CMBufferGetSizeCallback,
58}
59
60extern "C" {
61 pub fn CMBufferQueueGetCallbacksForUnsortedSampleBuffers() -> *const CMBufferCallbacks;
62 pub fn CMBufferQueueGetCallbacksForSampleBuffersSortedByOutputPTS() -> *const CMBufferCallbacks;
63 pub fn CMBufferQueueCreate(
64 allocator: CFAllocatorRef,
65 capacity: CMItemCount,
66 callbacks: *const CMBufferCallbacks,
67 queueOut: *mut CMBufferQueueRef,
68 ) -> OSStatus;
69 pub fn CMBufferQueueGetTypeID() -> CFTypeID;
70 pub fn CMBufferQueueEnqueue(queue: CMBufferQueueRef, buf: CMBufferRef) -> OSStatus;
71 pub fn CMBufferQueueDequeueAndRetain(queue: CMBufferQueueRef) -> CMBufferRef;
72 pub fn CMBufferQueueDequeueIfDataReadyAndRetain(queue: CMBufferQueueRef) -> CMBufferRef;
73 pub fn CMBufferQueueGetHead(queue: CMBufferQueueRef) -> CMBufferRef;
74 pub fn CMBufferQueueCopyHead(queue: CMBufferQueueRef) -> CMBufferRef;
75 pub fn CMBufferQueueIsEmpty(queue: CMBufferQueueRef) -> Boolean;
76 pub fn CMBufferQueueMarkEndOfData(queue: CMBufferQueueRef) -> OSStatus;
77 pub fn CMBufferQueueContainsEndOfData(queue: CMBufferQueueRef) -> Boolean;
78 pub fn CMBufferQueueIsAtEndOfData(queue: CMBufferQueueRef) -> Boolean;
79 pub fn CMBufferQueueReset(queue: CMBufferQueueRef) -> OSStatus;
80 pub fn CMBufferQueueResetWithCallback(
81 queue: CMBufferQueueRef,
82 callback: extern "C" fn(buffer: CMBufferRef, refcon: *mut c_void),
83 refcon: *mut c_void,
84 ) -> OSStatus;
85 pub fn CMBufferQueueGetBufferCount(queue: CMBufferQueueRef) -> CMItemCount;
86 pub fn CMBufferQueueGetDuration(queue: CMBufferQueueRef) -> CMTime;
87 pub fn CMBufferQueueGetMinDecodeTimeStamp(queue: CMBufferQueueRef) -> CMTime;
88 pub fn CMBufferQueueGetFirstDecodeTimeStamp(queue: CMBufferQueueRef) -> CMTime;
89 pub fn CMBufferQueueGetMinPresentationTimeStamp(queue: CMBufferQueueRef) -> CMTime;
90 pub fn CMBufferQueueGetFirstPresentationTimeStamp(queue: CMBufferQueueRef) -> CMTime;
91 pub fn CMBufferQueueGetMaxPresentationTimeStamp(queue: CMBufferQueueRef) -> CMTime;
92 pub fn CMBufferQueueGetEndPresentationTimeStamp(queue: CMBufferQueueRef) -> CMTime;
93 pub fn CMBufferQueueGetTotalSize(queue: CMBufferQueueRef) -> size_t;
94}
95
96#[repr(C)]
97pub struct opaqueCMBufferQueueTriggerToken(c_void);
98
99pub type CMBufferQueueTriggerToken = *const opaqueCMBufferQueueTriggerToken;
100
101pub type CMBufferQueueTriggerCallback = extern "C" fn(triggerRefcon: *mut c_void, triggerToken: CMBufferQueueTriggerToken);
102pub type CMBufferQueueTriggerHandler = *const Block<(CMBufferQueueTriggerToken,), ()>;
103
104pub type CMBufferQueueTriggerCondition = i32;
105
106pub const kCMBufferQueueTrigger_WhenDurationBecomesLessThan: CMBufferQueueTriggerCondition = 1;
107pub const kCMBufferQueueTrigger_WhenDurationBecomesLessThanOrEqualTo: CMBufferQueueTriggerCondition = 2;
108pub const kCMBufferQueueTrigger_WhenDurationBecomesGreaterThan: CMBufferQueueTriggerCondition = 3;
109pub const kCMBufferQueueTrigger_WhenDurationBecomesGreaterThanOrEqualTo: CMBufferQueueTriggerCondition = 4;
110pub const kCMBufferQueueTrigger_WhenMinPresentationTimeStampChanges: CMBufferQueueTriggerCondition = 5;
111pub const kCMBufferQueueTrigger_WhenMaxPresentationTimeStampChanges: CMBufferQueueTriggerCondition = 6;
112pub const kCMBufferQueueTrigger_WhenDataBecomesReady: CMBufferQueueTriggerCondition = 7;
113pub const kCMBufferQueueTrigger_WhenEndOfDataReached: CMBufferQueueTriggerCondition = 8;
114pub const kCMBufferQueueTrigger_WhenReset: CMBufferQueueTriggerCondition = 9;
115pub const kCMBufferQueueTrigger_WhenBufferCountBecomesLessThan: CMBufferQueueTriggerCondition = 10;
116pub const kCMBufferQueueTrigger_WhenBufferCountBecomesGreaterThan: CMBufferQueueTriggerCondition = 11;
117pub const kCMBufferQueueTrigger_WhenDurationBecomesGreaterThanOrEqualToAndBufferCountBecomesGreaterThan: CMBufferQueueTriggerCondition = 12;
118
119extern "C" {
120 pub fn CMBufferQueueInstallTrigger(
121 queue: CMBufferQueueRef,
122 callback: CMBufferQueueTriggerCallback,
123 refcon: *mut c_void,
124 condition: CMBufferQueueTriggerCondition,
125 time: CMTime,
126 triggerTokenOut: *mut CMBufferQueueTriggerToken,
127 ) -> OSStatus;
128 pub fn CMBufferQueueInstallTriggerWithIntegerThreshold(
129 queue: CMBufferQueueRef,
130 callback: CMBufferQueueTriggerCallback,
131 refcon: *mut c_void,
132 condition: CMBufferQueueTriggerCondition,
133 threshold: CMItemCount,
134 triggerTokenOut: *mut CMBufferQueueTriggerToken,
135 ) -> OSStatus;
136 pub fn CMBufferQueueInstallTriggerHandler(
137 queue: CMBufferQueueRef,
138 condition: CMBufferQueueTriggerCondition,
139 time: CMTime,
140 triggerTokenOut: *mut CMBufferQueueTriggerToken,
141 handler: CMBufferQueueTriggerHandler,
142 ) -> OSStatus;
143 pub fn CMBufferQueueInstallTriggerHandlerWithIntegerThreshold(
144 queue: CMBufferQueueRef,
145 condition: CMBufferQueueTriggerCondition,
146 threshold: CMItemCount,
147 triggerTokenOut: *mut CMBufferQueueTriggerToken,
148 handler: CMBufferQueueTriggerHandler,
149 ) -> OSStatus;
150 pub fn CMBufferQueueRemoveTrigger(queue: CMBufferQueueRef, triggerToken: CMBufferQueueTriggerToken) -> OSStatus;
151 pub fn CMBufferQueueTestTrigger(queue: CMBufferQueueRef, triggerToken: CMBufferQueueTriggerToken) -> Boolean;
152 pub fn CMBufferQueueCallForEachBuffer(
153 queue: CMBufferQueueRef,
154 callback: extern "C" fn(buffer: CMBufferRef, refcon: *mut c_void) -> OSStatus,
155 refcon: *mut c_void,
156 ) -> OSStatus;
157}
158
159pub type CMBufferValidationCallback = extern "C" fn(queue: CMBufferQueueRef, buf: CMBufferRef, validationRefCon: *mut c_void) -> OSStatus;
160pub type CMBufferValidationHandler = *const Block<(CMBufferQueueRef, CMBufferRef), OSStatus>;
161
162extern "C" {
163 pub fn CMBufferQueueSetValidationCallback(queue: CMBufferQueueRef, callback: CMBufferValidationCallback, refCon: *mut c_void) -> OSStatus;
164 pub fn CMBufferQueueSetValidationHandler(queue: CMBufferQueueRef, handler: CMBufferValidationHandler) -> OSStatus;
165}
166
167declare_TCFType!(CMBuffer, CMBufferRef);
168impl_CFTypeDescription!(CMBuffer);
169
170impl CMBuffer {
171 #[inline]
172 pub fn as_concrete_TypeRef(&self) -> CMBufferRef {
173 self.0
174 }
175
176 #[inline]
177 pub fn as_CFType(&self) -> CFType {
178 unsafe { CFType::wrap_under_get_rule(self.as_concrete_TypeRef()) }
179 }
180
181 #[inline]
182 pub fn as_CFTypeRef(&self) -> CFTypeRef {
183 self.as_concrete_TypeRef() as CFTypeRef
184 }
185
186 #[inline]
187 pub fn into_CFType(self) -> CFType
188 where
189 Self: Sized,
190 {
191 let reference = self.as_CFTypeRef();
192 mem::forget(self);
193 unsafe { CFType::wrap_under_create_rule(reference) }
194 }
195
196 #[inline]
197 pub unsafe fn wrap_under_create_rule(reference: CMBufferRef) -> Self {
198 CMBuffer(reference)
199 }
200
201 #[inline]
202 pub unsafe fn wrap_under_get_rule(reference: CMBufferRef) -> Self {
203 let reference = CFRetain(reference);
204 CMBuffer(reference)
205 }
206
207 #[inline]
208 pub fn type_of(&self) -> CFTypeID {
209 unsafe { CFGetTypeID(self.as_CFTypeRef()) }
210 }
211
212 #[inline]
213 pub fn instance_of<T: TCFType>(&self) -> bool {
214 self.type_of() == T::type_id()
215 }
216}
217
218declare_TCFType!(CMBufferQueue, CMBufferQueueRef);
219impl_TCFType!(CMBufferQueue, CMBufferQueueRef, CMBufferQueueGetTypeID);
220impl_CFTypeDescription!(CMBufferQueue);
221
222impl CMBufferQueue {
223 #[inline]
224 pub fn new(callbacks: &[CMBufferCallbacks]) -> Result<CMBufferQueue, OSStatus> {
225 unsafe {
226 let mut queue: CMBufferQueueRef = null_mut();
227 let status = CMBufferQueueCreate(kCFAllocatorDefault, callbacks.len() as CMItemCount, callbacks.as_ptr(), &mut queue);
228 status_to_result(status).map(|_| TCFType::wrap_under_create_rule(queue))
229 }
230 }
231
232 #[inline]
233 pub fn enqueue(&self, buf: &CMBuffer) -> Result<(), OSStatus> {
234 unsafe {
235 let status = CMBufferQueueEnqueue(self.as_concrete_TypeRef(), buf.as_concrete_TypeRef());
236 status_to_result(status)
237 }
238 }
239
240 #[inline]
241 pub fn dequeue_and_retain(&self) -> Option<CMBuffer> {
242 unsafe {
243 let buf = CMBufferQueueDequeueAndRetain(self.as_concrete_TypeRef());
244 if buf.is_null() {
245 None
246 } else {
247 Some(CMBuffer::wrap_under_create_rule(buf))
248 }
249 }
250 }
251
252 #[inline]
253 pub fn dequeue_if_data_ready_and_retain(&self) -> Option<CMBuffer> {
254 unsafe {
255 let buf = CMBufferQueueDequeueIfDataReadyAndRetain(self.as_concrete_TypeRef());
256 if buf.is_null() {
257 None
258 } else {
259 Some(CMBuffer::wrap_under_create_rule(buf))
260 }
261 }
262 }
263
264 #[inline]
265 pub fn get_head(&self) -> Option<CMBuffer> {
266 unsafe {
267 let buf = CMBufferQueueGetHead(self.as_concrete_TypeRef());
268 if buf.is_null() {
269 None
270 } else {
271 Some(CMBuffer::wrap_under_get_rule(buf))
272 }
273 }
274 }
275
276 #[inline]
277 pub fn copy_head(&self) -> Option<CMBuffer> {
278 unsafe {
279 let buf = CMBufferQueueCopyHead(self.as_concrete_TypeRef());
280 if buf.is_null() {
281 None
282 } else {
283 Some(CMBuffer::wrap_under_create_rule(buf))
284 }
285 }
286 }
287
288 #[inline]
289 pub fn is_empty(&self) -> bool {
290 unsafe { CMBufferQueueIsEmpty(self.as_concrete_TypeRef()) != 0 }
291 }
292
293 #[inline]
294 pub fn mark_end_of_data(&self) -> Result<(), OSStatus> {
295 unsafe {
296 let status = CMBufferQueueMarkEndOfData(self.as_concrete_TypeRef());
297 status_to_result(status)
298 }
299 }
300
301 #[inline]
302 pub fn contains_end_of_data(&self) -> bool {
303 unsafe { CMBufferQueueContainsEndOfData(self.as_concrete_TypeRef()) != 0 }
304 }
305
306 #[inline]
307 pub fn is_at_end_of_data(&self) -> bool {
308 unsafe { CMBufferQueueIsAtEndOfData(self.as_concrete_TypeRef()) != 0 }
309 }
310
311 #[inline]
312 pub fn reset(&self) -> Result<(), OSStatus> {
313 unsafe {
314 let status = CMBufferQueueReset(self.as_concrete_TypeRef());
315 status_to_result(status)
316 }
317 }
318
319 #[inline]
320 pub unsafe fn reset_with_callback(
321 &self,
322 callback: extern "C" fn(buffer: CMBufferRef, refcon: *mut c_void),
323 refcon: Option<*mut c_void>,
324 ) -> Result<(), OSStatus> {
325 unsafe {
326 let status = CMBufferQueueResetWithCallback(self.as_concrete_TypeRef(), callback, refcon.unwrap_or(null_mut()));
327 status_to_result(status)
328 }
329 }
330
331 #[inline]
332 pub fn get_buffer_count(&self) -> CMItemCount {
333 unsafe { CMBufferQueueGetBufferCount(self.as_concrete_TypeRef()) }
334 }
335
336 #[inline]
337 pub fn get_duration(&self) -> CMTime {
338 unsafe { CMBufferQueueGetDuration(self.as_concrete_TypeRef()) }
339 }
340
341 #[inline]
342 pub fn get_min_decode_time_stamp(&self) -> CMTime {
343 unsafe { CMBufferQueueGetMinDecodeTimeStamp(self.as_concrete_TypeRef()) }
344 }
345
346 #[inline]
347 pub fn get_first_decode_time_stamp(&self) -> CMTime {
348 unsafe { CMBufferQueueGetFirstDecodeTimeStamp(self.as_concrete_TypeRef()) }
349 }
350
351 #[inline]
352 pub fn get_min_presentation_time_stamp(&self) -> CMTime {
353 unsafe { CMBufferQueueGetMinPresentationTimeStamp(self.as_concrete_TypeRef()) }
354 }
355
356 #[inline]
357 pub fn get_first_presentation_time_stamp(&self) -> CMTime {
358 unsafe { CMBufferQueueGetFirstPresentationTimeStamp(self.as_concrete_TypeRef()) }
359 }
360
361 #[inline]
362 pub fn get_max_presentation_time_stamp(&self) -> CMTime {
363 unsafe { CMBufferQueueGetMaxPresentationTimeStamp(self.as_concrete_TypeRef()) }
364 }
365
366 #[inline]
367 pub fn get_end_presentation_time_stamp(&self) -> CMTime {
368 unsafe { CMBufferQueueGetEndPresentationTimeStamp(self.as_concrete_TypeRef()) }
369 }
370
371 #[inline]
372 pub fn get_total_size(&self) -> size_t {
373 unsafe { CMBufferQueueGetTotalSize(self.as_concrete_TypeRef()) }
374 }
375
376 pub unsafe fn install_trigger(
377 &self,
378 callback: CMBufferQueueTriggerCallback,
379 refcon: Option<*mut c_void>,
380 condition: CMBufferQueueTriggerCondition,
381 time: CMTime,
382 ) -> Result<CMBufferQueueTriggerToken, OSStatus> {
383 unsafe {
384 let mut token = null();
385 let status = CMBufferQueueInstallTrigger(self.as_concrete_TypeRef(), callback, refcon.unwrap_or(null_mut()), condition, time, &mut token);
386 status_to_result(status).map(|_| token)
387 }
388 }
389
390 pub unsafe fn install_trigger_with_integer_threshold(
391 &self,
392 callback: CMBufferQueueTriggerCallback,
393 refcon: Option<*mut c_void>,
394 condition: CMBufferQueueTriggerCondition,
395 threshold: CMItemCount,
396 ) -> Result<CMBufferQueueTriggerToken, OSStatus> {
397 unsafe {
398 let mut token = null();
399 let status = CMBufferQueueInstallTriggerWithIntegerThreshold(
400 self.as_concrete_TypeRef(),
401 callback,
402 refcon.unwrap_or(null_mut()),
403 condition,
404 threshold,
405 &mut token,
406 );
407 status_to_result(status).map(|_| token)
408 }
409 }
410
411 pub fn install_trigger_closure<F>(
412 &self,
413 condition: CMBufferQueueTriggerCondition,
414 time: CMTime,
415 closure: Option<F>,
416 ) -> Result<CMBufferQueueTriggerToken, OSStatus>
417 where
418 F: Fn(CMBufferQueueTriggerToken) + 'static,
419 {
420 let mut token = null();
421 let handler = closure.map(|closure| {
422 ConcreteBlock::new(move |trigger_token: CMBufferQueueTriggerToken| {
423 closure(trigger_token);
424 })
425 .copy()
426 });
427 let status =
428 unsafe { CMBufferQueueInstallTriggerHandler(self.as_concrete_TypeRef(), condition, time, &mut token, handler.map_or(null(), |h| &*h)) };
429 status_to_result(status).map(|_| token)
430 }
431
432 pub fn install_trigger_with_integer_threshold_closure<F>(
433 &self,
434 condition: CMBufferQueueTriggerCondition,
435 threshold: CMItemCount,
436 closure: Option<F>,
437 ) -> Result<CMBufferQueueTriggerToken, OSStatus>
438 where
439 F: Fn(CMBufferQueueTriggerToken) + 'static,
440 {
441 let mut token = null();
442 let handler = closure.map(|closure| {
443 ConcreteBlock::new(move |trigger_token: CMBufferQueueTriggerToken| {
444 closure(trigger_token);
445 })
446 .copy()
447 });
448 let status = unsafe {
449 CMBufferQueueInstallTriggerHandlerWithIntegerThreshold(
450 self.as_concrete_TypeRef(),
451 condition,
452 threshold,
453 &mut token,
454 handler.map_or(null(), |h| &*h),
455 )
456 };
457 status_to_result(status).map(|_| token)
458 }
459
460 #[inline]
461 pub unsafe fn remove_trigger(&self, token: CMBufferQueueTriggerToken) -> Result<(), OSStatus> {
462 unsafe {
463 let status = CMBufferQueueRemoveTrigger(self.as_concrete_TypeRef(), token);
464 status_to_result(status)
465 }
466 }
467
468 #[inline]
469 pub unsafe fn test_trigger(&self, token: CMBufferQueueTriggerToken) -> bool {
470 unsafe { CMBufferQueueTestTrigger(self.as_concrete_TypeRef(), token) != 0 }
471 }
472
473 #[inline]
474 pub unsafe fn call_for_each_buffer(
475 &self,
476 callback: extern "C" fn(buffer: CMBufferRef, refcon: *mut c_void) -> OSStatus,
477 refcon: Option<*mut c_void>,
478 ) -> Result<(), OSStatus> {
479 unsafe {
480 let status = CMBufferQueueCallForEachBuffer(self.as_concrete_TypeRef(), callback, refcon.unwrap_or(null_mut()));
481 status_to_result(status)
482 }
483 }
484
485 pub unsafe fn set_validation_callback(&self, callback: CMBufferValidationCallback, refcon: Option<*mut c_void>) -> Result<(), OSStatus> {
486 unsafe {
487 let status = CMBufferQueueSetValidationCallback(self.as_concrete_TypeRef(), callback, refcon.unwrap_or(null_mut()));
488 status_to_result(status)
489 }
490 }
491
492 pub fn set_validation_closure<F>(&self, closure: Option<F>) -> Result<(), OSStatus>
493 where
494 F: Fn(CMBufferQueue, CMBuffer) -> OSStatus + 'static,
495 {
496 let handler = closure.map(|closure| {
497 ConcreteBlock::new(move |queue: CMBufferQueueRef, buf: CMBufferRef| {
498 let queue = unsafe { CMBufferQueue::wrap_under_get_rule(queue) };
499 let buf = unsafe { CMBuffer::wrap_under_get_rule(buf) };
500 closure(queue, buf)
501 })
502 .copy()
503 });
504
505 let status = unsafe { CMBufferQueueSetValidationHandler(self.as_concrete_TypeRef(), handler.map_or(null(), |h| &*h)) };
506 status_to_result(status)
507 }
508}