Skip to main content

gstreamer_audio/
audio_channel_position.rs

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::{Type, prelude::*, translate::*, value::FromValue};
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
151impl std::fmt::Display for AudioChannelPosition {
152    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
153        <AudioChannelPosition as std::fmt::Debug>::fmt(self, f)
154    }
155}
156
157unsafe impl TransparentType for AudioChannelPosition {
158    type GlibType = ffi::GstAudioChannelPosition;
159}
160
161#[doc(hidden)]
162impl IntoGlib for AudioChannelPosition {
163    type GlibType = ffi::GstAudioChannelPosition;
164
165    #[inline]
166    fn into_glib(self) -> ffi::GstAudioChannelPosition {
167        self as ffi::GstAudioChannelPosition
168    }
169}
170
171#[doc(hidden)]
172impl FromGlib<ffi::GstAudioChannelPosition> for AudioChannelPosition {
173    #[inline]
174    unsafe fn from_glib(value: ffi::GstAudioChannelPosition) -> Self {
175        unsafe {
176            skip_assert_initialized!();
177            debug_assert!((ffi::GST_AUDIO_CHANNEL_POSITION_NONE..=64).contains(&value));
178            mem::transmute::<ffi::GstAudioChannelPosition, AudioChannelPosition>(value)
179        }
180    }
181}
182
183impl StaticType for AudioChannelPosition {
184    #[inline]
185    fn static_type() -> Type {
186        unsafe { from_glib(ffi::gst_audio_channel_position_get_type()) }
187    }
188}
189
190impl glib::value::ValueType for AudioChannelPosition {
191    type Type = Self;
192}
193
194unsafe impl<'a> FromValue<'a> for AudioChannelPosition {
195    type Checker = glib::value::GenericValueTypeChecker<Self>;
196
197    #[inline]
198    unsafe fn from_value(value: &'a glib::Value) -> Self {
199        unsafe {
200            skip_assert_initialized!();
201            from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
202        }
203    }
204}
205
206impl ToValue for AudioChannelPosition {
207    #[inline]
208    fn to_value(&self) -> glib::Value {
209        let mut value = glib::Value::for_value_type::<Self>();
210        unsafe {
211            glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
212        }
213        value
214    }
215
216    #[inline]
217    fn value_type(&self) -> glib::Type {
218        Self::static_type()
219    }
220}
221
222impl From<AudioChannelPosition> for glib::Value {
223    #[inline]
224    fn from(v: AudioChannelPosition) -> Self {
225        skip_assert_initialized!();
226        ToValue::to_value(&v)
227    }
228}
229
230impl AudioChannelPosition {
231    pub fn to_mask(self) -> u64 {
232        let pos = self.into_glib();
233        if pos < 0 {
234            return 0;
235        }
236
237        1 << (pos as u32)
238    }
239
240    #[doc(alias = "gst_audio_channel_positions_to_mask")]
241    pub fn positions_to_mask(
242        positions: &[Self],
243        force_order: bool,
244    ) -> Result<u64, glib::error::BoolError> {
245        assert_initialized_main_thread!();
246
247        let len = positions.len();
248        if len > 64 {
249            return Err(glib::bool_error!("Invalid number of channels"));
250        }
251
252        unsafe {
253            let mut mask = mem::MaybeUninit::uninit();
254            let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask(
255                positions.as_ptr() as *mut _,
256                len as i32,
257                force_order.into_glib(),
258                mask.as_mut_ptr(),
259            ));
260            if valid {
261                Ok(mask.assume_init())
262            } else {
263                Err(glib::bool_error!(
264                    "Couldn't convert channel positions to mask"
265                ))
266            }
267        }
268    }
269
270    #[doc(alias = "gst_audio_channel_positions_from_mask")]
271    pub fn positions_from_mask(mask: u64, positions: &mut [Self]) -> Result<(), glib::BoolError> {
272        assert_initialized_main_thread!();
273
274        if positions.len() > 64 {
275            return Err(glib::bool_error!("Invalid number of channels"));
276        }
277
278        let len = positions.len();
279        let valid: bool = unsafe {
280            from_glib(ffi::gst_audio_channel_positions_from_mask(
281                len as i32,
282                mask,
283                positions.as_mut_ptr() as *mut _,
284            ))
285        };
286
287        if valid {
288            Ok(())
289        } else {
290            Err(glib::bool_error!(
291                "Couldn't convert channel positions to mask",
292            ))
293        }
294    }
295
296    #[doc(alias = "gst_audio_channel_positions_to_valid_order")]
297    pub fn positions_to_valid_order(positions: &mut [Self]) -> Result<(), glib::BoolError> {
298        assert_initialized_main_thread!();
299
300        if positions.len() > 64 {
301            return Err(glib::bool_error!("Invalid number of channels"));
302        }
303
304        let len = positions.len();
305        let valid: bool = unsafe {
306            from_glib(ffi::gst_audio_channel_positions_to_valid_order(
307                positions.as_mut_ptr() as *mut _,
308                len as i32,
309            ))
310        };
311
312        if valid {
313            Ok(())
314        } else {
315            Err(glib::bool_error!(
316                "Couldn't convert channel positions to mask",
317            ))
318        }
319    }
320
321    #[doc(alias = "get_fallback_mask")]
322    #[doc(alias = "gst_audio_channel_get_fallback_mask")]
323    pub fn fallback_mask(channels: u32) -> u64 {
324        assert_initialized_main_thread!();
325
326        unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) }
327    }
328
329    #[doc(alias = "gst_audio_check_valid_channel_positions")]
330    pub fn check_valid_channel_positions(positions: &[Self], force_order: bool) -> bool {
331        assert_initialized_main_thread!();
332
333        if positions.len() > 64 {
334            return false;
335        }
336
337        let len = positions.len();
338        unsafe {
339            from_glib(ffi::gst_audio_check_valid_channel_positions(
340                positions.as_ptr() as *mut _,
341                len as i32,
342                force_order.into_glib(),
343            ))
344        }
345    }
346}
347
348#[doc(alias = "gst_audio_buffer_reorder_channels")]
349pub fn buffer_reorder_channels(
350    buffer: &mut gst::BufferRef,
351    format: crate::AudioFormat,
352    channels: u32,
353    from: &[AudioChannelPosition],
354    to: &[AudioChannelPosition],
355) -> Result<(), glib::BoolError> {
356    skip_assert_initialized!();
357
358    assert!(channels > 0 && channels <= 64);
359
360    if from.len() != to.len() || from.len() > 64 {
361        return Err(glib::bool_error!("Invalid number of channels"));
362    }
363
364    let formatinfo = crate::AudioFormatInfo::from_format(format);
365    if !buffer
366        .size()
367        .is_multiple_of((formatinfo.width() * channels) as usize)
368    {
369        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
370    }
371
372    let valid: bool = unsafe {
373        from_glib(ffi::gst_audio_buffer_reorder_channels(
374            buffer.as_mut_ptr(),
375            format.into_glib(),
376            channels as i32,
377            from.as_ptr() as *mut _,
378            to.as_ptr() as *mut _,
379        ))
380    };
381
382    if valid {
383        Ok(())
384    } else {
385        Err(glib::bool_error!("Failed to reorder channels"))
386    }
387}
388
389#[doc(alias = "gst_audio_reorder_channels")]
390pub fn reorder_channels(
391    data: &mut [u8],
392    format: crate::AudioFormat,
393    channels: u32,
394    from: &[AudioChannelPosition],
395    to: &[AudioChannelPosition],
396) -> Result<(), glib::BoolError> {
397    assert_initialized_main_thread!();
398
399    if from.len() != to.len() || from.len() > 64 {
400        return Err(glib::bool_error!("Invalid number of channels"));
401    }
402    assert!(channels > 0 && channels <= 64);
403
404    let formatinfo = crate::AudioFormatInfo::from_format(format);
405    if !data
406        .len()
407        .is_multiple_of((formatinfo.width() * channels) as usize)
408    {
409        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
410    }
411
412    let valid: bool = unsafe {
413        from_glib(ffi::gst_audio_reorder_channels(
414            data.as_mut_ptr() as *mut _,
415            data.len(),
416            format.into_glib(),
417            channels as i32,
418            from.as_ptr() as *mut _,
419            to.as_ptr() as *mut _,
420        ))
421    };
422
423    if valid {
424        Ok(())
425    } else {
426        Err(glib::bool_error!("Failed to reorder channels"))
427    }
428}
429
430#[doc(alias = "get_channel_reorder_map")]
431#[doc(alias = "gst_audio_get_channel_reorder_map")]
432pub fn channel_reorder_map(
433    from: &[AudioChannelPosition],
434    to: &[AudioChannelPosition],
435    reorder_map: &mut [usize],
436) -> Result<(), glib::BoolError> {
437    assert_initialized_main_thread!();
438
439    if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 {
440        return Err(glib::bool_error!("Invalid number of channels"));
441    }
442
443    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
444    let valid: bool = unsafe {
445        from_glib(ffi::gst_audio_get_channel_reorder_map(
446            from.len() as i32,
447            from.as_ptr() as *mut _,
448            to.as_ptr() as *mut _,
449            reorder_map_raw.as_mut_ptr() as *mut i32,
450        ))
451    };
452
453    if valid {
454        let reorder_map_raw =
455            unsafe { slice::from_raw_parts(reorder_map_raw.as_ptr() as *const i32, from.len()) };
456        for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) {
457            *d = *s as usize;
458        }
459        Ok(())
460    } else {
461        Err(glib::bool_error!("Failed to reorder channels"))
462    }
463}
464
465#[cfg(feature = "v1_26")]
466#[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
467#[doc(alias = "gst_audio_reorder_channels_with_reorder_map")]
468pub fn reorder_channels_with_reorder_map(
469    data: &mut [u8],
470    bps: usize,
471    channels: u32,
472    reorder_map: &[usize],
473) -> Result<(), glib::BoolError> {
474    skip_assert_initialized!();
475
476    assert!(bps > 0 && bps <= 64);
477    assert!(channels > 0 && channels <= 64);
478    if !data.len().is_multiple_of(bps * channels as usize) {
479        return Err(glib::bool_error!("Incomplete number of samples in buffer"));
480    }
481    if reorder_map.len() < channels as usize {
482        return Err(glib::bool_error!("Too small reorder map"));
483    }
484
485    let mut reorder_map_raw = mem::MaybeUninit::<[i32; 64]>::uninit();
486    for (i, c) in reorder_map[..channels as usize].iter().enumerate() {
487        if *c >= channels as usize {
488            return Err(glib::bool_error!("Invalid channel id in reorder map"));
489        }
490        unsafe {
491            *(reorder_map_raw.as_mut_ptr() as *mut i32).add(i) = *c as i32;
492        }
493    }
494
495    unsafe {
496        ffi::gst_audio_reorder_channels_with_reorder_map(
497            data.as_mut_ptr() as *mut _,
498            data.len(),
499            bps as i32,
500            channels as i32,
501            reorder_map_raw.as_ptr() as *const i32,
502        );
503    };
504
505    Ok(())
506}