apple_cf/cm/
format_description.rs1#![allow(dead_code)]
4
5use crate::{
6 cf::{CFArray, CFDictionary},
7 ffi,
8};
9use std::{fmt, ops::Deref};
10
11pub struct CMFormatDescription(*mut std::ffi::c_void);
13
14impl PartialEq for CMFormatDescription {
15 fn eq(&self, other: &Self) -> bool {
16 self.0 == other.0
17 }
18}
19
20impl Eq for CMFormatDescription {}
21
22impl std::hash::Hash for CMFormatDescription {
23 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
24 unsafe {
25 let hash_value = ffi::cm_format_description_hash(self.0);
26 hash_value.hash(state);
27 }
28 }
29}
30
31pub mod media_types {
33 use crate::utils::four_char_code::FourCharCode;
34
35 pub const VIDEO: FourCharCode = FourCharCode::from_bytes(*b"vide");
37 pub const AUDIO: FourCharCode = FourCharCode::from_bytes(*b"soun");
39 pub const MUXED: FourCharCode = FourCharCode::from_bytes(*b"mux ");
41 pub const TEXT: FourCharCode = FourCharCode::from_bytes(*b"text");
43 pub const CLOSED_CAPTION: FourCharCode = FourCharCode::from_bytes(*b"clcp");
45 pub const METADATA: FourCharCode = FourCharCode::from_bytes(*b"meta");
47 pub const TIMECODE: FourCharCode = FourCharCode::from_bytes(*b"tmcd");
49}
50
51pub mod codec_types {
53 use crate::utils::four_char_code::FourCharCode;
54
55 pub const H264: FourCharCode = FourCharCode::from_bytes(*b"avc1");
58 pub const HEVC: FourCharCode = FourCharCode::from_bytes(*b"hvc1");
60 pub const HEVC_2: FourCharCode = FourCharCode::from_bytes(*b"hev1");
62 pub const JPEG: FourCharCode = FourCharCode::from_bytes(*b"jpeg");
64 pub const PRORES_422: FourCharCode = FourCharCode::from_bytes(*b"apcn");
66 pub const PRORES_4444: FourCharCode = FourCharCode::from_bytes(*b"ap4h");
68
69 pub const AAC: FourCharCode = FourCharCode::from_bytes(*b"aac ");
72 pub const LPCM: FourCharCode = FourCharCode::from_bytes(*b"lpcm");
74 pub const ALAC: FourCharCode = FourCharCode::from_bytes(*b"alac");
76 pub const OPUS: FourCharCode = FourCharCode::from_bytes(*b"opus");
78 pub const FLAC: FourCharCode = FourCharCode::from_bytes(*b"flac");
80}
81
82pub mod metadata_format_types {
84 use crate::utils::four_char_code::FourCharCode;
85
86 pub const ICY: FourCharCode = FourCharCode::from_bytes(*b"icy ");
88 pub const ID3: FourCharCode = FourCharCode::from_bytes(*b"id3 ");
90 pub const BOXED: FourCharCode = FourCharCode::from_bytes(*b"mebx");
92 pub const EMSG: FourCharCode = FourCharCode::from_bytes(*b"emsg");
94}
95
96macro_rules! cfstring_constant_fn {
97 ($vis:vis fn $name:ident => $ffi_name:ident) => {
98 #[must_use]
99 $vis fn $name() -> CFString {
100 let ptr = unsafe { ffi::$ffi_name() };
101 unsafe { CFString::from_raw(ptr) }
102 .expect(concat!(stringify!($ffi_name), " returned NULL"))
103 }
104 };
105}
106
107pub mod format_description_extension_keys {
109 use crate::{cf::CFString, ffi};
110
111 cfstring_constant_fn!(pub fn metadata_key_table => cm_metadata_format_description_extension_key_metadata_key_table);
112}
113
114pub mod metadata_description_keys {
116 use crate::{cf::CFString, ffi};
117
118 cfstring_constant_fn!(pub fn conforming_data_types => cm_metadata_format_description_key_conforming_data_types);
119 cfstring_constant_fn!(pub fn data_type => cm_metadata_format_description_key_data_type);
120 cfstring_constant_fn!(pub fn data_type_namespace => cm_metadata_format_description_key_data_type_namespace);
121 cfstring_constant_fn!(pub fn language_tag => cm_metadata_format_description_key_language_tag);
122 cfstring_constant_fn!(pub fn local_id => cm_metadata_format_description_key_local_id);
123 cfstring_constant_fn!(pub fn namespace => cm_metadata_format_description_key_namespace);
124 cfstring_constant_fn!(pub fn setup_data => cm_metadata_format_description_key_setup_data);
125 cfstring_constant_fn!(pub fn structural_dependency => cm_metadata_format_description_key_structural_dependency);
126 cfstring_constant_fn!(pub fn value => cm_metadata_format_description_key_value);
127}
128
129pub mod metadata_specification_keys {
131 use crate::{cf::CFString, ffi};
132
133 cfstring_constant_fn!(pub fn data_type => cm_metadata_format_description_metadata_specification_key_data_type);
134 cfstring_constant_fn!(pub fn extended_language_tag => cm_metadata_format_description_metadata_specification_key_extended_language_tag);
135 cfstring_constant_fn!(pub fn identifier => cm_metadata_format_description_metadata_specification_key_identifier);
136 cfstring_constant_fn!(pub fn setup_data => cm_metadata_format_description_metadata_specification_key_setup_data);
137 cfstring_constant_fn!(pub fn structural_dependency => cm_metadata_format_description_metadata_specification_key_structural_dependency);
138}
139
140pub mod metadata_structural_dependency_keys {
142 use crate::{cf::CFString, ffi};
143
144 cfstring_constant_fn!(pub fn dependency_is_invalid_flag => cm_metadata_format_description_structural_dependency_key_dependency_is_invalid_flag);
145}
146
147impl CMFormatDescription {
148 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
156 if ptr.is_null() {
157 None
158 } else {
159 Some(Self(ptr))
160 }
161 }
162
163 #[must_use]
170 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
171 if ptr.is_null() {
172 None
173 } else {
174 let retained = unsafe { ffi::cm_format_description_retain(ptr) };
175 unsafe { Self::from_raw(retained) }
176 }
177 }
178
179 pub const unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
185 Self(ptr)
186 }
187
188 #[must_use]
190 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
191 self.0
192 }
193
194 #[must_use]
196 pub fn media_type_raw(&self) -> u32 {
197 unsafe { ffi::cm_format_description_get_media_type(self.0) }
198 }
199
200 #[must_use]
202 pub fn media_type(&self) -> crate::utils::four_char_code::FourCharCode {
203 crate::utils::four_char_code::FourCharCode::from(self.media_type_raw())
204 }
205
206 #[must_use]
208 pub fn media_subtype_raw(&self) -> u32 {
209 unsafe { ffi::cm_format_description_get_media_subtype(self.0) }
210 }
211
212 #[must_use]
214 pub fn media_subtype(&self) -> crate::utils::four_char_code::FourCharCode {
215 crate::utils::four_char_code::FourCharCode::from(self.media_subtype_raw())
216 }
217
218 #[must_use]
220 pub fn extensions(&self) -> Option<*const std::ffi::c_void> {
221 unsafe {
222 let ptr = ffi::cm_format_description_get_extensions(self.0);
223 if ptr.is_null() {
224 None
225 } else {
226 Some(ptr)
227 }
228 }
229 }
230
231 #[must_use]
233 pub fn is_video(&self) -> bool {
234 self.media_type() == media_types::VIDEO
235 }
236
237 #[must_use]
239 pub fn is_audio(&self) -> bool {
240 self.media_type() == media_types::AUDIO
241 }
242
243 #[must_use]
245 pub fn is_muxed(&self) -> bool {
246 self.media_type() == media_types::MUXED
247 }
248
249 #[must_use]
251 pub fn is_text(&self) -> bool {
252 self.media_type() == media_types::TEXT
253 }
254
255 #[must_use]
257 pub fn is_closed_caption(&self) -> bool {
258 self.media_type() == media_types::CLOSED_CAPTION
259 }
260
261 #[must_use]
263 pub fn is_metadata(&self) -> bool {
264 self.media_type() == media_types::METADATA
265 }
266
267 #[must_use]
269 pub fn is_timecode(&self) -> bool {
270 self.media_type() == media_types::TIMECODE
271 }
272
273 #[must_use]
275 pub fn media_type_string(&self) -> String {
276 self.media_type().display()
277 }
278
279 #[must_use]
281 pub fn media_subtype_string(&self) -> String {
282 self.media_subtype().display()
283 }
284
285 #[must_use]
287 pub fn is_h264(&self) -> bool {
288 self.media_subtype() == codec_types::H264
289 }
290
291 #[must_use]
293 pub fn is_hevc(&self) -> bool {
294 let subtype = self.media_subtype();
295 subtype == codec_types::HEVC || subtype == codec_types::HEVC_2
296 }
297
298 #[must_use]
300 pub fn is_aac(&self) -> bool {
301 self.media_subtype() == codec_types::AAC
302 }
303
304 #[must_use]
306 pub fn is_pcm(&self) -> bool {
307 self.media_subtype() == codec_types::LPCM
308 }
309
310 #[must_use]
312 pub fn is_prores(&self) -> bool {
313 let subtype = self.media_subtype();
314 subtype == codec_types::PRORES_422 || subtype == codec_types::PRORES_4444
315 }
316
317 #[must_use]
319 pub fn is_alac(&self) -> bool {
320 self.media_subtype() == codec_types::ALAC
321 }
322
323 #[must_use]
329 pub fn audio_sample_rate(&self) -> Option<f64> {
330 if !self.is_audio() {
331 return None;
332 }
333 let rate = unsafe { ffi::cm_format_description_get_audio_sample_rate(self.0) };
334 if rate > 0.0 {
335 Some(rate)
336 } else {
337 None
338 }
339 }
340
341 #[must_use]
345 pub fn audio_channel_count(&self) -> Option<u32> {
346 if !self.is_audio() {
347 return None;
348 }
349 let count = unsafe { ffi::cm_format_description_get_audio_channel_count(self.0) };
350 if count > 0 {
351 Some(count)
352 } else {
353 None
354 }
355 }
356
357 #[must_use]
361 pub fn audio_bits_per_channel(&self) -> Option<u32> {
362 if !self.is_audio() {
363 return None;
364 }
365 let bits = unsafe { ffi::cm_format_description_get_audio_bits_per_channel(self.0) };
366 if bits > 0 {
367 Some(bits)
368 } else {
369 None
370 }
371 }
372
373 #[must_use]
377 pub fn audio_bytes_per_frame(&self) -> Option<u32> {
378 if !self.is_audio() {
379 return None;
380 }
381 let bytes = unsafe { ffi::cm_format_description_get_audio_bytes_per_frame(self.0) };
382 if bytes > 0 {
383 Some(bytes)
384 } else {
385 None
386 }
387 }
388
389 #[must_use]
393 pub fn audio_format_flags(&self) -> Option<u32> {
394 if !self.is_audio() {
395 return None;
396 }
397 Some(unsafe { ffi::cm_format_description_get_audio_format_flags(self.0) })
398 }
399
400 #[must_use]
402 pub fn audio_is_float(&self) -> bool {
403 self.audio_format_flags().is_some_and(|f| f & 1 != 0)
405 }
406
407 #[must_use]
409 pub fn audio_is_big_endian(&self) -> bool {
410 self.audio_format_flags().is_some_and(|f| f & 2 != 0)
412 }
413}
414
415crate::utils::retained::cf_retained!(
416 CMFormatDescription,
417 retain = ffi::cm_format_description_retain,
418 release = ffi::cm_format_description_release,
419 drop = unchecked,
420);
421
422unsafe impl Send for CMFormatDescription {}
426unsafe impl Sync for CMFormatDescription {}
427
428impl fmt::Debug for CMFormatDescription {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 f.debug_struct("CMFormatDescription")
431 .field("media_type", &self.media_type_string())
432 .field("codec", &self.media_subtype_string())
433 .finish()
434 }
435}
436
437impl fmt::Display for CMFormatDescription {
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 write!(
440 f,
441 "CMFormatDescription(type: 0x{:08X}, subtype: 0x{:08X})",
442 self.media_type_raw(),
443 self.media_subtype_raw()
444 )
445 }
446}
447
448#[derive(Clone, PartialEq, Eq, Hash)]
450pub struct CMMetadataFormatDescription(CMFormatDescription);
451
452impl CMMetadataFormatDescription {
453 #[must_use]
461 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
462 unsafe { CMFormatDescription::from_raw(ptr) }.map(Self)
463 }
464
465 #[must_use]
472 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
473 unsafe { CMFormatDescription::from_raw_borrowed(ptr) }.map(Self)
474 }
475
476 pub const unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
482 Self(unsafe { CMFormatDescription::from_ptr(ptr) })
483 }
484
485 #[must_use]
487 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
488 self.0.as_ptr()
489 }
490
491 #[must_use]
493 pub const fn as_format_description(&self) -> &CMFormatDescription {
494 &self.0
495 }
496
497 #[must_use]
499 pub fn into_format_description(self) -> CMFormatDescription {
500 self.0
501 }
502
503 pub fn create_with_keys(
509 metadata_type: crate::utils::four_char_code::FourCharCode,
510 keys: Option<&CFArray>,
511 ) -> Result<Self, i32> {
512 let mut ptr = std::ptr::null_mut();
513 let status = unsafe {
514 ffi::cm_metadata_format_description_create_with_keys(
515 metadata_type.into(),
516 keys.map_or(std::ptr::null_mut(), CFArray::as_ptr),
517 &mut ptr,
518 )
519 };
520 if status == 0 && !ptr.is_null() {
521 unsafe { Self::from_raw(ptr) }.ok_or(status)
522 } else {
523 Err(status)
524 }
525 }
526
527 pub fn create_with_metadata_specifications(
533 metadata_type: crate::utils::four_char_code::FourCharCode,
534 metadata_specifications: &CFArray,
535 ) -> Result<Self, i32> {
536 let mut ptr = std::ptr::null_mut();
537 let status = unsafe {
538 ffi::cm_metadata_format_description_create_with_metadata_specifications(
539 metadata_type.into(),
540 metadata_specifications.as_ptr(),
541 &mut ptr,
542 )
543 };
544 if status == 0 && !ptr.is_null() {
545 unsafe { Self::from_raw(ptr) }.ok_or(status)
546 } else {
547 Err(status)
548 }
549 }
550
551 pub fn extend_with_metadata_specifications(
557 &self,
558 metadata_specifications: &CFArray,
559 ) -> Result<Self, i32> {
560 let mut ptr = std::ptr::null_mut();
561 let status = unsafe {
562 ffi::cm_metadata_format_description_create_with_description_and_metadata_specifications(
563 self.as_ptr(),
564 metadata_specifications.as_ptr(),
565 &mut ptr,
566 )
567 };
568 if status == 0 && !ptr.is_null() {
569 unsafe { Self::from_raw(ptr) }.ok_or(status)
570 } else {
571 Err(status)
572 }
573 }
574
575 pub fn merge(&self, other: &Self) -> Result<Self, i32> {
581 let mut ptr = std::ptr::null_mut();
582 let status = unsafe {
583 ffi::cm_metadata_format_description_create_by_merging_descriptions(
584 self.as_ptr(),
585 other.as_ptr(),
586 &mut ptr,
587 )
588 };
589 if status == 0 && !ptr.is_null() {
590 unsafe { Self::from_raw(ptr) }.ok_or(status)
591 } else {
592 Err(status)
593 }
594 }
595
596 #[must_use]
598 pub fn identifiers(&self) -> Option<CFArray> {
599 let ptr = unsafe { ffi::cm_metadata_format_description_get_identifiers(self.as_ptr()) };
600 unsafe { CFArray::from_raw(ptr) }
601 }
602
603 #[must_use]
605 pub fn key_with_local_id(&self, local_id: u32) -> Option<CFDictionary> {
606 let ptr = unsafe {
607 ffi::cm_metadata_format_description_get_key_with_local_id(self.as_ptr(), local_id)
608 };
609 unsafe { CFDictionary::from_raw(ptr) }
610 }
611}
612
613impl Deref for CMMetadataFormatDescription {
614 type Target = CMFormatDescription;
615
616 fn deref(&self) -> &Self::Target {
617 &self.0
618 }
619}
620
621impl TryFrom<CMFormatDescription> for CMMetadataFormatDescription {
622 type Error = CMFormatDescription;
623
624 fn try_from(value: CMFormatDescription) -> Result<Self, Self::Error> {
625 if value.is_metadata() {
626 Ok(Self(value))
627 } else {
628 Err(value)
629 }
630 }
631}
632
633impl From<CMMetadataFormatDescription> for CMFormatDescription {
634 fn from(value: CMMetadataFormatDescription) -> Self {
635 value.0
636 }
637}
638
639impl fmt::Debug for CMMetadataFormatDescription {
640 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
641 f.debug_struct("CMMetadataFormatDescription")
642 .field("media_type", &self.media_type_string())
643 .field("codec", &self.media_subtype_string())
644 .finish()
645 }
646}
647
648impl fmt::Display for CMMetadataFormatDescription {
649 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650 fmt::Display::fmt(&self.0, f)
651 }
652}