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