gstreamer_audio/
audio_format.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::str;
4
5use crate::ffi;
6use glib::translate::{from_glib, IntoGlib};
7use std::sync::LazyLock;
8
9/// List of all audio formats, for use in template caps strings.
10///
11/// Formats are sorted by decreasing "quality", using these criteria by priority:
12///  - depth
13///  - width
14///  - Float > Signed > Unsigned
15///  - native endianness preferred
16#[cfg(feature = "v1_18")]
17pub static AUDIO_FORMATS_ALL: LazyLock<Box<[crate::AudioFormat]>> = LazyLock::new(|| unsafe {
18    let mut len: u32 = 0;
19    let mut res = Vec::with_capacity(len as usize);
20    let formats = ffi::gst_audio_formats_raw(&mut len);
21    for i in 0..len {
22        let format = formats.offset(i as isize);
23        res.push(from_glib(*format));
24    }
25    res.into_boxed_slice()
26});
27
28#[cfg(not(feature = "v1_18"))]
29pub static AUDIO_FORMATS_ALL: LazyLock<Box<[crate::AudioFormat]>> = LazyLock::new(|| {
30    #[cfg(target_endian = "little")]
31    {
32        Box::new([
33            crate::AudioFormat::F64le,
34            crate::AudioFormat::F64be,
35            crate::AudioFormat::F32le,
36            crate::AudioFormat::F32be,
37            crate::AudioFormat::S32le,
38            crate::AudioFormat::S32be,
39            crate::AudioFormat::U32le,
40            crate::AudioFormat::U32be,
41            crate::AudioFormat::S2432le,
42            crate::AudioFormat::S2432be,
43            crate::AudioFormat::U2432le,
44            crate::AudioFormat::U2432be,
45            crate::AudioFormat::S24le,
46            crate::AudioFormat::S24be,
47            crate::AudioFormat::U24le,
48            crate::AudioFormat::U24be,
49            crate::AudioFormat::S20le,
50            crate::AudioFormat::S20be,
51            crate::AudioFormat::U20le,
52            crate::AudioFormat::U20be,
53            crate::AudioFormat::S18le,
54            crate::AudioFormat::S18be,
55            crate::AudioFormat::U18le,
56            crate::AudioFormat::U18be,
57            crate::AudioFormat::S16le,
58            crate::AudioFormat::S16be,
59            crate::AudioFormat::U16le,
60            crate::AudioFormat::U16be,
61            crate::AudioFormat::S8,
62            crate::AudioFormat::U8,
63        ])
64    }
65    #[cfg(target_endian = "big")]
66    {
67        Box::new([
68            crate::AudioFormat::F64be,
69            crate::AudioFormat::F64le,
70            crate::AudioFormat::F32be,
71            crate::AudioFormat::F32le,
72            crate::AudioFormat::S32be,
73            crate::AudioFormat::S32le,
74            crate::AudioFormat::U32be,
75            crate::AudioFormat::U32le,
76            crate::AudioFormat::S2432be,
77            crate::AudioFormat::S2432le,
78            crate::AudioFormat::U2432be,
79            crate::AudioFormat::U2432le,
80            crate::AudioFormat::S24be,
81            crate::AudioFormat::S24le,
82            crate::AudioFormat::U24be,
83            crate::AudioFormat::U24le,
84            crate::AudioFormat::S20be,
85            crate::AudioFormat::S20le,
86            crate::AudioFormat::U20be,
87            crate::AudioFormat::U20le,
88            crate::AudioFormat::S18be,
89            crate::AudioFormat::S18le,
90            crate::AudioFormat::U18be,
91            crate::AudioFormat::U18le,
92            crate::AudioFormat::S16be,
93            crate::AudioFormat::S16le,
94            crate::AudioFormat::U16be,
95            crate::AudioFormat::U16le,
96            crate::AudioFormat::S8,
97            crate::AudioFormat::U8,
98        ])
99    }
100});
101
102impl crate::AudioFormat {
103    #[doc(alias = "gst_audio_format_build_integer")]
104    pub fn build_integer(
105        sign: bool,
106        endianness: crate::AudioEndianness,
107        width: i32,
108        depth: i32,
109    ) -> Self {
110        assert_initialized_main_thread!();
111
112        unsafe {
113            from_glib(ffi::gst_audio_format_build_integer(
114                sign.into_glib(),
115                endianness.into_glib(),
116                width,
117                depth,
118            ))
119        }
120    }
121
122    #[doc(alias = "gst_audio_format_to_string")]
123    pub fn to_str<'a>(self) -> &'a glib::GStr {
124        if self == Self::Unknown {
125            return glib::gstr!("UNKNOWN");
126        }
127        unsafe {
128            glib::GStr::from_ptr(
129                ffi::gst_audio_format_to_string(self.into_glib())
130                    .as_ref()
131                    .expect("gst_audio_format_to_string returned NULL"),
132            )
133        }
134    }
135
136    pub fn iter_raw() -> AudioFormatIterator {
137        AudioFormatIterator::default()
138    }
139}
140
141impl str::FromStr for crate::AudioFormat {
142    type Err = glib::BoolError;
143
144    fn from_str(s: &str) -> Result<Self, Self::Err> {
145        skip_assert_initialized!();
146
147        let fmt = Self::from_string(s);
148        if fmt == Self::Unknown {
149            Err(glib::bool_error!(
150                "Failed to parse audio format from string"
151            ))
152        } else {
153            Ok(fmt)
154        }
155    }
156}
157
158impl PartialOrd for crate::AudioFormat {
159    #[inline]
160    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
161        Some(self.cmp(other))
162    }
163}
164
165impl Ord for crate::AudioFormat {
166    #[inline]
167    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
168        crate::AudioFormatInfo::from_format(*self).cmp(&crate::AudioFormatInfo::from_format(*other))
169    }
170}
171
172pub const AUDIO_FORMAT_UNKNOWN: crate::AudioFormat = crate::AudioFormat::Unknown;
173pub const AUDIO_FORMAT_ENCODED: crate::AudioFormat = crate::AudioFormat::Encoded;
174pub const AUDIO_FORMAT_S8: crate::AudioFormat = crate::AudioFormat::S8;
175pub const AUDIO_FORMAT_U8: crate::AudioFormat = crate::AudioFormat::U8;
176
177#[cfg(target_endian = "big")]
178pub const AUDIO_FORMAT_S16: crate::AudioFormat = crate::AudioFormat::S16be;
179#[cfg(target_endian = "big")]
180pub const AUDIO_FORMAT_U16: crate::AudioFormat = crate::AudioFormat::U16be;
181#[cfg(target_endian = "big")]
182pub const AUDIO_FORMAT_S2432: crate::AudioFormat = crate::AudioFormat::S2432be;
183#[cfg(target_endian = "big")]
184pub const AUDIO_FORMAT_U2432: crate::AudioFormat = crate::AudioFormat::U2432be;
185#[cfg(target_endian = "big")]
186pub const AUDIO_FORMAT_S32: crate::AudioFormat = crate::AudioFormat::S32be;
187#[cfg(target_endian = "big")]
188pub const AUDIO_FORMAT_U32: crate::AudioFormat = crate::AudioFormat::U32be;
189#[cfg(target_endian = "big")]
190pub const AUDIO_FORMAT_S24: crate::AudioFormat = crate::AudioFormat::S24be;
191#[cfg(target_endian = "big")]
192pub const AUDIO_FORMAT_U24: crate::AudioFormat = crate::AudioFormat::U24be;
193#[cfg(target_endian = "big")]
194pub const AUDIO_FORMAT_S20: crate::AudioFormat = crate::AudioFormat::S20be;
195#[cfg(target_endian = "big")]
196pub const AUDIO_FORMAT_U20: crate::AudioFormat = crate::AudioFormat::U20be;
197#[cfg(target_endian = "big")]
198pub const AUDIO_FORMAT_S18: crate::AudioFormat = crate::AudioFormat::S18be;
199#[cfg(target_endian = "big")]
200pub const AUDIO_FORMAT_U18: crate::AudioFormat = crate::AudioFormat::U18be;
201#[cfg(target_endian = "big")]
202pub const AUDIO_FORMAT_F32: crate::AudioFormat = crate::AudioFormat::F32be;
203#[cfg(target_endian = "big")]
204pub const AUDIO_FORMAT_F64: crate::AudioFormat = crate::AudioFormat::F64be;
205#[cfg(all(target_endian = "big", feature = "v1_28"))]
206pub const AUDIO_FORMAT_S20_32: crate::AudioFormat = crate::AudioFormat::S2032be;
207#[cfg(all(target_endian = "big", feature = "v1_28"))]
208pub const AUDIO_FORMAT_U20_32: crate::AudioFormat = crate::AudioFormat::U2032be;
209
210#[cfg(target_endian = "little")]
211pub const AUDIO_FORMAT_S16: crate::AudioFormat = crate::AudioFormat::S16le;
212#[cfg(target_endian = "little")]
213pub const AUDIO_FORMAT_U16: crate::AudioFormat = crate::AudioFormat::U16le;
214#[cfg(target_endian = "little")]
215pub const AUDIO_FORMAT_S2432: crate::AudioFormat = crate::AudioFormat::S2432le;
216#[cfg(target_endian = "little")]
217pub const AUDIO_FORMAT_U2432: crate::AudioFormat = crate::AudioFormat::U2432le;
218#[cfg(target_endian = "little")]
219pub const AUDIO_FORMAT_S32: crate::AudioFormat = crate::AudioFormat::S32le;
220#[cfg(target_endian = "little")]
221pub const AUDIO_FORMAT_U32: crate::AudioFormat = crate::AudioFormat::U32le;
222#[cfg(target_endian = "little")]
223pub const AUDIO_FORMAT_S24: crate::AudioFormat = crate::AudioFormat::S24le;
224#[cfg(target_endian = "little")]
225pub const AUDIO_FORMAT_U24: crate::AudioFormat = crate::AudioFormat::U24le;
226#[cfg(target_endian = "little")]
227pub const AUDIO_FORMAT_S20: crate::AudioFormat = crate::AudioFormat::S20le;
228#[cfg(target_endian = "little")]
229pub const AUDIO_FORMAT_U20: crate::AudioFormat = crate::AudioFormat::U20le;
230#[cfg(target_endian = "little")]
231pub const AUDIO_FORMAT_S18: crate::AudioFormat = crate::AudioFormat::S18le;
232#[cfg(target_endian = "little")]
233pub const AUDIO_FORMAT_U18: crate::AudioFormat = crate::AudioFormat::U18le;
234#[cfg(target_endian = "little")]
235pub const AUDIO_FORMAT_F32: crate::AudioFormat = crate::AudioFormat::F32le;
236#[cfg(target_endian = "little")]
237pub const AUDIO_FORMAT_F64: crate::AudioFormat = crate::AudioFormat::F64le;
238#[cfg(all(target_endian = "little", feature = "v1_28"))]
239pub const AUDIO_FORMAT_S20_32: crate::AudioFormat = crate::AudioFormat::S2032le;
240#[cfg(all(target_endian = "little", feature = "v1_28"))]
241pub const AUDIO_FORMAT_U20_32: crate::AudioFormat = crate::AudioFormat::U2032le;
242
243#[must_use = "iterators are lazy and do nothing unless consumed"]
244pub struct AudioFormatIterator {
245    idx: usize,
246    len: usize,
247}
248
249impl Default for AudioFormatIterator {
250    fn default() -> Self {
251        Self {
252            idx: 0,
253            len: AUDIO_FORMATS_ALL.len(),
254        }
255    }
256}
257
258impl Iterator for AudioFormatIterator {
259    type Item = crate::AudioFormat;
260
261    fn next(&mut self) -> Option<Self::Item> {
262        if self.idx >= self.len {
263            None
264        } else {
265            let fmt = AUDIO_FORMATS_ALL[self.idx];
266            self.idx += 1;
267            Some(fmt)
268        }
269    }
270
271    fn size_hint(&self) -> (usize, Option<usize>) {
272        let remaining = self.len - self.idx;
273
274        (remaining, Some(remaining))
275    }
276
277    fn count(self) -> usize {
278        self.len - self.idx
279    }
280
281    fn nth(&mut self, n: usize) -> Option<Self::Item> {
282        let (end, overflow) = self.idx.overflowing_add(n);
283        if end >= self.len || overflow {
284            self.idx = self.len;
285            None
286        } else {
287            self.idx = end + 1;
288            Some(AUDIO_FORMATS_ALL[end])
289        }
290    }
291
292    fn last(self) -> Option<Self::Item> {
293        if self.idx == self.len {
294            None
295        } else {
296            Some(AUDIO_FORMATS_ALL[self.len - 1])
297        }
298    }
299}
300
301impl ExactSizeIterator for AudioFormatIterator {}
302
303impl std::iter::FusedIterator for AudioFormatIterator {}
304
305impl DoubleEndedIterator for AudioFormatIterator {
306    fn next_back(&mut self) -> Option<Self::Item> {
307        if self.idx >= self.len {
308            None
309        } else {
310            self.len -= 1;
311            let fmt = AUDIO_FORMATS_ALL[self.len];
312            Some(fmt)
313        }
314    }
315
316    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
317        let (end, overflow) = self.len.overflowing_sub(n);
318        if end <= self.idx || overflow {
319            self.idx = self.len;
320            None
321        } else {
322            self.len = end - 1;
323            let fmt = AUDIO_FORMATS_ALL[self.len];
324            Some(fmt)
325        }
326    }
327}
328pub trait AudioFormatIteratorExt {
329    fn into_audio_caps(
330        self,
331        layout: crate::AudioLayout,
332    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
333}
334
335impl<T> AudioFormatIteratorExt for T
336where
337    T: Iterator<Item = crate::AudioFormat>,
338{
339    fn into_audio_caps(
340        self,
341        layout: crate::AudioLayout,
342    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
343        let formats: Vec<crate::AudioFormat> = self.collect();
344        if !formats.is_empty() {
345            Some(crate::functions::audio_make_raw_caps(&formats, layout))
346        } else {
347            None
348        }
349    }
350}
351
352pub trait AudioFormatIteratorExtRef {
353    fn into_audio_caps(
354        self,
355        layout: crate::AudioLayout,
356    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
357}
358
359impl<'a, T> AudioFormatIteratorExtRef for T
360where
361    T: Iterator<Item = &'a crate::AudioFormat>,
362{
363    fn into_audio_caps(
364        self,
365        layout: crate::AudioLayout,
366    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
367        let formats: Vec<crate::AudioFormat> = self.copied().collect();
368        if !formats.is_empty() {
369            Some(crate::functions::audio_make_raw_caps(&formats, layout))
370        } else {
371            None
372        }
373    }
374}
375
376#[cfg(test)]
377mod tests {
378    use itertools::Itertools;
379
380    #[test]
381    fn test_display() {
382        gst::init().unwrap();
383
384        assert_eq!(format!("{}", crate::AudioFormat::S16be), "S16BE");
385        assert_eq!(format!("{:?}", crate::AudioFormat::S16be), "S16be");
386    }
387
388    #[test]
389    fn iter() {
390        use super::*;
391        gst::init().unwrap();
392
393        assert!(crate::AudioFormat::iter_raw().count() > 0);
394        assert_eq!(
395            crate::AudioFormat::iter_raw().count(),
396            crate::AudioFormat::iter_raw().len()
397        );
398
399        let mut i = crate::AudioFormat::iter_raw();
400        let mut count = 0;
401        loop {
402            if i.next().is_none() {
403                break;
404            }
405            count += 1;
406            if i.next_back().is_none() {
407                break;
408            }
409            count += 1;
410        }
411        assert_eq!(count, crate::AudioFormat::iter_raw().len());
412
413        assert!(crate::AudioFormat::iter_raw().any(|f| f == crate::AudioFormat::F64be));
414        assert!(!crate::AudioFormat::iter_raw().any(|f| f == crate::AudioFormat::Encoded));
415
416        let caps = crate::AudioFormat::iter_raw().into_audio_caps(crate::AudioLayout::Interleaved);
417        assert!(caps.is_some());
418
419        let caps = crate::AudioFormat::iter_raw()
420            .filter(|f| crate::AudioFormatInfo::from_format(*f).is_little_endian())
421            .into_audio_caps(crate::AudioLayout::Interleaved);
422        assert!(caps.is_some());
423
424        let caps = crate::AudioFormat::iter_raw()
425            .skip(1000)
426            .into_audio_caps(crate::AudioLayout::Interleaved);
427        assert!(caps.is_none());
428
429        let caps = [crate::AudioFormat::S16le, crate::AudioFormat::S16be]
430            .iter()
431            .into_audio_caps(crate::AudioLayout::Interleaved)
432            .unwrap()
433            .build();
434        assert_eq!(caps.to_string(), "audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved, format=(string){ S16LE, S16BE }");
435    }
436
437    #[test]
438    fn sort() {
439        gst::init().unwrap();
440
441        assert!(
442            crate::AudioFormatInfo::from_format(crate::AudioFormat::F64be)
443                > crate::AudioFormatInfo::from_format(crate::AudioFormat::U8)
444        );
445        assert!(crate::AudioFormat::S20be > crate::AudioFormat::S18be);
446
447        let sorted: Vec<crate::AudioFormat> =
448            crate::AudioFormat::iter_raw().sorted().rev().collect();
449        // FIXME: use is_sorted_by() once API is in stable
450        assert_eq!(
451            sorted,
452            crate::AudioFormat::iter_raw().collect::<Vec<crate::AudioFormat>>()
453        );
454    }
455}