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