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