1use convert_case::{Case, Casing};
7use std::ffi::CStr;
8use std::fmt::Debug;
9use std::ops::Range;
10
11#[derive(PartialEq, Eq, Clone, Copy)]
13pub struct MediaType(pub spa_sys::spa_media_type);
14
15#[allow(non_upper_case_globals)]
16impl MediaType {
17 pub const Unknown: Self = Self(spa_sys::SPA_MEDIA_TYPE_unknown);
18 pub const Audio: Self = Self(spa_sys::SPA_MEDIA_TYPE_audio);
19 pub const Video: Self = Self(spa_sys::SPA_MEDIA_TYPE_video);
20 pub const Image: Self = Self(spa_sys::SPA_MEDIA_TYPE_image);
21 pub const Binary: Self = Self(spa_sys::SPA_MEDIA_TYPE_binary);
22 pub const Stream: Self = Self(spa_sys::SPA_MEDIA_TYPE_stream);
23 pub const Application: Self = Self(spa_sys::SPA_MEDIA_TYPE_application);
24
25 pub fn from_raw(raw: spa_sys::spa_media_type) -> Self {
27 Self(raw)
28 }
29
30 pub fn as_raw(&self) -> spa_sys::spa_media_type {
32 self.0
33 }
34}
35
36impl Debug for MediaType {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 let c_str = unsafe {
39 let c_buf = spa_sys::spa_debug_type_find_short_name(
40 spa_sys::spa_type_media_type,
41 self.as_raw(),
42 );
43 if c_buf.is_null() {
44 return f.write_str("Unsupported media type");
45 }
46 CStr::from_ptr(c_buf)
47 };
48 let name = format!(
49 "MediaType::{}",
50 c_str.to_string_lossy().to_case(Case::Pascal)
51 );
52 f.write_str(&name)
53 }
54}
55
56#[derive(PartialEq, PartialOrd, Eq, Clone, Copy)]
58pub struct MediaSubtype(pub spa_sys::spa_media_subtype);
59
60#[allow(non_upper_case_globals)]
61impl MediaSubtype {
62 pub const Unknown: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_unknown);
63 pub const Raw: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_raw);
64 pub const Dsp: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dsp);
65 pub const Iec958: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_iec958);
67 pub const Dsd: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dsd);
68
69 pub const Mp3: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mp3);
70 pub const Aac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_aac);
71 pub const Vorbis: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vorbis);
72 pub const Wma: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_wma);
73 pub const Ra: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_ra);
74 pub const Sbc: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_sbc);
75 pub const Adpcm: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_adpcm);
76 pub const G723: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g723);
77 pub const G726: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g726);
78 pub const G729: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g729);
79 pub const Amr: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_amr);
80 pub const Gsm: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_gsm);
81 #[cfg(feature = "v0_3_65")]
82 pub const Alac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_alac);
83 #[cfg(feature = "v0_3_65")]
84 pub const Flac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_flac);
85 #[cfg(feature = "v0_3_65")]
86 pub const Ape: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_ape);
87 #[cfg(feature = "v0_3_65")]
88 pub const Opus: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_opus);
89
90 pub const H264: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_h264);
91 pub const Mjpg: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mjpg);
92 pub const Dv: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dv);
93 pub const Mpegts: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpegts);
94 pub const H263: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_h263);
95 pub const Mpeg1: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg1);
96 pub const Mpeg2: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg2);
97 pub const Mpeg4: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg4);
98 pub const Xvid: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_xvid);
99 pub const Vc1: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vc1);
100 pub const Vp8: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vp8);
101 pub const Vp9: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vp9);
102 pub const Bayer: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_bayer);
103
104 pub const Jpeg: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_jpeg);
105
106 pub const Midi: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_midi);
107
108 pub const Control: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_control);
110
111 const AUDIO_RANGE: Range<Self> = Self::Mp3..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Video);
112 const VIDEO_RANGE: Range<Self> = Self::H264..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Image);
113 const IMAGE_RANGE: Range<Self> = Self::Jpeg..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Binary);
114 const BINARY_RANGE: Range<Self> = Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Binary)
115 ..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Stream);
116 const STREAM_RANGE: Range<Self> =
117 Self::Midi..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Application);
118 const APPLICATION_RANGE: Range<Self> = Self::Control..Self(spa_sys::spa_media_subtype::MAX);
119
120 pub fn is_audio(&self) -> bool {
121 Self::AUDIO_RANGE.contains(self)
122 }
123
124 pub fn is_video(&self) -> bool {
125 Self::VIDEO_RANGE.contains(self)
126 }
127
128 pub fn is_image(&self) -> bool {
129 Self::IMAGE_RANGE.contains(self)
130 }
131
132 pub fn is_binary(&self) -> bool {
133 Self::BINARY_RANGE.contains(self)
134 }
135
136 pub fn is_stream(&self) -> bool {
137 Self::STREAM_RANGE.contains(self)
138 }
139
140 pub fn is_application(&self) -> bool {
141 Self::APPLICATION_RANGE.contains(self)
142 }
143
144 pub fn from_raw(raw: spa_sys::spa_media_subtype) -> Self {
146 Self(raw)
147 }
148
149 pub fn as_raw(&self) -> spa_sys::spa_media_subtype {
151 self.0
152 }
153}
154
155impl Debug for MediaSubtype {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 let c_str = unsafe {
158 let c_buf = spa_sys::spa_debug_type_find_short_name(
159 spa_sys::spa_type_media_subtype,
160 self.as_raw(),
161 );
162 if c_buf.is_null() {
163 return f.write_str("Unsupported media subtype");
164 }
165 CStr::from_ptr(c_buf)
166 };
167 let name = format!(
168 "MediaSubtype::{}",
169 c_str.to_string_lossy().to_case(Case::Pascal)
170 );
171 f.write_str(&name)
172 }
173}
174
175#[derive(PartialEq, PartialOrd, Eq, Clone, Copy)]
176pub struct FormatProperties(pub spa_sys::spa_format);
177
178#[allow(non_upper_case_globals)]
179impl FormatProperties {
180 pub const MediaType: Self = Self(spa_sys::SPA_FORMAT_mediaType);
182 pub const MediaSubtype: Self = Self(spa_sys::SPA_FORMAT_mediaSubtype);
184
185 pub const AudioFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_format);
187 pub const AudioFlags: Self = Self(spa_sys::SPA_FORMAT_AUDIO_flags);
189 pub const AudioRate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_rate);
191 pub const AudioChannels: Self = Self(spa_sys::SPA_FORMAT_AUDIO_channels);
193 pub const AudioPosition: Self = Self(spa_sys::SPA_FORMAT_AUDIO_position);
195
196 pub const AudioIec958Codec: Self = Self(spa_sys::SPA_FORMAT_AUDIO_iec958Codec);
198
199 pub const AudioBitorder: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitorder);
201 pub const AudioInterleave: Self = Self(spa_sys::SPA_FORMAT_AUDIO_interleave);
203 #[cfg(feature = "v0_3_65")]
205 pub const AudioBitrate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitrate);
206 #[cfg(feature = "v0_3_65")]
208 pub const AudioBlockAlign: Self = Self(spa_sys::SPA_FORMAT_AUDIO_blockAlign);
209
210 #[cfg(feature = "v0_3_65")]
212 pub const AudioAacStreamFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AAC_streamFormat);
213
214 #[cfg(feature = "v0_3_65")]
216 pub const AudioWmaProfile: Self = Self(spa_sys::SPA_FORMAT_AUDIO_WMA_profile);
217
218 #[cfg(feature = "v0_3_65")]
220 pub const AudioAmrBandMode: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AMR_bandMode);
221
222 pub const VideoFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_format);
224 pub const VideoModifier: Self = Self(spa_sys::SPA_FORMAT_VIDEO_modifier);
226 pub const VideoSize: Self = Self(spa_sys::SPA_FORMAT_VIDEO_size);
228 pub const VideoFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_framerate);
230 pub const VideoMaxFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_maxFramerate);
232 pub const VideoViews: Self = Self(spa_sys::SPA_FORMAT_VIDEO_views);
234 pub const VideoInterlaceMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_interlaceMode);
236 pub const VideoPixelAspectRatio: Self = Self(spa_sys::SPA_FORMAT_VIDEO_pixelAspectRatio);
238 pub const VideoMultiviewMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewMode);
240 pub const VideoMultiviewFlags: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewFlags);
242 pub const VideoChromaSite: Self = Self(spa_sys::SPA_FORMAT_VIDEO_chromaSite);
244 pub const VideoColorRange: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorRange);
246 pub const VideoColorMatrix: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorMatrix);
248 pub const VideoTransferFunction: Self = Self(spa_sys::SPA_FORMAT_VIDEO_transferFunction);
250 pub const VideoColorPrimaries: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorPrimaries);
252 pub const VideoProfile: Self = Self(spa_sys::SPA_FORMAT_VIDEO_profile);
254 pub const VideoLevel: Self = Self(spa_sys::SPA_FORMAT_VIDEO_level);
256 pub const VideoH264StreamFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_H264_streamFormat);
258 pub const VideoH264Alignment: Self = Self(spa_sys::SPA_FORMAT_VIDEO_H264_alignment);
260
261 const AUDIO_RANGE: Range<Self> = Self::AudioFormat..Self(spa_sys::SPA_FORMAT_START_Video);
262 const VIDEO_RANGE: Range<Self> = Self::VideoFormat..Self(spa_sys::SPA_FORMAT_START_Image);
263 const IMAGE_RANGE: Range<Self> =
264 Self(spa_sys::SPA_FORMAT_START_Image)..Self(spa_sys::SPA_FORMAT_START_Binary);
265 const BINARY_RANGE: Range<Self> =
266 Self(spa_sys::SPA_FORMAT_START_Binary)..Self(spa_sys::SPA_FORMAT_START_Stream);
267 const STREAM_RANGE: Range<Self> =
268 Self(spa_sys::SPA_FORMAT_START_Stream)..Self(spa_sys::SPA_FORMAT_START_Application);
269 const APPLICATION_RANGE: Range<Self> =
270 Self(spa_sys::SPA_FORMAT_START_Application)..Self(spa_sys::spa_format::MAX);
271
272 pub fn is_audio(&self) -> bool {
273 Self::AUDIO_RANGE.contains(self)
274 }
275
276 pub fn is_video(&self) -> bool {
277 Self::VIDEO_RANGE.contains(self)
278 }
279
280 pub fn is_image(&self) -> bool {
281 Self::IMAGE_RANGE.contains(self)
282 }
283
284 pub fn is_binary(&self) -> bool {
285 Self::BINARY_RANGE.contains(self)
286 }
287
288 pub fn is_stream(&self) -> bool {
289 Self::STREAM_RANGE.contains(self)
290 }
291
292 pub fn is_application(&self) -> bool {
293 Self::APPLICATION_RANGE.contains(self)
294 }
295
296 pub fn from_raw(raw: spa_sys::spa_format) -> Self {
298 Self(raw)
299 }
300
301 pub fn as_raw(&self) -> spa_sys::spa_format {
303 self.0
304 }
305}
306
307impl Debug for FormatProperties {
308 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309 let c_str = unsafe {
310 let c_buf = spa_sys::spa_debug_type_find_name(spa_sys::spa_type_format, self.as_raw());
311 if c_buf.is_null() {
312 return f.write_str("Unsupported format");
313 }
314 CStr::from_ptr(c_buf)
315 };
316 let name = format!(
317 "FormatProperties::{}",
318 c_str
319 .to_string_lossy()
320 .replace("Spa:Pod:Object:Param:Format:", "")
321 .replace(':', " ")
322 .to_case(Case::Pascal)
323 );
324 f.write_str(&name)
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 #[test]
333 #[cfg_attr(miri, ignore)]
334 fn debug_format() {
335 assert_eq!("MediaType::Audio", format!("{:?}", MediaType::Audio));
336 assert_eq!("MediaSubtype::Raw", format!("{:?}", MediaSubtype::Raw));
337 assert_eq!(
338 "FormatProperties::VideoTransferFunction",
339 format!("{:?}", FormatProperties::VideoTransferFunction)
340 );
341 }
342}