Skip to main content

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    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::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        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: Option<CMSampleBufferMakeDataReadyCallback>,
456        make_data_ready_refcon: Option<*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.unwrap_or(null_mut()),
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: Option<CMSampleBufferMakeDataReadyCallback>,
555        make_data_ready_refcon: Option<*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.unwrap_or(null_mut()),
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}