Skip to main content

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