| 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 | |