screencapturekit/cm/
format_description.rs1#![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
27pub mod media_types {
29 use crate::utils::four_char_code::FourCharCode;
30
31 pub const VIDEO: FourCharCode = FourCharCode::from_bytes(*b"vide");
33 pub const AUDIO: FourCharCode = FourCharCode::from_bytes(*b"soun");
35 pub const MUXED: FourCharCode = FourCharCode::from_bytes(*b"mux ");
37 pub const TEXT: FourCharCode = FourCharCode::from_bytes(*b"text");
39 pub const CLOSED_CAPTION: FourCharCode = FourCharCode::from_bytes(*b"clcp");
41 pub const METADATA: FourCharCode = FourCharCode::from_bytes(*b"meta");
43 pub const TIMECODE: FourCharCode = FourCharCode::from_bytes(*b"tmcd");
45}
46
47pub mod codec_types {
49 use crate::utils::four_char_code::FourCharCode;
50
51 pub const H264: FourCharCode = FourCharCode::from_bytes(*b"avc1");
54 pub const HEVC: FourCharCode = FourCharCode::from_bytes(*b"hvc1");
56 pub const HEVC_2: FourCharCode = FourCharCode::from_bytes(*b"hev1");
58 pub const JPEG: FourCharCode = FourCharCode::from_bytes(*b"jpeg");
60 pub const PRORES_422: FourCharCode = FourCharCode::from_bytes(*b"apcn");
62 pub const PRORES_4444: FourCharCode = FourCharCode::from_bytes(*b"ap4h");
64
65 pub const AAC: FourCharCode = FourCharCode::from_bytes(*b"aac ");
68 pub const LPCM: FourCharCode = FourCharCode::from_bytes(*b"lpcm");
70 pub const ALAC: FourCharCode = FourCharCode::from_bytes(*b"alac");
72 pub const OPUS: FourCharCode = FourCharCode::from_bytes(*b"opus");
74 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 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 pub fn media_type_raw(&self) -> u32 {
99 unsafe { ffi::cm_format_description_get_media_type(self.0) }
100 }
101
102 pub fn media_type(&self) -> crate::utils::four_char_code::FourCharCode {
104 crate::utils::four_char_code::FourCharCode::from(self.media_type_raw())
105 }
106
107 pub fn media_subtype_raw(&self) -> u32 {
109 unsafe { ffi::cm_format_description_get_media_subtype(self.0) }
110 }
111
112 pub fn media_subtype(&self) -> crate::utils::four_char_code::FourCharCode {
114 crate::utils::four_char_code::FourCharCode::from(self.media_subtype_raw())
115 }
116
117 pub fn 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 pub fn is_video(&self) -> bool {
131 self.media_type() == media_types::VIDEO
132 }
133
134 pub fn is_audio(&self) -> bool {
136 self.media_type() == media_types::AUDIO
137 }
138
139 pub fn is_muxed(&self) -> bool {
141 self.media_type() == media_types::MUXED
142 }
143
144 pub fn is_text(&self) -> bool {
146 self.media_type() == media_types::TEXT
147 }
148
149 pub fn is_closed_caption(&self) -> bool {
151 self.media_type() == media_types::CLOSED_CAPTION
152 }
153
154 pub fn is_metadata(&self) -> bool {
156 self.media_type() == media_types::METADATA
157 }
158
159 pub fn is_timecode(&self) -> bool {
161 self.media_type() == media_types::TIMECODE
162 }
163
164 pub fn media_type_string(&self) -> String {
166 self.media_type().display()
167 }
168
169 pub fn media_subtype_string(&self) -> String {
171 self.media_subtype().display()
172 }
173
174 pub fn is_h264(&self) -> bool {
176 self.media_subtype() == codec_types::H264
177 }
178
179 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 pub fn is_aac(&self) -> bool {
187 self.media_subtype() == codec_types::AAC
188 }
189
190 pub fn is_pcm(&self) -> bool {
192 self.media_subtype() == codec_types::LPCM
193 }
194
195 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 pub fn is_alac(&self) -> bool {
203 self.media_subtype() == codec_types::ALAC
204 }
205
206 pub fn audio_sample_rate(&self) -> Option<f64> {
212 if !self.is_audio() {
213 return None;
214 }
215 let rate = unsafe { ffi::cm_format_description_get_audio_sample_rate(self.0) };
216 if rate > 0.0 {
217 Some(rate)
218 } else {
219 None
220 }
221 }
222
223 pub fn audio_channel_count(&self) -> Option<u32> {
227 if !self.is_audio() {
228 return None;
229 }
230 let count = unsafe { ffi::cm_format_description_get_audio_channel_count(self.0) };
231 if count > 0 {
232 Some(count)
233 } else {
234 None
235 }
236 }
237
238 pub fn audio_bits_per_channel(&self) -> Option<u32> {
242 if !self.is_audio() {
243 return None;
244 }
245 let bits = unsafe { ffi::cm_format_description_get_audio_bits_per_channel(self.0) };
246 if bits > 0 {
247 Some(bits)
248 } else {
249 None
250 }
251 }
252
253 pub fn audio_bytes_per_frame(&self) -> Option<u32> {
257 if !self.is_audio() {
258 return None;
259 }
260 let bytes = unsafe { ffi::cm_format_description_get_audio_bytes_per_frame(self.0) };
261 if bytes > 0 {
262 Some(bytes)
263 } else {
264 None
265 }
266 }
267
268 pub fn audio_format_flags(&self) -> Option<u32> {
272 if !self.is_audio() {
273 return None;
274 }
275 Some(unsafe { ffi::cm_format_description_get_audio_format_flags(self.0) })
276 }
277
278 pub fn audio_is_float(&self) -> bool {
280 self.audio_format_flags().is_some_and(|f| f & 1 != 0)
282 }
283
284 pub fn audio_is_big_endian(&self) -> bool {
286 self.audio_format_flags().is_some_and(|f| f & 2 != 0)
288 }
289}
290
291impl Clone for CMFormatDescription {
292 fn clone(&self) -> Self {
293 unsafe {
294 let ptr = ffi::cm_format_description_retain(self.0);
295 Self(ptr)
296 }
297 }
298}
299
300impl Drop for CMFormatDescription {
301 fn drop(&mut self) {
302 unsafe {
303 ffi::cm_format_description_release(self.0);
304 }
305 }
306}
307
308unsafe impl Send for CMFormatDescription {}
309unsafe impl Sync for CMFormatDescription {}
310
311impl fmt::Debug for CMFormatDescription {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 f.debug_struct("CMFormatDescription")
314 .field("media_type", &self.media_type_string())
315 .field("codec", &self.media_subtype_string())
316 .finish()
317 }
318}
319
320impl fmt::Display for CMFormatDescription {
321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 write!(
323 f,
324 "CMFormatDescription(type: 0x{:08X}, subtype: 0x{:08X})",
325 self.media_type_raw(),
326 self.media_subtype_raw()
327 )
328 }
329}