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