1use std::ptr::{null, null_mut};
2
3use block::{Block, ConcreteBlock};
4use core_audio_types::{AudioBufferList, AudioStreamPacketDescription};
5use core_foundation::{
6 array::{CFArray, CFArrayRef},
7 base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, CFRange, CFType, CFTypeID, OSStatus, TCFType},
8 declare_TCFType,
9 dictionary::CFDictionary,
10 impl_CFTypeDescription, impl_TCFType,
11 string::{CFString, CFStringRef},
12};
13use core_video::image_buffer::{CVImageBuffer, CVImageBufferRef};
14use libc::{c_void, size_t};
15#[cfg(feature = "objc")]
16use objc2::encode::{Encoding, RefEncode};
17
18use crate::{
19 base::{status_to_result, CMItemCount},
20 block_buffer::{CMBlockBuffer, CMBlockBufferRef},
21 format_description::{CMFormatDescription, CMFormatDescriptionRef, CMVideoFormatDescription, CMVideoFormatDescriptionRef},
22 time::CMTime,
23};
24
25pub const kCMSampleBufferError_AllocationFailed: OSStatus = -12730;
26pub const kCMSampleBufferError_RequiredParameterMissing: OSStatus = -12731;
27pub const kCMSampleBufferError_AlreadyHasDataBuffer: OSStatus = -12732;
28pub const kCMSampleBufferError_BufferNotReady: OSStatus = -12733;
29pub const kCMSampleBufferError_SampleIndexOutOfRange: OSStatus = -12734;
30pub const kCMSampleBufferError_BufferHasNoSampleSizes: OSStatus = -12735;
31pub const kCMSampleBufferError_BufferHasNoSampleTimingInfo: OSStatus = -12736;
32pub const kCMSampleBufferError_ArrayTooSmall: OSStatus = -12737;
33pub const kCMSampleBufferError_InvalidEntryCount: OSStatus = -12738;
34pub const kCMSampleBufferError_CannotSubdivide: OSStatus = -12739;
35pub const kCMSampleBufferError_SampleTimingInfoInvalid: OSStatus = -12740;
36pub const kCMSampleBufferError_InvalidMediaTypeForOperation: OSStatus = -12741;
37pub const kCMSampleBufferError_InvalidSampleData: OSStatus = -12742;
38pub const kCMSampleBufferError_InvalidMediaFormat: OSStatus = -12743;
39pub const kCMSampleBufferError_Invalidated: OSStatus = -12744;
40pub const kCMSampleBufferError_DataFailed: OSStatus = -16750;
41pub const kCMSampleBufferError_DataCanceled: OSStatus = -16751;
42
43pub const kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment: u32 = 1 << 0;
44
45#[repr(C)]
46pub struct opaqueCMSampleBuffer(c_void);
47
48pub type CMSampleBufferRef = *mut opaqueCMSampleBuffer;
49
50#[repr(C, packed(4))]
51#[derive(Clone, Copy, Debug, Default, PartialEq)]
52pub struct CMSampleTimingInfo {
53 pub duration: CMTime,
54 pub presentationTimeStamp: CMTime,
55 pub decodeTimeStamp: CMTime,
56}
57
58extern "C" {
59 pub static kCMTimingInfoInvalid: CMSampleTimingInfo;
60}
61
62pub type CMSampleBufferMakeDataReadyCallback = extern "C" fn(CMSampleBufferRef, *mut c_void) -> OSStatus;
63pub type CMSampleBufferMakeDataReadyHandler = *const Block<(CMSampleBufferRef,), OSStatus>;
64
65extern "C" {
66 pub fn CMSampleBufferCreate(
67 allocator: CFAllocatorRef,
68 dataBuffer: CMBlockBufferRef,
69 dataReady: Boolean,
70 makeDataReadyCallback: Option<CMSampleBufferMakeDataReadyCallback>,
71 makeDataReadyRefcon: *mut c_void,
72 formatDescription: CMFormatDescriptionRef,
73 numSamples: CMItemCount,
74 numSampleTimingEntries: CMItemCount,
75 sampleTimingArray: *const CMSampleTimingInfo,
76 numSampleSizeEntries: CMItemCount,
77 sampleSizeArray: *const size_t,
78 sampleBufferOut: *mut CMSampleBufferRef,
79 ) -> OSStatus;
80 pub fn CMSampleBufferCreateWithMakeDataReadyHandler(
81 allocator: CFAllocatorRef,
82 dataBuffer: CMBlockBufferRef,
83 dataReady: Boolean,
84 formatDescription: CMFormatDescriptionRef,
85 numSamples: CMItemCount,
86 numSampleTimingEntries: CMItemCount,
87 sampleTimingArray: *const CMSampleTimingInfo,
88 numSampleSizeEntries: CMItemCount,
89 sampleSizeArray: *const size_t,
90 sampleBufferOut: *mut CMSampleBufferRef,
91 makeDataReadyHandler: CMSampleBufferMakeDataReadyHandler,
92 ) -> OSStatus;
93 pub fn CMSampleBufferCreateReady(
94 allocator: CFAllocatorRef,
95 dataBuffer: CMBlockBufferRef,
96 formatDescription: CMFormatDescriptionRef,
97 numSamples: CMItemCount,
98 numSampleTimingEntries: CMItemCount,
99 sampleTimingArray: *const CMSampleTimingInfo,
100 numSampleSizeEntries: CMItemCount,
101 sampleSizeArray: *const size_t,
102 sampleBufferOut: *mut CMSampleBufferRef,
103 ) -> OSStatus;
104 pub fn CMAudioSampleBufferCreateWithPacketDescriptions(
105 allocator: CFAllocatorRef,
106 dataBuffer: CMBlockBufferRef,
107 dataReady: Boolean,
108 makeDataReadyCallback: Option<CMSampleBufferMakeDataReadyCallback>,
109 makeDataReadyRefcon: *mut c_void,
110 formatDescription: CMFormatDescriptionRef,
111 numSamples: CMItemCount,
112 presentationTimeStamp: CMTime,
113 packetDescriptions: *const AudioStreamPacketDescription,
114 sampleBufferOut: *mut CMSampleBufferRef,
115 ) -> OSStatus;
116 pub fn CMAudioSampleBufferCreateWithPacketDescriptionsAndMakeDataReadyHandler(
117 allocator: CFAllocatorRef,
118 dataBuffer: CMBlockBufferRef,
119 dataReady: Boolean,
120 formatDescription: CMFormatDescriptionRef,
121 numSamples: CMItemCount,
122 presentationTimeStamp: CMTime,
123 packetDescriptions: *const AudioStreamPacketDescription,
124 sampleBufferOut: *mut CMSampleBufferRef,
125 makeDataReadyHandler: CMSampleBufferMakeDataReadyHandler,
126 ) -> OSStatus;
127 pub fn CMAudioSampleBufferCreateReadyWithPacketDescriptions(
128 allocator: CFAllocatorRef,
129 dataBuffer: CMBlockBufferRef,
130 formatDescription: CMFormatDescriptionRef,
131 numSamples: CMItemCount,
132 presentationTimeStamp: CMTime,
133 packetDescriptions: *const AudioStreamPacketDescription,
134 sampleBufferOut: *mut CMSampleBufferRef,
135 ) -> OSStatus;
136 pub fn CMSampleBufferCreateForImageBuffer(
137 allocator: CFAllocatorRef,
138 imageBuffer: CVImageBufferRef,
139 dataReady: Boolean,
140 makeDataReadyCallback: Option<CMSampleBufferMakeDataReadyCallback>,
141 makeDataReadyRefcon: *mut c_void,
142 formatDescription: CMVideoFormatDescriptionRef,
143 sampleTiming: *const CMSampleTimingInfo,
144 sampleBufferOut: *mut CMSampleBufferRef,
145 ) -> OSStatus;
146 pub fn CMSampleBufferCreateForImageBufferWithMakeDataReadyHandler(
147 allocator: CFAllocatorRef,
148 imageBuffer: CVImageBufferRef,
149 dataReady: Boolean,
150 formatDescription: CMVideoFormatDescriptionRef,
151 sampleTiming: *const CMSampleTimingInfo,
152 sampleBufferOut: *mut CMSampleBufferRef,
153 makeDataReadyHandler: CMSampleBufferMakeDataReadyHandler,
154 ) -> OSStatus;
155 pub fn CMSampleBufferCreateReadyWithImageBuffer(
156 allocator: CFAllocatorRef,
157 imageBuffer: CVImageBufferRef,
158 formatDescription: CMVideoFormatDescriptionRef,
159 sampleTiming: *const CMSampleTimingInfo,
160 sampleBufferOut: *mut CMSampleBufferRef,
161 ) -> OSStatus;
162 pub fn CMSampleBufferCreateCopy(allocator: CFAllocatorRef, sbuf: CMSampleBufferRef, sampleBufferOut: *mut CMSampleBufferRef) -> OSStatus;
163 pub fn CMSampleBufferCreateCopyWithNewTiming(
164 allocator: CFAllocatorRef,
165 originalSBuf: CMSampleBufferRef,
166 numSampleTimingEntries: CMItemCount,
167 sampleTimingArray: *const CMSampleTimingInfo,
168 sampleBufferOut: *mut CMSampleBufferRef,
169 ) -> OSStatus;
170 pub fn CMSampleBufferCopySampleBufferForRange(
171 allocator: CFAllocatorRef,
172 sbuf: CMSampleBufferRef,
173 sampleRange: CFRange,
174 sampleBufferOut: *mut CMSampleBufferRef,
175 ) -> OSStatus;
176 pub fn CMSampleBufferGetTypeID() -> CFTypeID;
177 pub fn CMSampleBufferSetDataBuffer(sbuf: CMSampleBufferRef, dataBuffer: CMBlockBufferRef) -> OSStatus;
178 pub fn CMSampleBufferGetDataBuffer(sbuf: CMSampleBufferRef) -> CMBlockBufferRef;
179 pub fn CMSampleBufferGetImageBuffer(sbuf: CMSampleBufferRef) -> CVImageBufferRef;
180 pub fn CMSampleBufferSetDataBufferFromAudioBufferList(
181 sbuf: CMSampleBufferRef,
182 blockBufferStructureAllocator: CFAllocatorRef,
183 blockBufferBlockAllocator: CFAllocatorRef,
184 flags: u32,
185 bufferList: *const AudioBufferList,
186 ) -> OSStatus;
187 pub fn CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
188 sbuf: CMSampleBufferRef,
189 bufferListSizeNeededOut: *mut size_t,
190 bufferListOut: *mut AudioBufferList,
191 bufferListSize: size_t,
192 blockBufferStructureAllocator: CFAllocatorRef,
193 blockBufferBlockAllocator: CFAllocatorRef,
194 flags: u32,
195 blockBufferOut: *mut CMBlockBufferRef,
196 ) -> OSStatus;
197 pub fn CMSampleBufferGetAudioStreamPacketDescriptions(
198 sbuf: CMSampleBufferRef,
199 packetDescriptionsSize: size_t,
200 packetDescriptionsOut: *mut AudioStreamPacketDescription,
201 packetDescriptionsSizeNeededOut: *mut size_t,
202 ) -> OSStatus;
203 pub fn CMSampleBufferGetAudioStreamPacketDescriptionsPtr(
204 sbuf: CMSampleBufferRef,
205 packetDescriptionsPointerOut: *mut *mut AudioStreamPacketDescription,
206 packetDescriptionsSizeOut: *mut size_t,
207 ) -> OSStatus;
208 pub fn CMSampleBufferCopyPCMDataIntoAudioBufferList(
209 sbuf: CMSampleBufferRef,
210 frameOffset: i32,
211 numFrames: i32,
212 bufferList: *mut AudioBufferList,
213 ) -> OSStatus;
214 pub fn CMSampleBufferSetDataReady(sbuf: CMSampleBufferRef) -> OSStatus;
215 pub fn CMSampleBufferDataIsReady(sbuf: CMSampleBufferRef) -> Boolean;
216 pub fn CMSampleBufferSetDataFailed(sbuf: CMSampleBufferRef, status: OSStatus) -> OSStatus;
217 pub fn CMSampleBufferHasDataFailed(sbuf: CMSampleBufferRef, statusOut: *mut OSStatus) -> Boolean;
218 pub fn CMSampleBufferMakeDataReady(sbuf: CMSampleBufferRef) -> OSStatus;
219 pub fn CMSampleBufferTrackDataReadiness(sbuf: CMSampleBufferRef, sampleBufferToTrack: CMSampleBufferRef) -> OSStatus;
220 pub fn CMSampleBufferInvalidate(sbuf: CMSampleBufferRef) -> OSStatus;
221}
222
223pub type CMSampleBufferInvalidateCallback = extern "C" fn(CMSampleBufferRef, u64);
224pub type CMSampleBufferInvalidateHandler = *const Block<(CMSampleBufferRef,), ()>;
225
226extern "C" {
227 pub fn CMSampleBufferSetInvalidateCallback(
228 sbuf: CMSampleBufferRef,
229 invalidateCallback: CMSampleBufferInvalidateCallback,
230 invalidateRefCon: u64,
231 ) -> OSStatus;
232 pub fn CMSampleBufferSetInvalidateHandler(sbuf: CMSampleBufferRef, invalidateHandler: CMSampleBufferInvalidateHandler) -> OSStatus;
233 pub fn CMSampleBufferIsValid(sbuf: CMSampleBufferRef) -> Boolean;
234
235 pub static kCMSampleBufferNotification_DataBecameReady: CFStringRef;
236 pub static kCMSampleBufferNotification_DataFailed: CFStringRef;
237 pub static kCMSampleBufferNotificationParameter_OSStatus: CFStringRef;
238 pub static kCMSampleBufferConduitNotification_InhibitOutputUntil: CFStringRef;
239 pub static kCMSampleBufferConduitNotificationParameter_ResumeTag: CFStringRef;
240 pub static kCMSampleBufferConduitNotification_ResetOutput: CFStringRef;
241 pub static kCMSampleBufferConduitNotification_UpcomingOutputPTSRangeChanged: CFStringRef;
242 pub static kCMSampleBufferConduitNotificationParameter_UpcomingOutputPTSRangeMayOverlapQueuedOutputPTSRange: CFStringRef;
243 pub static kCMSampleBufferConduitNotificationParameter_MinUpcomingOutputPTS: CFStringRef;
244 pub static kCMSampleBufferConduitNotificationParameter_MaxUpcomingOutputPTS: CFStringRef;
245 pub static kCMSampleBufferConsumerNotification_BufferConsumed: CFStringRef;
246
247 pub fn CMSampleBufferGetNumSamples(sbuf: CMSampleBufferRef) -> CMItemCount;
248 pub fn CMSampleBufferGetDuration(sbuf: CMSampleBufferRef) -> CMTime;
249 pub fn CMSampleBufferGetPresentationTimeStamp(sbuf: CMSampleBufferRef) -> CMTime;
250 pub fn CMSampleBufferGetDecodeTimeStamp(sbuf: CMSampleBufferRef) -> CMTime;
251 pub fn CMSampleBufferGetOutputDuration(sbuf: CMSampleBufferRef) -> CMTime;
252 pub fn CMSampleBufferGetOutputPresentationTimeStamp(sbuf: CMSampleBufferRef) -> CMTime;
253 pub fn CMSampleBufferSetOutputPresentationTimeStamp(sbuf: CMSampleBufferRef, outputPresentationTimeStamp: CMTime) -> OSStatus;
254 pub fn CMSampleBufferGetOutputDecodeTimeStamp(sbuf: CMSampleBufferRef) -> CMTime;
255 pub fn CMSampleBufferGetSampleTimingInfoArray(
256 sbuf: CMSampleBufferRef,
257 numSampleTimingEntries: CMItemCount,
258 timingArrayOut: *mut CMSampleTimingInfo,
259 timingArrayEntriesNeededOut: *mut CMItemCount,
260 ) -> OSStatus;
261 pub fn CMSampleBufferGetSampleTimingInfo(sbuf: CMSampleBufferRef, sampleIndex: CMItemCount, timingInfoOut: *mut CMSampleTimingInfo) -> OSStatus;
262 pub fn CMSampleBufferGetSampleSizeArray(
263 sbuf: CMSampleBufferRef,
264 sizeArrayEntries: CMItemCount,
265 sizeArrayOut: *mut size_t,
266 sizeArrayEntriesNeededOut: *mut CMItemCount,
267 ) -> OSStatus;
268 pub fn CMSampleBufferGetSampleSize(sbuf: CMSampleBufferRef, sampleIndex: CMItemCount) -> size_t;
269 pub fn CMSampleBufferGetTotalSampleSize(sbuf: CMSampleBufferRef) -> size_t;
270 pub fn CMSampleBufferGetFormatDescription(sbuf: CMSampleBufferRef) -> CMFormatDescriptionRef;
271 pub fn CMSampleBufferGetSampleAttachmentsArray(sbuf: CMSampleBufferRef, createIfNecessary: Boolean) -> CFArrayRef;
272
273 pub static kCMSampleAttachmentKey_NotSync: CFStringRef;
274 pub static kCMSampleAttachmentKey_PartialSync: CFStringRef;
275 pub static kCMSampleAttachmentKey_HasRedundantCoding: CFStringRef;
276 pub static kCMSampleAttachmentKey_IsDependedOnByOthers: CFStringRef;
277 pub static kCMSampleAttachmentKey_DependsOnOthers: CFStringRef;
278 pub static kCMSampleAttachmentKey_EarlierDisplayTimesAllowed: CFStringRef;
279 pub static kCMSampleAttachmentKey_DisplayImmediately: CFStringRef;
280 pub static kCMSampleAttachmentKey_DoNotDisplay: CFStringRef;
281 pub static kCMSampleBufferAttachmentKey_ResetDecoderBeforeDecoding: CFStringRef;
282 pub static kCMSampleBufferAttachmentKey_DrainAfterDecoding: CFStringRef;
283 pub static kCMSampleBufferAttachmentKey_PostNotificationWhenConsumed: CFStringRef;
284 pub static kCMSampleBufferAttachmentKey_ResumeOutput: CFStringRef;
285 pub static kCMSampleAttachmentKey_HEVCTemporalLevelInfo: CFStringRef;
286 pub static kCMHEVCTemporalLevelInfoKey_TemporalLevel: CFStringRef;
287 pub static kCMHEVCTemporalLevelInfoKey_ProfileSpace: CFStringRef;
288 pub static kCMHEVCTemporalLevelInfoKey_TierFlag: CFStringRef;
289 pub static kCMHEVCTemporalLevelInfoKey_ProfileIndex: CFStringRef;
290 pub static kCMHEVCTemporalLevelInfoKey_ProfileCompatibilityFlags: CFStringRef;
291 pub static kCMHEVCTemporalLevelInfoKey_ConstraintIndicatorFlags: CFStringRef;
292 pub static kCMHEVCTemporalLevelInfoKey_LevelIndex: CFStringRef;
293 pub static kCMSampleAttachmentKey_HEVCTemporalSubLayerAccess: CFStringRef;
294 pub static kCMSampleAttachmentKey_HEVCStepwiseTemporalSubLayerAccess: CFStringRef;
295 pub static kCMSampleAttachmentKey_HEVCSyncSampleNALUnitType: CFStringRef;
296 pub static kCMSampleAttachmentKey_AudioIndependentSampleDecoderRefreshCount: CFStringRef;
297 pub static kCMSampleBufferAttachmentKey_TransitionID: CFStringRef;
298 pub static kCMSampleBufferAttachmentKey_TrimDurationAtStart: CFStringRef;
299 pub static kCMSampleBufferAttachmentKey_TrimDurationAtEnd: CFStringRef;
300 pub static kCMSampleBufferAttachmentKey_SpeedMultiplier: CFStringRef;
301 pub static kCMSampleBufferAttachmentKey_Reverse: CFStringRef;
302 pub static kCMSampleBufferAttachmentKey_FillDiscontinuitiesWithSilence: CFStringRef;
303 pub static kCMSampleBufferAttachmentKey_EmptyMedia: CFStringRef;
304 pub static kCMSampleBufferAttachmentKey_PermanentEmptyMedia: CFStringRef;
305 pub static kCMSampleBufferAttachmentKey_DisplayEmptyMediaImmediately: CFStringRef;
306 pub static kCMSampleBufferAttachmentKey_EndsPreviousSampleDuration: CFStringRef;
307 pub static kCMSampleBufferAttachmentKey_SampleReferenceURL: CFStringRef;
308 pub static kCMSampleBufferAttachmentKey_SampleReferenceByteOffset: CFStringRef;
309 pub static kCMSampleBufferAttachmentKey_GradualDecoderRefresh: CFStringRef;
310 pub static kCMSampleBufferAttachmentKey_DroppedFrameReason: CFStringRef;
311 pub static kCMSampleBufferDroppedFrameReason_FrameWasLate: CFStringRef;
312 pub static kCMSampleBufferDroppedFrameReason_OutOfBuffers: CFStringRef;
313 pub static kCMSampleBufferDroppedFrameReason_Discontinuity: CFStringRef;
314 pub static kCMSampleBufferAttachmentKey_DroppedFrameReasonInfo: CFStringRef;
315 pub static kCMSampleBufferDroppedFrameReasonInfo_CameraModeSwitch: CFStringRef;
316 pub static kCMSampleBufferAttachmentKey_StillImageLensStabilizationInfo: CFStringRef;
317 pub static kCMSampleBufferLensStabilizationInfo_Active: CFStringRef;
318 pub static kCMSampleBufferLensStabilizationInfo_OutOfRange: CFStringRef;
319 pub static kCMSampleBufferLensStabilizationInfo_Unavailable: CFStringRef;
320 pub static kCMSampleBufferLensStabilizationInfo_Off: CFStringRef;
321 pub static kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix: CFStringRef;
322 pub static kCMSampleBufferAttachmentKey_ForceKeyFrame: CFStringRef;
323 pub static kCMSampleAttachmentKey_CryptorSubsampleAuxiliaryData: CFStringRef;
324 pub static kCMSampleAttachmentKey_HDR10PlusPerFrameData: CFStringRef;
325
326 pub fn CMSampleBufferCallForEachSample(
327 sbuf: CMSampleBufferRef,
328 callback: extern "C" fn(CMSampleBufferRef, CMItemCount, *mut c_void) -> OSStatus,
329 refcon: *mut c_void,
330 ) -> OSStatus;
331 pub fn CMSampleBufferCallBlockForEachSample(sbuf: CMSampleBufferRef, block: *const Block<(CMSampleBufferRef, CMItemCount), OSStatus>)
332 -> OSStatus;
333}
334
335#[cfg(feature = "objc")]
336unsafe impl RefEncode for opaqueCMSampleBuffer {
337 const ENCODING_REF: Encoding = Encoding::Pointer(&Encoding::Struct("opaqueCMSampleBuffer", &[]));
338}
339
340declare_TCFType!(CMSampleBuffer, CMSampleBufferRef);
341impl_TCFType!(CMSampleBuffer, CMSampleBufferRef, CMSampleBufferGetTypeID);
342impl_CFTypeDescription!(CMSampleBuffer);
343
344impl CMSampleBuffer {
345 #[inline]
346 pub unsafe fn new(
347 data_buffer: Option<&CMBlockBuffer>,
348 data_ready: bool,
349 make_data_ready_callback: Option<CMSampleBufferMakeDataReadyCallback>,
350 make_data_ready_refcon: Option<*mut c_void>,
351 format_description: Option<&CMFormatDescription>,
352 num_samples: CMItemCount,
353 sample_timing_array: Option<&[CMSampleTimingInfo]>,
354 sample_size_array: Option<&[size_t]>,
355 ) -> Result<CMSampleBuffer, OSStatus> {
356 let mut sample_buffer: CMSampleBufferRef = null_mut();
357 let status = unsafe {
358 CMSampleBufferCreate(
359 kCFAllocatorDefault,
360 data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
361 data_ready as Boolean,
362 make_data_ready_callback,
363 make_data_ready_refcon.unwrap_or(null_mut()),
364 format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
365 num_samples,
366 sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
367 sample_timing_array.map_or(null(), |a| a.as_ptr()),
368 sample_size_array.map_or(0, |a| a.len() as CMItemCount),
369 sample_size_array.map_or(null(), |a| a.as_ptr()),
370 &mut sample_buffer,
371 )
372 };
373 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
374 }
375
376 #[inline]
377 pub fn new_with_make_data_ready_closure<F>(
378 data_buffer: Option<&CMBlockBuffer>,
379 data_ready: bool,
380 format_description: Option<&CMFormatDescription>,
381 num_samples: CMItemCount,
382 sample_timing_array: Option<&[CMSampleTimingInfo]>,
383 sample_size_array: Option<&[size_t]>,
384 make_data_ready_closure: Option<F>,
385 ) -> Result<CMSampleBuffer, OSStatus>
386 where
387 F: Fn(CMSampleBuffer) -> OSStatus + 'static,
388 {
389 let mut sample_buffer: CMSampleBufferRef = null_mut();
390 let handler = make_data_ready_closure.map(|closure| {
391 ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
392 let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
393 closure(sbuf)
394 })
395 .copy()
396 });
397 let status = unsafe {
398 CMSampleBufferCreateWithMakeDataReadyHandler(
399 kCFAllocatorDefault,
400 data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
401 data_ready as Boolean,
402 format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
403 num_samples,
404 sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
405 sample_timing_array.map_or(null(), |a| a.as_ptr()),
406 sample_size_array.map_or(0, |a| a.len() as CMItemCount),
407 sample_size_array.map_or(null(), |a| a.as_ptr()),
408 &mut sample_buffer,
409 handler.map_or(null(), |h| &*h),
410 )
411 };
412 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
413 }
414
415 #[inline]
416 pub fn new_ready(
417 data_buffer: &CMBlockBuffer,
418 format_description: Option<&CMFormatDescription>,
419 num_samples: CMItemCount,
420 sample_timing_array: Option<&[CMSampleTimingInfo]>,
421 sample_size_array: Option<&[size_t]>,
422 ) -> Result<CMSampleBuffer, OSStatus> {
423 let mut sample_buffer: CMSampleBufferRef = null_mut();
424 let status = unsafe {
425 CMSampleBufferCreateReady(
426 kCFAllocatorDefault,
427 data_buffer.as_concrete_TypeRef(),
428 format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
429 num_samples,
430 sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
431 sample_timing_array.map_or(null(), |a| a.as_ptr()),
432 sample_size_array.map_or(0, |a| a.len() as CMItemCount),
433 sample_size_array.map_or(null(), |a| a.as_ptr()),
434 &mut sample_buffer,
435 )
436 };
437 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
438 }
439
440 pub unsafe fn new_audio_sample_buffer_with_packet_descriptions(
441 data_buffer: Option<&CMBlockBuffer>,
442 data_ready: bool,
443 make_data_ready_callback: Option<CMSampleBufferMakeDataReadyCallback>,
444 make_data_ready_refcon: Option<*mut c_void>,
445 format_description: &CMFormatDescription,
446 num_samples: CMItemCount,
447 presentation_time_stamp: CMTime,
448 packet_descriptions: Option<&[AudioStreamPacketDescription]>,
449 ) -> Result<CMSampleBuffer, OSStatus> {
450 let mut sample_buffer: CMSampleBufferRef = null_mut();
451 let status = unsafe {
452 CMAudioSampleBufferCreateWithPacketDescriptions(
453 kCFAllocatorDefault,
454 data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
455 data_ready as Boolean,
456 make_data_ready_callback,
457 make_data_ready_refcon.unwrap_or(null_mut()),
458 format_description.as_concrete_TypeRef(),
459 num_samples,
460 presentation_time_stamp,
461 packet_descriptions.map_or(null(), |a| a.as_ptr()),
462 &mut sample_buffer,
463 )
464 };
465 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
466 }
467
468 pub fn new_audio_sample_buffer_with_packet_descriptions_and_make_data_ready_closure<F>(
469 data_buffer: Option<&CMBlockBuffer>,
470 data_ready: bool,
471 format_description: &CMFormatDescription,
472 num_samples: CMItemCount,
473 presentation_time_stamp: CMTime,
474 packet_descriptions: Option<&[AudioStreamPacketDescription]>,
475 make_data_ready_closure: Option<F>,
476 ) -> Result<CMSampleBuffer, OSStatus>
477 where
478 F: Fn(CMSampleBuffer) -> OSStatus + 'static,
479 {
480 let mut sample_buffer: CMSampleBufferRef = null_mut();
481 let handler = make_data_ready_closure.map(|closure| {
482 ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
483 let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
484 closure(sbuf)
485 })
486 .copy()
487 });
488 let status = unsafe {
489 CMAudioSampleBufferCreateWithPacketDescriptionsAndMakeDataReadyHandler(
490 kCFAllocatorDefault,
491 data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
492 data_ready as Boolean,
493 format_description.as_concrete_TypeRef(),
494 num_samples,
495 presentation_time_stamp,
496 packet_descriptions.map_or(null(), |a| a.as_ptr()),
497 &mut sample_buffer,
498 handler.map_or(null(), |h| &*h),
499 )
500 };
501 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
502 }
503
504 #[inline]
505 pub fn new_audio_sample_buffer_ready_with_packet_descriptions(
506 data_buffer: &CMBlockBuffer,
507 format_description: &CMFormatDescription,
508 num_samples: CMItemCount,
509 presentation_time_stamp: CMTime,
510 packet_descriptions: Option<&[AudioStreamPacketDescription]>,
511 ) -> Result<CMSampleBuffer, OSStatus> {
512 let mut sample_buffer: CMSampleBufferRef = null_mut();
513 let status = unsafe {
514 CMAudioSampleBufferCreateReadyWithPacketDescriptions(
515 kCFAllocatorDefault,
516 data_buffer.as_concrete_TypeRef(),
517 format_description.as_concrete_TypeRef(),
518 num_samples,
519 presentation_time_stamp,
520 packet_descriptions.map_or(null(), |a| a.as_ptr()),
521 &mut sample_buffer,
522 )
523 };
524 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
525 }
526
527 pub unsafe fn from_image_buffer(
528 image_buffer: &CVImageBuffer,
529 data_ready: bool,
530 make_data_ready_callback: Option<CMSampleBufferMakeDataReadyCallback>,
531 make_data_ready_refcon: Option<*mut c_void>,
532 format_description: &CMVideoFormatDescription,
533 sample_timing: &CMSampleTimingInfo,
534 ) -> Result<CMSampleBuffer, OSStatus> {
535 let mut sample_buffer: CMSampleBufferRef = null_mut();
536 let status = CMSampleBufferCreateForImageBuffer(
537 kCFAllocatorDefault,
538 image_buffer.as_concrete_TypeRef(),
539 data_ready as Boolean,
540 make_data_ready_callback,
541 make_data_ready_refcon.unwrap_or(null_mut()),
542 format_description.as_concrete_TypeRef(),
543 sample_timing,
544 &mut sample_buffer,
545 );
546 status_to_result(status).map(|_| CMSampleBuffer::wrap_under_create_rule(sample_buffer))
547 }
548
549 pub fn from_image_buffer_with_make_data_ready_closure<F>(
550 image_buffer: &CVImageBuffer,
551 data_ready: bool,
552 format_description: &CMVideoFormatDescription,
553 sample_timing: &CMSampleTimingInfo,
554 make_data_ready_closure: Option<F>,
555 ) -> Result<CMSampleBuffer, OSStatus>
556 where
557 F: Fn(CMSampleBuffer) -> OSStatus + 'static,
558 {
559 let mut sample_buffer: CMSampleBufferRef = null_mut();
560 let handler = make_data_ready_closure.map(|closure| {
561 ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
562 let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
563 closure(sbuf)
564 })
565 .copy()
566 });
567 let status = unsafe {
568 CMSampleBufferCreateForImageBufferWithMakeDataReadyHandler(
569 kCFAllocatorDefault,
570 image_buffer.as_concrete_TypeRef(),
571 data_ready as Boolean,
572 format_description.as_concrete_TypeRef(),
573 sample_timing,
574 &mut sample_buffer,
575 handler.map_or(null(), |h| &*h),
576 )
577 };
578 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
579 }
580
581 #[inline]
582 pub fn from_image_buffer_ready(
583 image_buffer: &CVImageBuffer,
584 format_description: &CMVideoFormatDescription,
585 sample_timing: &CMSampleTimingInfo,
586 ) -> Result<CMSampleBuffer, OSStatus> {
587 let mut sample_buffer: CMSampleBufferRef = null_mut();
588 let status = unsafe {
589 CMSampleBufferCreateReadyWithImageBuffer(
590 kCFAllocatorDefault,
591 image_buffer.as_concrete_TypeRef(),
592 format_description.as_concrete_TypeRef(),
593 sample_timing,
594 &mut sample_buffer,
595 )
596 };
597 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
598 }
599
600 #[inline]
601 pub fn copy(&self) -> Result<CMSampleBuffer, OSStatus> {
602 let mut sample_buffer: CMSampleBufferRef = null_mut();
603 let status = unsafe { CMSampleBufferCreateCopy(kCFAllocatorDefault, self.as_concrete_TypeRef(), &mut sample_buffer) };
604 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
605 }
606
607 #[inline]
608 pub fn copy_with_new_timing(&self, sample_timing_array: Option<&[CMSampleTimingInfo]>) -> Result<CMSampleBuffer, OSStatus> {
609 let mut sample_buffer: CMSampleBufferRef = null_mut();
610 let status = unsafe {
611 CMSampleBufferCreateCopyWithNewTiming(
612 kCFAllocatorDefault,
613 self.as_concrete_TypeRef(),
614 sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
615 sample_timing_array.map_or(null(), |a| a.as_ptr()),
616 &mut sample_buffer,
617 )
618 };
619 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
620 }
621
622 #[inline]
623 pub fn copy_for_range(&self, sample_range: CFRange) -> Result<CMSampleBuffer, OSStatus> {
624 let mut sample_buffer: CMSampleBufferRef = null_mut();
625 let status =
626 unsafe { CMSampleBufferCopySampleBufferForRange(kCFAllocatorDefault, self.as_concrete_TypeRef(), sample_range, &mut sample_buffer) };
627 status_to_result(status).map(|_| unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
628 }
629
630 #[inline]
631 pub fn set_data_buffer(&self, data_buffer: &CMBlockBuffer) -> Result<(), OSStatus> {
632 let status = unsafe { CMSampleBufferSetDataBuffer(self.as_concrete_TypeRef(), data_buffer.as_concrete_TypeRef()) };
633 status_to_result(status)
634 }
635
636 #[inline]
637 pub fn get_data_buffer(&self) -> Option<CMBlockBuffer> {
638 unsafe {
639 let data_buffer = CMSampleBufferGetDataBuffer(self.as_concrete_TypeRef());
640 if data_buffer.is_null() {
641 None
642 } else {
643 Some(TCFType::wrap_under_get_rule(data_buffer))
644 }
645 }
646 }
647
648 #[inline]
649 pub fn get_image_buffer(&self) -> Option<CVImageBuffer> {
650 unsafe {
651 let image_buffer = CMSampleBufferGetImageBuffer(self.as_concrete_TypeRef());
652 if image_buffer.is_null() {
653 None
654 } else {
655 Some(CVImageBuffer::wrap_under_get_rule(image_buffer))
656 }
657 }
658 }
659
660 #[inline]
661 pub fn set_data_buffer_from_audio_buffer_list(&self, flags: u32, buffer_list: &AudioBufferList) -> Result<(), OSStatus> {
662 let status = unsafe {
663 CMSampleBufferSetDataBufferFromAudioBufferList(self.as_concrete_TypeRef(), kCFAllocatorDefault, kCFAllocatorDefault, flags, buffer_list)
664 };
665 status_to_result(status)
666 }
667
668 #[inline]
669 pub fn set_data_ready(&self) -> Result<(), OSStatus> {
670 let status = unsafe { CMSampleBufferSetDataReady(self.as_concrete_TypeRef()) };
671 status_to_result(status)
672 }
673
674 #[inline]
675 pub fn is_data_ready(&self) -> bool {
676 unsafe { CMSampleBufferDataIsReady(self.as_concrete_TypeRef()) != 0 }
677 }
678
679 #[inline]
680 pub fn set_data_failed(&self, status: OSStatus) -> Result<(), OSStatus> {
681 let status = unsafe { CMSampleBufferSetDataFailed(self.as_concrete_TypeRef(), status) };
682 status_to_result(status)
683 }
684
685 #[inline]
686 pub fn has_data_failed(&self) -> (OSStatus, bool) {
687 let mut status = 0;
688 let has_failed = unsafe { CMSampleBufferHasDataFailed(self.as_concrete_TypeRef(), &mut status) != 0 };
689 (status, has_failed)
690 }
691
692 #[inline]
693 pub fn make_data_ready(&self) -> Result<(), OSStatus> {
694 let status = unsafe { CMSampleBufferMakeDataReady(self.as_concrete_TypeRef()) };
695 status_to_result(status)
696 }
697
698 #[inline]
699 pub fn track_data_readiness(&self, sample_buffer_to_track: &CMSampleBuffer) -> Result<(), OSStatus> {
700 let status = unsafe { CMSampleBufferTrackDataReadiness(self.as_concrete_TypeRef(), sample_buffer_to_track.as_concrete_TypeRef()) };
701 status_to_result(status)
702 }
703
704 #[inline]
705 pub fn invalidate(&self) -> Result<(), OSStatus> {
706 let status = unsafe { CMSampleBufferInvalidate(self.as_concrete_TypeRef()) };
707 status_to_result(status)
708 }
709
710 pub unsafe fn set_invalidate_callback(
711 &self,
712 invalidate_callback: CMSampleBufferInvalidateCallback,
713 invalidate_ref_con: u64,
714 ) -> Result<(), OSStatus> {
715 let status = unsafe { CMSampleBufferSetInvalidateCallback(self.as_concrete_TypeRef(), invalidate_callback, invalidate_ref_con) };
716 status_to_result(status)
717 }
718
719 pub fn set_invalidate_closure<F>(&self, invalidate_closure: Option<F>) -> Result<(), OSStatus>
720 where
721 F: Fn(CMSampleBuffer) + 'static,
722 {
723 let status = unsafe {
724 CMSampleBufferSetInvalidateHandler(
725 self.as_concrete_TypeRef(),
726 invalidate_closure
727 .map(|closure| {
728 ConcreteBlock::new(move |sbuf: CMSampleBufferRef| {
729 let sbuf = CMSampleBuffer::wrap_under_get_rule(sbuf);
730 closure(sbuf);
731 })
732 .copy()
733 })
734 .map_or(null(), |h| &*h),
735 )
736 };
737 status_to_result(status)
738 }
739
740 #[inline]
741 pub fn is_valid(&self) -> bool {
742 unsafe { CMSampleBufferIsValid(self.as_concrete_TypeRef()) != 0 }
743 }
744
745 #[inline]
746 pub fn get_num_samples(&self) -> CMItemCount {
747 unsafe { CMSampleBufferGetNumSamples(self.as_concrete_TypeRef()) }
748 }
749
750 #[inline]
751 pub fn get_duration(&self) -> CMTime {
752 unsafe { CMSampleBufferGetDuration(self.as_concrete_TypeRef()) }
753 }
754
755 #[inline]
756 pub fn get_presentation_time_stamp(&self) -> CMTime {
757 unsafe { CMSampleBufferGetPresentationTimeStamp(self.as_concrete_TypeRef()) }
758 }
759
760 #[inline]
761 pub fn get_decode_time_stamp(&self) -> CMTime {
762 unsafe { CMSampleBufferGetDecodeTimeStamp(self.as_concrete_TypeRef()) }
763 }
764
765 #[inline]
766 pub fn get_output_duration(&self) -> CMTime {
767 unsafe { CMSampleBufferGetOutputDuration(self.as_concrete_TypeRef()) }
768 }
769
770 #[inline]
771 pub fn get_output_presentation_time_stamp(&self) -> CMTime {
772 unsafe { CMSampleBufferGetOutputPresentationTimeStamp(self.as_concrete_TypeRef()) }
773 }
774
775 #[inline]
776 pub fn set_output_presentation_time_stamp(&self, output_presentation_time_stamp: CMTime) -> Result<(), OSStatus> {
777 let status = unsafe { CMSampleBufferSetOutputPresentationTimeStamp(self.as_concrete_TypeRef(), output_presentation_time_stamp) };
778 status_to_result(status)
779 }
780
781 #[inline]
782 pub fn get_output_decode_time_stamp(&self) -> CMTime {
783 unsafe { CMSampleBufferGetOutputDecodeTimeStamp(self.as_concrete_TypeRef()) }
784 }
785
786 #[inline]
787 pub fn get_sample_timing_info_array(&self) -> Option<Vec<CMSampleTimingInfo>> {
788 unsafe {
789 let mut timing_array_entries_needed = 0;
790 let status = CMSampleBufferGetSampleTimingInfoArray(self.as_concrete_TypeRef(), 0, null_mut(), &mut timing_array_entries_needed);
791 if status != 0 {
792 return None;
793 }
794 let mut timing_array = vec![CMSampleTimingInfo::default(); timing_array_entries_needed as usize];
795 let status = CMSampleBufferGetSampleTimingInfoArray(
796 self.as_concrete_TypeRef(),
797 timing_array_entries_needed,
798 timing_array.as_mut_ptr(),
799 &mut timing_array_entries_needed,
800 );
801 if status != 0 {
802 return None;
803 }
804 Some(timing_array)
805 }
806 }
807
808 #[inline]
809 pub fn get_sample_timing_info(&self, sample_index: CMItemCount) -> Option<CMSampleTimingInfo> {
810 unsafe {
811 let mut timing_info = CMSampleTimingInfo::default();
812 let status = CMSampleBufferGetSampleTimingInfo(self.as_concrete_TypeRef(), sample_index, &mut timing_info);
813 if status == 0 {
814 Some(timing_info)
815 } else {
816 None
817 }
818 }
819 }
820
821 #[inline]
822 pub fn get_sample_size_array(&self) -> Option<Vec<size_t>> {
823 unsafe {
824 let mut size_array_entries_needed = 0;
825 let status = CMSampleBufferGetSampleSizeArray(self.as_concrete_TypeRef(), 0, null_mut(), &mut size_array_entries_needed);
826 if status != 0 {
827 return None;
828 }
829 let mut size_array = vec![0; size_array_entries_needed as usize];
830 let status = CMSampleBufferGetSampleSizeArray(
831 self.as_concrete_TypeRef(),
832 size_array_entries_needed,
833 size_array.as_mut_ptr(),
834 &mut size_array_entries_needed,
835 );
836 if status != 0 {
837 return None;
838 }
839 Some(size_array)
840 }
841 }
842
843 #[inline]
844 pub fn get_sample_size(&self, sample_index: CMItemCount) -> size_t {
845 unsafe { CMSampleBufferGetSampleSize(self.as_concrete_TypeRef(), sample_index) }
846 }
847
848 #[inline]
849 pub fn get_total_sample_size(&self) -> usize {
850 unsafe { CMSampleBufferGetTotalSampleSize(self.as_concrete_TypeRef()) }
851 }
852
853 #[inline]
854 pub fn get_format_description(&self) -> Option<CMFormatDescription> {
855 unsafe {
856 let format_description = CMSampleBufferGetFormatDescription(self.as_concrete_TypeRef());
857 if format_description.is_null() {
858 None
859 } else {
860 Some(TCFType::wrap_under_get_rule(format_description))
861 }
862 }
863 }
864
865 #[inline]
866 pub fn get_sample_attachments_array(&self, create_if_necessary: bool) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
867 unsafe {
868 let attachments = CMSampleBufferGetSampleAttachmentsArray(self.as_concrete_TypeRef(), create_if_necessary as Boolean);
869 if attachments.is_null() {
870 None
871 } else {
872 Some(TCFType::wrap_under_get_rule(attachments))
873 }
874 }
875 }
876
877 pub unsafe fn call_for_each_sample(
878 &self,
879 callback: extern "C" fn(CMSampleBufferRef, CMItemCount, *mut c_void) -> OSStatus,
880 refcon: Option<*mut c_void>,
881 ) -> Result<(), OSStatus> {
882 let status = unsafe { CMSampleBufferCallForEachSample(self.as_concrete_TypeRef(), callback, refcon.unwrap_or(null_mut())) };
883 status_to_result(status)
884 }
885
886 pub fn call_closure_for_each_sample<F>(&self, closure: Option<F>) -> Result<(), OSStatus>
887 where
888 F: Fn(CMSampleBuffer, CMItemCount) -> OSStatus + 'static,
889 {
890 let status = unsafe {
891 CMSampleBufferCallBlockForEachSample(
892 self.as_concrete_TypeRef(),
893 closure
894 .map(|closure| {
895 ConcreteBlock::new(move |sbuf: CMSampleBufferRef, sample_index: CMItemCount| -> OSStatus {
896 let sbuf = CMSampleBuffer::wrap_under_get_rule(sbuf);
897 closure(sbuf, sample_index)
898 })
899 .copy()
900 })
901 .map_or(null(), |h| &*h),
902 )
903 };
904 status_to_result(status)
905 }
906}