screencapturekit/cm/
format_description.rs

1//! `CMFormatDescription` - Media format description
2
3#![allow(dead_code)]
4
5use super::ffi;
6use std::fmt;
7
8pub struct CMFormatDescription(*mut std::ffi::c_void);
9
10impl PartialEq for CMFormatDescription {
11    fn eq(&self, other: &Self) -> bool {
12        self.0 == other.0
13    }
14}
15
16impl Eq for CMFormatDescription {}
17
18impl std::hash::Hash for CMFormatDescription {
19    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
20        unsafe {
21            let hash_value = ffi::cm_format_description_hash(self.0);
22            hash_value.hash(state);
23        }
24    }
25}
26
27/// Common media type constants
28pub mod media_types {
29    use crate::utils::four_char_code::FourCharCode;
30
31    /// Video media type ('vide')
32    pub const VIDEO: FourCharCode = FourCharCode::from_bytes(*b"vide");
33    /// Audio media type ('soun')
34    pub const AUDIO: FourCharCode = FourCharCode::from_bytes(*b"soun");
35    /// Muxed media type ('mux ')
36    pub const MUXED: FourCharCode = FourCharCode::from_bytes(*b"mux ");
37    /// Text/subtitle media type ('text')
38    pub const TEXT: FourCharCode = FourCharCode::from_bytes(*b"text");
39    /// Closed caption media type ('clcp')
40    pub const CLOSED_CAPTION: FourCharCode = FourCharCode::from_bytes(*b"clcp");
41    /// Metadata media type ('meta')
42    pub const METADATA: FourCharCode = FourCharCode::from_bytes(*b"meta");
43    /// Timecode media type ('tmcd')
44    pub const TIMECODE: FourCharCode = FourCharCode::from_bytes(*b"tmcd");
45}
46
47/// Common codec type constants
48pub mod codec_types {
49    use crate::utils::four_char_code::FourCharCode;
50
51    // Video codecs
52    /// H.264/AVC ('avc1')
53    pub const H264: FourCharCode = FourCharCode::from_bytes(*b"avc1");
54    /// HEVC/H.265 ('hvc1')
55    pub const HEVC: FourCharCode = FourCharCode::from_bytes(*b"hvc1");
56    /// HEVC/H.265 alternative ('hev1')
57    pub const HEVC_2: FourCharCode = FourCharCode::from_bytes(*b"hev1");
58    /// JPEG ('jpeg')
59    pub const JPEG: FourCharCode = FourCharCode::from_bytes(*b"jpeg");
60    /// Apple `ProRes` 422 ('apcn')
61    pub const PRORES_422: FourCharCode = FourCharCode::from_bytes(*b"apcn");
62    /// Apple `ProRes` 4444 ('ap4h')
63    pub const PRORES_4444: FourCharCode = FourCharCode::from_bytes(*b"ap4h");
64
65    // Audio codecs
66    /// AAC ('aac ')
67    pub const AAC: FourCharCode = FourCharCode::from_bytes(*b"aac ");
68    /// Linear PCM ('lpcm')
69    pub const LPCM: FourCharCode = FourCharCode::from_bytes(*b"lpcm");
70    /// Apple Lossless ('alac')
71    pub const ALAC: FourCharCode = FourCharCode::from_bytes(*b"alac");
72    /// Opus ('opus')
73    pub const OPUS: FourCharCode = FourCharCode::from_bytes(*b"opus");
74    /// FLAC ('flac')
75    pub const FLAC: FourCharCode = FourCharCode::from_bytes(*b"flac");
76}
77
78impl CMFormatDescription {
79    pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
80        if ptr.is_null() {
81            None
82        } else {
83            Some(Self(ptr))
84        }
85    }
86
87    /// # Safety
88    /// The caller must ensure the pointer is a valid `CMFormatDescription` pointer.
89    pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
90        Self(ptr)
91    }
92
93    pub fn as_ptr(&self) -> *mut std::ffi::c_void {
94        self.0
95    }
96
97    /// Get the media type (video, audio, etc.)
98    pub fn get_media_type(&self) -> u32 {
99        unsafe { ffi::cm_format_description_get_media_type(self.0) }
100    }
101
102    /// Get the media type as `FourCharCode`
103    pub fn media_type(&self) -> crate::utils::four_char_code::FourCharCode {
104        crate::utils::four_char_code::FourCharCode::from(self.get_media_type())
105    }
106
107    /// Get the media subtype (codec type)
108    pub fn get_media_subtype(&self) -> u32 {
109        unsafe { ffi::cm_format_description_get_media_subtype(self.0) }
110    }
111
112    /// Get the media subtype as `FourCharCode`
113    pub fn media_subtype(&self) -> crate::utils::four_char_code::FourCharCode {
114        crate::utils::four_char_code::FourCharCode::from(self.get_media_subtype())
115    }
116
117    /// Get format description extensions
118    pub fn get_extensions(&self) -> Option<*const std::ffi::c_void> {
119        unsafe {
120            let ptr = ffi::cm_format_description_get_extensions(self.0);
121            if ptr.is_null() {
122                None
123            } else {
124                Some(ptr)
125            }
126        }
127    }
128
129    /// Check if this is a video format description
130    pub fn is_video(&self) -> bool {
131        self.media_type() == media_types::VIDEO
132    }
133
134    /// Check if this is an audio format description
135    pub fn is_audio(&self) -> bool {
136        self.media_type() == media_types::AUDIO
137    }
138
139    /// Check if this is a muxed format description
140    pub fn is_muxed(&self) -> bool {
141        self.media_type() == media_types::MUXED
142    }
143
144    /// Check if this is a text/subtitle format description
145    pub fn is_text(&self) -> bool {
146        self.media_type() == media_types::TEXT
147    }
148
149    /// Check if this is a closed caption format description
150    pub fn is_closed_caption(&self) -> bool {
151        self.media_type() == media_types::CLOSED_CAPTION
152    }
153
154    /// Check if this is a metadata format description
155    pub fn is_metadata(&self) -> bool {
156        self.media_type() == media_types::METADATA
157    }
158
159    /// Check if this is a timecode format description
160    pub fn is_timecode(&self) -> bool {
161        self.media_type() == media_types::TIMECODE
162    }
163
164    /// Get a human-readable string for the media type
165    pub fn media_type_string(&self) -> String {
166        self.media_type().display()
167    }
168
169    /// Get a human-readable string for the media subtype (codec)
170    pub fn media_subtype_string(&self) -> String {
171        self.media_subtype().display()
172    }
173
174    /// Check if the codec is H.264
175    pub fn is_h264(&self) -> bool {
176        self.media_subtype() == codec_types::H264
177    }
178
179    /// Check if the codec is HEVC/H.265
180    pub fn is_hevc(&self) -> bool {
181        let subtype = self.media_subtype();
182        subtype == codec_types::HEVC || subtype == codec_types::HEVC_2
183    }
184
185    /// Check if the codec is AAC
186    pub fn is_aac(&self) -> bool {
187        self.media_subtype() == codec_types::AAC
188    }
189
190    /// Check if the codec is PCM
191    pub fn is_pcm(&self) -> bool {
192        self.media_subtype() == codec_types::LPCM
193    }
194
195    /// Check if the codec is `ProRes`
196    pub fn is_prores(&self) -> bool {
197        let subtype = self.media_subtype();
198        subtype == codec_types::PRORES_422 || subtype == codec_types::PRORES_4444
199    }
200
201    /// Check if the codec is Apple Lossless (ALAC)
202    pub fn is_alac(&self) -> bool {
203        self.media_subtype() == codec_types::ALAC
204    }
205}
206
207impl Clone for CMFormatDescription {
208    fn clone(&self) -> Self {
209        unsafe {
210            let ptr = ffi::cm_format_description_retain(self.0);
211            Self(ptr)
212        }
213    }
214}
215
216impl Drop for CMFormatDescription {
217    fn drop(&mut self) {
218        unsafe {
219            ffi::cm_format_description_release(self.0);
220        }
221    }
222}
223
224unsafe impl Send for CMFormatDescription {}
225unsafe impl Sync for CMFormatDescription {}
226
227impl fmt::Display for CMFormatDescription {
228    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229        write!(
230            f,
231            "CMFormatDescription(type: 0x{:08X}, subtype: 0x{:08X})",
232            self.get_media_type(),
233            self.get_media_subtype()
234        )
235    }
236}