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 std::ffi::CStr;
7use std::fmt::Debug;
8use std::ops::Range;
9
10use crate::utils::fmt_pascal_case;
11
12/// Different media types
13#[derive(PartialEq, Eq, Clone, Copy)]
14pub struct MediaType(pub spa_sys::spa_media_type);
15
16#[allow(non_upper_case_globals)]
17impl MediaType {
18    pub const Unknown: Self = Self(spa_sys::SPA_MEDIA_TYPE_unknown);
19    pub const Audio: Self = Self(spa_sys::SPA_MEDIA_TYPE_audio);
20    pub const Video: Self = Self(spa_sys::SPA_MEDIA_TYPE_video);
21    pub const Image: Self = Self(spa_sys::SPA_MEDIA_TYPE_image);
22    pub const Binary: Self = Self(spa_sys::SPA_MEDIA_TYPE_binary);
23    pub const Stream: Self = Self(spa_sys::SPA_MEDIA_TYPE_stream);
24    pub const Application: Self = Self(spa_sys::SPA_MEDIA_TYPE_application);
25
26    /// Obtain a [`MediaType`] from a raw `spa_media_type` variant.
27    pub fn from_raw(raw: spa_sys::spa_media_type) -> Self {
28        Self(raw)
29    }
30
31    /// Get the raw [`spa_sys::spa_media_type`] representing this `MediaType`.
32    pub fn as_raw(&self) -> spa_sys::spa_media_type {
33        self.0
34    }
35}
36
37impl Debug for MediaType {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        let c_str = unsafe {
40            let c_buf = spa_sys::spa_debug_type_find_short_name(
41                spa_sys::spa_type_media_type,
42                self.as_raw(),
43            );
44            if c_buf.is_null() {
45                return f.write_str("Unsupported media type");
46            }
47            CStr::from_ptr(c_buf)
48        };
49        f.write_str("MediaType::")?;
50        fmt_pascal_case(f, &c_str.to_string_lossy())
51    }
52}
53
54/// Different media sub-types
55#[derive(PartialEq, PartialOrd, Eq, Clone, Copy)]
56pub struct MediaSubtype(pub spa_sys::spa_media_subtype);
57
58#[allow(non_upper_case_globals)]
59impl MediaSubtype {
60    pub const Unknown: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_unknown);
61    pub const Raw: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_raw);
62    pub const Dsp: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dsp);
63    /// S/PDIF
64    pub const Iec958: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_iec958);
65    pub const Dsd: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dsd);
66
67    pub const Mp3: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mp3);
68    pub const Aac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_aac);
69    pub const Vorbis: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vorbis);
70    pub const Wma: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_wma);
71    pub const Ra: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_ra);
72    pub const Sbc: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_sbc);
73    pub const Adpcm: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_adpcm);
74    pub const G723: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g723);
75    pub const G726: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g726);
76    pub const G729: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_g729);
77    pub const Amr: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_amr);
78    pub const Gsm: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_gsm);
79    #[cfg(feature = "v0_3_65")]
80    pub const Alac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_alac);
81    #[cfg(feature = "v0_3_65")]
82    pub const Flac: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_flac);
83    #[cfg(feature = "v0_3_65")]
84    pub const Ape: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_ape);
85    #[cfg(feature = "v0_3_65")]
86    pub const Opus: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_opus);
87
88    pub const H264: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_h264);
89    pub const Mjpg: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mjpg);
90    pub const Dv: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_dv);
91    pub const Mpegts: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpegts);
92    pub const H263: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_h263);
93    pub const Mpeg1: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg1);
94    pub const Mpeg2: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg2);
95    pub const Mpeg4: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_mpeg4);
96    pub const Xvid: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_xvid);
97    pub const Vc1: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vc1);
98    pub const Vp8: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vp8);
99    pub const Vp9: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_vp9);
100    pub const Bayer: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_bayer);
101
102    pub const Jpeg: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_jpeg);
103
104    pub const Midi: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_midi);
105
106    /// control stream, data contains spa_pod_sequence with control info.
107    pub const Control: Self = Self(spa_sys::SPA_MEDIA_SUBTYPE_control);
108
109    const AUDIO_RANGE: Range<Self> = Self::Mp3..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Video);
110    const VIDEO_RANGE: Range<Self> = Self::H264..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Image);
111    const IMAGE_RANGE: Range<Self> = Self::Jpeg..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Binary);
112    const BINARY_RANGE: Range<Self> = Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Binary)
113        ..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Stream);
114    const STREAM_RANGE: Range<Self> =
115        Self::Midi..Self(spa_sys::SPA_MEDIA_SUBTYPE_START_Application);
116    const APPLICATION_RANGE: Range<Self> = Self::Control..Self(spa_sys::spa_media_subtype::MAX);
117
118    pub fn is_audio(&self) -> bool {
119        Self::AUDIO_RANGE.contains(self)
120    }
121
122    pub fn is_video(&self) -> bool {
123        Self::VIDEO_RANGE.contains(self)
124    }
125
126    pub fn is_image(&self) -> bool {
127        Self::IMAGE_RANGE.contains(self)
128    }
129
130    pub fn is_binary(&self) -> bool {
131        Self::BINARY_RANGE.contains(self)
132    }
133
134    pub fn is_stream(&self) -> bool {
135        Self::STREAM_RANGE.contains(self)
136    }
137
138    pub fn is_application(&self) -> bool {
139        Self::APPLICATION_RANGE.contains(self)
140    }
141
142    /// Obtain a [`MediaSubtype`] from a raw `spa_media_subtype` variant.
143    pub fn from_raw(raw: spa_sys::spa_media_subtype) -> Self {
144        Self(raw)
145    }
146
147    /// Get the raw [`spa_sys::spa_media_subtype`] representing this `MediaSubtype`.
148    pub fn as_raw(&self) -> spa_sys::spa_media_subtype {
149        self.0
150    }
151}
152
153impl Debug for MediaSubtype {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        let c_str = unsafe {
156            let c_buf = spa_sys::spa_debug_type_find_short_name(
157                spa_sys::spa_type_media_subtype,
158                self.as_raw(),
159            );
160            if c_buf.is_null() {
161                return f.write_str("Unsupported media subtype");
162            }
163            CStr::from_ptr(c_buf)
164        };
165        f.write_str("MediaSubtype::")?;
166        fmt_pascal_case(f, &c_str.to_string_lossy())
167    }
168}
169
170#[derive(PartialEq, PartialOrd, Eq, Clone, Copy)]
171pub struct FormatProperties(pub spa_sys::spa_format);
172
173#[allow(non_upper_case_globals)]
174impl FormatProperties {
175    /// media type (Id enum spa_media_type)
176    pub const MediaType: Self = Self(spa_sys::SPA_FORMAT_mediaType);
177    /// media subtype (Id enum spa_media_subtype)
178    pub const MediaSubtype: Self = Self(spa_sys::SPA_FORMAT_mediaSubtype);
179
180    /// audio format, (Id enum spa_audio_format)
181    pub const AudioFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_format);
182    /// optional flags (Int)
183    pub const AudioFlags: Self = Self(spa_sys::SPA_FORMAT_AUDIO_flags);
184    /// sample rate (Int)
185    pub const AudioRate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_rate);
186    /// number of audio channels (Int)
187    pub const AudioChannels: Self = Self(spa_sys::SPA_FORMAT_AUDIO_channels);
188    /// channel positions (Id enum spa_audio_position)
189    pub const AudioPosition: Self = Self(spa_sys::SPA_FORMAT_AUDIO_position);
190
191    /// codec used (IEC958) (Id enum spa_audio_iec958_codec)
192    pub const AudioIec958Codec: Self = Self(spa_sys::SPA_FORMAT_AUDIO_iec958Codec);
193
194    /// bit order (Id enum spa_param_bitorder)
195    pub const AudioBitorder: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitorder);
196    /// Interleave bytes (Int)
197    pub const AudioInterleave: Self = Self(spa_sys::SPA_FORMAT_AUDIO_interleave);
198    /// bit rate (Int)
199    #[cfg(feature = "v0_3_65")]
200    pub const AudioBitrate: Self = Self(spa_sys::SPA_FORMAT_AUDIO_bitrate);
201    /// audio data block alignment (Int)
202    #[cfg(feature = "v0_3_65")]
203    pub const AudioBlockAlign: Self = Self(spa_sys::SPA_FORMAT_AUDIO_blockAlign);
204
205    /// AAC stream format, (Id enum spa_audio_aac_stream_format)
206    #[cfg(feature = "v0_3_65")]
207    pub const AudioAacStreamFormat: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AAC_streamFormat);
208
209    /// WMA profile (Id enum spa_audio_wma_profile)
210    #[cfg(feature = "v0_3_65")]
211    pub const AudioWmaProfile: Self = Self(spa_sys::SPA_FORMAT_AUDIO_WMA_profile);
212
213    /// AMR band mode (Id enum spa_audio_amr_band_mode)
214    #[cfg(feature = "v0_3_65")]
215    pub const AudioAmrBandMode: Self = Self(spa_sys::SPA_FORMAT_AUDIO_AMR_bandMode);
216
217    /// video format (Id enum spa_video_format)
218    pub const VideoFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_format);
219    /// format modifier (Long), use only with DMA-BUF and omit for other buffer types
220    pub const VideoModifier: Self = Self(spa_sys::SPA_FORMAT_VIDEO_modifier);
221    /// size (Rectangle)
222    pub const VideoSize: Self = Self(spa_sys::SPA_FORMAT_VIDEO_size);
223    /// frame rate (Fraction)
224    pub const VideoFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_framerate);
225    /// maximum frame rate (Fraction)
226    pub const VideoMaxFramerate: Self = Self(spa_sys::SPA_FORMAT_VIDEO_maxFramerate);
227    /// number of views (Int)
228    pub const VideoViews: Self = Self(spa_sys::SPA_FORMAT_VIDEO_views);
229    /// (Id enum spa_video_interlace_mode)
230    pub const VideoInterlaceMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_interlaceMode);
231    /// (Rectangle)
232    pub const VideoPixelAspectRatio: Self = Self(spa_sys::SPA_FORMAT_VIDEO_pixelAspectRatio);
233    /// (Id enum spa_video_multiview_mode)
234    pub const VideoMultiviewMode: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewMode);
235    /// (Id enum spa_video_multiview_flags)
236    pub const VideoMultiviewFlags: Self = Self(spa_sys::SPA_FORMAT_VIDEO_multiviewFlags);
237    /// /Id enum spa_video_chroma_site)
238    pub const VideoChromaSite: Self = Self(spa_sys::SPA_FORMAT_VIDEO_chromaSite);
239    /// /Id enum spa_video_color_range)
240    pub const VideoColorRange: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorRange);
241    /// /Id enum spa_video_color_matrix)
242    pub const VideoColorMatrix: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorMatrix);
243    /// /Id enum spa_video_transfer_function)
244    pub const VideoTransferFunction: Self = Self(spa_sys::SPA_FORMAT_VIDEO_transferFunction);
245    ///  /Id enum spa_video_color_primaries)
246    pub const VideoColorPrimaries: Self = Self(spa_sys::SPA_FORMAT_VIDEO_colorPrimaries);
247    /// (Int)
248    pub const VideoProfile: Self = Self(spa_sys::SPA_FORMAT_VIDEO_profile);
249    /// (Int)
250    pub const VideoLevel: Self = Self(spa_sys::SPA_FORMAT_VIDEO_level);
251    /// (Id enum spa_h264_stream_format)
252    pub const VideoH264StreamFormat: Self = Self(spa_sys::SPA_FORMAT_VIDEO_H264_streamFormat);
253    /// (Id enum spa_h264_alignment)
254    pub const VideoH264Alignment: Self = Self(spa_sys::SPA_FORMAT_VIDEO_H264_alignment);
255
256    const AUDIO_RANGE: Range<Self> = Self::AudioFormat..Self(spa_sys::SPA_FORMAT_START_Video);
257    const VIDEO_RANGE: Range<Self> = Self::VideoFormat..Self(spa_sys::SPA_FORMAT_START_Image);
258    const IMAGE_RANGE: Range<Self> =
259        Self(spa_sys::SPA_FORMAT_START_Image)..Self(spa_sys::SPA_FORMAT_START_Binary);
260    const BINARY_RANGE: Range<Self> =
261        Self(spa_sys::SPA_FORMAT_START_Binary)..Self(spa_sys::SPA_FORMAT_START_Stream);
262    const STREAM_RANGE: Range<Self> =
263        Self(spa_sys::SPA_FORMAT_START_Stream)..Self(spa_sys::SPA_FORMAT_START_Application);
264    const APPLICATION_RANGE: Range<Self> =
265        Self(spa_sys::SPA_FORMAT_START_Application)..Self(spa_sys::spa_format::MAX);
266
267    pub fn is_audio(&self) -> bool {
268        Self::AUDIO_RANGE.contains(self)
269    }
270
271    pub fn is_video(&self) -> bool {
272        Self::VIDEO_RANGE.contains(self)
273    }
274
275    pub fn is_image(&self) -> bool {
276        Self::IMAGE_RANGE.contains(self)
277    }
278
279    pub fn is_binary(&self) -> bool {
280        Self::BINARY_RANGE.contains(self)
281    }
282
283    pub fn is_stream(&self) -> bool {
284        Self::STREAM_RANGE.contains(self)
285    }
286
287    pub fn is_application(&self) -> bool {
288        Self::APPLICATION_RANGE.contains(self)
289    }
290
291    /// Obtain a [`FormatProperties`] from a raw `spa_format` variant.
292    pub fn from_raw(raw: spa_sys::spa_format) -> Self {
293        Self(raw)
294    }
295
296    /// Get the raw [`spa_sys::spa_format`] representing this `FormatProperties`.
297    pub fn as_raw(&self) -> spa_sys::spa_format {
298        self.0
299    }
300}
301
302impl Debug for FormatProperties {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        let c_str = unsafe {
305            let c_buf = spa_sys::spa_debug_type_find_name(spa_sys::spa_type_format, self.as_raw());
306            if c_buf.is_null() {
307                return f.write_str("Unsupported format");
308            }
309            CStr::from_ptr(c_buf)
310        };
311        let replaced = c_str
312            .to_string_lossy()
313            .replace("Spa:Pod:Object:Param:Format:", "")
314            .replace(':', " ");
315        f.write_str("FormatProperties::")?;
316        fmt_pascal_case(f, &replaced)
317    }
318}
319
320#[cfg(test)]
321mod tests {
322    use super::*;
323
324    #[test]
325    #[cfg_attr(miri, ignore)]
326    fn debug_format() {
327        assert_eq!("MediaType::Audio", format!("{:?}", MediaType::Audio));
328        assert_eq!("MediaSubtype::Raw", format!("{:?}", MediaSubtype::Raw));
329        assert_eq!(
330            "FormatProperties::VideoTransferFunction",
331            format!("{:?}", FormatProperties::VideoTransferFunction)
332        );
333    }
334}