Skip to main content

core_media/
block_buffer.rs

1use std::{
2    ptr::{null, null_mut},
3    slice::from_raw_parts_mut,
4};
5
6use core_foundation::{
7    base::{kCFAllocatorDefault, kCFAllocatorNull, Boolean, CFAllocatorRef, CFTypeID, OSStatus, TCFType},
8    declare_TCFType, impl_CFTypeDescription, impl_TCFType,
9};
10use libc::{c_void, size_t};
11
12use crate::base::status_to_result;
13
14pub const kCMBlockBufferNoErr: OSStatus = 0;
15pub const kCMBlockBufferStructureAllocationFailedErr: OSStatus = -12700;
16pub const kCMBlockBufferBlockAllocationFailedErr: OSStatus = -12701;
17pub const kCMBlockBufferBadCustomBlockSourceErr: OSStatus = -12702;
18pub const kCMBlockBufferBadOffsetParameterErr: OSStatus = -12703;
19pub const kCMBlockBufferBadLengthParameterErr: OSStatus = -12704;
20pub const kCMBlockBufferBadPointerParameterErr: OSStatus = -12705;
21pub const kCMBlockBufferEmptyBBufErr: OSStatus = -12706;
22pub const kCMBlockBufferUnallocatedBlock: OSStatus = -12707;
23pub const kCMBlockBufferInsufficientSpaceErr: OSStatus = -12708;
24
25pub type CMBlockBufferFlags = u32;
26
27pub const kCMBlockBufferAssureMemoryNowFlag: CMBlockBufferFlags = 1 << 0;
28pub const kCMBlockBufferAlwaysCopyDataFlag: CMBlockBufferFlags = 1 << 1;
29pub const kCMBlockBufferDontOptimizeDepthFlag: CMBlockBufferFlags = 1 << 2;
30pub const kCMBlockBufferPermitEmptyReferenceFlag: CMBlockBufferFlags = 1 << 3;
31
32#[repr(C)]
33pub struct OpaqueCMBlockBuffer(c_void);
34
35pub type CMBlockBufferRef = *mut OpaqueCMBlockBuffer;
36
37#[repr(C, packed(4))]
38pub struct CMBlockBufferCustomBlockSource {
39    pub version: u32,
40    pub AllocateBlock: Option<extern "C" fn(refcon: *mut c_void, size_in_bytes: usize) -> *mut c_void>,
41    pub FreeBlock: Option<extern "C" fn(refcon: *mut c_void, doomed_memory_block: *mut c_void, size_in_bytes: usize)>,
42    pub refCon: *mut c_void,
43}
44
45pub const kCMBlockBufferCustomBlockSourceVersion: u32 = 0;
46
47extern "C" {
48    pub fn CMBlockBufferCreateEmpty(
49        structureAllocator: CFAllocatorRef,
50        subBlockCapacity: size_t,
51        flags: CMBlockBufferFlags,
52        blockBufferOut: *mut CMBlockBufferRef,
53    ) -> OSStatus;
54    pub fn CMBlockBufferCreateWithMemoryBlock(
55        structureAllocator: CFAllocatorRef,
56        memoryBlock: *const c_void,
57        blockLength: size_t,
58        blockAllocator: CFAllocatorRef,
59        customBlockSource: *const CMBlockBufferCustomBlockSource,
60        offsetToData: size_t,
61        dataLength: size_t,
62        flags: CMBlockBufferFlags,
63        blockBufferOut: *mut CMBlockBufferRef,
64    ) -> OSStatus;
65    pub fn CMBlockBufferCreateWithBufferReference(
66        structureAllocator: CFAllocatorRef,
67        bufferReference: CMBlockBufferRef,
68        offsetToData: size_t,
69        dataLength: size_t,
70        flags: CMBlockBufferFlags,
71        blockBufferOut: *mut CMBlockBufferRef,
72    ) -> OSStatus;
73    pub fn CMBlockBufferCreateContiguous(
74        structureAllocator: CFAllocatorRef,
75        sourceBuffer: CMBlockBufferRef,
76        blockAllocator: CFAllocatorRef,
77        customBlockSource: *const CMBlockBufferCustomBlockSource,
78        offsetToData: size_t,
79        dataLength: size_t,
80        flags: CMBlockBufferFlags,
81        blockBufferOut: *mut CMBlockBufferRef,
82    ) -> OSStatus;
83    pub fn CMBlockBufferGetTypeID() -> CFTypeID;
84    pub fn CMBlockBufferAppendMemoryBlock(
85        theBuffer: CMBlockBufferRef,
86        memoryBlock: *const c_void,
87        blockLength: size_t,
88        blockAllocator: CFAllocatorRef,
89        customBlockSource: *const CMBlockBufferCustomBlockSource,
90        offsetToData: size_t,
91        dataLength: size_t,
92        flags: CMBlockBufferFlags,
93    ) -> OSStatus;
94    pub fn CMBlockBufferAppendBufferReference(
95        theBuffer: CMBlockBufferRef,
96        targetBBuf: CMBlockBufferRef,
97        offsetToData: size_t,
98        dataLength: size_t,
99        flags: CMBlockBufferFlags,
100    ) -> OSStatus;
101    pub fn CMBlockBufferAssureBlockMemory(theBuffer: CMBlockBufferRef) -> OSStatus;
102    pub fn CMBlockBufferAccessDataBytes(
103        theBuffer: CMBlockBufferRef,
104        offset: size_t,
105        length: size_t,
106        temporaryBlock: *mut c_void,
107        returnedPointer: *mut *mut c_void,
108    ) -> OSStatus;
109    pub fn CMBlockBufferCopyDataBytes(
110        theSourceBuffer: CMBlockBufferRef,
111        offsetToData: size_t,
112        dataLength: size_t,
113        destination: *mut c_void,
114    ) -> OSStatus;
115    pub fn CMBlockBufferReplaceDataBytes(
116        sourceBytes: *const c_void,
117        destinationBuffer: CMBlockBufferRef,
118        offsetIntoDestination: size_t,
119        dataLength: size_t,
120    ) -> OSStatus;
121    pub fn CMBlockBufferFillDataBytes(
122        fillByte: u8,
123        destinationBuffer: CMBlockBufferRef,
124        offsetIntoDestination: size_t,
125        dataLength: size_t,
126    ) -> OSStatus;
127    pub fn CMBlockBufferGetDataPointer(
128        theBuffer: CMBlockBufferRef,
129        offset: size_t,
130        lengthAtOffset: *mut size_t,
131        totalLength: *mut size_t,
132        dataPointer: *mut *mut c_void,
133    ) -> OSStatus;
134    pub fn CMBlockBufferGetDataLength(theBuffer: CMBlockBufferRef) -> size_t;
135    pub fn CMBlockBufferIsRangeContiguous(theBuffer: CMBlockBufferRef, offset: size_t, length: size_t) -> Boolean;
136    pub fn CMBlockBufferIsEmpty(theBuffer: CMBlockBufferRef) -> Boolean;
137}
138
139declare_TCFType!(CMBlockBuffer, CMBlockBufferRef);
140impl_TCFType!(CMBlockBuffer, CMBlockBufferRef, CMBlockBufferGetTypeID);
141impl_CFTypeDescription!(CMBlockBuffer);
142
143impl CMBlockBuffer {
144    #[inline]
145    pub fn new_empty(sub_block_capacity: size_t, flags: CMBlockBufferFlags) -> Result<CMBlockBuffer, OSStatus> {
146        unsafe {
147            let mut block_buffer: CMBlockBufferRef = null_mut();
148            let status = CMBlockBufferCreateEmpty(kCFAllocatorDefault, sub_block_capacity, flags, &mut block_buffer);
149            status_to_result(status).map(|_| TCFType::wrap_under_create_rule(block_buffer))
150        }
151    }
152
153    #[inline]
154    pub unsafe fn new_with_memory_block(
155        memory_block: Option<*const c_void>,
156        block_length: size_t,
157        custom_block_source: Option<*const CMBlockBufferCustomBlockSource>,
158        offset_to_data: size_t,
159        data_length: size_t,
160        flags: CMBlockBufferFlags,
161    ) -> Result<CMBlockBuffer, OSStatus> {
162        unsafe {
163            let mut block_buffer: CMBlockBufferRef = null_mut();
164            let status = CMBlockBufferCreateWithMemoryBlock(
165                kCFAllocatorDefault,
166                memory_block.unwrap_or(null()),
167                block_length,
168                kCFAllocatorDefault,
169                custom_block_source.unwrap_or(null()),
170                offset_to_data,
171                data_length,
172                flags,
173                &mut block_buffer,
174            );
175            if status == kCMBlockBufferNoErr {
176                Ok(TCFType::wrap_under_create_rule(block_buffer))
177            } else {
178                Err(status)
179            }
180        }
181    }
182
183    #[inline]
184    pub unsafe fn new_with_memory_block_from_slice(
185        memory_block: &[u8],
186        offset_to_data: size_t,
187        data_length: size_t,
188        flags: CMBlockBufferFlags,
189    ) -> Result<CMBlockBuffer, OSStatus> {
190        unsafe {
191            let mut block_buffer: CMBlockBufferRef = null_mut();
192            let status = CMBlockBufferCreateWithMemoryBlock(
193                kCFAllocatorDefault,
194                memory_block.as_ptr() as *const c_void,
195                memory_block.len() as size_t,
196                kCFAllocatorNull,
197                null(),
198                offset_to_data,
199                data_length,
200                flags,
201                &mut block_buffer,
202            );
203            status_to_result(status).map(|_| TCFType::wrap_under_create_rule(block_buffer))
204        }
205    }
206
207    #[inline]
208    pub fn new_with_length(data_length: size_t, flags: CMBlockBufferFlags) -> Result<CMBlockBuffer, OSStatus> {
209        unsafe {
210            let mut block_buffer: CMBlockBufferRef = null_mut();
211            let status = CMBlockBufferCreateWithMemoryBlock(
212                kCFAllocatorDefault,
213                null(),
214                data_length,
215                kCFAllocatorDefault,
216                null(),
217                0,
218                data_length,
219                flags,
220                &mut block_buffer,
221            );
222            status_to_result(status).map(|_| TCFType::wrap_under_create_rule(block_buffer))
223        }
224    }
225
226    #[inline]
227    pub fn new_with_buffer_reference(
228        &self,
229        offset_to_data: size_t,
230        data_length: size_t,
231        flags: CMBlockBufferFlags,
232    ) -> Result<CMBlockBuffer, OSStatus> {
233        unsafe {
234            let mut block_buffer: CMBlockBufferRef = null_mut();
235            let status = CMBlockBufferCreateWithBufferReference(
236                kCFAllocatorDefault,
237                self.as_concrete_TypeRef(),
238                offset_to_data,
239                data_length,
240                flags,
241                &mut block_buffer,
242            );
243            status_to_result(status).map(|_| TCFType::wrap_under_create_rule(block_buffer))
244        }
245    }
246
247    #[inline]
248    pub unsafe fn new_contiguous(
249        &self,
250        custom_block_source: Option<*const CMBlockBufferCustomBlockSource>,
251        offset_to_data: size_t,
252        data_length: size_t,
253        flags: CMBlockBufferFlags,
254    ) -> Result<CMBlockBuffer, OSStatus> {
255        unsafe {
256            let mut block_buffer: CMBlockBufferRef = null_mut();
257            let status = CMBlockBufferCreateContiguous(
258                kCFAllocatorDefault,
259                self.as_concrete_TypeRef(),
260                kCFAllocatorDefault,
261                custom_block_source.unwrap_or(null()),
262                offset_to_data,
263                data_length,
264                flags,
265                &mut block_buffer,
266            );
267            status_to_result(status).map(|_| TCFType::wrap_under_create_rule(block_buffer))
268        }
269    }
270
271    #[inline]
272    pub unsafe fn append_memory_block(
273        &self,
274        memory_block: Option<*const c_void>,
275        block_length: size_t,
276        custom_block_source: Option<*const CMBlockBufferCustomBlockSource>,
277        offset_to_data: size_t,
278        data_length: size_t,
279        flags: CMBlockBufferFlags,
280    ) -> Result<(), OSStatus> {
281        unsafe {
282            let status = CMBlockBufferAppendMemoryBlock(
283                self.as_concrete_TypeRef(),
284                memory_block.unwrap_or(null()),
285                block_length,
286                kCFAllocatorDefault,
287                custom_block_source.unwrap_or(null()),
288                offset_to_data,
289                data_length,
290                flags,
291            );
292            status_to_result(status)
293        }
294    }
295
296    #[inline]
297    pub fn append_buffer_reference(
298        &self,
299        target_block_buf: &CMBlockBuffer,
300        offset_to_data: size_t,
301        data_length: size_t,
302        flags: CMBlockBufferFlags,
303    ) -> Result<(), OSStatus> {
304        unsafe {
305            let status = CMBlockBufferAppendBufferReference(self.as_concrete_TypeRef(), target_block_buf.0, offset_to_data, data_length, flags);
306            status_to_result(status)
307        }
308    }
309
310    #[inline]
311    pub fn assure_block_memory(&self) -> OSStatus {
312        unsafe { CMBlockBufferAssureBlockMemory(self.as_concrete_TypeRef()) }
313    }
314
315    #[inline]
316    pub fn access_data_bytes(&mut self, offset: size_t, temporary_block: &mut [u8]) -> Result<&mut [u8], OSStatus> {
317        unsafe {
318            let mut returned_pointer: *mut c_void = null_mut();
319            let status = CMBlockBufferAccessDataBytes(
320                self.as_concrete_TypeRef(),
321                offset,
322                temporary_block.len() as size_t,
323                temporary_block.as_mut_ptr() as *mut c_void,
324                &mut returned_pointer,
325            );
326            status_to_result(status).map(|_| from_raw_parts_mut(returned_pointer as *mut u8, temporary_block.len()))
327        }
328    }
329
330    #[inline]
331    pub fn copy_data_bytes(&self, offset_to_data: size_t, destination: &mut [u8]) -> Result<(), OSStatus> {
332        unsafe {
333            let status = CMBlockBufferCopyDataBytes(
334                self.as_concrete_TypeRef(),
335                offset_to_data,
336                destination.len() as size_t,
337                destination.as_mut_ptr() as *mut c_void,
338            );
339            status_to_result(status)
340        }
341    }
342
343    #[inline]
344    pub fn replace_data_bytes(&self, source_bytes: &[u8], offset_into_destination: size_t) -> Result<(), OSStatus> {
345        unsafe {
346            let status = CMBlockBufferReplaceDataBytes(
347                source_bytes.as_ptr() as *const c_void,
348                self.as_concrete_TypeRef(),
349                offset_into_destination,
350                source_bytes.len() as size_t,
351            );
352            status_to_result(status)
353        }
354    }
355
356    #[inline]
357    pub fn fill_data_bytes(&self, fill_byte: u8, offset_into_destination: size_t, data_length: size_t) -> Result<(), OSStatus> {
358        unsafe {
359            let status = CMBlockBufferFillDataBytes(fill_byte, self.as_concrete_TypeRef(), offset_into_destination, data_length);
360            status_to_result(status)
361        }
362    }
363
364    #[inline]
365    pub fn get_data(&mut self, offset: size_t) -> Result<&mut [u8], OSStatus> {
366        unsafe {
367            let mut length_at_offset: size_t = 0;
368            let mut total_length: size_t = 0;
369            let mut data_pointer: *mut c_void = null_mut();
370            let status = CMBlockBufferGetDataPointer(self.as_concrete_TypeRef(), offset, &mut length_at_offset, &mut total_length, &mut data_pointer);
371            status_to_result(status).map(|_| from_raw_parts_mut(data_pointer as *mut u8, length_at_offset))
372        }
373    }
374
375    #[inline]
376    pub fn get_data_length(&self) -> size_t {
377        unsafe { CMBlockBufferGetDataLength(self.as_concrete_TypeRef()) }
378    }
379
380    #[inline]
381    pub fn is_range_contiguous(&self, offset: size_t, length: size_t) -> bool {
382        unsafe { CMBlockBufferIsRangeContiguous(self.as_concrete_TypeRef(), offset, length) != 0 }
383    }
384
385    #[inline]
386    pub fn is_empty(&self) -> bool {
387        unsafe { CMBlockBufferIsEmpty(self.as_concrete_TypeRef()) != 0 }
388    }
389}