Skip to main content

core_media/
format_description_bridge.rs

1use std::ptr::null_mut;
2
3use cfg_if::cfg_if;
4use core_foundation::{
5    base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, OSStatus, TCFType},
6    string::{CFString, CFStringEncoding, CFStringRef},
7};
8use libc::size_t;
9
10use crate::{
11    block_buffer::{CMBlockBuffer, CMBlockBufferRef},
12    format_description::{
13        CMAudioFormatDescription, CMAudioFormatDescriptionRef, CMClosedCaptionFormatDescriptionRef, CMMediaType, CMMetadataFormatDescriptionRef,
14        CMTextFormatDescriptionRef, CMTimeCodeFormatDescriptionRef, CMVideoFormatDescription, CMVideoFormatDescriptionRef,
15    },
16};
17
18pub const kCMFormatDescriptionBridgeError_InvalidParameter: OSStatus = -12712;
19pub const kCMFormatDescriptionBridgeError_AllocationFailed: OSStatus = -12713;
20pub const kCMFormatDescriptionBridgeError_InvalidSerializedSampleDescription: OSStatus = -12714;
21pub const kCMFormatDescriptionBridgeError_InvalidFormatDescription: OSStatus = -12715;
22pub const kCMFormatDescriptionBridgeError_IncompatibleFormatDescription: OSStatus = -12716;
23pub const kCMFormatDescriptionBridgeError_UnsupportedSampleDescriptionFlavor: OSStatus = -12717;
24pub const kCMFormatDescriptionBridgeError_InvalidSlice: OSStatus = -12719;
25
26extern "C" {
27    pub static kCMImageDescriptionFlavor_QuickTimeMovie: CFStringRef;
28    pub static kCMImageDescriptionFlavor_ISOFamily: CFStringRef;
29    pub static kCMImageDescriptionFlavor_3GPFamily: CFStringRef;
30    pub static kCMImageDescriptionFlavor_ISOFamilyWithAppleExtensions: CFStringRef;
31
32    pub fn CMVideoFormatDescriptionCreateFromBigEndianImageDescriptionData(
33        allocator: CFAllocatorRef,
34        imageDescriptionData: *const u8,
35        size: size_t,
36        stringEncoding: CFStringEncoding,
37        flavor: CFStringRef,
38        formatDescriptionOut: *mut CMVideoFormatDescriptionRef,
39    ) -> OSStatus;
40    pub fn CMVideoFormatDescriptionCreateFromBigEndianImageDescriptionBlockBuffer(
41        allocator: CFAllocatorRef,
42        imageDescriptionBlockBuffer: CMBlockBufferRef,
43        stringEncoding: CFStringEncoding,
44        flavor: CFStringRef,
45        formatDescriptionOut: *mut CMVideoFormatDescriptionRef,
46    ) -> OSStatus;
47    pub fn CMVideoFormatDescriptionCopyAsBigEndianImageDescriptionBlockBuffer(
48        allocator: CFAllocatorRef,
49        videoFormatDescription: CMVideoFormatDescriptionRef,
50        stringEncoding: CFStringEncoding,
51        flavor: CFStringRef,
52        blockBufferOut: *mut CMBlockBufferRef,
53    ) -> OSStatus;
54
55    cfg_if! {
56        if #[cfg(target_endian = "little")] {
57            pub fn CMSwapBigEndianImageDescriptionToHost(imageDescriptionData: *mut u8, imageDescriptionSize: size_t) -> OSStatus;
58            pub fn CMSwapHostEndianImageDescriptionToBig(imageDescriptionData: *mut u8, imageDescriptionSize: size_t) -> OSStatus;
59        }
60    }
61
62    pub static kCMSoundDescriptionFlavor_QuickTimeMovie: CFStringRef;
63    pub static kCMSoundDescriptionFlavor_QuickTimeMovieV2: CFStringRef;
64    pub static kCMSoundDescriptionFlavor_ISOFamily: CFStringRef;
65    pub static kCMSoundDescriptionFlavor_3GPFamily: CFStringRef;
66
67    pub fn CMAudioFormatDescriptionCreateFromBigEndianSoundDescriptionData(
68        allocator: CFAllocatorRef,
69        soundDescriptionData: *const u8,
70        size: size_t,
71        flavor: CFStringRef,
72        formatDescriptionOut: *mut CMAudioFormatDescriptionRef,
73    ) -> OSStatus;
74    pub fn CMAudioFormatDescriptionCreateFromBigEndianSoundDescriptionBlockBuffer(
75        allocator: CFAllocatorRef,
76        soundDescriptionBlockBuffer: CMBlockBufferRef,
77        flavor: CFStringRef,
78        formatDescriptionOut: *mut CMAudioFormatDescriptionRef,
79    ) -> OSStatus;
80    pub fn CMAudioFormatDescriptionCopyAsBigEndianSoundDescriptionBlockBuffer(
81        allocator: CFAllocatorRef,
82        audioFormatDescription: CMAudioFormatDescriptionRef,
83        flavor: CFStringRef,
84        blockBufferOut: *mut CMBlockBufferRef,
85    ) -> OSStatus;
86    pub fn CMDoesBigEndianSoundDescriptionRequireLegacyCBRSampleTableLayout(
87        soundDescriptionBlockBuffer: CMBlockBufferRef,
88        flavor: CFStringRef,
89    ) -> Boolean;
90
91    cfg_if! {
92        if #[cfg(target_endian = "little")] {
93            pub fn CMSwapBigEndianSoundDescriptionToHost(soundDescriptionData: *mut u8, soundDescriptionSize: size_t) -> OSStatus;
94            pub fn CMSwapHostEndianSoundDescriptionToBig(soundDescriptionData: *mut u8, soundDescriptionSize: size_t) -> OSStatus;
95        }
96    }
97
98    pub fn CMTextFormatDescriptionCreateFromBigEndianTextDescriptionData(
99        allocator: CFAllocatorRef,
100        textDescriptionData: *const u8,
101        size: size_t,
102        flavor: CFStringRef,
103        mediaType: CMMediaType,
104        formatDescriptionOut: *mut CMTextFormatDescriptionRef,
105    ) -> OSStatus;
106    pub fn CMTextFormatDescriptionCreateFromBigEndianTextDescriptionBlockBuffer(
107        allocator: CFAllocatorRef,
108        textDescriptionBlockBuffer: CMBlockBufferRef,
109        flavor: CFStringRef,
110        mediaType: CMMediaType,
111        formatDescriptionOut: *mut CMTextFormatDescriptionRef,
112    ) -> OSStatus;
113    pub fn CMTextFormatDescriptionCopyAsBigEndianTextDescriptionBlockBuffer(
114        allocator: CFAllocatorRef,
115        textFormatDescription: CMTextFormatDescriptionRef,
116        flavor: CFStringRef,
117        blockBufferOut: *mut CMBlockBufferRef,
118    ) -> OSStatus;
119
120    cfg_if! {
121        if #[cfg(target_endian = "little")] {
122            pub fn CMSwapBigEndianTextDescriptionToHost(textDescriptionData: *mut u8, textDescriptionSize: size_t) -> OSStatus;
123            pub fn CMSwapHostEndianTextDescriptionToBig(textDescriptionData: *mut u8, textDescriptionSize: size_t) -> OSStatus;
124        }
125    }
126
127    pub fn CMClosedCaptionFormatDescriptionCreateFromBigEndianClosedCaptionDescriptionData(
128        allocator: CFAllocatorRef,
129        closedCaptionDescriptionData: *const u8,
130        size: size_t,
131        flavor: CFStringRef,
132        formatDescriptionOut: *mut CMClosedCaptionFormatDescriptionRef,
133    ) -> OSStatus;
134    pub fn CMClosedCaptionFormatDescriptionCreateFromBigEndianClosedCaptionDescriptionBlockBuffer(
135        allocator: CFAllocatorRef,
136        closedCaptionDescriptionBlockBuffer: CMBlockBufferRef,
137        flavor: CFStringRef,
138        formatDescriptionOut: *mut CMClosedCaptionFormatDescriptionRef,
139    ) -> OSStatus;
140    pub fn CMClosedCaptionFormatDescriptionCopyAsBigEndianClosedCaptionDescriptionBlockBuffer(
141        allocator: CFAllocatorRef,
142        closedCaptionFormatDescription: CMClosedCaptionFormatDescriptionRef,
143        flavor: CFStringRef,
144        blockBufferOut: *mut CMBlockBufferRef,
145    ) -> OSStatus;
146
147    cfg_if! {
148        if #[cfg(target_endian = "little")] {
149            pub fn CMSwapBigEndianClosedCaptionDescriptionToHost(closedCaptionDescriptionData: *mut u8, closedCaptionDescriptionSize: size_t) -> OSStatus;
150            pub fn CMSwapHostEndianClosedCaptionDescriptionToBig(closedCaptionDescriptionData: *mut u8, closedCaptionDescriptionSize: size_t) -> OSStatus;
151        }
152    }
153
154    pub fn CMTimeCodeFormatDescriptionCreateFromBigEndianTimeCodeDescriptionData(
155        allocator: CFAllocatorRef,
156        timeCodeDescriptionData: *const u8,
157        size: size_t,
158        flavor: CFStringRef,
159        formatDescriptionOut: *mut CMTimeCodeFormatDescriptionRef,
160    ) -> OSStatus;
161    pub fn CMTimeCodeFormatDescriptionCreateFromBigEndianTimeCodeDescriptionBlockBuffer(
162        allocator: CFAllocatorRef,
163        timeCodeDescriptionBlockBuffer: CMBlockBufferRef,
164        flavor: CFStringRef,
165        formatDescriptionOut: *mut CMTimeCodeFormatDescriptionRef,
166    ) -> OSStatus;
167    pub fn CMTimeCodeFormatDescriptionCopyAsBigEndianTimeCodeDescriptionBlockBuffer(
168        allocator: CFAllocatorRef,
169        timeCodeFormatDescription: CMTimeCodeFormatDescriptionRef,
170        flavor: CFStringRef,
171        blockBufferOut: *mut CMBlockBufferRef,
172    ) -> OSStatus;
173
174    cfg_if! {
175        if #[cfg(target_endian = "little")] {
176            pub fn CMSwapBigEndianTimeCodeDescriptionToHost(timeCodeDescriptionData: *mut u8, timeCodeDescriptionSize: size_t) -> OSStatus;
177            pub fn CMSwapHostEndianTimeCodeDescriptionToBig(timeCodeDescriptionData: *mut u8, timeCodeDescriptionSize: size_t) -> OSStatus;
178        }
179    }
180
181    pub fn CMMetadataFormatDescriptionCreateFromBigEndianMetadataDescriptionData(
182        allocator: CFAllocatorRef,
183        metadataDescriptionData: *const u8,
184        size: size_t,
185        flavor: CFStringRef,
186        formatDescriptionOut: *mut CMMetadataFormatDescriptionRef,
187    ) -> OSStatus;
188    pub fn CMMetadataFormatDescriptionCreateFromBigEndianMetadataDescriptionBlockBuffer(
189        allocator: CFAllocatorRef,
190        metadataDescriptionBlockBuffer: CMBlockBufferRef,
191        flavor: CFStringRef,
192        formatDescriptionOut: *mut CMMetadataFormatDescriptionRef,
193    ) -> OSStatus;
194    pub fn CMMetadataFormatDescriptionCopyAsBigEndianMetadataDescriptionBlockBuffer(
195        allocator: CFAllocatorRef,
196        metadataFormatDescription: CMMetadataFormatDescriptionRef,
197        flavor: CFStringRef,
198        blockBufferOut: *mut CMBlockBufferRef,
199    ) -> OSStatus;
200
201    cfg_if! {
202        if #[cfg(target_endian = "little")] {
203            pub fn CMSwapBigEndianMetadataDescriptionToHost(metadataDescriptionData: *mut u8, metadataDescriptionSize: size_t) -> OSStatus;
204            pub fn CMSwapHostEndianMetadataDescriptionToBig(metadataDescriptionData: *mut u8, metadataDescriptionSize: size_t) -> OSStatus;
205        }
206    }
207}
208
209impl CMAudioFormatDescription {
210    #[inline]
211    pub fn from_big_endian_sound_description_data(sound_descriptionData: &[u8], flavor: &CFString) -> Result<CMAudioFormatDescription, OSStatus> {
212        let mut format_description: CMAudioFormatDescriptionRef = null_mut();
213        let status = unsafe {
214            CMAudioFormatDescriptionCreateFromBigEndianSoundDescriptionData(
215                kCFAllocatorDefault,
216                sound_descriptionData.as_ptr(),
217                sound_descriptionData.len(),
218                flavor.as_concrete_TypeRef(),
219                &mut format_description,
220            )
221        };
222        if status == 0 {
223            Ok(unsafe { CMAudioFormatDescription::wrap_under_create_rule(format_description) })
224        } else {
225            Err(status)
226        }
227    }
228
229    #[inline]
230    pub fn from_big_endian_sound_description_block_buffer(
231        sound_description_block_buffer: &CMBlockBuffer,
232        flavor: &CFString,
233    ) -> Result<CMAudioFormatDescription, OSStatus> {
234        let mut format_description: CMAudioFormatDescriptionRef = null_mut();
235        let status = unsafe {
236            CMAudioFormatDescriptionCreateFromBigEndianSoundDescriptionBlockBuffer(
237                kCFAllocatorDefault,
238                sound_description_block_buffer.as_concrete_TypeRef(),
239                flavor.as_concrete_TypeRef(),
240                &mut format_description,
241            )
242        };
243        if status == 0 {
244            Ok(unsafe { CMAudioFormatDescription::wrap_under_create_rule(format_description) })
245        } else {
246            Err(status)
247        }
248    }
249
250    #[inline]
251    pub fn copy_as_big_endian_sound_description_block_buffer(&self, flavor: &CFString) -> Result<CMBlockBuffer, OSStatus> {
252        let mut block_buffer: CMBlockBufferRef = null_mut();
253        let status = unsafe {
254            CMAudioFormatDescriptionCopyAsBigEndianSoundDescriptionBlockBuffer(
255                kCFAllocatorDefault,
256                self.as_concrete_TypeRef(),
257                flavor.as_concrete_TypeRef(),
258                &mut block_buffer,
259            )
260        };
261        if status == 0 {
262            Ok(unsafe { CMBlockBuffer::wrap_under_create_rule(block_buffer) })
263        } else {
264            Err(status)
265        }
266    }
267}
268
269impl CMBlockBuffer {
270    #[inline]
271    pub fn does_big_endian_sound_description_require_legacy_cbr_sample_table_layout(&self, flavor: &CFString) -> bool {
272        unsafe { CMDoesBigEndianSoundDescriptionRequireLegacyCBRSampleTableLayout(self.as_concrete_TypeRef(), flavor.as_concrete_TypeRef()) != 0 }
273    }
274}
275
276impl CMVideoFormatDescription {
277    #[inline]
278    pub fn from_big_endian_image_description_data(
279        image_description_data: &[u8],
280        string_encoding: CFStringEncoding,
281        flavor: &CFString,
282    ) -> Result<CMVideoFormatDescription, OSStatus> {
283        let mut format_description: CMVideoFormatDescriptionRef = null_mut();
284        let status = unsafe {
285            CMVideoFormatDescriptionCreateFromBigEndianImageDescriptionData(
286                kCFAllocatorDefault,
287                image_description_data.as_ptr(),
288                image_description_data.len(),
289                string_encoding,
290                flavor.as_concrete_TypeRef(),
291                &mut format_description,
292            )
293        };
294        if status == 0 {
295            Ok(unsafe { CMVideoFormatDescription::wrap_under_create_rule(format_description) })
296        } else {
297            Err(status)
298        }
299    }
300
301    #[inline]
302    pub fn from_big_endian_image_description_block_buffer(
303        image_description_block_buffer: &CMBlockBuffer,
304        string_encoding: CFStringEncoding,
305        flavor: &CFString,
306    ) -> Result<CMVideoFormatDescription, OSStatus> {
307        let mut format_description: CMVideoFormatDescriptionRef = null_mut();
308        let status = unsafe {
309            CMVideoFormatDescriptionCreateFromBigEndianImageDescriptionBlockBuffer(
310                kCFAllocatorDefault,
311                image_description_block_buffer.as_concrete_TypeRef(),
312                string_encoding,
313                flavor.as_concrete_TypeRef(),
314                &mut format_description,
315            )
316        };
317        if status == 0 {
318            Ok(unsafe { CMVideoFormatDescription::wrap_under_create_rule(format_description) })
319        } else {
320            Err(status)
321        }
322    }
323
324    #[inline]
325    pub fn copy_as_big_endian_image_description_block_buffer(
326        &self,
327        string_encoding: CFStringEncoding,
328        flavor: &CFString,
329    ) -> Result<CMBlockBuffer, OSStatus> {
330        let mut block_buffer: CMBlockBufferRef = null_mut();
331        let status = unsafe {
332            CMVideoFormatDescriptionCopyAsBigEndianImageDescriptionBlockBuffer(
333                kCFAllocatorDefault,
334                self.as_concrete_TypeRef(),
335                string_encoding,
336                flavor.as_concrete_TypeRef(),
337                &mut block_buffer,
338            )
339        };
340        if status == 0 {
341            Ok(unsafe { CMBlockBuffer::wrap_under_create_rule(block_buffer) })
342        } else {
343            Err(status)
344        }
345    }
346}