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