1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, slice};
4
5use crate::ffi;
6use glib::{prelude::*, translate::*, value::FromValue, Type};
7
8#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
9#[non_exhaustive]
10#[doc(alias = "GstAudioChannelPosition")]
11#[repr(i32)]
12pub enum AudioChannelPosition {
13 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_NONE")]
14 None = ffi::GST_AUDIO_CHANNEL_POSITION_NONE,
15 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_MONO")]
16 Mono,
17 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_INVALID")]
18 Invalid,
19 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT")]
20 FrontLeft,
21 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT")]
22 FrontRight,
23 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER")]
24 FrontCenter,
25 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE1")]
26 Lfe1,
27 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_LEFT")]
28 RearLeft,
29 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT")]
30 RearRight,
31 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER")]
32 FrontLeftOfCenter,
33 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER")]
34 FrontRightOfCenter,
35 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_REAR_CENTER")]
36 RearCenter,
37 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_LFE2")]
38 Lfe2,
39 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT")]
40 SideLeft,
41 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT")]
42 SideRight,
43 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT")]
44 TopFrontLeft,
45 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT")]
46 TopFrontRight,
47 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER")]
48 TopFrontCenter,
49 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_CENTER")]
50 TopCenter,
51 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT")]
52 TopRearLeft,
53 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT")]
54 TopRearRight,
55 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT")]
56 TopSideLeft,
57 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT")]
58 TopSideRight,
59 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER")]
60 TopRearCenter,
61 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER")]
62 BottomFrontCenter,
63 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT")]
64 BottomFrontLeft,
65 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT")]
66 BottomFrontRight,
67 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT")]
68 WideLeft,
69 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT")]
70 WideRight,
71 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT")]
72 SurroundLeft,
73 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT")]
74 SurroundRight = ffi::GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT,
75 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SURROUND_LEFT")]
76 TopSurroundLeft = 28,
77 #[doc(alias = "GST_AUDIO_CHANNEL_POSITION_TOP_SURROUND_RIGHT")]
78 TopSurroundRight = 29,
79 #[doc(hidden)]
80 UnknownChannel30 = 30,
81 #[doc(hidden)]
82 UnknownChannel31 = 31,
83 #[doc(hidden)]
84 UnknownChannel32 = 32,
85 #[doc(hidden)]
86 UnknownChannel33 = 33,
87 #[doc(hidden)]
88 UnknownChannel34 = 34,
89 #[doc(hidden)]
90 UnknownChannel35 = 35,
91 #[doc(hidden)]
92 UnknownChannel36 = 36,
93 #[doc(hidden)]
94 UnknownChannel37 = 37,
95 #[doc(hidden)]
96 UnknownChannel38 = 38,
97 #[doc(hidden)]
98 UnknownChannel39 = 39,
99 #[doc(hidden)]
100 UnknownChannel40 = 40,
101 #[doc(hidden)]
102 UnknownChannel41 = 41,
103 #[doc(hidden)]
104 UnknownChannel42 = 42,
105 #[doc(hidden)]
106 UnknownChannel43 = 43,
107 #[doc(hidden)]
108 UnknownChannel44 = 44,
109 #[doc(hidden)]
110 UnknownChannel45 = 45,
111 #[doc(hidden)]
112 UnknownChannel46 = 46,
113 #[doc(hidden)]
114 UnknownChannel47 = 47,
115 #[doc(hidden)]
116 UnknownChannel48 = 48,
117 #[doc(hidden)]
118 UnknownChannel49 = 49,
119 #[doc(hidden)]
120 UnknownChannel50 = 50,
121 #[doc(hidden)]
122 UnknownChannel51 = 51,
123 #[doc(hidden)]
124 UnknownChannel52 = 52,
125 #[doc(hidden)]
126 UnknownChannel53 = 53,
127 #[doc(hidden)]
128 UnknownChannel54 = 54,
129 #[doc(hidden)]
130 UnknownChannel55 = 55,
131 #[doc(hidden)]
132 UnknownChannel56 = 56,
133 #[doc(hidden)]
134 UnknownChannel57 = 57,
135 #[doc(hidden)]
136 UnknownChannel58 = 58,
137 #[doc(hidden)]
138 UnknownChannel59 = 59,
139 #[doc(hidden)]
140 UnknownChannel60 = 60,
141 #[doc(hidden)]
142 UnknownChannel61 = 61,
143 #[doc(hidden)]
144 UnknownChannel62 = 62,
145 #[doc(hidden)]
146 UnknownChannel63 = 63,
147 #[doc(hidden)]
148 UnknownChannel64 = 64,
149}
150
151unsafe impl TransparentType for AudioChannelPosition {
152 type GlibType = ffi::GstAudioChannelPosition;
153}
154
155#[doc(hidden)]
156impl IntoGlib for AudioChannelPosition {
157 type GlibType = ffi::GstAudioChannelPosition;
158
159 #[inline]
160 fn into_glib(self) -> ffi::GstAudioChannelPosition {
161 self as ffi::GstAudioChannelPosition
162 }
163}
164
165#[doc(hidden)]
166impl FromGlib<ffi::GstAudioChannelPosition> for AudioChannelPosition {
167 #[inline]
168 unsafe fn from_glib(value: ffi::GstAudioChannelPosition) -> Self {
169 skip_assert_initialized!();
170 debug_assert!((ffi::GST_AUDIO_CHANNEL_POSITION_NONE..=64).contains(&value));
171 mem::transmute::<ffi::GstAudioChannelPosition, AudioChannelPosition>(src:value)
172 }
173}
174
175impl StaticType for AudioChannelPosition {
176 #[inline]
177 fn static_type() -> Type {
178 unsafe { from_glib(val:ffi::gst_audio_channel_position_get_type()) }
179 }
180}
181
182impl glib::value::ValueType for AudioChannelPosition {
183 type Type = Self;
184}
185
186unsafe impl<'a> FromValue<'a> for AudioChannelPosition {
187 type Checker = glib::value::GenericValueTypeChecker<Self>;
188
189 #[inline]
190 unsafe fn from_value(value: &'a glib::Value) -> Self {
191 skip_assert_initialized!();
192 from_glib(val:glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
193 }
194}
195
196impl ToValue for AudioChannelPosition {
197 #[inline]
198 fn to_value(&self) -> glib::Value {
199 let mut value: Value = glib::Value::for_value_type::<Self>();
200 unsafe {
201 glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
202 }
203 value
204 }
205
206 #[inline]
207 fn value_type(&self) -> glib::Type {
208 Self::static_type()
209 }
210}
211
212impl From<AudioChannelPosition> for glib::Value {
213 #[inline]
214 fn from(v: AudioChannelPosition) -> Self {
215 skip_assert_initialized!();
216 ToValue::to_value(&v)
217 }
218}
219
220impl AudioChannelPosition {
221 pub fn to_mask(self) -> u64 {
222 let pos = self.into_glib();
223 if pos < 0 {
224 return 0;
225 }
226
227 1 << (pos as u32)
228 }
229
230 #[doc(alias = "gst_audio_channel_positions_to_mask")]
231 pub fn positions_to_mask(
232 positions: &[Self],
233 force_order: bool,
234 ) -> Result<u64, glib::error::BoolError> {
235 assert_initialized_main_thread!();
236
237 let len = positions.len();
238 if len > 64 {
239 return Err(glib::bool_error!("Invalid number of channels"));
240 }
241
242 unsafe {
243 let mut mask = mem::MaybeUninit::uninit();
244 let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask(
245 positions.as_ptr() as *mut _,
246 len as i32,
247 force_order.into_glib(),
248 mask.as_mut_ptr(),
249 ));
250 if valid {
251 Ok(mask.assume_init())
252 } else {
253 Err(glib::bool_error!(
254 "Couldn't convert channel positions to mask"
255 ))
256 }
257 }
258 }
259
260 #[doc(alias = "gst_audio_channel_positions_from_mask")]
261 pub fn positions_from_mask(mask: u64, positions: &mut [Self]) -> Result<(), glib::BoolError> {
262 assert_initialized_main_thread!();
263
264 if positions.len() > 64 {
265 return Err(glib::bool_error!("Invalid number of channels"));
266 }
267
268 let len = positions.len();
269 let valid: bool = unsafe {
270 from_glib(ffi::gst_audio_channel_positions_from_mask(
271 len as i32,
272 mask,
273 positions.as_mut_ptr() as *mut _,
274 ))
275 };
276
277 if valid {
278 Ok(())
279 } else {
280 Err(glib::bool_error!(
281 "Couldn't convert channel positions to mask",
282 ))
283 }
284 }
285
286 #[doc(alias = "gst_audio_channel_positions_to_valid_order")]
287 pub fn positions_to_valid_order(positions: &mut [Self]) -> Result<(), glib::BoolError> {
288 assert_initialized_main_thread!();
289
290 if positions.len() > 64 {
291 return Err(glib::bool_error!("Invalid number of channels"));
292 }
293
294 let len = positions.len();
295 let valid: bool = unsafe {
296 from_glib(ffi::gst_audio_channel_positions_to_valid_order(
297 positions.as_mut_ptr() as *mut _,
298 len as i32,
299 ))
300 };
301
302 if valid {
303 Ok(())
304 } else {
305 Err(glib::bool_error!(
306 "Couldn't convert channel positions to mask",
307 ))
308 }
309 }
310
311 #[doc(alias = "get_fallback_mask")]
312 #[doc(alias = "gst_audio_channel_get_fallback_mask")]
313 pub fn fallback_mask(channels: u32) -> u64 {
314 assert_initialized_main_thread!();
315
316 unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) }
317 }
318
319 #[doc(alias = "gst_audio_check_valid_channel_positions")]
320 pub fn check_valid_channel_positions(positions: &[Self], force_order: bool) -> bool {
321 assert_initialized_main_thread!();
322
323 if positions.len() > 64 {
324 return false;
325 }
326
327 let len = positions.len();
328 unsafe {
329 from_glib(ffi::gst_audio_check_valid_channel_positions(
330 positions.as_ptr() as *mut _,
331 len as i32,
332 force_order.into_glib(),
333 ))
334 }
335 }
336}
337
338#[doc(alias = "gst_audio_buffer_reorder_channels")]
339pub fn buffer_reorder_channels(
340 buffer: &mut gst::BufferRef,
341 format: crate::AudioFormat,
342 channels: u32,
343 from: &[AudioChannelPosition],
344 to: &[AudioChannelPosition],
345) -> Result<(), glib::BoolError> {
346 skip_assert_initialized!();
347
348 assert!(channels > 0 && channels <= 64);
349
350 if from.len() != to.len() || from.len() > 64 {
351 return Err(glib::bool_error!("Invalid number of channels"));
352 }
353
354 let formatinfo = crate::AudioFormatInfo::from_format(format);
355 if buffer.size() % ((formatinfo.width() * channels) as usize) != 0 {
356 return Err(glib::bool_error!("Incomplete number of samples in buffer"));
357 }
358
359 let valid: bool = unsafe {
360 from_glib(ffi::gst_audio_buffer_reorder_channels(
361 buffer.as_mut_ptr(),
362 format.into_glib(),
363 channels as i32,
364 from.as_ptr() as *mut _,
365 to.as_ptr() as *mut _,
366 ))
367 };
368
369 if valid {
370 Ok(())
371 } else {
372 Err(glib::bool_error!("Failed to reorder channels"))
373 }
374}
375
376#[doc(alias = "gst_audio_reorder_channels")]
377pub fn reorder_channels(
378 data: &mut [u8],
379 format: crate::AudioFormat,
380 channels: u32,
381 from: &[AudioChannelPosition],
382 to: &[AudioChannelPosition],
383) -> Result<(), glib::BoolError> {
384 assert_initialized_main_thread!();
385
386 if from.len() != to.len() || from.len() > 64 {
387 return Err(glib::bool_error!("Invalid number of channels"));
388 }
389 assert!(channels > 0 && channels <= 64);
390
391 let formatinfo = crate::AudioFormatInfo::from_format(format);
392 if data.len() % ((formatinfo.width() * channels) as usize) != 0 {
393 return Err(glib::bool_error!("Incomplete number of samples in buffer"));
394 }
395
396 let valid: bool = unsafe {
397 from_glib(ffi::gst_audio_reorder_channels(
398 data.as_mut_ptr() as *mut _,
399 data.len(),
400 format.into_glib(),
401 channels as i32,
402 from.as_ptr() as *mut _,
403 to.as_ptr() as *mut _,
404 ))
405 };
406
407 if valid {
408 Ok(())
409 } else {
410 Err(glib::bool_error!("Failed to reorder channels"))
411 }
412}
413
414#[doc(alias = "get_channel_reorder_map")]
415#[doc(alias = "gst_audio_get_channel_reorder_map")]
416pub fn channel_reorder_map(
417 from: &[AudioChannelPosition],
418 to: &[AudioChannelPosition],
419 reorder_map: &mut [usize],
420) -> Result<(), glib::BoolError> {
421 assert_initialized_main_thread!();
422
423 if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 {
424 return Err(glib::bool_error!("Invalid number of channels"));
425 }
426
427 let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
428 let valid: bool = unsafe {
429 from_glib(ffi::gst_audio_get_channel_reorder_map(
430 from.len() as i32,
431 from.as_ptr() as *mut _,
432 to.as_ptr() as *mut _,
433 reorder_map_raw.as_mut_ptr() as *mut i32,
434 ))
435 };
436
437 if valid {
438 let reorder_map_raw =
439 unsafe { slice::from_raw_parts(reorder_map_raw.as_ptr() as *const i32, from.len()) };
440 for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) {
441 *d = *s as usize;
442 }
443 Ok(())
444 } else {
445 Err(glib::bool_error!("Failed to reorder channels"))
446 }
447}
448
449#[cfg(feature = "v1_26")]
450#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
451#[doc(alias = "gst_audio_reorder_channels_with_reorder_map")]
452pub fn reorder_channels_with_reorder_map(
453 data: &mut [u8],
454 bps: usize,
455 channels: u32,
456 reorder_map: &[usize],
457) -> Result<(), glib::BoolError> {
458 skip_assert_initialized!();
459
460 assert!(bps > 0 && bps <= 64);
461 assert!(channels > 0 && channels <= 64);
462 if data.len() % (bps * channels as usize) != 0 {
463 return Err(glib::bool_error!("Incomplete number of samples in buffer"));
464 }
465 if reorder_map.len() < channels as usize {
466 return Err(glib::bool_error!("Too small reorder map"));
467 }
468
469 let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
470 for (i, c) in reorder_map[..channels as usize].iter().enumerate() {
471 if *c >= channels as usize {
472 return Err(glib::bool_error!("Invalid channel id in reorder map"));
473 }
474 unsafe {
475 *(reorder_map_raw.as_mut_ptr() as *mut i32).add(i) = *c as i32;
476 }
477 }
478
479 unsafe {
480 ffi::gst_audio_reorder_channels_with_reorder_map(
481 data.as_mut_ptr() as *mut _,
482 data.len(),
483 bps as i32,
484 channels as i32,
485 reorder_map_raw.as_ptr() as *const i32,
486 );
487 };
488
489 Ok(())
490}
491