diff --git a/src/avutil/channel_layout.rs b/src/avutil/channel_layout.rs index e1211e3..fa74251 100644 --- a/src/avutil/channel_layout.rs +++ b/src/avutil/channel_layout.rs @@ -1,14 +1,7 @@ -use crate::{ - error::Result, - ffi, - shared::{PointerUpgrade, RetUpgrade}, -}; -use libc::c_void; -use std::{ - ffi::{CStr, CString}, - mem::MaybeUninit, - ptr::NonNull, -}; +use crate::ffi; + +#[cfg(feature = "ffmpeg6")] +pub use av_channel_layout::*; pub fn av_get_channel_layout_nb_channels(channel_layout: u64) -> i32 { unsafe { ffi::av_get_channel_layout_nb_channels(channel_layout) } @@ -19,178 +12,202 @@ pub fn av_get_default_channel_layout(nb_channels: i32) -> u64 { unsafe { ffi::av_get_default_channel_layout(nb_channels) as u64 } } -wrap_ref!(AVChannelLayout: ffi::AVChannelLayout); - -impl Drop for AVChannelLayout { - fn drop(&mut self) { - let layout = self.as_mut_ptr(); - unsafe { ffi::av_channel_layout_uninit(layout) }; - let _ = unsafe { Box::from_raw(layout) }; +#[cfg(feature = "ffmpeg6")] +mod av_channel_layout { + use crate::{ + error::Result, + ffi, + shared::{PointerUpgrade, RetUpgrade}, + }; + use libc::c_void; + use std::{ + ffi::{CStr, CString}, + mem::MaybeUninit, + ptr::NonNull, + }; + + wrap_ref!(AVChannelLayout: ffi::AVChannelLayout); + + impl Drop for AVChannelLayout { + fn drop(&mut self) { + let layout = self.as_mut_ptr(); + unsafe { ffi::av_channel_layout_uninit(layout) }; + let _ = unsafe { Box::from_raw(layout) }; + } } -} -impl AVChannelLayout { - /// Convert self into [`ffi::AVChannelLayout`]` - pub fn into_inner(mut self) -> ffi::AVChannelLayout { - let layout = self.as_mut_ptr(); - let layout = *unsafe { Box::from_raw(layout) }; - std::mem::forget(self); - layout - } + impl AVChannelLayout { + /// Convert self into [`ffi::AVChannelLayout`]` + pub fn into_inner(mut self) -> ffi::AVChannelLayout { + let layout = self.as_mut_ptr(); + let layout = *unsafe { Box::from_raw(layout) }; + std::mem::forget(self); + layout + } - /// Initialize a native channel layout from a bitmask indicating which channels are present. - pub fn from_mask(mask: u64) -> Option { - let mut layout = MaybeUninit::::uninit(); - if unsafe { ffi::av_channel_layout_from_mask(layout.as_mut_ptr(), mask) } == 0 { - let layout = unsafe { layout.assume_init() }; - Some(unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) }) - } else { - None + /// Initialize a native channel layout from a bitmask indicating which channels are present. + pub fn from_mask(mask: u64) -> Option { + let mut layout = MaybeUninit::::uninit(); + if unsafe { ffi::av_channel_layout_from_mask(layout.as_mut_ptr(), mask) } == 0 { + let layout = unsafe { layout.assume_init() }; + Some(unsafe { + Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) + }) + } else { + None + } } - } - /// Initialize a channel layout from a given string description. - /// The input string can be represented by: - /// - the formal channel layout name (returned by av_channel_layout_describe()) - /// - single or multiple channel names (returned by av_channel_name(), eg. "FL", - /// or concatenated with "+", each optionally containing a custom name after - /// a "@", eg. "FL@Left+FR@Right+LFE") - /// - a decimal or hexadecimal value of a native channel layout (eg. "4" or "0x4") - /// - the number of channels with default layout (eg. "4c") - /// - the number of unordered channels (eg. "4C" or "4 channels") - /// - the ambisonic order followed by optional non-diegetic channels (eg. - /// "ambisonic 2+stereo") - pub fn from_string(str: &CStr) -> Option { - let mut layout = MaybeUninit::::uninit(); - if unsafe { ffi::av_channel_layout_from_string(layout.as_mut_ptr(), str.as_ptr()) } == 0 { - let layout = unsafe { layout.assume_init() }; - Some(unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) }) - } else { - None + /// Initialize a channel layout from a given string description. + /// The input string can be represented by: + /// - the formal channel layout name (returned by av_channel_layout_describe()) + /// - single or multiple channel names (returned by av_channel_name(), eg. "FL", + /// or concatenated with "+", each optionally containing a custom name after + /// a "@", eg. "FL@Left+FR@Right+LFE") + /// - a decimal or hexadecimal value of a native channel layout (eg. "4" or "0x4") + /// - the number of channels with default layout (eg. "4c") + /// - the number of unordered channels (eg. "4C" or "4 channels") + /// - the ambisonic order followed by optional non-diegetic channels (eg. + /// "ambisonic 2+stereo") + pub fn from_string(str: &CStr) -> Option { + let mut layout = MaybeUninit::::uninit(); + if unsafe { ffi::av_channel_layout_from_string(layout.as_mut_ptr(), str.as_ptr()) } == 0 + { + let layout = unsafe { layout.assume_init() }; + Some(unsafe { + Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) + }) + } else { + None + } } - } - /// Get the default channel layout for a given number of channels. - pub fn from_nb_channels(nb_channels: i32) -> Self { - let mut layout = MaybeUninit::::uninit(); - unsafe { ffi::av_channel_layout_default(layout.as_mut_ptr(), nb_channels) } - let layout = unsafe { layout.assume_init() }; - unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) } - } + /// Get the default channel layout for a given number of channels. + pub fn from_nb_channels(nb_channels: i32) -> Self { + let mut layout = MaybeUninit::::uninit(); + unsafe { ffi::av_channel_layout_default(layout.as_mut_ptr(), nb_channels) } + let layout = unsafe { layout.assume_init() }; + unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) } + } - /// Make a copy of a channel layout. This differs from just assigning src to dst - /// in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM. - pub fn copy(&self) -> Result { - let mut layout = MaybeUninit::::uninit(); - unsafe { ffi::av_channel_layout_copy(layout.as_mut_ptr(), self.as_ptr()) }.upgrade()?; - let layout = unsafe { layout.assume_init() }; - Ok(unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) }) - } + /// Make a copy of a channel layout. This differs from just assigning src to dst + /// in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM. + pub fn copy(&self) -> Result { + let mut layout = MaybeUninit::::uninit(); + unsafe { ffi::av_channel_layout_copy(layout.as_mut_ptr(), self.as_ptr()) }.upgrade()?; + let layout = unsafe { layout.assume_init() }; + Ok(unsafe { Self::from_raw(NonNull::new(Box::into_raw(Box::new(layout))).unwrap()) }) + } - /// Get a human-readable string describing the channel layout properties. - /// The string will be in the same format that is accepted by - /// [`AVChannelLayout::from_string`], allowing to rebuild the same - /// channel layout, except for opaque pointers. - pub fn describe(&self) -> Result { - const BUF_SIZE: usize = 32; - let mut buf = vec![0u8; BUF_SIZE]; - let len = unsafe { - ffi::av_channel_layout_describe(self.as_ptr(), buf.as_mut_ptr() as *mut i8, BUF_SIZE) - } - .upgrade()?; - // # Safety: after upgrading len is assumed to be positive. - let len = len as usize; - if len > BUF_SIZE { - buf.resize(len, 0); - unsafe { - ffi::av_channel_layout_describe(self.as_ptr(), buf.as_mut_ptr() as *mut i8, len) + /// Get a human-readable string describing the channel layout properties. + /// The string will be in the same format that is accepted by + /// [`AVChannelLayout::from_string`], allowing to rebuild the same + /// channel layout, except for opaque pointers. + pub fn describe(&self) -> Result { + const BUF_SIZE: usize = 32; + let mut buf = vec![0u8; BUF_SIZE]; + let len = unsafe { + ffi::av_channel_layout_describe( + self.as_ptr(), + buf.as_mut_ptr() as *mut i8, + BUF_SIZE, + ) } .upgrade()?; + // # Safety: after upgrading len is assumed to be positive. + let len = len as usize; + if len > BUF_SIZE { + buf.resize(len, 0); + unsafe { + ffi::av_channel_layout_describe(self.as_ptr(), buf.as_mut_ptr() as *mut i8, len) + } + .upgrade()?; + } + Ok(CString::new(buf).unwrap()) } - Ok(CString::new(buf).unwrap()) - } - /// Get the channel with the given index in a channel layout. - /// - /// Return `None` if idx is not valid or the channel order is unspecified - pub fn channel_from_index(&self, idx: u32) -> Option { - let channel = unsafe { ffi::av_channel_layout_channel_from_index(self.as_ptr(), idx) }; - (channel != ffi::AVChannel_AV_CHAN_NONE).then_some(channel) - } + /// Get the channel with the given index in a channel layout. + /// + /// Return `None` if idx is not valid or the channel order is unspecified + pub fn channel_from_index(&self, idx: u32) -> Option { + let channel = unsafe { ffi::av_channel_layout_channel_from_index(self.as_ptr(), idx) }; + (channel != ffi::AVChannel_AV_CHAN_NONE).then_some(channel) + } - /// Get the index of a given channel in a channel layout. In case multiple - /// channels are found, only the first match will be returned. - /// - /// Return `None` when channel is not present in channel_layout - pub fn index_from_channel(&self, channel: ffi::AVChannel) -> Option { - unsafe { ffi::av_channel_layout_index_from_channel(self.as_ptr(), channel) } - .upgrade() - .ok() - .map(|x| x as u32) - } + /// Get the index of a given channel in a channel layout. In case multiple + /// channels are found, only the first match will be returned. + /// + /// Return `None` when channel is not present in channel_layout + pub fn index_from_channel(&self, channel: ffi::AVChannel) -> Option { + unsafe { ffi::av_channel_layout_index_from_channel(self.as_ptr(), channel) } + .upgrade() + .ok() + .map(|x| x as u32) + } - /// Get the index in a channel layout of a channel described by the given string. - /// In case multiple channels are found, only the first match will be returned. - pub fn index_from_string(&self, name: &CStr) -> Option { - unsafe { ffi::av_channel_layout_index_from_string(self.as_ptr(), name.as_ptr()) } - .upgrade() - .ok() - .map(|x| x as u32) - } + /// Get the index in a channel layout of a channel described by the given string. + /// In case multiple channels are found, only the first match will be returned. + pub fn index_from_string(&self, name: &CStr) -> Option { + unsafe { ffi::av_channel_layout_index_from_string(self.as_ptr(), name.as_ptr()) } + .upgrade() + .ok() + .map(|x| x as u32) + } - /// Get a channel described by the given string. - pub fn channel_from_string(&self, name: &CStr) -> Option { - let channel = - unsafe { ffi::av_channel_layout_channel_from_string(self.as_ptr(), name.as_ptr()) }; - (channel != ffi::AVChannel_AV_CHAN_NONE).then_some(channel) - } + /// Get a channel described by the given string. + pub fn channel_from_string(&self, name: &CStr) -> Option { + let channel = + unsafe { ffi::av_channel_layout_channel_from_string(self.as_ptr(), name.as_ptr()) }; + (channel != ffi::AVChannel_AV_CHAN_NONE).then_some(channel) + } - /// Find out what channels from a given set are present in a channel layout, - /// without regard for their positions. - pub fn subset(&self, mask: u64) -> u64 { - unsafe { ffi::av_channel_layout_subset(self.as_ptr(), mask) } - } + /// Find out what channels from a given set are present in a channel layout, + /// without regard for their positions. + pub fn subset(&self, mask: u64) -> u64 { + unsafe { ffi::av_channel_layout_subset(self.as_ptr(), mask) } + } - /// Check whether a channel layout is valid, i.e. can possibly describe audio data. - /// - /// Return `true` if channel_layout is valid, `false` otherwise. - pub fn check(&self) -> bool { - let ret = unsafe { ffi::av_channel_layout_check(self.as_ptr()) }; - ret == 1 - } + /// Check whether a channel layout is valid, i.e. can possibly describe audio data. + /// + /// Return `true` if channel_layout is valid, `false` otherwise. + pub fn check(&self) -> bool { + let ret = unsafe { ffi::av_channel_layout_check(self.as_ptr()) }; + ret == 1 + } - /// Check whether two channel layouts are semantically the same, i.e. the same - /// channels are present on the same positions in both. - /// - /// If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is - /// not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC, - /// they are considered equal iff the channel counts are the same in both. - pub fn equal(&self, other: &Self) -> Result { - let ret = - unsafe { ffi::av_channel_layout_compare(self.as_ptr(), other.as_ptr()) }.upgrade()?; - Ok(ret == 0) + /// Check whether two channel layouts are semantically the same, i.e. the same + /// channels are present on the same positions in both. + /// + /// If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is + /// not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC, + /// they are considered equal iff the channel counts are the same in both. + pub fn equal(&self, other: &Self) -> Result { + let ret = unsafe { ffi::av_channel_layout_compare(self.as_ptr(), other.as_ptr()) } + .upgrade()?; + Ok(ret == 0) + } } -} -/// Iterate over all standard channel layouts. -pub struct AVChannelLayoutIter { - opaque: *mut *mut c_void, -} + /// Iterate over all standard channel layouts. + pub struct AVChannelLayoutIter { + opaque: *mut *mut c_void, + } -impl Default for AVChannelLayoutIter { - fn default() -> Self { - Self { - opaque: std::ptr::null_mut(), + impl Default for AVChannelLayoutIter { + fn default() -> Self { + Self { + opaque: std::ptr::null_mut(), + } } } -} -impl Iterator for AVChannelLayoutIter { - type Item = AVChannelLayoutRef<'static>; + impl Iterator for AVChannelLayoutIter { + type Item = AVChannelLayoutRef<'static>; - fn next(&mut self) -> Option { - unsafe { ffi::av_channel_layout_standard(self.opaque) } - .upgrade() - .map(|ptr| unsafe { AVChannelLayoutRef::from_raw(ptr) }) + fn next(&mut self) -> Option { + unsafe { ffi::av_channel_layout_standard(self.opaque) } + .upgrade() + .map(|ptr| unsafe { AVChannelLayoutRef::from_raw(ptr) }) + } } } diff --git a/tests/transcode_aac.rs b/tests/transcode_aac.rs index 4c51676..5c5c39f 100644 --- a/tests/transcode_aac.rs +++ b/tests/transcode_aac.rs @@ -1,3 +1,5 @@ +// Due to usage of new channel layout api +#![cfg(feature = "ffmpeg6")] use anyhow::{bail, Context as AnyhowContext, Result}; use cstr::cstr; use once_cell::sync::Lazy as SyncLazy; @@ -76,7 +78,7 @@ fn init_resampler( encode_context: &mut AVCodecContext, ) -> Result { let mut resample_context = SwrContext::new( - &encode_context.ch_layout, + &encode_context.ch_layout, encode_context.sample_fmt, encode_context.sample_rate, &decode_context.ch_layout,