Skip to main content

core_media/
block_buffer.rs

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