mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-23 02:26:35 +00:00
audiofx: Derive from AudioFilter where possible
Saves a little bit of code. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1013>
This commit is contained in:
parent
3a8536b45e
commit
473e7d951b
4 changed files with 204 additions and 228 deletions
|
@ -9,7 +9,7 @@
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gst::subclass::prelude::*;
|
use gst::subclass::prelude::*;
|
||||||
use gst_base::subclass::prelude::*;
|
use gst_audio::subclass::prelude::*;
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::{cmp, u64};
|
use std::{cmp, u64};
|
||||||
|
@ -20,7 +20,7 @@ use num_traits::cast::{FromPrimitive, ToPrimitive};
|
||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
static _CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
|
||||||
gst::DebugCategory::new(
|
gst::DebugCategory::new(
|
||||||
"rsaudioecho",
|
"rsaudioecho",
|
||||||
gst::DebugColorFlags::empty(),
|
gst::DebugColorFlags::empty(),
|
||||||
|
@ -89,7 +89,7 @@ impl AudioEcho {
|
||||||
impl ObjectSubclass for AudioEcho {
|
impl ObjectSubclass for AudioEcho {
|
||||||
const NAME: &'static str = "GstRsAudioEcho";
|
const NAME: &'static str = "GstRsAudioEcho";
|
||||||
type Type = super::AudioEcho;
|
type Type = super::AudioEcho;
|
||||||
type ParentType = gst_base::BaseTransform;
|
type ParentType = gst_audio::AudioFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for AudioEcho {
|
impl ObjectImpl for AudioEcho {
|
||||||
|
@ -194,32 +194,6 @@ impl ElementImpl for AudioEcho {
|
||||||
|
|
||||||
Some(&*ELEMENT_METADATA)
|
Some(&*ELEMENT_METADATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pad_templates() -> &'static [gst::PadTemplate] {
|
|
||||||
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = 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 {
|
impl BaseTransformImpl for AudioEcho {
|
||||||
|
@ -252,28 +226,6 @@ impl BaseTransformImpl for AudioEcho {
|
||||||
Ok(gst::FlowSuccess::Ok)
|
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> {
|
fn stop(&self) -> Result<(), gst::ErrorMessage> {
|
||||||
// Drop state
|
// Drop state
|
||||||
let _ = self.state.lock().unwrap().take();
|
let _ = self.state.lock().unwrap().take();
|
||||||
|
@ -281,3 +233,28 @@ impl BaseTransformImpl for AudioEcho {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AudioFilterImpl for AudioEcho {
|
||||||
|
fn allowed_caps() -> &'static gst::Caps {
|
||||||
|
static CAPS: Lazy<gst::Caps> = 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ use std::sync::Mutex;
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gst::subclass::prelude::*;
|
use gst::subclass::prelude::*;
|
||||||
|
use gst_audio::subclass::prelude::*;
|
||||||
use gst_base::prelude::*;
|
use gst_base::prelude::*;
|
||||||
use gst_base::subclass::base_transform::BaseTransformImplExt;
|
use gst_base::subclass::base_transform::BaseTransformImplExt;
|
||||||
use gst_base::subclass::base_transform::GenerateOutputSuccess;
|
use gst_base::subclass::base_transform::GenerateOutputSuccess;
|
||||||
use gst_base::subclass::prelude::*;
|
|
||||||
|
|
||||||
use nnnoiseless::DenoiseState;
|
use nnnoiseless::DenoiseState;
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ impl AudioRNNoise {
|
||||||
impl ObjectSubclass for AudioRNNoise {
|
impl ObjectSubclass for AudioRNNoise {
|
||||||
const NAME: &'static str = "GstAudioRNNoise";
|
const NAME: &'static str = "GstAudioRNNoise";
|
||||||
type Type = super::AudioRNNoise;
|
type Type = super::AudioRNNoise;
|
||||||
type ParentType = gst_base::BaseTransform;
|
type ParentType = gst_audio::AudioFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for AudioRNNoise {
|
impl ObjectImpl for AudioRNNoise {
|
||||||
|
@ -282,34 +282,6 @@ impl ElementImpl for AudioRNNoise {
|
||||||
|
|
||||||
Some(&*ELEMENT_METADATA)
|
Some(&*ELEMENT_METADATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pad_templates() -> &'static [gst::PadTemplate] {
|
|
||||||
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = 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 {
|
impl BaseTransformImpl for AudioRNNoise {
|
||||||
|
@ -318,44 +290,6 @@ impl BaseTransformImpl for AudioRNNoise {
|
||||||
const PASSTHROUGH_ON_SAME_CAPS: bool = false;
|
const PASSTHROUGH_ON_SAME_CAPS: bool = false;
|
||||||
const TRANSFORM_IP_ON_PASSTHROUGH: 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<GenerateOutputSuccess, gst::FlowError> {
|
fn generate_output(&self) -> Result<GenerateOutputSuccess, gst::FlowError> {
|
||||||
// Check if there are enough data in the queued buffer and adapter,
|
// 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
|
// if it is not the case, just notify the parent class to not generate
|
||||||
|
@ -427,3 +361,45 @@ impl BaseTransformImpl for AudioRNNoise {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AudioFilterImpl for AudioRNNoise {
|
||||||
|
fn allowed_caps() -> &'static gst::Caps {
|
||||||
|
static CAPS: Lazy<gst::Caps> = 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gst::subclass::prelude::*;
|
use gst::subclass::prelude::*;
|
||||||
|
use gst_audio::subclass::prelude::*;
|
||||||
use gst_base::prelude::*;
|
use gst_base::prelude::*;
|
||||||
use gst_base::subclass::prelude::*;
|
|
||||||
|
|
||||||
use std::i32;
|
use std::i32;
|
||||||
use std::sync::atomic;
|
use std::sync::atomic;
|
||||||
|
@ -118,7 +118,7 @@ pub struct EbuR128Level {
|
||||||
impl ObjectSubclass for EbuR128Level {
|
impl ObjectSubclass for EbuR128Level {
|
||||||
const NAME: &'static str = "GstEbuR128Level";
|
const NAME: &'static str = "GstEbuR128Level";
|
||||||
type Type = super::EbuR128Level;
|
type Type = super::EbuR128Level;
|
||||||
type ParentType = gst_base::BaseTransform;
|
type ParentType = gst_audio::AudioFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for EbuR128Level {
|
impl ObjectImpl for EbuR128Level {
|
||||||
|
@ -283,113 +283,6 @@ impl BaseTransformImpl for EbuR128Level {
|
||||||
const PASSTHROUGH_ON_SAME_CAPS: bool = true;
|
const PASSTHROUGH_ON_SAME_CAPS: bool = true;
|
||||||
const TRANSFORM_IP_ON_PASSTHROUGH: 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::<Vec<_>>();
|
|
||||||
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::<Vec<_>>();
|
|
||||||
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> {
|
fn stop(&self) -> Result<(), gst::ErrorMessage> {
|
||||||
// Drop state
|
// Drop state
|
||||||
let _ = self.state.borrow_mut().take();
|
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<gst::Caps> = 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::<Vec<_>>();
|
||||||
|
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::<Vec<_>>();
|
||||||
|
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.
|
/// Helper struct to handle the different sample formats and layouts generically.
|
||||||
enum Frames<'a> {
|
enum Frames<'a> {
|
||||||
S16(&'a [i16], usize),
|
S16(&'a [i16], usize),
|
||||||
|
|
|
@ -3804,6 +3804,7 @@
|
||||||
"description": "Removes noise from an audio stream",
|
"description": "Removes noise from an audio stream",
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"GstAudioRNNoise",
|
"GstAudioRNNoise",
|
||||||
|
"GstAudioFilter",
|
||||||
"GstBaseTransform",
|
"GstBaseTransform",
|
||||||
"GstElement",
|
"GstElement",
|
||||||
"GstObject",
|
"GstObject",
|
||||||
|
@ -3847,6 +3848,7 @@
|
||||||
"description": "Measures different loudness metrics according to EBU R128",
|
"description": "Measures different loudness metrics according to EBU R128",
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"GstEbuR128Level",
|
"GstEbuR128Level",
|
||||||
|
"GstAudioFilter",
|
||||||
"GstBaseTransform",
|
"GstBaseTransform",
|
||||||
"GstElement",
|
"GstElement",
|
||||||
"GstObject",
|
"GstObject",
|
||||||
|
@ -4013,6 +4015,7 @@
|
||||||
"description": "Adds an echo or reverb effect to an audio stream",
|
"description": "Adds an echo or reverb effect to an audio stream",
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"GstRsAudioEcho",
|
"GstRsAudioEcho",
|
||||||
|
"GstAudioFilter",
|
||||||
"GstBaseTransform",
|
"GstBaseTransform",
|
||||||
"GstElement",
|
"GstElement",
|
||||||
"GstObject",
|
"GstObject",
|
||||||
|
|
Loading…
Reference in a new issue