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
206#[cfg(target_endian = "little")]
207pub const AUDIO_FORMAT_S16: crate::AudioFormat = crate::AudioFormat::S16le;
208#[cfg(target_endian = "little")]
209pub const AUDIO_FORMAT_U16: crate::AudioFormat = crate::AudioFormat::U16le;
210#[cfg(target_endian = "little")]
211pub const AUDIO_FORMAT_S2432: crate::AudioFormat = crate::AudioFormat::S2432le;
212#[cfg(target_endian = "little")]
213pub const AUDIO_FORMAT_U2432: crate::AudioFormat = crate::AudioFormat::U2432le;
214#[cfg(target_endian = "little")]
215pub const AUDIO_FORMAT_S32: crate::AudioFormat = crate::AudioFormat::S32le;
216#[cfg(target_endian = "little")]
217pub const AUDIO_FORMAT_U32: crate::AudioFormat = crate::AudioFormat::U32le;
218#[cfg(target_endian = "little")]
219pub const AUDIO_FORMAT_S24: crate::AudioFormat = crate::AudioFormat::S24le;
220#[cfg(target_endian = "little")]
221pub const AUDIO_FORMAT_U24: crate::AudioFormat = crate::AudioFormat::U24le;
222#[cfg(target_endian = "little")]
223pub const AUDIO_FORMAT_S20: crate::AudioFormat = crate::AudioFormat::S20le;
224#[cfg(target_endian = "little")]
225pub const AUDIO_FORMAT_U20: crate::AudioFormat = crate::AudioFormat::U20le;
226#[cfg(target_endian = "little")]
227pub const AUDIO_FORMAT_S18: crate::AudioFormat = crate::AudioFormat::S18le;
228#[cfg(target_endian = "little")]
229pub const AUDIO_FORMAT_U18: crate::AudioFormat = crate::AudioFormat::U18le;
230#[cfg(target_endian = "little")]
231pub const AUDIO_FORMAT_F32: crate::AudioFormat = crate::AudioFormat::F32le;
232#[cfg(target_endian = "little")]
233pub const AUDIO_FORMAT_F64: crate::AudioFormat = crate::AudioFormat::F64le;
234
235#[must_use = "iterators are lazy and do nothing unless consumed"]
236pub struct AudioFormatIterator {
237    idx: usize,
238    len: usize,
239}
240
241impl Default for AudioFormatIterator {
242    fn default() -> Self {
243        Self {
244            idx: 0,
245            len: AUDIO_FORMATS_ALL.len(),
246        }
247    }
248}
249
250impl Iterator for AudioFormatIterator {
251    type Item = crate::AudioFormat;
252
253    fn next(&mut self) -> Option<Self::Item> {
254        if self.idx >= self.len {
255            None
256        } else {
257            let fmt = AUDIO_FORMATS_ALL[self.idx];
258            self.idx += 1;
259            Some(fmt)
260        }
261    }
262
263    fn size_hint(&self) -> (usize, Option<usize>) {
264        let remaining = self.len - self.idx;
265
266        (remaining, Some(remaining))
267    }
268
269    fn count(self) -> usize {
270        self.len - self.idx
271    }
272
273    fn nth(&mut self, n: usize) -> Option<Self::Item> {
274        let (end, overflow) = self.idx.overflowing_add(n);
275        if end >= self.len || overflow {
276            self.idx = self.len;
277            None
278        } else {
279            self.idx = end + 1;
280            Some(AUDIO_FORMATS_ALL[end])
281        }
282    }
283
284    fn last(self) -> Option<Self::Item> {
285        if self.idx == self.len {
286            None
287        } else {
288            Some(AUDIO_FORMATS_ALL[self.len - 1])
289        }
290    }
291}
292
293impl ExactSizeIterator for AudioFormatIterator {}
294
295impl std::iter::FusedIterator for AudioFormatIterator {}
296
297impl DoubleEndedIterator for AudioFormatIterator {
298    fn next_back(&mut self) -> Option<Self::Item> {
299        if self.idx >= self.len {
300            None
301        } else {
302            self.len -= 1;
303            let fmt = AUDIO_FORMATS_ALL[self.len];
304            Some(fmt)
305        }
306    }
307
308    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
309        let (end, overflow) = self.len.overflowing_sub(n);
310        if end <= self.idx || overflow {
311            self.idx = self.len;
312            None
313        } else {
314            self.len = end - 1;
315            let fmt = AUDIO_FORMATS_ALL[self.len];
316            Some(fmt)
317        }
318    }
319}
320pub trait AudioFormatIteratorExt {
321    fn into_audio_caps(
322        self,
323        layout: crate::AudioLayout,
324    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
325}
326
327impl<T> AudioFormatIteratorExt for T
328where
329    T: Iterator<Item = crate::AudioFormat>,
330{
331    fn into_audio_caps(
332        self,
333        layout: crate::AudioLayout,
334    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
335        let formats: Vec<crate::AudioFormat> = self.collect();
336        if !formats.is_empty() {
337            Some(crate::functions::audio_make_raw_caps(&formats, layout))
338        } else {
339            None
340        }
341    }
342}
343
344pub trait AudioFormatIteratorExtRef {
345    fn into_audio_caps(
346        self,
347        layout: crate::AudioLayout,
348    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>>;
349}
350
351impl<'a, T> AudioFormatIteratorExtRef for T
352where
353    T: Iterator<Item = &'a crate::AudioFormat>,
354{
355    fn into_audio_caps(
356        self,
357        layout: crate::AudioLayout,
358    ) -> Option<crate::AudioCapsBuilder<gst::caps::NoFeature>> {
359        let formats: Vec<crate::AudioFormat> = self.copied().collect();
360        if !formats.is_empty() {
361            Some(crate::functions::audio_make_raw_caps(&formats, layout))
362        } else {
363            None
364        }
365    }
366}
367
368#[cfg(test)]
369mod tests {
370    use itertools::Itertools;
371
372    #[test]
373    fn test_display() {
374        gst::init().unwrap();
375
376        assert_eq!(format!("{}", crate::AudioFormat::S16be), "S16BE");
377        assert_eq!(format!("{:?}", crate::AudioFormat::S16be), "S16be");
378    }
379
380    #[test]
381    fn iter() {
382        use super::*;
383        gst::init().unwrap();
384
385        assert!(crate::AudioFormat::iter_raw().count() > 0);
386        assert_eq!(
387            crate::AudioFormat::iter_raw().count(),
388            crate::AudioFormat::iter_raw().len()
389        );
390
391        let mut i = crate::AudioFormat::iter_raw();
392        let mut count = 0;
393        loop {
394            if i.next().is_none() {
395                break;
396            }
397            count += 1;
398            if i.next_back().is_none() {
399                break;
400            }
401            count += 1;
402        }
403        assert_eq!(count, crate::AudioFormat::iter_raw().len());
404
405        assert!(crate::AudioFormat::iter_raw().any(|f| f == crate::AudioFormat::F64be));
406        assert!(!crate::AudioFormat::iter_raw().any(|f| f == crate::AudioFormat::Encoded));
407
408        let caps = crate::AudioFormat::iter_raw().into_audio_caps(crate::AudioLayout::Interleaved);
409        assert!(caps.is_some());
410
411        let caps = crate::AudioFormat::iter_raw()
412            .filter(|f| crate::AudioFormatInfo::from_format(*f).is_little_endian())
413            .into_audio_caps(crate::AudioLayout::Interleaved);
414        assert!(caps.is_some());
415
416        let caps = crate::AudioFormat::iter_raw()
417            .skip(1000)
418            .into_audio_caps(crate::AudioLayout::Interleaved);
419        assert!(caps.is_none());
420
421        let caps = [crate::AudioFormat::S16le, crate::AudioFormat::S16be]
422            .iter()
423            .into_audio_caps(crate::AudioLayout::Interleaved)
424            .unwrap()
425            .build();
426        assert_eq!(caps.to_string(), "audio/x-raw, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved, format=(string){ S16LE, S16BE }");
427    }
428
429    #[test]
430    fn sort() {
431        gst::init().unwrap();
432
433        assert!(
434            crate::AudioFormatInfo::from_format(crate::AudioFormat::F64be)
435                > crate::AudioFormatInfo::from_format(crate::AudioFormat::U8)
436        );
437        assert!(crate::AudioFormat::S20be > crate::AudioFormat::S18be);
438
439        let sorted: Vec<crate::AudioFormat> =
440            crate::AudioFormat::iter_raw().sorted().rev().collect();
441        // FIXME: use is_sorted_by() once API is in stable
442        assert_eq!(
443            sorted,
444            crate::AudioFormat::iter_raw().collect::<Vec<crate::AudioFormat>>()
445        );
446    }
447}