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}