1use crate::ffi::*;
2
3use std::ffi::CString;
4
5#[cfg(feature = "serialize")]
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
10pub enum Channel {
11 None,
12 FrontLeft,
13 FrontRight,
14 FrontCenter,
15 LowFrequency,
16 BackLeft,
17 BackRight,
18 FrontLeftOfCenter,
19 FrontRightOfCenter,
20 BackCenter,
21 SideLeft,
22 SideRight,
23 TopCenter,
24 TopFrontLeft,
25 TopFrontCenter,
26 TopFrontRight,
27 TopBackLeft,
28 TopBackCenter,
29 TopBackRight,
30 StereoLeft,
31 StereoRight,
32 WideLeft,
33 WideRight,
34 SurroundDirectLeft,
35 SurroundDirectRight,
36 LowFrequency2,
37 TopSideLeft,
38 TopSideRight,
39 BottomFrontCenter,
40 BottomFrontLeft,
41 BottomFrontRight,
42
43 #[cfg(feature = "ffmpeg_7_1")]
44 SideSurroundLeft,
45 #[cfg(feature = "ffmpeg_7_1")]
46 SideSurroundRight,
47 #[cfg(feature = "ffmpeg_7_1")]
48 TopSurroundLeft,
49 #[cfg(feature = "ffmpeg_7_1")]
50 TopSurroundRight,
51
52 #[cfg(feature = "ffmpeg_8_0")]
53 BinauralLeft,
54 #[cfg(feature = "ffmpeg_8_0")]
55 BinauralRight,
56
57 Unused,
59
60 Unknown,
62
63 AmbisonicBase,
65 AmbisonicEnd,
67}
68
69impl Channel {
70 pub fn name(self) -> String {
72 let mut buf = vec![0u8; 32];
73
74 unsafe {
75 let ret_val = av_channel_name(buf.as_mut_ptr() as _, buf.len(), AVChannel::from(self));
76
77 match usize::try_from(ret_val) {
78 Ok(out_len) if out_len > 0 => {
79 #[cfg(feature = "ffmpeg_6_1")]
80 let out_len = out_len - 1;
82
83 buf.truncate(out_len);
84 String::from_utf8_unchecked(buf)
85 }
86 _ => String::new(),
88 }
89 }
90 }
91
92 pub fn description(self) -> String {
94 let mut buf = vec![0u8; 256];
95
96 unsafe {
97 let ret_val =
98 av_channel_description(buf.as_mut_ptr() as _, buf.len(), AVChannel::from(self));
99
100 match usize::try_from(ret_val) {
101 Ok(out_len) if out_len > 0 => {
102 #[cfg(feature = "ffmpeg_6_1")]
103 let out_len = out_len - 1;
105
106 buf.truncate(out_len);
107 String::from_utf8_unchecked(buf)
108 }
109 _ => String::new(),
111 }
112 }
113 }
114
115 pub fn from_string<S: AsRef<str>>(name: S) -> Self {
117 let cstr = CString::new(name.as_ref()).expect("no nul byte in name");
118 Self::from(unsafe { av_channel_from_string(cstr.as_ptr()) })
119 }
120}
121
122impl From<AVChannel> for Channel {
123 fn from(value: AVChannel) -> Self {
124 use crate::ffi::AVChannel::*;
125 use Channel::*;
126
127 match value {
128 AV_CHAN_NONE => None,
129 AV_CHAN_FRONT_LEFT => FrontLeft,
130 AV_CHAN_FRONT_RIGHT => FrontRight,
131 AV_CHAN_FRONT_CENTER => FrontCenter,
132 AV_CHAN_LOW_FREQUENCY => LowFrequency,
133 AV_CHAN_BACK_LEFT => BackLeft,
134 AV_CHAN_BACK_RIGHT => BackRight,
135 AV_CHAN_FRONT_LEFT_OF_CENTER => FrontLeftOfCenter,
136 AV_CHAN_FRONT_RIGHT_OF_CENTER => FrontRightOfCenter,
137 AV_CHAN_BACK_CENTER => BackCenter,
138 AV_CHAN_SIDE_LEFT => SideLeft,
139 AV_CHAN_SIDE_RIGHT => SideRight,
140 AV_CHAN_TOP_CENTER => TopCenter,
141 AV_CHAN_TOP_FRONT_LEFT => TopFrontLeft,
142 AV_CHAN_TOP_FRONT_CENTER => TopFrontCenter,
143 AV_CHAN_TOP_FRONT_RIGHT => TopFrontRight,
144 AV_CHAN_TOP_BACK_LEFT => TopBackLeft,
145 AV_CHAN_TOP_BACK_CENTER => TopBackCenter,
146 AV_CHAN_TOP_BACK_RIGHT => TopBackRight,
147 AV_CHAN_STEREO_LEFT => StereoLeft,
148 AV_CHAN_STEREO_RIGHT => StereoRight,
149 AV_CHAN_WIDE_LEFT => WideLeft,
150 AV_CHAN_WIDE_RIGHT => WideRight,
151 AV_CHAN_SURROUND_DIRECT_LEFT => SurroundDirectLeft,
152 AV_CHAN_SURROUND_DIRECT_RIGHT => SurroundDirectRight,
153 AV_CHAN_LOW_FREQUENCY_2 => LowFrequency2,
154 AV_CHAN_TOP_SIDE_LEFT => TopSideLeft,
155 AV_CHAN_TOP_SIDE_RIGHT => TopSideRight,
156 AV_CHAN_BOTTOM_FRONT_CENTER => BottomFrontCenter,
157 AV_CHAN_BOTTOM_FRONT_LEFT => BottomFrontLeft,
158 AV_CHAN_BOTTOM_FRONT_RIGHT => BottomFrontRight,
159
160 #[cfg(feature = "ffmpeg_7_1")]
161 AV_CHAN_SIDE_SURROUND_LEFT => SideSurroundLeft,
162 #[cfg(feature = "ffmpeg_7_1")]
163 AV_CHAN_SIDE_SURROUND_RIGHT => SideSurroundRight,
164 #[cfg(feature = "ffmpeg_7_1")]
165 AV_CHAN_TOP_SURROUND_LEFT => TopSurroundLeft,
166 #[cfg(feature = "ffmpeg_7_1")]
167 AV_CHAN_TOP_SURROUND_RIGHT => TopSurroundRight,
168
169 #[cfg(feature = "ffmpeg_8_0")]
170 AV_CHAN_BINAURAL_LEFT => BinauralLeft,
171 #[cfg(feature = "ffmpeg_8_0")]
172 AV_CHAN_BINAURAL_RIGHT => BinauralRight,
173
174 AV_CHAN_UNUSED => Unused,
175 AV_CHAN_UNKNOWN => Unknown,
176 AV_CHAN_AMBISONIC_BASE => AmbisonicBase,
177 AV_CHAN_AMBISONIC_END => AmbisonicEnd,
178
179 #[cfg(feature = "non-exhaustive-enums")]
180 _ => unimplemented!(),
181 }
182 }
183}
184
185impl From<Channel> for AVChannel {
186 fn from(value: Channel) -> Self {
187 use crate::ffi::AVChannel::*;
188 use Channel::*;
189
190 match value {
191 None => AV_CHAN_NONE,
192 FrontLeft => AV_CHAN_FRONT_LEFT,
193 FrontRight => AV_CHAN_FRONT_RIGHT,
194 FrontCenter => AV_CHAN_FRONT_CENTER,
195 LowFrequency => AV_CHAN_LOW_FREQUENCY,
196 BackLeft => AV_CHAN_BACK_LEFT,
197 BackRight => AV_CHAN_BACK_RIGHT,
198 FrontLeftOfCenter => AV_CHAN_FRONT_LEFT_OF_CENTER,
199 FrontRightOfCenter => AV_CHAN_FRONT_RIGHT_OF_CENTER,
200 BackCenter => AV_CHAN_BACK_CENTER,
201 SideLeft => AV_CHAN_SIDE_LEFT,
202 SideRight => AV_CHAN_SIDE_RIGHT,
203 TopCenter => AV_CHAN_TOP_CENTER,
204 TopFrontLeft => AV_CHAN_TOP_FRONT_LEFT,
205 TopFrontCenter => AV_CHAN_TOP_FRONT_CENTER,
206 TopFrontRight => AV_CHAN_TOP_FRONT_RIGHT,
207 TopBackLeft => AV_CHAN_TOP_BACK_LEFT,
208 TopBackCenter => AV_CHAN_TOP_BACK_CENTER,
209 TopBackRight => AV_CHAN_TOP_BACK_RIGHT,
210 StereoLeft => AV_CHAN_STEREO_LEFT,
211 StereoRight => AV_CHAN_STEREO_RIGHT,
212 WideLeft => AV_CHAN_WIDE_LEFT,
213 WideRight => AV_CHAN_WIDE_RIGHT,
214 SurroundDirectLeft => AV_CHAN_SURROUND_DIRECT_LEFT,
215 SurroundDirectRight => AV_CHAN_SURROUND_DIRECT_RIGHT,
216 LowFrequency2 => AV_CHAN_LOW_FREQUENCY_2,
217 TopSideLeft => AV_CHAN_TOP_SIDE_LEFT,
218 TopSideRight => AV_CHAN_TOP_SIDE_RIGHT,
219 BottomFrontCenter => AV_CHAN_BOTTOM_FRONT_CENTER,
220 BottomFrontLeft => AV_CHAN_BOTTOM_FRONT_LEFT,
221 BottomFrontRight => AV_CHAN_BOTTOM_FRONT_RIGHT,
222
223 #[cfg(feature = "ffmpeg_7_1")]
224 SideSurroundLeft => AV_CHAN_SIDE_SURROUND_LEFT,
225 #[cfg(feature = "ffmpeg_7_1")]
226 SideSurroundRight => AV_CHAN_SIDE_SURROUND_RIGHT,
227 #[cfg(feature = "ffmpeg_7_1")]
228 TopSurroundLeft => AV_CHAN_TOP_SURROUND_LEFT,
229 #[cfg(feature = "ffmpeg_7_1")]
230 TopSurroundRight => AV_CHAN_TOP_SURROUND_RIGHT,
231
232 #[cfg(feature = "ffmpeg_8_0")]
233 BinauralLeft => AV_CHAN_BINAURAL_LEFT,
234 #[cfg(feature = "ffmpeg_8_0")]
235 BinauralRight => AV_CHAN_BINAURAL_RIGHT,
236
237 Unused => AV_CHAN_UNUSED,
238 Unknown => AV_CHAN_UNKNOWN,
239 AmbisonicBase => AV_CHAN_AMBISONIC_BASE,
240 AmbisonicEnd => AV_CHAN_AMBISONIC_END,
241 }
242 }
243}
244
245#[cfg(test)]
246mod test {
247 use super::*;
248
249 const TEST_VALUES: &[Channel] = &[
251 Channel::None,
252 Channel::FrontLeft,
253 Channel::FrontRight,
254 Channel::FrontCenter,
255 Channel::LowFrequency,
256 Channel::BackLeft,
257 Channel::BackRight,
258 Channel::FrontLeftOfCenter,
259 Channel::FrontRightOfCenter,
260 Channel::BackCenter,
261 Channel::SideLeft,
262 Channel::SideRight,
263 Channel::TopCenter,
264 Channel::TopFrontLeft,
265 Channel::TopFrontCenter,
266 Channel::TopFrontRight,
267 Channel::TopBackLeft,
268 Channel::TopBackCenter,
269 Channel::TopBackRight,
270 Channel::StereoLeft,
271 Channel::StereoRight,
272 Channel::WideLeft,
273 Channel::WideRight,
274 Channel::SurroundDirectLeft,
275 Channel::SurroundDirectRight,
276 Channel::LowFrequency2,
277 Channel::TopSideLeft,
278 Channel::TopSideRight,
279 Channel::BottomFrontCenter,
280 Channel::BottomFrontLeft,
281 Channel::BottomFrontRight,
282 Channel::Unused,
283 Channel::Unknown,
284 Channel::AmbisonicBase,
285 Channel::AmbisonicEnd,
286 ];
287
288 #[test]
289 fn name() {
290 for ch in TEST_VALUES {
291 let name = ch.name();
292 assert!(!name.is_empty());
293 println!("{name}");
294 }
295 }
296
297 #[test]
298 fn description() {
299 for ch in TEST_VALUES {
300 let desc = ch.description();
301 assert!(!desc.is_empty());
302 println!("{desc}");
303 }
304 }
305
306 #[test]
307 fn from_string() {
308 for ch in TEST_VALUES {
309 let name = ch.name();
310 let found = Channel::from_string(name);
311 assert_eq!(found, *ch);
312 }
313 }
314}