gstreamer-rs/gstreamer-audio/src/audio_channel_position.rs
Sebastian Dröge eadb3c6db2 audio: Reduce size of AudioInfo from 832 to 320 bytes and make audio channel position handling more efficient
Assume that there are never more than 64 named channel positions and by
that provide an 1:1 mapping between the C and Rust types.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1198>
2023-01-23 12:58:16 +02:00

433 lines
12 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use std::{mem, slice};
use glib::{translate::*, value::FromValue, StaticType, ToValue, Type};
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
#[non_exhaustive]
#[doc(alias = "GstAudioChannelPosition")]
#[repr(i32)]
pub enum AudioChannelPosition {
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_NONE")]
None = ffi::GST_AUDIO_CHANNEL_POSITION_NONE,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_MONO")]
Mono,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_INVALID")]
Invalid,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT")]
FrontLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT")]
FrontRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER")]
FrontCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE1")]
Lfe1,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_LEFT")]
RearLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT")]
RearRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER")]
FrontLeftOfCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER")]
FrontRightOfCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_CENTER")]
RearCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE2")]
Lfe2,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT")]
SideLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT")]
SideRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT")]
TopFrontLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT")]
TopFrontRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER")]
TopFrontCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_CENTER")]
TopCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT")]
TopRearLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT")]
TopRearRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT")]
TopSideLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT")]
TopSideRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER")]
TopRearCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER")]
BottomFrontCenter,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT")]
BottomFrontLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT")]
BottomFrontRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT")]
WideLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT")]
WideRight,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT")]
SurroundLeft,
#[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT")]
SurroundRight = ffi::GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT,
#[doc(hidden)]
UnknownChannel28 = 28,
#[doc(hidden)]
UnknownChannel29 = 29,
#[doc(hidden)]
UnknownChannel30 = 30,
#[doc(hidden)]
UnknownChannel31 = 31,
#[doc(hidden)]
UnknownChannel32 = 32,
#[doc(hidden)]
UnknownChannel33 = 33,
#[doc(hidden)]
UnknownChannel34 = 34,
#[doc(hidden)]
UnknownChannel35 = 35,
#[doc(hidden)]
UnknownChannel36 = 36,
#[doc(hidden)]
UnknownChannel37 = 37,
#[doc(hidden)]
UnknownChannel38 = 38,
#[doc(hidden)]
UnknownChannel39 = 39,
#[doc(hidden)]
UnknownChannel40 = 40,
#[doc(hidden)]
UnknownChannel41 = 41,
#[doc(hidden)]
UnknownChannel42 = 42,
#[doc(hidden)]
UnknownChannel43 = 43,
#[doc(hidden)]
UnknownChannel44 = 44,
#[doc(hidden)]
UnknownChannel45 = 45,
#[doc(hidden)]
UnknownChannel46 = 46,
#[doc(hidden)]
UnknownChannel47 = 47,
#[doc(hidden)]
UnknownChannel48 = 48,
#[doc(hidden)]
UnknownChannel49 = 49,
#[doc(hidden)]
UnknownChannel50 = 50,
#[doc(hidden)]
UnknownChannel51 = 51,
#[doc(hidden)]
UnknownChannel52 = 52,
#[doc(hidden)]
UnknownChannel53 = 53,
#[doc(hidden)]
UnknownChannel54 = 54,
#[doc(hidden)]
UnknownChannel55 = 55,
#[doc(hidden)]
UnknownChannel56 = 56,
#[doc(hidden)]
UnknownChannel57 = 57,
#[doc(hidden)]
UnknownChannel58 = 58,
#[doc(hidden)]
UnknownChannel59 = 59,
#[doc(hidden)]
UnknownChannel60 = 60,
#[doc(hidden)]
UnknownChannel61 = 61,
#[doc(hidden)]
UnknownChannel62 = 62,
#[doc(hidden)]
UnknownChannel63 = 63,
#[doc(hidden)]
UnknownChannel64 = 64,
}
unsafe impl TransparentType for AudioChannelPosition {
type GlibType = ffi::GstAudioChannelPosition;
}
#[doc(hidden)]
impl IntoGlib for AudioChannelPosition {
type GlibType = ffi::GstAudioChannelPosition;
#[inline]
fn into_glib(self) -> ffi::GstAudioChannelPosition {
self as ffi::GstAudioChannelPosition
}
}
#[doc(hidden)]
impl FromGlib<ffi::GstAudioChannelPosition> for AudioChannelPosition {
#[inline]
unsafe fn from_glib(value: ffi::GstAudioChannelPosition) -> Self {
skip_assert_initialized!();
debug_assert!((ffi::GST_AUDIO_CHANNEL_POSITION_NONE..=64).contains(&value));
mem::transmute::<ffi::GstAudioChannelPosition, AudioChannelPosition>(value)
}
}
impl StaticType for AudioChannelPosition {
#[inline]
fn static_type() -> Type {
unsafe { from_glib(ffi::gst_audio_channel_position_get_type()) }
}
}
impl glib::value::ValueType for AudioChannelPosition {
type Type = Self;
}
unsafe impl<'a> FromValue<'a> for AudioChannelPosition {
type Checker = glib::value::GenericValueTypeChecker<Self>;
#[inline]
unsafe fn from_value(value: &'a glib::Value) -> Self {
skip_assert_initialized!();
from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
}
}
impl ToValue for AudioChannelPosition {
#[inline]
fn to_value(&self) -> glib::Value {
let mut value = glib::Value::for_value_type::<Self>();
unsafe {
glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
}
value
}
#[inline]
fn value_type(&self) -> glib::Type {
Self::static_type()
}
}
impl From<AudioChannelPosition> for glib::Value {
#[inline]
fn from(v: AudioChannelPosition) -> Self {
skip_assert_initialized!();
ToValue::to_value(&v)
}
}
impl AudioChannelPosition {
pub fn to_mask(self) -> u64 {
let pos = self.into_glib();
if pos < 0 {
return 0;
}
1 << (pos as u32)
}
#[doc(alias = "gst_audio_channel_positions_to_mask")]
pub fn positions_to_mask(
positions: &[Self],
force_order: bool,
) -> Result<u64, glib::error::BoolError> {
assert_initialized_main_thread!();
let len = positions.len();
if len > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
unsafe {
let mut mask = mem::MaybeUninit::uninit();
let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask(
positions.as_ptr() as *mut _,
len as i32,
force_order.into_glib(),
mask.as_mut_ptr(),
));
if valid {
Ok(mask.assume_init())
} else {
Err(glib::bool_error!(
"Couldn't convert channel positions to mask"
))
}
}
}
#[doc(alias = "gst_audio_channel_positions_from_mask")]
pub fn positions_from_mask(mask: u64, positions: &mut [Self]) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
if positions.len() > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
let len = positions.len();
let valid: bool = unsafe {
from_glib(ffi::gst_audio_channel_positions_from_mask(
len as i32,
mask,
positions.as_mut_ptr() as *mut _,
))
};
if valid {
Ok(())
} else {
Err(glib::bool_error!(
"Couldn't convert channel positions to mask",
))
}
}
#[doc(alias = "gst_audio_channel_positions_to_valid_order")]
pub fn positions_to_valid_order(positions: &mut [Self]) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
if positions.len() > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
let len = positions.len();
let valid: bool = unsafe {
from_glib(ffi::gst_audio_channel_positions_to_valid_order(
positions.as_mut_ptr() as *mut _,
len as i32,
))
};
if valid {
Ok(())
} else {
Err(glib::bool_error!(
"Couldn't convert channel positions to mask",
))
}
}
#[doc(alias = "get_fallback_mask")]
#[doc(alias = "gst_audio_channel_get_fallback_mask")]
pub fn fallback_mask(channels: u32) -> u64 {
assert_initialized_main_thread!();
unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) }
}
#[doc(alias = "gst_audio_check_valid_channel_positions")]
pub fn check_valid_channel_positions(positions: &[Self], force_order: bool) -> bool {
assert_initialized_main_thread!();
if positions.len() > 64 {
return false;
}
let len = positions.len();
unsafe {
from_glib(ffi::gst_audio_check_valid_channel_positions(
positions.as_ptr() as *mut _,
len as i32,
force_order.into_glib(),
))
}
}
}
#[doc(alias = "gst_audio_buffer_reorder_channels")]
pub fn buffer_reorder_channels(
buffer: &mut gst::BufferRef,
format: crate::AudioFormat,
channels: u32,
from: &[AudioChannelPosition],
to: &[AudioChannelPosition],
) -> Result<(), glib::BoolError> {
skip_assert_initialized!();
if from.len() != to.len() || from.len() > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
let valid: bool = unsafe {
from_glib(ffi::gst_audio_buffer_reorder_channels(
buffer.as_mut_ptr(),
format.into_glib(),
channels as i32,
from.as_ptr() as *mut _,
to.as_ptr() as *mut _,
))
};
if valid {
Ok(())
} else {
Err(glib::bool_error!("Failed to reorder channels"))
}
}
#[doc(alias = "gst_audio_reorder_channels")]
pub fn reorder_channels(
data: &mut [u8],
format: crate::AudioFormat,
channels: u32,
from: &[AudioChannelPosition],
to: &[AudioChannelPosition],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
if from.len() != to.len() || from.len() > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
let valid: bool = unsafe {
from_glib(ffi::gst_audio_reorder_channels(
data.as_mut_ptr() as *mut _,
data.len(),
format.into_glib(),
channels as i32,
from.as_ptr() as *mut _,
to.as_ptr() as *mut _,
))
};
if valid {
Ok(())
} else {
Err(glib::bool_error!("Failed to reorder channels"))
}
}
#[doc(alias = "get_channel_reorder_map")]
#[doc(alias = "gst_audio_get_channel_reorder_map")]
pub fn channel_reorder_map(
from: &[AudioChannelPosition],
to: &[AudioChannelPosition],
reorder_map: &mut [usize],
) -> Result<(), glib::BoolError> {
assert_initialized_main_thread!();
if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 {
return Err(glib::bool_error!("Invalid number of channels"));
}
let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
let valid: bool = unsafe {
from_glib(ffi::gst_audio_get_channel_reorder_map(
from.len() as i32,
from.as_ptr() as *mut _,
to.as_ptr() as *mut _,
reorder_map_raw.as_mut_ptr() as *mut i32,
))
};
if valid {
let reorder_map_raw =
unsafe { slice::from_raw_parts(reorder_map_raw.as_ptr() as *const i32, from.len()) };
for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) {
*d = *s as usize;
}
Ok(())
} else {
Err(glib::bool_error!("Failed to reorder channels"))
}
}