ac_ffmpeg/codec/audio/frame/
channels_v2.rs

1use std::{
2    borrow::Borrow,
3    ffi::CString,
4    io,
5    ops::Deref,
6    os::raw::{c_char, c_int, c_void},
7    ptr,
8    str::FromStr,
9};
10
11use super::UnknownChannelLayout;
12
13use crate::Error;
14
15extern "C" {
16    fn ffw_channel_layout_get_default(layout: *mut *mut c_void, channels: u32) -> c_int;
17    fn ffw_channel_layout_from_string(layout: *mut *mut c_void, s: *const c_char) -> c_int;
18    fn ffw_channel_layout_clone(dst: *mut *mut c_void, src: *const c_void) -> c_int;
19    fn ffw_channel_layout_is_valid(layout: *const c_void) -> c_int;
20    fn ffw_channel_layout_get_channels(layout: *const c_void) -> u32;
21    fn ffw_channel_layout_compare(a: *const c_void, b: *const c_void) -> c_int;
22    fn ffw_channel_layout_free(layout: *mut c_void);
23}
24
25/// Channel layout reference.
26pub struct ChannelLayoutRef(());
27
28impl ChannelLayoutRef {
29    /// Create channel layout reference from a given pointer.
30    #[inline]
31    pub(crate) unsafe fn from_raw_ptr<'a>(ptr: *const c_void) -> &'a Self {
32        &*(ptr as *const Self)
33    }
34
35    /// Get raw pointer.
36    pub(crate) fn as_ptr(&self) -> *const c_void {
37        self as *const Self as *const c_void
38    }
39
40    /// Get number of channels.
41    pub fn channels(&self) -> u32 {
42        unsafe { ffw_channel_layout_get_channels(self.as_ptr()) }
43    }
44
45    /// Check if the channel layout is valid.
46    fn is_valid(&self) -> bool {
47        unsafe { ffw_channel_layout_is_valid(self.as_ptr()) != 0 }
48    }
49}
50
51impl PartialEq for ChannelLayoutRef {
52    fn eq(&self, other: &Self) -> bool {
53        unsafe { ffw_channel_layout_compare(self.as_ptr(), other.as_ptr()) == 0 }
54    }
55}
56
57impl ToOwned for ChannelLayoutRef {
58    type Owned = ChannelLayout;
59
60    fn to_owned(&self) -> Self::Owned {
61        unsafe {
62            let mut dst = ptr::null_mut();
63
64            let ret = ffw_channel_layout_clone(&mut dst, self.as_ptr());
65
66            if ret == 0 {
67                ChannelLayout::from_raw_ptr(dst)
68            } else {
69                panic!("unable to allocate channel layout")
70            }
71        }
72    }
73}
74
75/// Channel layout.
76pub struct ChannelLayout {
77    ptr: *mut c_void,
78}
79
80impl ChannelLayout {
81    /// Create channel layout from a given pointer.
82    unsafe fn from_raw_ptr(ptr: *mut c_void) -> Self {
83        Self { ptr }
84    }
85
86    /// Get default channel layout for a given number of channels.
87    pub fn from_channels(channels: u32) -> Option<Self> {
88        unsafe {
89            let mut ptr = ptr::null_mut();
90
91            let ret = ffw_channel_layout_get_default(&mut ptr, channels);
92
93            if ret != 0 {
94                panic!("unable to allocate channel layout");
95            }
96
97            let res = Self::from_raw_ptr(ptr);
98
99            if res.is_valid() {
100                Some(res)
101            } else {
102                None
103            }
104        }
105    }
106}
107
108impl Drop for ChannelLayout {
109    fn drop(&mut self) {
110        unsafe {
111            ffw_channel_layout_free(self.ptr);
112        }
113    }
114}
115
116impl AsRef<ChannelLayoutRef> for ChannelLayout {
117    #[inline]
118    fn as_ref(&self) -> &ChannelLayoutRef {
119        unsafe { ChannelLayoutRef::from_raw_ptr(self.ptr) }
120    }
121}
122
123impl Borrow<ChannelLayoutRef> for ChannelLayout {
124    #[inline]
125    fn borrow(&self) -> &ChannelLayoutRef {
126        self.as_ref()
127    }
128}
129
130impl Deref for ChannelLayout {
131    type Target = ChannelLayoutRef;
132
133    #[inline]
134    fn deref(&self) -> &Self::Target {
135        self.as_ref()
136    }
137}
138
139impl PartialEq for ChannelLayout {
140    #[inline]
141    fn eq(&self, other: &Self) -> bool {
142        self.as_ref() == other.as_ref()
143    }
144}
145
146impl PartialEq<ChannelLayoutRef> for ChannelLayout {
147    #[inline]
148    fn eq(&self, other: &ChannelLayoutRef) -> bool {
149        self.as_ref() == other
150    }
151}
152
153impl PartialEq<ChannelLayout> for ChannelLayoutRef {
154    #[inline]
155    fn eq(&self, other: &ChannelLayout) -> bool {
156        self == other.as_ref()
157    }
158}
159
160impl Clone for ChannelLayout {
161    #[inline]
162    fn clone(&self) -> Self {
163        self.as_ref().to_owned()
164    }
165}
166
167impl FromStr for ChannelLayout {
168    type Err = UnknownChannelLayout;
169
170    fn from_str(s: &str) -> Result<Self, Self::Err> {
171        let name = CString::new(s).expect("invalid channel layout name");
172
173        let mut ptr = ptr::null_mut();
174
175        let ret = unsafe { ffw_channel_layout_from_string(&mut ptr, name.as_ptr()) };
176
177        if ret == 0 {
178            unsafe { Ok(Self::from_raw_ptr(ptr)) }
179        } else {
180            let err = Error::from_raw_error_code(ret)
181                .to_io_error()
182                .map(|err| err.kind());
183
184            if err == Some(io::ErrorKind::OutOfMemory) {
185                panic!("unable to allocate channel layout")
186            } else {
187                Err(UnknownChannelLayout)
188            }
189        }
190    }
191}
192
193unsafe impl Send for ChannelLayout {}
194unsafe impl Sync for ChannelLayout {}