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, align(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: 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: 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: 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! {
341    CMSampleBuffer, CMSampleBufferRef
342}
343impl_TCFType!(CMSampleBuffer, CMSampleBufferRef, CMSampleBufferGetTypeID);
344impl_CFTypeDescription!(CMSampleBuffer);
345
346impl CMSampleBuffer {
347    #[inline]
348    pub unsafe fn new(
349        data_buffer: Option<&CMBlockBuffer>,
350        data_ready: bool,
351        make_data_ready_callback: CMSampleBufferMakeDataReadyCallback,
352        make_data_ready_refcon: *mut c_void,
353        format_description: Option<&CMFormatDescription>,
354        num_samples: CMItemCount,
355        sample_timing_array: Option<&[CMSampleTimingInfo]>,
356        sample_size_array: Option<&[size_t]>,
357    ) -> Result<CMSampleBuffer, OSStatus> {
358        let mut sample_buffer: CMSampleBufferRef = null_mut();
359        let status = unsafe {
360            CMSampleBufferCreate(
361                kCFAllocatorDefault,
362                data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
363                data_ready as Boolean,
364                make_data_ready_callback,
365                make_data_ready_refcon,
366                format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
367                num_samples,
368                sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
369                sample_timing_array.map_or(null(), |a| a.as_ptr()),
370                sample_size_array.map_or(0, |a| a.len() as CMItemCount),
371                sample_size_array.map_or(null(), |a| a.as_ptr()),
372                &mut sample_buffer,
373            )
374        };
375        if status == 0 {
376            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
377        } else {
378            Err(status)
379        }
380    }
381
382    #[inline]
383    pub fn new_with_make_data_ready_closure<F>(
384        data_buffer: Option<&CMBlockBuffer>,
385        data_ready: bool,
386        format_description: Option<&CMFormatDescription>,
387        num_samples: CMItemCount,
388        sample_timing_array: Option<&[CMSampleTimingInfo]>,
389        sample_size_array: Option<&[size_t]>,
390        make_data_ready_closure: Option<F>,
391    ) -> Result<CMSampleBuffer, OSStatus>
392    where
393        F: Fn(CMSampleBuffer) -> OSStatus + 'static,
394    {
395        let mut sample_buffer: CMSampleBufferRef = null_mut();
396        let handler = make_data_ready_closure.map(|closure| {
397            ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
398                let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
399                closure(sbuf)
400            })
401            .copy()
402        });
403        let status = unsafe {
404            CMSampleBufferCreateWithMakeDataReadyHandler(
405                kCFAllocatorDefault,
406                data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
407                data_ready as Boolean,
408                format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
409                num_samples,
410                sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
411                sample_timing_array.map_or(null(), |a| a.as_ptr()),
412                sample_size_array.map_or(0, |a| a.len() as CMItemCount),
413                sample_size_array.map_or(null(), |a| a.as_ptr()),
414                &mut sample_buffer,
415                handler.as_ref().map_or(null(), |h| &**h),
416            )
417        };
418        if status == 0 {
419            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
420        } else {
421            Err(status)
422        }
423    }
424
425    #[inline]
426    pub fn new_ready(
427        data_buffer: &CMBlockBuffer,
428        format_description: Option<&CMFormatDescription>,
429        num_samples: CMItemCount,
430        sample_timing_array: Option<&[CMSampleTimingInfo]>,
431        sample_size_array: Option<&[size_t]>,
432    ) -> Result<CMSampleBuffer, OSStatus> {
433        let mut sample_buffer: CMSampleBufferRef = null_mut();
434        let status = unsafe {
435            CMSampleBufferCreateReady(
436                kCFAllocatorDefault,
437                data_buffer.as_concrete_TypeRef(),
438                format_description.map_or(null_mut(), |f| f.as_concrete_TypeRef()),
439                num_samples,
440                sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
441                sample_timing_array.map_or(null(), |a| a.as_ptr()),
442                sample_size_array.map_or(0, |a| a.len() as CMItemCount),
443                sample_size_array.map_or(null(), |a| a.as_ptr()),
444                &mut sample_buffer,
445            )
446        };
447        if status == 0 {
448            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
449        } else {
450            Err(status)
451        }
452    }
453
454    pub unsafe fn new_audio_sample_buffer_with_packet_descriptions(
455        data_buffer: Option<&CMBlockBuffer>,
456        data_ready: bool,
457        make_data_ready_callback: CMSampleBufferMakeDataReadyCallback,
458        make_data_ready_refcon: *mut c_void,
459        format_description: &CMFormatDescription,
460        num_samples: CMItemCount,
461        presentation_time_stamp: CMTime,
462        packet_descriptions: Option<&[AudioStreamPacketDescription]>,
463    ) -> Result<CMSampleBuffer, OSStatus> {
464        let mut sample_buffer: CMSampleBufferRef = null_mut();
465        let status = unsafe {
466            CMAudioSampleBufferCreateWithPacketDescriptions(
467                kCFAllocatorDefault,
468                data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
469                data_ready as Boolean,
470                make_data_ready_callback,
471                make_data_ready_refcon,
472                format_description.as_concrete_TypeRef(),
473                num_samples,
474                presentation_time_stamp,
475                packet_descriptions.map_or(null(), |a| a.as_ptr()),
476                &mut sample_buffer,
477            )
478        };
479        if status == 0 {
480            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
481        } else {
482            Err(status)
483        }
484    }
485
486    pub fn new_audio_sample_buffer_with_packet_descriptions_and_make_data_ready_closure<F>(
487        data_buffer: Option<&CMBlockBuffer>,
488        data_ready: bool,
489        format_description: &CMFormatDescription,
490        num_samples: CMItemCount,
491        presentation_time_stamp: CMTime,
492        packet_descriptions: Option<&[AudioStreamPacketDescription]>,
493        make_data_ready_closure: Option<F>,
494    ) -> Result<CMSampleBuffer, OSStatus>
495    where
496        F: Fn(CMSampleBuffer) -> OSStatus + 'static,
497    {
498        let mut sample_buffer: CMSampleBufferRef = null_mut();
499        let handler = make_data_ready_closure.map(|closure| {
500            ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
501                let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
502                closure(sbuf)
503            })
504            .copy()
505        });
506        let status = unsafe {
507            CMAudioSampleBufferCreateWithPacketDescriptionsAndMakeDataReadyHandler(
508                kCFAllocatorDefault,
509                data_buffer.map_or(null_mut(), |b| b.as_concrete_TypeRef()),
510                data_ready as Boolean,
511                format_description.as_concrete_TypeRef(),
512                num_samples,
513                presentation_time_stamp,
514                packet_descriptions.map_or(null(), |a| a.as_ptr()),
515                &mut sample_buffer,
516                handler.as_ref().map_or(null(), |h| &**h),
517            )
518        };
519        if status == 0 {
520            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
521        } else {
522            Err(status)
523        }
524    }
525
526    #[inline]
527    pub fn new_audio_sample_buffer_ready_with_packet_descriptions(
528        data_buffer: &CMBlockBuffer,
529        format_description: &CMFormatDescription,
530        num_samples: CMItemCount,
531        presentation_time_stamp: CMTime,
532        packet_descriptions: Option<&[AudioStreamPacketDescription]>,
533    ) -> Result<CMSampleBuffer, OSStatus> {
534        let mut sample_buffer: CMSampleBufferRef = null_mut();
535        let status = unsafe {
536            CMAudioSampleBufferCreateReadyWithPacketDescriptions(
537                kCFAllocatorDefault,
538                data_buffer.as_concrete_TypeRef(),
539                format_description.as_concrete_TypeRef(),
540                num_samples,
541                presentation_time_stamp,
542                packet_descriptions.map_or(null(), |a| a.as_ptr()),
543                &mut sample_buffer,
544            )
545        };
546        if status == 0 {
547            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
548        } else {
549            Err(status)
550        }
551    }
552
553    pub unsafe fn from_image_buffer(
554        image_buffer: &CVImageBuffer,
555        data_ready: bool,
556        make_data_ready_callback: CMSampleBufferMakeDataReadyCallback,
557        make_data_ready_refcon: *mut c_void,
558        format_description: &CMVideoFormatDescription,
559        sample_timing: &CMSampleTimingInfo,
560    ) -> Result<CMSampleBuffer, OSStatus> {
561        let mut sample_buffer: CMSampleBufferRef = null_mut();
562        let status = CMSampleBufferCreateForImageBuffer(
563            kCFAllocatorDefault,
564            image_buffer.as_concrete_TypeRef(),
565            data_ready as Boolean,
566            make_data_ready_callback,
567            make_data_ready_refcon,
568            format_description.as_concrete_TypeRef(),
569            sample_timing,
570            &mut sample_buffer,
571        );
572        if status == 0 {
573            Ok(CMSampleBuffer::wrap_under_create_rule(sample_buffer))
574        } else {
575            Err(status)
576        }
577    }
578
579    pub fn from_image_buffer_with_make_data_ready_closure<F>(
580        image_buffer: &CVImageBuffer,
581        data_ready: bool,
582        format_description: &CMVideoFormatDescription,
583        sample_timing: &CMSampleTimingInfo,
584        make_data_ready_closure: Option<F>,
585    ) -> Result<CMSampleBuffer, OSStatus>
586    where
587        F: Fn(CMSampleBuffer) -> OSStatus + 'static,
588    {
589        let mut sample_buffer: CMSampleBufferRef = null_mut();
590        let handler = make_data_ready_closure.map(|closure| {
591            ConcreteBlock::new(move |sbuf: CMSampleBufferRef| -> OSStatus {
592                let sbuf = unsafe { CMSampleBuffer::wrap_under_get_rule(sbuf) };
593                closure(sbuf)
594            })
595            .copy()
596        });
597        let status = unsafe {
598            CMSampleBufferCreateForImageBufferWithMakeDataReadyHandler(
599                kCFAllocatorDefault,
600                image_buffer.as_concrete_TypeRef(),
601                data_ready as Boolean,
602                format_description.as_concrete_TypeRef(),
603                sample_timing,
604                &mut sample_buffer,
605                handler.as_ref().map_or(null(), |h| &**h),
606            )
607        };
608        if status == 0 {
609            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
610        } else {
611            Err(status)
612        }
613    }
614
615    #[inline]
616    pub fn from_image_buffer_ready(
617        image_buffer: &CVImageBuffer,
618        format_description: &CMVideoFormatDescription,
619        sample_timing: &CMSampleTimingInfo,
620    ) -> Result<CMSampleBuffer, OSStatus> {
621        let mut sample_buffer: CMSampleBufferRef = null_mut();
622        let status = unsafe {
623            CMSampleBufferCreateReadyWithImageBuffer(
624                kCFAllocatorDefault,
625                image_buffer.as_concrete_TypeRef(),
626                format_description.as_concrete_TypeRef(),
627                sample_timing,
628                &mut sample_buffer,
629            )
630        };
631        if status == 0 {
632            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
633        } else {
634            Err(status)
635        }
636    }
637
638    #[inline]
639    pub fn copy(&self) -> Result<CMSampleBuffer, OSStatus> {
640        let mut sample_buffer: CMSampleBufferRef = null_mut();
641        let status = unsafe { CMSampleBufferCreateCopy(kCFAllocatorDefault, self.as_concrete_TypeRef(), &mut sample_buffer) };
642        if status == 0 {
643            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
644        } else {
645            Err(status)
646        }
647    }
648
649    #[inline]
650    pub fn copy_with_new_timing(&self, sample_timing_array: Option<&[CMSampleTimingInfo]>) -> Result<CMSampleBuffer, OSStatus> {
651        let mut sample_buffer: CMSampleBufferRef = null_mut();
652        let status = unsafe {
653            CMSampleBufferCreateCopyWithNewTiming(
654                kCFAllocatorDefault,
655                self.as_concrete_TypeRef(),
656                sample_timing_array.map_or(0, |a| a.len() as CMItemCount),
657                sample_timing_array.map_or(null(), |a| a.as_ptr()),
658                &mut sample_buffer,
659            )
660        };
661        if status == 0 {
662            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
663        } else {
664            Err(status)
665        }
666    }
667
668    #[inline]
669    pub fn copy_for_range(&self, sample_range: CFRange) -> Result<CMSampleBuffer, OSStatus> {
670        let mut sample_buffer: CMSampleBufferRef = null_mut();
671        let status =
672            unsafe { CMSampleBufferCopySampleBufferForRange(kCFAllocatorDefault, self.as_concrete_TypeRef(), sample_range, &mut sample_buffer) };
673        if status == 0 {
674            Ok(unsafe { CMSampleBuffer::wrap_under_create_rule(sample_buffer) })
675        } else {
676            Err(status)
677        }
678    }
679
680    #[inline]
681    pub fn set_data_buffer(&self, data_buffer: &CMBlockBuffer) -> Result<(), OSStatus> {
682        let status = unsafe { CMSampleBufferSetDataBuffer(self.as_concrete_TypeRef(), data_buffer.as_concrete_TypeRef()) };
683        if status == 0 {
684            Ok(())
685        } else {
686            Err(status)
687        }
688    }
689
690    #[inline]
691    pub fn get_data_buffer(&self) -> Option<CMBlockBuffer> {
692        unsafe {
693            let data_buffer = CMSampleBufferGetDataBuffer(self.as_concrete_TypeRef());
694            if data_buffer.is_null() {
695                None
696            } else {
697                Some(TCFType::wrap_under_get_rule(data_buffer))
698            }
699        }
700    }
701
702    #[inline]
703    pub fn get_image_buffer(&self) -> Option<CVImageBuffer> {
704        unsafe {
705            let image_buffer = CMSampleBufferGetImageBuffer(self.as_concrete_TypeRef());
706            if image_buffer.is_null() {
707                None
708            } else {
709                Some(CVImageBuffer::wrap_under_get_rule(image_buffer))
710            }
711        }
712    }
713
714    #[inline]
715    pub fn set_data_buffer_from_audio_buffer_list(&self, flags: u32, buffer_list: &AudioBufferList) -> Result<(), OSStatus> {
716        let status = unsafe {
717            CMSampleBufferSetDataBufferFromAudioBufferList(self.as_concrete_TypeRef(), kCFAllocatorDefault, kCFAllocatorDefault, flags, buffer_list)
718        };
719        if status == 0 {
720            Ok(())
721        } else {
722            Err(status)
723        }
724    }
725
726    #[inline]
727    pub fn set_data_ready(&self) -> Result<(), OSStatus> {
728        let status = unsafe { CMSampleBufferSetDataReady(self.as_concrete_TypeRef()) };
729        if status == 0 {
730            Ok(())
731        } else {
732            Err(status)
733        }
734    }
735
736    #[inline]
737    pub fn is_data_ready(&self) -> bool {
738        unsafe { CMSampleBufferDataIsReady(self.as_concrete_TypeRef()) != 0 }
739    }
740
741    #[inline]
742    pub fn set_data_failed(&self, status: OSStatus) -> Result<(), OSStatus> {
743        let status = unsafe { CMSampleBufferSetDataFailed(self.as_concrete_TypeRef(), status) };
744        if status == 0 {
745            Ok(())
746        } else {
747            Err(status)
748        }
749    }
750
751    #[inline]
752    pub fn has_data_failed(&self) -> (OSStatus, bool) {
753        let mut status = 0;
754        let has_failed = unsafe { CMSampleBufferHasDataFailed(self.as_concrete_TypeRef(), &mut status) != 0 };
755        (status, has_failed)
756    }
757
758    #[inline]
759    pub fn make_data_ready(&self) -> Result<(), OSStatus> {
760        let status = unsafe { CMSampleBufferMakeDataReady(self.as_concrete_TypeRef()) };
761        if status == 0 {
762            Ok(())
763        } else {
764            Err(status)
765        }
766    }
767
768    #[inline]
769    pub fn track_data_readiness(&self, sample_buffer_to_track: &CMSampleBuffer) -> Result<(), OSStatus> {
770        let status = unsafe { CMSampleBufferTrackDataReadiness(self.as_concrete_TypeRef(), sample_buffer_to_track.as_concrete_TypeRef()) };
771        if status == 0 {
772            Ok(())
773        } else {
774            Err(status)
775        }
776    }
777
778    #[inline]
779    pub fn invalidate(&self) -> Result<(), OSStatus> {
780        let status = unsafe { CMSampleBufferInvalidate(self.as_concrete_TypeRef()) };
781        if status == 0 {
782            Ok(())
783        } else {
784            Err(status)
785        }
786    }
787
788    pub unsafe fn set_invalidate_callback(
789        &self,
790        invalidate_callback: CMSampleBufferInvalidateCallback,
791        invalidate_ref_con: u64,
792    ) -> Result<(), OSStatus> {
793        let status = unsafe { CMSampleBufferSetInvalidateCallback(self.as_concrete_TypeRef(), invalidate_callback, invalidate_ref_con) };
794        if status == 0 {
795            Ok(())
796        } else {
797            Err(status)
798        }
799    }
800
801    pub fn set_invalidate_closure<F>(&self, invalidate_closure: Option<F>) -> Result<(), OSStatus>
802    where
803        F: Fn(CMSampleBuffer) + 'static,
804    {
805        let status = unsafe {
806            CMSampleBufferSetInvalidateHandler(
807                self.as_concrete_TypeRef(),
808                invalidate_closure
809                    .map(|closure| {
810                        ConcreteBlock::new(move |sbuf: CMSampleBufferRef| {
811                            let sbuf = CMSampleBuffer::wrap_under_get_rule(sbuf);
812                            closure(sbuf);
813                        })
814                        .copy()
815                    })
816                    .as_ref()
817                    .map_or(null(), |h| &**h),
818            )
819        };
820        if status == 0 {
821            Ok(())
822        } else {
823            Err(status)
824        }
825    }
826
827    #[inline]
828    pub fn is_valid(&self) -> bool {
829        unsafe { CMSampleBufferIsValid(self.as_concrete_TypeRef()) != 0 }
830    }
831
832    #[inline]
833    pub fn get_num_samples(&self) -> CMItemCount {
834        unsafe { CMSampleBufferGetNumSamples(self.as_concrete_TypeRef()) }
835    }
836
837    #[inline]
838    pub fn get_duration(&self) -> CMTime {
839        unsafe { CMSampleBufferGetDuration(self.as_concrete_TypeRef()) }
840    }
841
842    #[inline]
843    pub fn get_presentation_time_stamp(&self) -> CMTime {
844        unsafe { CMSampleBufferGetPresentationTimeStamp(self.as_concrete_TypeRef()) }
845    }
846
847    #[inline]
848    pub fn get_decode_time_stamp(&self) -> CMTime {
849        unsafe { CMSampleBufferGetDecodeTimeStamp(self.as_concrete_TypeRef()) }
850    }
851
852    #[inline]
853    pub fn get_output_duration(&self) -> CMTime {
854        unsafe { CMSampleBufferGetOutputDuration(self.as_concrete_TypeRef()) }
855    }
856
857    #[inline]
858    pub fn get_output_presentation_time_stamp(&self) -> CMTime {
859        unsafe { CMSampleBufferGetOutputPresentationTimeStamp(self.as_concrete_TypeRef()) }
860    }
861
862    #[inline]
863    pub fn set_output_presentation_time_stamp(&self, output_presentation_time_stamp: CMTime) -> Result<(), OSStatus> {
864        let status = unsafe { CMSampleBufferSetOutputPresentationTimeStamp(self.as_concrete_TypeRef(), output_presentation_time_stamp) };
865        if status == 0 {
866            Ok(())
867        } else {
868            Err(status)
869        }
870    }
871
872    #[inline]
873    pub fn get_output_decode_time_stamp(&self) -> CMTime {
874        unsafe { CMSampleBufferGetOutputDecodeTimeStamp(self.as_concrete_TypeRef()) }
875    }
876
877    #[inline]
878    pub fn get_sample_timing_info_array(&self) -> Option<Vec<CMSampleTimingInfo>> {
879        unsafe {
880            let mut timing_array_entries_needed = 0;
881            let status = CMSampleBufferGetSampleTimingInfoArray(self.as_concrete_TypeRef(), 0, null_mut(), &mut timing_array_entries_needed);
882            if status != 0 {
883                return None;
884            }
885            let mut timing_array = vec![CMSampleTimingInfo::default(); timing_array_entries_needed as usize];
886            let status = CMSampleBufferGetSampleTimingInfoArray(
887                self.as_concrete_TypeRef(),
888                timing_array_entries_needed,
889                timing_array.as_mut_ptr(),
890                &mut timing_array_entries_needed,
891            );
892            if status != 0 {
893                return None;
894            }
895            Some(timing_array)
896        }
897    }
898
899    #[inline]
900    pub fn get_sample_timing_info(&self, sample_index: CMItemCount) -> Option<CMSampleTimingInfo> {
901        unsafe {
902            let mut timing_info = CMSampleTimingInfo::default();
903            let status = CMSampleBufferGetSampleTimingInfo(self.as_concrete_TypeRef(), sample_index, &mut timing_info);
904            if status == 0 {
905                Some(timing_info)
906            } else {
907                None
908            }
909        }
910    }
911
912    #[inline]
913    pub fn get_sample_size_array(&self) -> Option<Vec<size_t>> {
914        unsafe {
915            let mut size_array_entries_needed = 0;
916            let status = CMSampleBufferGetSampleSizeArray(self.as_concrete_TypeRef(), 0, null_mut(), &mut size_array_entries_needed);
917            if status != 0 {
918                return None;
919            }
920            let mut size_array = vec![0; size_array_entries_needed as usize];
921            let status = CMSampleBufferGetSampleSizeArray(
922                self.as_concrete_TypeRef(),
923                size_array_entries_needed,
924                size_array.as_mut_ptr(),
925                &mut size_array_entries_needed,
926            );
927            if status != 0 {
928                return None;
929            }
930            Some(size_array)
931        }
932    }
933
934    #[inline]
935    pub fn get_sample_size(&self, sample_index: CMItemCount) -> size_t {
936        unsafe { CMSampleBufferGetSampleSize(self.as_concrete_TypeRef(), sample_index) }
937    }
938
939    #[inline]
940    pub fn get_total_sample_size(&self) -> usize {
941        unsafe { CMSampleBufferGetTotalSampleSize(self.as_concrete_TypeRef()) }
942    }
943
944    #[inline]
945    pub fn get_format_description(&self) -> Option<CMFormatDescription> {
946        unsafe {
947            let format_description = CMSampleBufferGetFormatDescription(self.as_concrete_TypeRef());
948            if format_description.is_null() {
949                None
950            } else {
951                Some(TCFType::wrap_under_create_rule(format_description))
952            }
953        }
954    }
955
956    #[inline]
957    pub fn get_sample_attachments_array(&self, create_if_necessary: bool) -> Option<CFArray<CFDictionary<CFString, CFType>>> {
958        unsafe {
959            let attachments = CMSampleBufferGetSampleAttachmentsArray(self.as_concrete_TypeRef(), create_if_necessary as Boolean);
960            if attachments.is_null() {
961                None
962            } else {
963                Some(TCFType::wrap_under_get_rule(attachments))
964            }
965        }
966    }
967
968    pub unsafe fn call_for_each_sample(
969        &self,
970        callback: extern "C" fn(CMSampleBufferRef, CMItemCount, *mut c_void) -> OSStatus,
971        refcon: *mut c_void,
972    ) -> Result<(), OSStatus> {
973        let status = unsafe { CMSampleBufferCallForEachSample(self.as_concrete_TypeRef(), callback, refcon) };
974        if status == 0 {
975            Ok(())
976        } else {
977            Err(status)
978        }
979    }
980
981    pub fn call_closure_for_each_sample<F>(&self, closure: Option<F>) -> Result<(), OSStatus>
982    where
983        F: Fn(CMSampleBuffer, CMItemCount) -> OSStatus + 'static,
984    {
985        let status = unsafe {
986            CMSampleBufferCallBlockForEachSample(
987                self.as_concrete_TypeRef(),
988                closure
989                    .map(|closure| {
990                        ConcreteBlock::new(move |sbuf: CMSampleBufferRef, sample_index: CMItemCount| -> OSStatus {
991                            let sbuf = CMSampleBuffer::wrap_under_get_rule(sbuf);
992                            closure(sbuf, sample_index)
993                        })
994                        .copy()
995                    })
996                    .as_ref()
997                    .map_or(null(), |h| &**h),
998            )
999        };
1000        if status == 0 {
1001            Ok(())
1002        } else {
1003            Err(status)
1004        }
1005    }
1006}