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}