core_media/
format_description_bridge.rs

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