libspa/param/
format.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4//! Types for dealing with SPA formats.
5
6use convert_case::{Case, Casing};
7use std::ffi::CStr;
8use std::fmt::Debug;
9use std::ops::Range;
10
11/// Different media types
12#[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    /// Obtain a [`MediaType`] from a raw `spa_media_type` variant.
26    pub fn from_raw(raw: spa_sys::spa_media_type) -> Self {
27        Self(raw)
28    }
29
30    /// Get the raw [`spa_sys::spa_media_type`] representing this `MediaType`.
31    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/// Different media sub-types
57#[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    /// S/PDIF
66    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    /// control stream, data contains spa_pod_sequence with control info.
109    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    /// Obtain a [`MediaSubtype`] from a raw `spa_media_subtype` variant.
145    pub fn from_raw(raw: spa_sys::spa_media_subtype) -> Self {
146        Self(raw)
147    }
148
149    /// Get the raw [`spa_sys::spa_media_subtype`] representing this `MediaSubtype`.
150    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    /// media type (Id enum spa_media_type)
181    pub const MediaType: Self = Self(spa_sys::SPA_FORMAT_mediaType);
182    /// media subtype (Id enum spa_media_subtype)
183    pub const MediaSubtype: Self = Self(spa_sys::SPA_FORMAT_mediaSubtype);
184
185    /// audio format, (Id enum spa_audio_format)
186    pub const AudioFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_format);
187    /// optional flags (Int)
188    pub const AudioFlags: Self = Self(spa_sys::SPA_FORMAT_AUDIO_flags);
189    /// sample rate (Int)
190    pub const AudioRate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_rate);
191    /// number of audio channels (Int)
192    pub const AudioChannels: Self = Self(spa_sys::SPA_FORMAT_AUDIO_channels);
193    /// channel positions (Id enum spa_audio_position)
194    pub const AudioPosition: Self = Self(spa_sys::SPA_FORMAT_AUDIO_position);
195
196    /// codec used (IEC958) (Id enum spa_audio_iec958_codec)
197    pub const AudioIec958Codec: Self = Self(spa_sys::SPA_FORMAT_AUDIO_iec958Codec);
198
199    /// bit order (Id enum spa_param_bitorder)
200    pub const AudioBitorder: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitorder);
201    /// Interleave bytes (Int)
202    pub const AudioInterleave: Self = Self(spa_sys::SPA_FORMAT_AUDIO_interleave);
203    /// bit rate (Int)
204    #[cfg(feature = "v0_3_65")]
205    pub const AudioBitrate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitrate);
206    /// audio data block alignment (Int)
207    #[cfg(feature = "v0_3_65")]
208    pub const AudioBlockAlign: Self = Self(spa_sys::SPA_FORMAT_AUDIO_blockAlign);
209
210    /// AAC stream format, (Id enum spa_audio_aac_stream_format)
211    #[cfg(feature = "v0_3_65")]
212    pub const AudioAacStreamFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AAC_streamFormat);
213
214    /// WMA profile (Id enum spa_audio_wma_profile)
215    #[cfg(feature = "v0_3_65")]
216    pub const AudioWmaProfile: Self = Self(spa_sys::SPA_FORMAT_AUDIO_WMA_profile);
217
218    /// AMR band mode (Id enum spa_audio_amr_band_mode)
219    #[cfg(feature = "v0_3_65")]
220    pub const AudioAmrBandMode: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AMR_bandMode);
221
222    /// video format (Id enum spa_video_format)
223    pub const VideoFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_format);
224    /// format modifier (Long), use only with DMA-BUF and omit for other buffer types
225    pub const VideoModifier: Self = Self(spa_sys::SPA_FORMAT_VIDEO_modifier);
226    /// size (Rectangle)
227    pub const VideoSize: Self = Self(spa_sys::SPA_FORMAT_VIDEO_size);
228    /// frame rate (Fraction)
229    pub const VideoFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_framerate);
230    /// maximum frame rate (Fraction)
231    pub const VideoMaxFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_maxFramerate);
232    /// number of views (Int)
233    pub const VideoViews: Self = Self(spa_sys::SPA_FORMAT_VIDEO_views);
234    /// (Id enum spa_video_interlace_mode)
235    pub const VideoInterlaceMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_interlaceMode);
236    /// (Rectangle)
237    pub const VideoPixelAspectRatio: Self = Self(spa_sys::SPA_FORMAT_VIDEO_pixelAspectRatio);
238    /// (Id enum spa_video_multiview_mode)
239    pub const VideoMultiviewMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewMode);
240    /// (Id enum spa_video_multiview_flags)
241    pub const VideoMultiviewFlags: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewFlags);
242    /// /Id enum spa_video_chroma_site)
243    pub const VideoChromaSite: Self = Self(spa_sys::SPA_FORMAT_VIDEO_chromaSite);
244    /// /Id enum spa_video_color_range)
245    pub const VideoColorRange: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorRange);
246    /// /Id enum spa_video_color_matrix)
247    pub const VideoColorMatrix: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorMatrix);
248    /// /Id enum spa_video_transfer_function)
249    pub const VideoTransferFunction: Self = Self(spa_sys::SPA_FORMAT_VIDEO_transferFunction);
250    ///  /Id enum spa_video_color_primaries)
251    pub const VideoColorPrimaries: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorPrimaries);
252    /// (Int)
253    pub const VideoProfile: Self = Self(spa_sys::SPA_FORMAT_VIDEO_profile);
254    /// (Int)
255    pub const VideoLevel: Self = Self(spa_sys::SPA_FORMAT_VIDEO_level);
256    /// (Id enum spa_h264_stream_format)
257    pub const VideoH264StreamFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_H264_streamFormat);
258    /// (Id enum spa_h264_alignment)
259    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    /// Obtain a [`FormatProperties`] from a raw `spa_format` variant.
297    pub fn from_raw(raw: spa_sys::spa_format) -> Self {
298        Self(raw)
299    }
300
301    /// Get the raw [`spa_sys::spa_format`] representing this `FormatProperties`.
302    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}