1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{mem, slice}; |
4 | |
5 | use crate::ffi; |
6 | use 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)] |
12 | pub 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 | |
151 | unsafe impl TransparentType for AudioChannelPosition { |
152 | type GlibType = ffi::GstAudioChannelPosition; |
153 | } |
154 | |
155 | #[doc (hidden)] |
156 | impl 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)] |
166 | impl 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 | |
175 | impl 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 | |
182 | impl glib::value::ValueType for AudioChannelPosition { |
183 | type Type = Self; |
184 | } |
185 | |
186 | unsafe 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 | |
196 | impl 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 | |
212 | impl 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 | |
220 | impl 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" )] |
339 | pub 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" )] |
377 | pub 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" )] |
416 | pub 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" )] |
452 | pub 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 | |