core_media/
sample_buffer.rs

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