Skip to main content

core_media/
sample_buffer.rs

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