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