// Copyright (C) 2017 Sebastian Dröge // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use gst_audio_sys; use std::ffi::CStr; use std::fmt; use std::str; use glib::translate::{from_glib, FromGlib, ToGlib, ToGlibPtr}; use once_cell::sync::Lazy; #[cfg(feature = "v1_18")] pub static AUDIO_FORMATS_ALL: Lazy> = Lazy::new(|| unsafe { let mut len: u32 = 0; let mut res = Vec::with_capacity(len as usize); let formats = gst_audio_sys::gst_audio_formats_raw(&mut len); for i in 0..len { let format = formats.offset(i as isize); res.push(from_glib(*format)); } res.into_boxed_slice() }); #[cfg(not(feature = "v1_18"))] pub static AUDIO_FORMATS_ALL: Lazy> = Lazy::new(|| { #[cfg(target_endian = "little")] { Box::new([ ::AudioFormat::F64le, ::AudioFormat::F64be, ::AudioFormat::F32le, ::AudioFormat::F32be, ::AudioFormat::S32le, ::AudioFormat::S32be, ::AudioFormat::U32le, ::AudioFormat::U32be, ::AudioFormat::S2432le, ::AudioFormat::S2432be, ::AudioFormat::U2432le, ::AudioFormat::U2432be, ::AudioFormat::S24le, ::AudioFormat::S24be, ::AudioFormat::U24le, ::AudioFormat::U24be, ::AudioFormat::S20le, ::AudioFormat::S20be, ::AudioFormat::U20le, ::AudioFormat::U20be, ::AudioFormat::S18le, ::AudioFormat::S18be, ::AudioFormat::U18le, ::AudioFormat::U18be, ::AudioFormat::S16le, ::AudioFormat::S16be, ::AudioFormat::U16le, ::AudioFormat::U16be, ::AudioFormat::S8, ::AudioFormat::U8, ]) } #[cfg(target_endian = "big")] { Box::new([ ::AudioFormat::F64be, ::AudioFormat::F64le, ::AudioFormat::F32be, ::AudioFormat::F32le, ::AudioFormat::S32be, ::AudioFormat::S32le, ::AudioFormat::U32be, ::AudioFormat::U32le, ::AudioFormat::S2432be, ::AudioFormat::S2432le, ::AudioFormat::U2432be, ::AudioFormat::U2432le, ::AudioFormat::S24be, ::AudioFormat::S24le, ::AudioFormat::U24be, ::AudioFormat::U24le, ::AudioFormat::S20be, ::AudioFormat::S20le, ::AudioFormat::U20be, ::AudioFormat::U20le, ::AudioFormat::S18be, ::AudioFormat::S18le, ::AudioFormat::U18be, ::AudioFormat::U18le, ::AudioFormat::S16be, ::AudioFormat::S16le, ::AudioFormat::U16be, ::AudioFormat::U16le, ::AudioFormat::S8, ::AudioFormat::U8, ]) } }); impl ::AudioFormat { pub fn build_integer( sign: bool, endianness: ::AudioEndianness, width: i32, depth: i32, ) -> ::AudioFormat { assert_initialized_main_thread!(); unsafe { from_glib(gst_audio_sys::gst_audio_format_build_integer( sign.to_glib(), endianness.to_glib(), width, depth, )) } } pub fn to_str<'a>(self) -> &'a str { if self == ::AudioFormat::Unknown { return "UNKNOWN"; } unsafe { CStr::from_ptr(gst_audio_sys::gst_audio_format_to_string(self.to_glib())) .to_str() .unwrap() } } pub fn iter_raw() -> AudioFormatIterator { AudioFormatIterator::default() } } impl str::FromStr for ::AudioFormat { type Err = glib::BoolError; fn from_str(s: &str) -> Result { assert_initialized_main_thread!(); unsafe { let fmt = ::AudioFormat::from_glib(gst_audio_sys::gst_audio_format_from_string( s.to_glib_none().0, )); if fmt == ::AudioFormat::Unknown { Err(glib_bool_error!("Failed to parse audio format from string")) } else { Ok(fmt) } } } } impl fmt::Display for ::AudioFormat { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.write_str((*self).to_str()) } } impl PartialOrd for ::AudioFormat { fn partial_cmp(&self, other: &::AudioFormat) -> Option { ::AudioFormatInfo::from_format(*self).partial_cmp(&::AudioFormatInfo::from_format(*other)) } } impl Ord for ::AudioFormat { fn cmp(&self, other: &::AudioFormat) -> std::cmp::Ordering { ::AudioFormatInfo::from_format(*self).cmp(&::AudioFormatInfo::from_format(*other)) } } pub const AUDIO_FORMAT_UNKNOWN: ::AudioFormat = ::AudioFormat::Unknown; pub const AUDIO_FORMAT_ENCODED: ::AudioFormat = ::AudioFormat::Encoded; pub const AUDIO_FORMAT_S8: ::AudioFormat = ::AudioFormat::S8; pub const AUDIO_FORMAT_U8: ::AudioFormat = ::AudioFormat::U8; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S16: ::AudioFormat = ::AudioFormat::S16be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U16: ::AudioFormat = ::AudioFormat::U16be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S2432: ::AudioFormat = ::AudioFormat::S2432be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U2432: ::AudioFormat = ::AudioFormat::U2432be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S32: ::AudioFormat = ::AudioFormat::S32be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U32: ::AudioFormat = ::AudioFormat::U32be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S24: ::AudioFormat = ::AudioFormat::S24be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U24: ::AudioFormat = ::AudioFormat::U24be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S20: ::AudioFormat = ::AudioFormat::S20be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U20: ::AudioFormat = ::AudioFormat::U20be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_S18: ::AudioFormat = ::AudioFormat::S18be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_U18: ::AudioFormat = ::AudioFormat::U18be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_F32: ::AudioFormat = ::AudioFormat::F32be; #[cfg(target_endian = "big")] pub const AUDIO_FORMAT_F64: ::AudioFormat = ::AudioFormat::F64be; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S16: ::AudioFormat = ::AudioFormat::S16le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U16: ::AudioFormat = ::AudioFormat::U16le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S2432: ::AudioFormat = ::AudioFormat::S2432le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U2432: ::AudioFormat = ::AudioFormat::U2432le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S32: ::AudioFormat = ::AudioFormat::S32le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U32: ::AudioFormat = ::AudioFormat::U32le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S24: ::AudioFormat = ::AudioFormat::S24le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U24: ::AudioFormat = ::AudioFormat::U24le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S20: ::AudioFormat = ::AudioFormat::S20le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U20: ::AudioFormat = ::AudioFormat::U20le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_S18: ::AudioFormat = ::AudioFormat::S18le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_U18: ::AudioFormat = ::AudioFormat::U18le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_F32: ::AudioFormat = ::AudioFormat::F32le; #[cfg(target_endian = "little")] pub const AUDIO_FORMAT_F64: ::AudioFormat = ::AudioFormat::F64le; pub struct AudioFormatIterator { idx: usize, len: usize, } impl Default for AudioFormatIterator { fn default() -> Self { Self { idx: 0, len: AUDIO_FORMATS_ALL.len(), } } } impl Iterator for AudioFormatIterator { type Item = ::AudioFormat; fn next(&mut self) -> Option { if self.idx >= self.len { None } else { let fmt = AUDIO_FORMATS_ALL[self.idx]; self.idx += 1; Some(fmt) } } } impl ExactSizeIterator for AudioFormatIterator { fn len(&self) -> usize { self.len } } impl DoubleEndedIterator for AudioFormatIterator { fn next_back(&mut self) -> Option { if self.idx >= self.len { None } else { let fmt = AUDIO_FORMATS_ALL[self.len - 1]; self.len -= 1; Some(fmt) } } } pub trait AudioFormatIteratorExt { fn into_audio_caps( self, layout: ::AudioLayout, ) -> Option>; } impl AudioFormatIteratorExt for T where T: Iterator, { fn into_audio_caps( self, layout: ::AudioLayout, ) -> Option> { let formats: Vec<::AudioFormat> = self.collect(); if !formats.is_empty() { Some(::functions::audio_make_raw_caps(&formats, layout)) } else { None } } } pub trait AudioFormatIteratorExtRef { fn into_audio_caps( self, layout: ::AudioLayout, ) -> Option>; } impl<'a, T> AudioFormatIteratorExtRef for T where T: Iterator, { fn into_audio_caps( self, layout: ::AudioLayout, ) -> Option> { let formats: Vec<::AudioFormat> = self.copied().collect(); if !formats.is_empty() { Some(::functions::audio_make_raw_caps(&formats, layout)) } else { None } } } #[cfg(test)] mod tests { use gst; use itertools::Itertools; #[test] fn test_display() { gst::init().unwrap(); format!("{}", ::AudioFormat::S16be); } #[test] fn iter() { use super::*; gst::init().unwrap(); assert!(::AudioFormat::iter_raw().count() > 0); assert_eq!( ::AudioFormat::iter_raw().count(), ::AudioFormat::iter_raw().len() ); let mut i = ::AudioFormat::iter_raw(); let mut count = 0; loop { if i.next().is_none() { break; } count += 1; if i.next_back().is_none() { break; } count += 1; } assert_eq!(count, ::AudioFormat::iter_raw().len()); assert!(::AudioFormat::iter_raw().any(|f| f == ::AudioFormat::F64be)); assert!(::AudioFormat::iter_raw() .find(|f| *f == ::AudioFormat::Encoded) .is_none()); let caps = ::AudioFormat::iter_raw().into_audio_caps(::AudioLayout::Interleaved); assert!(caps.is_some()); let caps = ::AudioFormat::iter_raw() .filter(|f| ::AudioFormatInfo::from_format(*f).is_little_endian()) .into_audio_caps(::AudioLayout::Interleaved); assert!(caps.is_some()); let caps = ::AudioFormat::iter_raw() .skip(1000) .into_audio_caps(::AudioLayout::Interleaved); assert!(caps.is_none()); let caps = [::AudioFormat::S16le, ::AudioFormat::S16be] .iter() .into_audio_caps(::AudioLayout::Interleaved) .unwrap() .build(); assert_eq!(caps.to_string(), "audio/x-raw, format=(string){ S16LE, S16BE }, rate=(int)[ 1, 2147483647 ], channels=(int)[ 1, 2147483647 ], layout=(string)interleaved"); } #[test] fn sort() { gst::init().unwrap(); assert!( ::AudioFormatInfo::from_format(::AudioFormat::F64be) > ::AudioFormatInfo::from_format(::AudioFormat::U8) ); assert!(::AudioFormat::S20be > ::AudioFormat::S18be); let sorted: Vec<::AudioFormat> = ::AudioFormat::iter_raw().sorted().rev().collect(); // FIXME: use is_sorted_by() once API is in stable assert_eq!( sorted, ::AudioFormat::iter_raw().collect::>() ); } }