diff --git a/Cargo.lock b/Cargo.lock index f0c1813d1..1ab6db234 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,7 @@ name = "gstreamer-audio" version = "0.1.0" dependencies = [ + "array-init 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.1.3 (git+https://github.com/gtk-rs/glib)", "glib-sys 0.3.4 (git+https://github.com/gtk-rs/sys)", @@ -13,6 +14,14 @@ dependencies = [ "rustdoc-stripper 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "array-init" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atk-sys" version = "0.3.4" @@ -465,6 +474,14 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.35" @@ -487,6 +504,11 @@ name = "num-traits" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "odds" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pango" version = "0.1.3" @@ -582,6 +604,7 @@ dependencies = [ ] [metadata] +"checksum array-init 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4d3b508d35216892b50a135fb52c9bb90f04a97b7782230805dff1a156ad5469" "checksum atk-sys 0.3.4 (git+https://github.com/gtk-rs/sys)" = "" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" @@ -621,9 +644,11 @@ dependencies = [ "checksum mio 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "dbd91d3bfbceb13897065e97b2ef177a09a438cb33612b2d371bf568819a9313" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "94101fd932816f97eb9a5116f6c1a11511a1fed7db21c5ccd823b2dc11abf566" +"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum pango 0.1.3 (git+https://github.com/gtk-rs/pango)" = "" "checksum pango-sys 0.3.4 (git+https://github.com/gtk-rs/sys)" = "" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" diff --git a/gstreamer-audio/Cargo.toml b/gstreamer-audio/Cargo.toml index 47ed558e4..e455fe780 100644 --- a/gstreamer-audio/Cargo.toml +++ b/gstreamer-audio/Cargo.toml @@ -19,6 +19,7 @@ gstreamer-sys = { version = "0.1.1", git = "https://github.com/sdroege/gstreamer gstreamer-audio-sys = { version = "0.1.1", git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] } glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" } gstreamer = { version = "0.1.0", path = "../gstreamer" } +array-init = "0.0" [build-dependencies.rustdoc-stripper] version = "0.1" diff --git a/gstreamer-audio/src/audio_channel_position.rs b/gstreamer-audio/src/audio_channel_position.rs new file mode 100644 index 000000000..27ac41f7c --- /dev/null +++ b/gstreamer-audio/src/audio_channel_position.rs @@ -0,0 +1,288 @@ +// Copyright (C) 2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ffi; +use AudioChannelPosition; + +use std::mem; + +use gst; +use gst::MiniObject; +use glib; +use glib::translate::{from_glib, ToGlib}; + +use array_init; + +impl AudioChannelPosition { + pub fn to_mask(&self) -> u64 { + unsafe { + let val = mem::transmute::(self.to_glib()); + 1 << val + } + } + + pub fn positions_to_mask(positions: &[AudioChannelPosition], force_order: bool) -> Option { + let len = positions.len(); + if len > 64 { + return None; + } + + let positions_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + positions[i].to_glib() + }); + + unsafe { + let mut mask = mem::uninitialized(); + let valid: bool = from_glib(ffi::gst_audio_channel_positions_to_mask( + positions_raw.as_ptr() as *mut _, + len as i32, + force_order.to_glib(), + &mut mask, + )); + if valid { + Some(mask) + } else { + None + } + } + } + + pub fn positions_from_mask( + mask: u64, + positions: &mut [AudioChannelPosition], + ) -> Result<(), glib::BoolError> { + if positions.len() > 64 { + return Err(glib::BoolError("Invalid number of channels")); + } + + let len = positions.len(); + let mut positions_raw: [ffi::GstAudioChannelPosition; 64] = + [ffi::GstAudioChannelPosition::Invalid; 64]; + let valid: bool = unsafe { + from_glib(ffi::gst_audio_channel_positions_from_mask( + len as i32, + mask, + positions_raw.as_mut_ptr(), + )) + }; + + if valid { + for (d, s) in positions.iter_mut().zip(positions_raw.iter()) { + *d = from_glib(*s); + } + Ok(()) + } else { + Err(glib::BoolError( + "Couldn't convert channel positions to mask", + )) + } + } + + pub fn positions_to_valid_order( + positions: &mut [AudioChannelPosition], + ) -> Result<(), glib::BoolError> { + if positions.len() > 64 { + return Err(glib::BoolError("Invalid number of channels")); + } + + let len = positions.len(); + let mut positions_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + positions[i].to_glib() + }); + + let valid: bool = unsafe { + from_glib(ffi::gst_audio_channel_positions_to_valid_order( + positions_raw.as_mut_ptr(), + len as i32, + )) + }; + + if valid { + for (d, s) in positions.iter_mut().zip(positions_raw.iter()) { + *d = from_glib(*s); + } + Ok(()) + } else { + Err(glib::BoolError( + "Couldn't convert channel positions to mask", + )) + } + } + + pub fn get_fallback_mask(channels: u32) -> u64 { + unsafe { ffi::gst_audio_channel_get_fallback_mask(channels as i32) } + } + + pub fn check_valid_channel_positions( + positions: &[::AudioChannelPosition], + force_order: bool, + ) -> bool { + if positions.len() > 64 { + return false; + } + + let len = positions.len(); + let positions_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + positions[i].to_glib() + }); + + unsafe { + from_glib(ffi::gst_audio_check_valid_channel_positions( + positions_raw.as_ptr() as *mut _, + len as i32, + force_order.to_glib(), + )) + } + } +} + +pub fn buffer_reorder_channels( + buffer: &mut gst::BufferRef, + format: ::AudioFormat, + channels: u32, + from: &[AudioChannelPosition], + to: &[AudioChannelPosition], +) -> Result<(), glib::BoolError> { + if from.len() != to.len() || from.len() > 64 { + return Err(glib::BoolError("Invalid number of channels")); + } + + let from_len = from.len(); + let to_len = to.len(); + + let from_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= from_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + from[i].to_glib() + }); + + let to_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= to_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + to[i].to_glib() + }); + + let valid: bool = unsafe { + from_glib(ffi::gst_audio_buffer_reorder_channels( + buffer.as_mut_ptr(), + format.to_glib(), + channels as i32, + from_raw.as_ptr() as *mut _, + to_raw.as_ptr() as *mut _, + )) + }; + + if valid { + Ok(()) + } else { + Err(glib::BoolError("Failed to reorder channels")) + } +} + +pub fn reorder_channels( + data: &mut [u8], + format: ::AudioFormat, + channels: u32, + from: &[AudioChannelPosition], + to: &[AudioChannelPosition], +) -> Result<(), glib::BoolError> { + if from.len() != to.len() || from.len() > 64 { + return Err(glib::BoolError("Invalid number of channels")); + } + + let from_len = from.len(); + let to_len = to.len(); + + let from_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= from_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + from[i].to_glib() + }); + + let to_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= to_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + to[i].to_glib() + }); + + let valid: bool = unsafe { + from_glib(ffi::gst_audio_reorder_channels( + data.as_mut_ptr() as *mut _, + data.len(), + format.to_glib(), + channels as i32, + from_raw.as_ptr() as *mut _, + to_raw.as_ptr() as *mut _, + )) + }; + + if valid { + Ok(()) + } else { + Err(glib::BoolError("Failed to reorder channels")) + } +} + +pub fn get_channel_reorder_map( + from: &[AudioChannelPosition], + to: &[AudioChannelPosition], + reorder_map: &mut [usize], +) -> Result<(), glib::BoolError> { + if from.len() != to.len() || from.len() != reorder_map.len() || from.len() > 64 { + return Err(glib::BoolError("Invalid number of channels")); + } + + let from_len = from.len(); + let to_len = to.len(); + + let from_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= from_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + from[i].to_glib() + }); + + let to_raw: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= to_len as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + to[i].to_glib() + }); + + let mut reorder_map_raw = [0i32, 64]; + let valid: bool = unsafe { + from_glib(ffi::gst_audio_get_channel_reorder_map( + from_len as i32, + from_raw.as_ptr() as *mut _, + to_raw.as_ptr() as *mut _, + reorder_map_raw.as_mut_ptr(), + )) + }; + + if valid { + for (d, s) in reorder_map.iter_mut().zip(reorder_map_raw.iter()) { + *d = *s as usize; + } + Ok(()) + } else { + Err(glib::BoolError("Failed to reorder channels")) + } +} diff --git a/gstreamer-audio/src/audio_info.rs b/gstreamer-audio/src/audio_info.rs index 6e3c871ab..7d0face86 100644 --- a/gstreamer-audio/src/audio_info.rs +++ b/gstreamer-audio/src/audio_info.rs @@ -19,7 +19,9 @@ use glib::translate::{from_glib, from_glib_full, from_glib_none, FromGlibPtrNone use std::mem; use std::ptr; -pub struct AudioInfo(ffi::GstAudioInfo); +use array_init; + +pub struct AudioInfo(ffi::GstAudioInfo, [::AudioChannelPosition; 64]); pub struct AudioInfoBuilder<'a> { format: ::AudioFormat, @@ -34,33 +36,37 @@ impl<'a> AudioInfoBuilder<'a> { pub fn build(self) -> Option { unsafe { let mut info = mem::uninitialized(); - let mut positions_raw = Vec::new(); - let positions_ptr = match self.positions { - Some(p) => { - if p.len() != self.channels as usize { - return None; - } - - positions_raw.reserve(self.channels as usize); - for i in p { - positions_raw.push(i.to_glib()); - } - - let valid: bool = from_glib(ffi::gst_audio_check_valid_channel_positions( - positions_raw.as_mut_ptr(), - self.channels as i32, - true.to_glib(), - )); - if !valid { - return None; - } - - positions_raw.as_ptr() + let positions = if let Some(p) = self.positions { + if p.len() != self.channels as usize || p.len() > 64 { + return None; } - None => ptr::null(), + + let positions: [ffi::GstAudioChannelPosition; 64] = + array_init::array_init_copy(|i| if i >= self.channels as usize { + ffi::GstAudioChannelPosition::Invalid + } else { + p[i].to_glib() + }); + + let valid: bool = from_glib(ffi::gst_audio_check_valid_channel_positions( + positions.as_ptr() as *mut _, + self.channels as i32, + true.to_glib(), + )); + if !valid { + return None; + } + + Some(positions) + } else { + None }; + let positions_ptr = positions + .as_ref() + .map(|p| p.as_ptr()) + .unwrap_or(ptr::null()); ffi::gst_audio_info_set_format( &mut info, @@ -82,7 +88,8 @@ impl<'a> AudioInfoBuilder<'a> { info.layout = layout.to_glib(); } - Some(AudioInfo(info)) + let positions = array_init::array_init_copy(|i| from_glib(info.position[i])); + Some(AudioInfo(info, positions)) } } @@ -124,7 +131,8 @@ impl AudioInfo { unsafe { let mut info = mem::uninitialized(); if from_glib(ffi::gst_audio_info_from_caps(&mut info, caps.as_ptr())) { - Some(AudioInfo(info)) + let positions = array_init::array_init_copy(|i| from_glib(info.position[i])); + Some(AudioInfo(info, positions)) } else { None } @@ -228,13 +236,12 @@ impl AudioInfo { self.format_info().is_signed() } - pub fn positions(&self) -> Vec<::AudioChannelPosition> { - let mut v = Vec::with_capacity(self.0.channels as usize); - for i in 0..(self.0.channels as usize) { - v.push(from_glib(self.0.position[i])); + pub fn positions(&self) -> Option<&[::AudioChannelPosition]> { + if self.0.channels > 64 || self.is_unpositioned() { + return None; } - v + Some(&self.1[0..(self.0.channels as usize)]) } pub fn is_unpositioned(&self) -> bool { @@ -244,7 +251,7 @@ impl AudioInfo { impl Clone for AudioInfo { fn clone(&self) -> Self { - unsafe { AudioInfo(ptr::read(&self.0)) } + unsafe { AudioInfo(ptr::read(&self.0), self.1) } } } @@ -322,7 +329,10 @@ impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstAudioInfo> for AudioInfo impl glib::translate::FromGlibPtrNone<*mut ffi::GstAudioInfo> for AudioInfo { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstAudioInfo) -> Self { - AudioInfo(ptr::read(ptr)) + AudioInfo( + ptr::read(ptr), + array_init::array_init_copy(|i| from_glib((*ptr).position[i])), + ) } } @@ -352,7 +362,7 @@ mod tests { assert_eq!(info.rate(), 48000); assert_eq!(info.channels(), 2); assert_eq!( - &info.positions(), + &info.positions().unwrap(), &[ ::AudioChannelPosition::FrontLeft, ::AudioChannelPosition::FrontRight @@ -371,7 +381,7 @@ mod tests { assert_eq!(info.rate(), 48000); assert_eq!(info.channels(), 2); assert_eq!( - &info.positions(), + &info.positions().unwrap(), &[ ::AudioChannelPosition::RearLeft, ::AudioChannelPosition::RearRight @@ -398,7 +408,7 @@ mod tests { assert_eq!(info.rate(), 48000); assert_eq!(info.channels(), 2); assert_eq!( - &info.positions(), + &info.positions().unwrap(), &[ ::AudioChannelPosition::FrontLeft, ::AudioChannelPosition::FrontRight diff --git a/gstreamer-audio/src/lib.rs b/gstreamer-audio/src/lib.rs index 780c2394c..f74170ca6 100644 --- a/gstreamer-audio/src/lib.rs +++ b/gstreamer-audio/src/lib.rs @@ -9,6 +9,7 @@ #[macro_use] extern crate bitflags; extern crate libc; +extern crate array_init; extern crate glib_sys as glib_ffi; extern crate gobject_sys as gobject_ffi; @@ -46,3 +47,5 @@ mod audio_format_info; pub use audio_format_info::*; mod audio_info; pub use audio_info::*; +mod audio_channel_position; +pub use audio_channel_position::*; diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 1df804bbd..5294e0ceb 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -53,7 +53,7 @@ pub use auto::traits::*; pub use auto::functions::{parse_bin_from_description, parse_launch}; pub mod miniobject; -pub use miniobject::GstRc; +pub use miniobject::{GstRc, MiniObject}; pub mod message; pub use message::{Message, MessageRef, MessageView}; pub mod structure;