diff --git a/audio/audiofx/src/audioecho/imp.rs b/audio/audiofx/src/audioecho/imp.rs index cdf553c2..a3f9423c 100644 --- a/audio/audiofx/src/audioecho/imp.rs +++ b/audio/audiofx/src/audioecho/imp.rs @@ -9,7 +9,7 @@ use gst::glib; use gst::prelude::*; use gst::subclass::prelude::*; -use gst_base::subclass::prelude::*; +use gst_audio::subclass::prelude::*; use std::sync::Mutex; use std::{cmp, u64}; @@ -20,7 +20,7 @@ use num_traits::cast::{FromPrimitive, ToPrimitive}; use num_traits::float::Float; use once_cell::sync::Lazy; -static CAT: Lazy = Lazy::new(|| { +static _CAT: Lazy = Lazy::new(|| { gst::DebugCategory::new( "rsaudioecho", gst::DebugColorFlags::empty(), @@ -89,7 +89,7 @@ impl AudioEcho { impl ObjectSubclass for AudioEcho { const NAME: &'static str = "GstRsAudioEcho"; type Type = super::AudioEcho; - type ParentType = gst_base::BaseTransform; + type ParentType = gst_audio::AudioFilter; } impl ObjectImpl for AudioEcho { @@ -194,32 +194,6 @@ impl ElementImpl for AudioEcho { Some(&*ELEMENT_METADATA) } - - fn pad_templates() -> &'static [gst::PadTemplate] { - static PAD_TEMPLATES: Lazy> = Lazy::new(|| { - let caps = gst_audio::AudioCapsBuilder::new_interleaved() - .format_list([gst_audio::AUDIO_FORMAT_F32, gst_audio::AUDIO_FORMAT_F64]) - .build(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - vec![src_pad_template, sink_pad_template] - }); - - PAD_TEMPLATES.as_ref() - } } impl BaseTransformImpl for AudioEcho { @@ -252,28 +226,6 @@ impl BaseTransformImpl for AudioEcho { Ok(gst::FlowSuccess::Ok) } - fn set_caps(&self, incaps: &gst::Caps, outcaps: &gst::Caps) -> Result<(), gst::LoggableError> { - if incaps != outcaps { - return Err(gst::loggable_error!( - CAT, - "Input and output caps are not the same" - )); - } - - let info = gst_audio::AudioInfo::from_caps(incaps) - .map_err(|_| gst::loggable_error!(CAT, "Failed to parse input caps"))?; - let max_delay = self.settings.lock().unwrap().max_delay; - let size = (max_delay * (info.rate() as u64)).seconds() as usize; - let buffer_size = size * (info.channels() as usize); - - *self.state.lock().unwrap() = Some(State { - info, - buffer: RingBuffer::new(buffer_size), - }); - - Ok(()) - } - fn stop(&self) -> Result<(), gst::ErrorMessage> { // Drop state let _ = self.state.lock().unwrap().take(); @@ -281,3 +233,28 @@ impl BaseTransformImpl for AudioEcho { Ok(()) } } + +impl AudioFilterImpl for AudioEcho { + fn allowed_caps() -> &'static gst::Caps { + static CAPS: Lazy = Lazy::new(|| { + gst_audio::AudioCapsBuilder::new_interleaved() + .format_list([gst_audio::AUDIO_FORMAT_F32, gst_audio::AUDIO_FORMAT_F64]) + .build() + }); + + &CAPS + } + + fn setup(&self, info: &gst_audio::AudioInfo) -> Result<(), gst::LoggableError> { + let max_delay = self.settings.lock().unwrap().max_delay; + let size = (max_delay * (info.rate() as u64)).seconds() as usize; + let buffer_size = size * (info.channels() as usize); + + *self.state.lock().unwrap() = Some(State { + info: info.clone(), + buffer: RingBuffer::new(buffer_size), + }); + + Ok(()) + } +} diff --git a/audio/audiofx/src/audiornnoise/imp.rs b/audio/audiofx/src/audiornnoise/imp.rs index 2eb66a6c..8ebb9046 100644 --- a/audio/audiofx/src/audiornnoise/imp.rs +++ b/audio/audiofx/src/audiornnoise/imp.rs @@ -12,10 +12,10 @@ use std::sync::Mutex; use gst::glib; use gst::prelude::*; use gst::subclass::prelude::*; +use gst_audio::subclass::prelude::*; use gst_base::prelude::*; use gst_base::subclass::base_transform::BaseTransformImplExt; use gst_base::subclass::base_transform::GenerateOutputSuccess; -use gst_base::subclass::prelude::*; use nnnoiseless::DenoiseState; @@ -227,7 +227,7 @@ impl AudioRNNoise { impl ObjectSubclass for AudioRNNoise { const NAME: &'static str = "GstAudioRNNoise"; type Type = super::AudioRNNoise; - type ParentType = gst_base::BaseTransform; + type ParentType = gst_audio::AudioFilter; } impl ObjectImpl for AudioRNNoise { @@ -282,34 +282,6 @@ impl ElementImpl for AudioRNNoise { Some(&*ELEMENT_METADATA) } - - fn pad_templates() -> &'static [gst::PadTemplate] { - static PAD_TEMPLATES: Lazy> = Lazy::new(|| { - let caps = gst_audio::AudioCapsBuilder::new_interleaved() - .format(gst_audio::AUDIO_FORMAT_F32) - .rate(48000) - .build(); - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - - let sink_pad_template = gst::PadTemplate::new( - "sink", - gst::PadDirection::Sink, - gst::PadPresence::Always, - &caps, - ) - .unwrap(); - - vec![src_pad_template, sink_pad_template] - }); - - PAD_TEMPLATES.as_ref() - } } impl BaseTransformImpl for AudioRNNoise { @@ -318,44 +290,6 @@ impl BaseTransformImpl for AudioRNNoise { const PASSTHROUGH_ON_SAME_CAPS: bool = false; const TRANSFORM_IP_ON_PASSTHROUGH: bool = false; - fn set_caps(&self, incaps: &gst::Caps, outcaps: &gst::Caps) -> Result<(), gst::LoggableError> { - // Flush previous state - if self.state.borrow_mut().is_some() { - self.drain().map_err(|e| { - gst::loggable_error!(CAT, "Error flushing previous state data {:?}", e) - })?; - } - if incaps != outcaps { - return Err(gst::loggable_error!( - CAT, - "Input and output caps are not the same" - )); - } - - gst::debug!(CAT, imp: self, "Set caps to {}", incaps); - - let in_info = gst_audio::AudioInfo::from_caps(incaps) - .map_err(|e| gst::loggable_error!(CAT, "Failed to parse input caps {:?}", e))?; - - let mut denoisers = vec![]; - for _i in 0..in_info.channels() { - denoisers.push(ChannelDenoiser { - denoiser: DenoiseState::new(), - frame_chunk: Box::new([0.0; FRAME_SIZE]), - out_chunk: Box::new([0.0; FRAME_SIZE]), - }) - } - - let mut state_lock = self.state.borrow_mut(); - *state_lock = Some(State { - in_info, - denoisers, - adapter: gst_base::UniqueAdapter::new(), - }); - - Ok(()) - } - fn generate_output(&self) -> Result { // Check if there are enough data in the queued buffer and adapter, // if it is not the case, just notify the parent class to not generate @@ -427,3 +361,45 @@ impl BaseTransformImpl for AudioRNNoise { Ok(()) } } + +impl AudioFilterImpl for AudioRNNoise { + fn allowed_caps() -> &'static gst::Caps { + static CAPS: Lazy = Lazy::new(|| { + gst_audio::AudioCapsBuilder::new_interleaved() + .format(gst_audio::AUDIO_FORMAT_F32) + .rate(48000) + .build() + }); + + &CAPS + } + + fn setup(&self, info: &gst_audio::AudioInfo) -> Result<(), gst::LoggableError> { + // Flush previous state + if self.state.borrow_mut().is_some() { + self.drain().map_err(|e| { + gst::loggable_error!(CAT, "Error flushing previous state data {:?}", e) + })?; + } + + gst::debug!(CAT, imp: self, "Set caps to {:?}", info); + + let mut denoisers = vec![]; + for _i in 0..info.channels() { + denoisers.push(ChannelDenoiser { + denoiser: DenoiseState::new(), + frame_chunk: Box::new([0.0; FRAME_SIZE]), + out_chunk: Box::new([0.0; FRAME_SIZE]), + }) + } + + let mut state_lock = self.state.borrow_mut(); + *state_lock = Some(State { + in_info: info.clone(), + denoisers, + adapter: gst_base::UniqueAdapter::new(), + }); + + Ok(()) + } +} diff --git a/audio/audiofx/src/ebur128level/imp.rs b/audio/audiofx/src/ebur128level/imp.rs index f61d55c3..add9de30 100644 --- a/audio/audiofx/src/ebur128level/imp.rs +++ b/audio/audiofx/src/ebur128level/imp.rs @@ -9,8 +9,8 @@ use gst::glib; use gst::prelude::*; use gst::subclass::prelude::*; +use gst_audio::subclass::prelude::*; use gst_base::prelude::*; -use gst_base::subclass::prelude::*; use std::i32; use std::sync::atomic; @@ -118,7 +118,7 @@ pub struct EbuR128Level { impl ObjectSubclass for EbuR128Level { const NAME: &'static str = "GstEbuR128Level"; type Type = super::EbuR128Level; - type ParentType = gst_base::BaseTransform; + type ParentType = gst_audio::AudioFilter; } impl ObjectImpl for EbuR128Level { @@ -283,113 +283,6 @@ impl BaseTransformImpl for EbuR128Level { const PASSTHROUGH_ON_SAME_CAPS: bool = true; const TRANSFORM_IP_ON_PASSTHROUGH: bool = true; - fn set_caps(&self, incaps: &gst::Caps, _outcaps: &gst::Caps) -> Result<(), gst::LoggableError> { - let info = match gst_audio::AudioInfo::from_caps(incaps) { - Err(_) => return Err(gst::loggable_error!(CAT, "Failed to parse input caps")), - Ok(info) => info, - }; - - gst::debug!(CAT, imp: self, "Configured for caps {}", incaps,); - - let settings = *self.settings.lock().unwrap(); - - let mut ebur128 = ebur128::EbuR128::new(info.channels(), info.rate(), settings.mode.into()) - .map_err(|err| gst::loggable_error!(CAT, "Failed to create EBU R128: {}", err))?; - - // Map channel positions if we can to give correct weighting - if let Some(positions) = info.positions() { - let channel_map = positions - .iter() - .map(|p| { - match p { - gst_audio::AudioChannelPosition::Mono => ebur128::Channel::DualMono, - gst_audio::AudioChannelPosition::FrontLeft => ebur128::Channel::Left, - gst_audio::AudioChannelPosition::FrontRight => ebur128::Channel::Right, - gst_audio::AudioChannelPosition::FrontCenter => ebur128::Channel::Center, - gst_audio::AudioChannelPosition::Lfe1 - | gst_audio::AudioChannelPosition::Lfe2 => ebur128::Channel::Unused, - gst_audio::AudioChannelPosition::RearLeft => ebur128::Channel::Mp135, - gst_audio::AudioChannelPosition::RearRight => ebur128::Channel::Mm135, - gst_audio::AudioChannelPosition::FrontLeftOfCenter => { - ebur128::Channel::MpSC - } - gst_audio::AudioChannelPosition::FrontRightOfCenter => { - ebur128::Channel::MmSC - } - gst_audio::AudioChannelPosition::RearCenter => ebur128::Channel::Mp180, - gst_audio::AudioChannelPosition::SideLeft => ebur128::Channel::Mp090, - gst_audio::AudioChannelPosition::SideRight => ebur128::Channel::Mm090, - gst_audio::AudioChannelPosition::TopFrontLeft => ebur128::Channel::Up030, - gst_audio::AudioChannelPosition::TopFrontRight => ebur128::Channel::Um030, - gst_audio::AudioChannelPosition::TopFrontCenter => ebur128::Channel::Up000, - gst_audio::AudioChannelPosition::TopCenter => ebur128::Channel::Tp000, - gst_audio::AudioChannelPosition::TopRearLeft => ebur128::Channel::Up135, - gst_audio::AudioChannelPosition::TopRearRight => ebur128::Channel::Um135, - gst_audio::AudioChannelPosition::TopSideLeft => ebur128::Channel::Up090, - gst_audio::AudioChannelPosition::TopSideRight => ebur128::Channel::Um090, - gst_audio::AudioChannelPosition::TopRearCenter => ebur128::Channel::Up180, - gst_audio::AudioChannelPosition::BottomFrontCenter => { - ebur128::Channel::Bp000 - } - gst_audio::AudioChannelPosition::BottomFrontLeft => ebur128::Channel::Bp045, - gst_audio::AudioChannelPosition::BottomFrontRight => { - ebur128::Channel::Bm045 - } - gst_audio::AudioChannelPosition::WideLeft => { - ebur128::Channel::Mp135 // Mp110? - } - gst_audio::AudioChannelPosition::WideRight => { - ebur128::Channel::Mm135 // Mm110? - } - gst_audio::AudioChannelPosition::SurroundLeft => { - ebur128::Channel::Mp135 // Mp110? - } - gst_audio::AudioChannelPosition::SurroundRight => { - ebur128::Channel::Mm135 // Mm110? - } - gst_audio::AudioChannelPosition::Invalid - | gst_audio::AudioChannelPosition::None => ebur128::Channel::Unused, - val => { - gst::debug!( - CAT, - imp: self, - "Unknown channel position {:?}, ignoring channel", - val - ); - ebur128::Channel::Unused - } - } - }) - .collect::>(); - ebur128 - .set_channel_map(&channel_map) - .map_err(|err| gst::loggable_error!(CAT, "Failed to set channel map: {}", err))?; - } else { - // Weight all channels equally if we have no channel map - let channel_map = std::iter::repeat(ebur128::Channel::Center) - .take(info.channels() as usize) - .collect::>(); - ebur128 - .set_channel_map(&channel_map) - .map_err(|err| gst::loggable_error!(CAT, "Failed to set channel map: {}", err))?; - } - - let interval_frames = settings - .interval - .mul_div_floor(info.rate() as u64, *gst::ClockTime::SECOND) - .unwrap(); - - *self.state.borrow_mut() = Some(State { - info, - ebur128, - num_frames: 0, - interval_frames, - interval_frames_remaining: interval_frames, - }); - - Ok(()) - } - fn stop(&self) -> Result<(), gst::ErrorMessage> { // Drop state let _ = self.state.borrow_mut().take(); @@ -587,6 +480,133 @@ impl BaseTransformImpl for EbuR128Level { } } +impl AudioFilterImpl for EbuR128Level { + fn allowed_caps() -> &'static gst::Caps { + static CAPS: Lazy = Lazy::new(|| { + gst_audio::AudioCapsBuilder::new() + .format_list([ + gst_audio::AUDIO_FORMAT_S16, + gst_audio::AUDIO_FORMAT_S32, + gst_audio::AUDIO_FORMAT_F32, + gst_audio::AUDIO_FORMAT_F64, + ]) + // Limit from ebur128 + .rate_range(1..2_822_400) + // Limit from ebur128 + .channels_range(1..64) + .layout_list([ + gst_audio::AudioLayout::Interleaved, + gst_audio::AudioLayout::NonInterleaved, + ]) + .build() + }); + + &CAPS + } + + fn setup(&self, info: &gst_audio::AudioInfo) -> Result<(), gst::LoggableError> { + gst::debug!(CAT, imp: self, "Configured for caps {:?}", info); + + let settings = *self.settings.lock().unwrap(); + + let mut ebur128 = ebur128::EbuR128::new(info.channels(), info.rate(), settings.mode.into()) + .map_err(|err| gst::loggable_error!(CAT, "Failed to create EBU R128: {}", err))?; + + // Map channel positions if we can to give correct weighting + if let Some(positions) = info.positions() { + let channel_map = positions + .iter() + .map(|p| { + match p { + gst_audio::AudioChannelPosition::Mono => ebur128::Channel::DualMono, + gst_audio::AudioChannelPosition::FrontLeft => ebur128::Channel::Left, + gst_audio::AudioChannelPosition::FrontRight => ebur128::Channel::Right, + gst_audio::AudioChannelPosition::FrontCenter => ebur128::Channel::Center, + gst_audio::AudioChannelPosition::Lfe1 + | gst_audio::AudioChannelPosition::Lfe2 => ebur128::Channel::Unused, + gst_audio::AudioChannelPosition::RearLeft => ebur128::Channel::Mp135, + gst_audio::AudioChannelPosition::RearRight => ebur128::Channel::Mm135, + gst_audio::AudioChannelPosition::FrontLeftOfCenter => { + ebur128::Channel::MpSC + } + gst_audio::AudioChannelPosition::FrontRightOfCenter => { + ebur128::Channel::MmSC + } + gst_audio::AudioChannelPosition::RearCenter => ebur128::Channel::Mp180, + gst_audio::AudioChannelPosition::SideLeft => ebur128::Channel::Mp090, + gst_audio::AudioChannelPosition::SideRight => ebur128::Channel::Mm090, + gst_audio::AudioChannelPosition::TopFrontLeft => ebur128::Channel::Up030, + gst_audio::AudioChannelPosition::TopFrontRight => ebur128::Channel::Um030, + gst_audio::AudioChannelPosition::TopFrontCenter => ebur128::Channel::Up000, + gst_audio::AudioChannelPosition::TopCenter => ebur128::Channel::Tp000, + gst_audio::AudioChannelPosition::TopRearLeft => ebur128::Channel::Up135, + gst_audio::AudioChannelPosition::TopRearRight => ebur128::Channel::Um135, + gst_audio::AudioChannelPosition::TopSideLeft => ebur128::Channel::Up090, + gst_audio::AudioChannelPosition::TopSideRight => ebur128::Channel::Um090, + gst_audio::AudioChannelPosition::TopRearCenter => ebur128::Channel::Up180, + gst_audio::AudioChannelPosition::BottomFrontCenter => { + ebur128::Channel::Bp000 + } + gst_audio::AudioChannelPosition::BottomFrontLeft => ebur128::Channel::Bp045, + gst_audio::AudioChannelPosition::BottomFrontRight => { + ebur128::Channel::Bm045 + } + gst_audio::AudioChannelPosition::WideLeft => { + ebur128::Channel::Mp135 // Mp110? + } + gst_audio::AudioChannelPosition::WideRight => { + ebur128::Channel::Mm135 // Mm110? + } + gst_audio::AudioChannelPosition::SurroundLeft => { + ebur128::Channel::Mp135 // Mp110? + } + gst_audio::AudioChannelPosition::SurroundRight => { + ebur128::Channel::Mm135 // Mm110? + } + gst_audio::AudioChannelPosition::Invalid + | gst_audio::AudioChannelPosition::None => ebur128::Channel::Unused, + val => { + gst::debug!( + CAT, + imp: self, + "Unknown channel position {:?}, ignoring channel", + val + ); + ebur128::Channel::Unused + } + } + }) + .collect::>(); + ebur128 + .set_channel_map(&channel_map) + .map_err(|err| gst::loggable_error!(CAT, "Failed to set channel map: {}", err))?; + } else { + // Weight all channels equally if we have no channel map + let channel_map = std::iter::repeat(ebur128::Channel::Center) + .take(info.channels() as usize) + .collect::>(); + ebur128 + .set_channel_map(&channel_map) + .map_err(|err| gst::loggable_error!(CAT, "Failed to set channel map: {}", err))?; + } + + let interval_frames = settings + .interval + .mul_div_floor(info.rate() as u64, *gst::ClockTime::SECOND) + .unwrap(); + + *self.state.borrow_mut() = Some(State { + info: info.clone(), + ebur128, + num_frames: 0, + interval_frames, + interval_frames_remaining: interval_frames, + }); + + Ok(()) + } +} + /// Helper struct to handle the different sample formats and layouts generically. enum Frames<'a> { S16(&'a [i16], usize), diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index 9253303b..42779a54 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -3804,6 +3804,7 @@ "description": "Removes noise from an audio stream", "hierarchy": [ "GstAudioRNNoise", + "GstAudioFilter", "GstBaseTransform", "GstElement", "GstObject", @@ -3847,6 +3848,7 @@ "description": "Measures different loudness metrics according to EBU R128", "hierarchy": [ "GstEbuR128Level", + "GstAudioFilter", "GstBaseTransform", "GstElement", "GstObject", @@ -4013,6 +4015,7 @@ "description": "Adds an echo or reverb effect to an audio stream", "hierarchy": [ "GstRsAudioEcho", + "GstAudioFilter", "GstBaseTransform", "GstElement", "GstObject",