pbutils: Add bindings for the AudioVisualizer base class

This commit is contained in:
Rafael Caricio 2022-08-30 16:13:45 +02:00
parent 44d899a0eb
commit 6163914605
Signed by: rafaelcaricio
GPG key ID: 3C86DBCE8E93C947
9 changed files with 545 additions and 0 deletions

View file

@ -19,6 +19,8 @@ libc = "0.2"
ffi = { package = "gstreamer-pbutils-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-video = { package = "gstreamer-video", path = "../gstreamer-video" }
gst-audio = { package = "gstreamer-audio", path = "../gstreamer-audio" }
thiserror = "1.0"
serde = { version = "1.0", optional = true }

View file

@ -16,6 +16,8 @@ external_libraries = [
]
generate = [
"GstPbutils.AudioVisualizer",
"GstPbutils.AudioVisualizerShader",
"GstPbutils.DiscovererResult",
"GstPbutils.PbUtilsCapsDescriptionFlags",
]

View file

@ -0,0 +1,72 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use crate::auto::AudioVisualizer;
use crate::subclass::AudioVisualizerSetupToken;
use glib::object::IsA;
use gst::prelude::*;
pub trait AudioVisualizerExtManual: 'static {
// rustdoc-stripper-ignore-next
/// Returns the number of samples per frame required before calling the render method
fn req_spf(&self) -> u32;
// rustdoc-stripper-ignore-next
/// Modify the request of samples per frame required to be present in buffer before calling
/// the render method
fn set_req_spf(&self, spf: u32, token: &AudioVisualizerSetupToken);
fn audio_info(&self) -> gst_audio::AudioInfo;
fn video_info(&self) -> gst_video::VideoInfo;
}
impl<O: IsA<AudioVisualizer> + ElementExt> AudioVisualizerExtManual for O {
fn req_spf(&self) -> u32 {
let sinkpad = self.static_pad("sink").expect("sink pad presence");
let _stream_lock = sinkpad.stream_lock();
let ptr = self.as_ptr() as *mut ffi::GstAudioVisualizer;
unsafe { (*ptr).req_spf }
}
fn set_req_spf(&self, spf: u32, token: &AudioVisualizerSetupToken) {
assert_eq!(
self.as_ptr() as *mut ffi::GstAudioVisualizer,
token.0.as_ptr() as *mut ffi::GstAudioVisualizer
);
let sinkpad = self.static_pad("sink").expect("sink pad presence");
let _stream_lock = sinkpad.stream_lock();
let mut ptr = self.as_ptr() as *mut ffi::GstAudioVisualizer;
unsafe {
(*ptr).req_spf = spf;
}
}
fn audio_info(&self) -> gst_audio::AudioInfo {
let sinkpad = self.static_pad("sink").expect("sink pad presence");
let _stream_lock = sinkpad.stream_lock();
let ptr = self.as_ptr() as *mut ffi::GstAudioVisualizer;
unsafe {
let info = &(*ptr).ainfo;
glib::translate::from_glib_none(glib::translate::mut_override(
info as *const gst_audio::ffi::GstAudioInfo,
))
}
}
fn video_info(&self) -> gst_video::VideoInfo {
let srcpad = self.static_pad("src").expect("src pad presence");
let _stream_lock = srcpad.stream_lock();
let ptr = self.as_ptr() as *mut ffi::GstAudioVisualizer;
unsafe {
let info = &(*ptr).vinfo;
glib::translate::from_glib_none(glib::translate::mut_override(
info as *const gst_video::ffi::GstVideoInfo,
))
}
}
}

View file

@ -0,0 +1,123 @@
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use crate::AudioVisualizerShader;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::connect_raw;
use glib::signal::SignalHandlerId;
use glib::translate::*;
use glib::StaticType;
use glib::ToValue;
use std::boxed::Box as Box_;
use std::mem::transmute;
glib::wrapper! {
#[doc(alias = "GstAudioVisualizer")]
pub struct AudioVisualizer(Object<ffi::GstAudioVisualizer, ffi::GstAudioVisualizerClass>) @extends gst::Element, gst::Object;
match fn {
type_ => || ffi::gst_audio_visualizer_get_type(),
}
}
impl AudioVisualizer {
pub const NONE: Option<&'static AudioVisualizer> = None;
}
unsafe impl Send for AudioVisualizer {}
unsafe impl Sync for AudioVisualizer {}
pub trait AudioVisualizerExt: 'static {
#[doc(alias = "shade-amount")]
fn shade_amount(&self) -> u32;
#[doc(alias = "shade-amount")]
fn set_shade_amount(&self, shade_amount: u32);
fn shader(&self) -> AudioVisualizerShader;
fn set_shader(&self, shader: AudioVisualizerShader);
#[doc(alias = "shade-amount")]
fn connect_shade_amount_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self,
f: F,
) -> SignalHandlerId;
#[doc(alias = "shader")]
fn connect_shader_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId;
}
impl<O: IsA<AudioVisualizer>> AudioVisualizerExt for O {
fn shade_amount(&self) -> u32 {
glib::ObjectExt::property(self.as_ref(), "shade-amount")
}
fn set_shade_amount(&self, shade_amount: u32) {
glib::ObjectExt::set_property(self.as_ref(), "shade-amount", &shade_amount)
}
fn shader(&self) -> AudioVisualizerShader {
glib::ObjectExt::property(self.as_ref(), "shader")
}
fn set_shader(&self, shader: AudioVisualizerShader) {
glib::ObjectExt::set_property(self.as_ref(), "shader", &shader)
}
fn connect_shade_amount_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self,
f: F,
) -> SignalHandlerId {
unsafe extern "C" fn notify_shade_amount_trampoline<
P: IsA<AudioVisualizer>,
F: Fn(&P) + Send + Sync + 'static,
>(
this: *mut ffi::GstAudioVisualizer,
_param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer,
) {
let f: &F = &*(f as *const F);
f(AudioVisualizer::from_glib_borrow(this).unsafe_cast_ref())
}
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(
self.as_ptr() as *mut _,
b"notify::shade-amount\0".as_ptr() as *const _,
Some(transmute::<_, unsafe extern "C" fn()>(
notify_shade_amount_trampoline::<Self, F> as *const (),
)),
Box_::into_raw(f),
)
}
}
fn connect_shader_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe extern "C" fn notify_shader_trampoline<
P: IsA<AudioVisualizer>,
F: Fn(&P) + Send + Sync + 'static,
>(
this: *mut ffi::GstAudioVisualizer,
_param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer,
) {
let f: &F = &*(f as *const F);
f(AudioVisualizer::from_glib_borrow(this).unsafe_cast_ref())
}
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(
self.as_ptr() as *mut _,
b"notify::shader\0".as_ptr() as *const _,
Some(transmute::<_, unsafe extern "C" fn()>(
notify_shader_trampoline::<Self, F> as *const (),
)),
Box_::into_raw(f),
)
}
}
}

View file

@ -9,6 +9,108 @@ use glib::value::ToValue;
use glib::StaticType;
use glib::Type;
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
#[non_exhaustive]
#[doc(alias = "GstAudioVisualizerShader")]
pub enum AudioVisualizerShader {
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_NONE")]
None,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE")]
Fade,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP")]
FadeAndMoveUp,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN")]
FadeAndMoveDown,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT")]
FadeAndMoveLeft,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT")]
FadeAndMoveRight,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT")]
FadeAndMoveHorizOut,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN")]
FadeAndMoveHorizIn,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT")]
FadeAndMoveVertOut,
#[doc(alias = "GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN")]
FadeAndMoveVertIn,
#[doc(hidden)]
__Unknown(i32),
}
#[doc(hidden)]
impl IntoGlib for AudioVisualizerShader {
type GlibType = ffi::GstAudioVisualizerShader;
fn into_glib(self) -> ffi::GstAudioVisualizerShader {
match self {
Self::None => ffi::GST_AUDIO_VISUALIZER_SHADER_NONE,
Self::Fade => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE,
Self::FadeAndMoveUp => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP,
Self::FadeAndMoveDown => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN,
Self::FadeAndMoveLeft => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT,
Self::FadeAndMoveRight => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT,
Self::FadeAndMoveHorizOut => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT,
Self::FadeAndMoveHorizIn => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN,
Self::FadeAndMoveVertOut => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT,
Self::FadeAndMoveVertIn => ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN,
Self::__Unknown(value) => value,
}
}
}
#[doc(hidden)]
impl FromGlib<ffi::GstAudioVisualizerShader> for AudioVisualizerShader {
unsafe fn from_glib(value: ffi::GstAudioVisualizerShader) -> Self {
skip_assert_initialized!();
match value {
ffi::GST_AUDIO_VISUALIZER_SHADER_NONE => Self::None,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE => Self::Fade,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_UP => Self::FadeAndMoveUp,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_DOWN => Self::FadeAndMoveDown,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_LEFT => Self::FadeAndMoveLeft,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_RIGHT => Self::FadeAndMoveRight,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_OUT => Self::FadeAndMoveHorizOut,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_HORIZ_IN => Self::FadeAndMoveHorizIn,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_OUT => Self::FadeAndMoveVertOut,
ffi::GST_AUDIO_VISUALIZER_SHADER_FADE_AND_MOVE_VERT_IN => Self::FadeAndMoveVertIn,
value => Self::__Unknown(value),
}
}
}
impl StaticType for AudioVisualizerShader {
fn static_type() -> Type {
unsafe { from_glib(ffi::gst_audio_visualizer_shader_get_type()) }
}
}
impl glib::value::ValueType for AudioVisualizerShader {
type Type = Self;
}
unsafe impl<'a> FromValue<'a> for AudioVisualizerShader {
type Checker = glib::value::GenericValueTypeChecker<Self>;
unsafe fn from_value(value: &'a glib::Value) -> Self {
skip_assert_initialized!();
from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
}
}
impl ToValue for AudioVisualizerShader {
fn to_value(&self) -> glib::Value {
let mut value = glib::Value::for_value_type::<Self>();
unsafe {
glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib());
}
value
}
fn value_type(&self) -> glib::Type {
Self::static_type()
}
}
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
#[non_exhaustive]
#[doc(alias = "GstDiscovererResult")]

View file

@ -3,6 +3,9 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
mod audio_visualizer;
pub use self::audio_visualizer::AudioVisualizer;
mod discoverer;
pub use self::discoverer::Discoverer;
@ -40,6 +43,7 @@ mod encoding_video_profile;
pub use self::encoding_video_profile::EncodingVideoProfile;
mod enums;
pub use self::enums::AudioVisualizerShader;
pub use self::enums::DiscovererResult;
mod flags;
@ -52,6 +56,7 @@ pub mod functions;
#[doc(hidden)]
pub mod traits {
pub use super::audio_visualizer::AudioVisualizerExt;
pub use super::discoverer_stream_info::DiscovererStreamInfoExt;
pub use super::encoding_profile::EncodingProfileExt;
}

View file

@ -57,12 +57,17 @@ pub mod encoding_profile;
pub mod functions;
pub use crate::functions::*;
pub mod subclass;
pub mod audio_visualizer;
// Re-export all the traits in a prelude module, so that applications
// can always "use gst_pbutils::prelude::*" without getting conflicts
pub mod prelude {
#[doc(hidden)]
pub use gst::prelude::*;
pub use crate::audio_visualizer::*;
pub use crate::auto::traits::*;
pub use crate::encoding_profile::{
EncodingProfileBuilder, EncodingProfileHasRestrictionGetter,

View file

@ -0,0 +1,226 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::prelude::*;
use glib::translate::*;
use gst::subclass::prelude::*;
use gst::{result_from_gboolean, LoggableError, CAT_RUST};
use crate::AudioVisualizer;
pub struct AudioVisualizerSetupToken<'a>(pub(crate) &'a AudioVisualizer);
pub trait AudioVisualizerImpl: AudioVisualizerImplExt + ElementImpl {
fn setup(
&self,
element: &Self::Type,
token: &AudioVisualizerSetupToken,
) -> Result<(), LoggableError> {
self.parent_setup(element, token)
}
fn render(
&self,
element: &Self::Type,
audio_buffer: &gst::BufferRef,
video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
) -> Result<(), LoggableError> {
self.parent_render(element, audio_buffer, video_frame)
}
fn decide_allocation(
&self,
element: &Self::Type,
query: &mut gst::query::Allocation,
) -> Result<(), gst::LoggableError> {
self.parent_decide_allocation(element, query)
}
}
pub trait AudioVisualizerImplExt: ObjectSubclass {
fn parent_setup(
&self,
element: &Self::Type,
token: &AudioVisualizerSetupToken,
) -> Result<(), LoggableError>;
fn parent_render(
&self,
element: &Self::Type,
audio_buffer: &gst::BufferRef,
video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
) -> Result<(), LoggableError>;
fn parent_decide_allocation(
&self,
element: &Self::Type,
query: &mut gst::query::Allocation,
) -> Result<(), gst::LoggableError>;
}
impl<T: AudioVisualizerImpl> AudioVisualizerImplExt for T {
fn parent_setup(
&self,
element: &Self::Type,
token: &AudioVisualizerSetupToken,
) -> Result<(), LoggableError> {
assert_eq!(
element.as_ptr() as *mut ffi::GstAudioVisualizer,
token.0.as_ptr() as *mut ffi::GstAudioVisualizer
);
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
(*parent_class)
.setup
.map(|f| {
result_from_gboolean!(
f(element
.unsafe_cast_ref::<AudioVisualizer>()
.to_glib_none()
.0,),
CAT_RUST,
"Parent function `setup` failed",
)
})
.unwrap_or(Ok(()))
}
}
fn parent_render(
&self,
element: &Self::Type,
audio_buffer: &gst::BufferRef,
video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
) -> Result<(), LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
(*parent_class)
.render
.map(|f| {
result_from_gboolean!(
f(
element
.unsafe_cast_ref::<AudioVisualizer>()
.to_glib_none()
.0,
audio_buffer.as_mut_ptr(),
video_frame.as_mut_ptr(),
),
CAT_RUST,
"Parent function `render` failed",
)
})
.unwrap_or(Ok(()))
}
}
fn parent_decide_allocation(
&self,
element: &Self::Type,
query: &mut gst::query::Allocation,
) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
(*parent_class)
.decide_allocation
.map(|f| {
gst::result_from_gboolean!(
f(
element
.unsafe_cast_ref::<AudioVisualizer>()
.to_glib_none()
.0,
query.as_mut_ptr(),
),
gst::CAT_RUST,
"Parent function `decide_allocation` failed",
)
})
.unwrap_or(Ok(()))
}
}
}
unsafe impl<T: AudioVisualizerImpl> IsSubclassable<T> for AudioVisualizer {
fn class_init(klass: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(klass);
let klass = klass.as_mut();
klass.setup = Some(audio_visualizer_setup::<T>);
klass.render = Some(audio_visualizer_render::<T>);
klass.decide_allocation = Some(audio_visualizer_decide_allocation::<T>);
}
}
unsafe extern "C" fn audio_visualizer_setup<T: AudioVisualizerImpl>(
ptr: *mut ffi::GstAudioVisualizer,
) -> gst::ffi::GstFlowReturn {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<AudioVisualizer> = from_glib_borrow(ptr);
gst::panic_to_error!(&wrap, imp.panicked(), false, {
let token = AudioVisualizerSetupToken(&*wrap);
match imp.setup(wrap.unsafe_cast_ref(), &token) {
Ok(()) => true,
Err(err) => {
err.log_with_object(&*wrap);
false
}
}
})
.into_glib()
}
unsafe extern "C" fn audio_visualizer_render<T: AudioVisualizerImpl>(
ptr: *mut ffi::GstAudioVisualizer,
audio_buffer: *mut gst::ffi::GstBuffer,
video_frame: *mut gst_video::ffi::GstVideoFrame,
) -> gst::ffi::GstFlowReturn {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<AudioVisualizer> = from_glib_borrow(ptr);
let buffer = gst::BufferRef::from_ptr(audio_buffer);
gst::panic_to_error!(&wrap, imp.panicked(), false, {
match imp.render(
wrap.unsafe_cast_ref(),
buffer,
&mut gst_video::VideoFrameRef::from_glib_borrow_mut(video_frame),
) {
Ok(()) => true,
Err(err) => {
err.log_with_object(&*wrap);
false
}
}
})
.into_glib()
}
unsafe extern "C" fn audio_visualizer_decide_allocation<T: AudioVisualizerImpl>(
ptr: *mut ffi::GstAudioVisualizer,
query: *mut gst::ffi::GstQuery,
) -> gst::ffi::GstFlowReturn {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let wrap: Borrowed<AudioVisualizer> = from_glib_borrow(ptr);
let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
gst::QueryViewMut::Allocation(allocation) => allocation,
_ => unreachable!(),
};
gst::panic_to_error!(&wrap, imp.panicked(), false, {
match imp.decide_allocation(wrap.unsafe_cast_ref(), query) {
Ok(()) => true,
Err(err) => {
err.log_with_object(&*wrap);
false
}
}
})
.into_glib()
}

View file

@ -0,0 +1,8 @@
// Take a look at the license at the top of the repository in the LICENSE file.
mod audio_visualizer;
pub use audio_visualizer::AudioVisualizerSetupToken;
pub mod prelude {
pub use super::audio_visualizer::{AudioVisualizerImpl, AudioVisualizerImplExt};
}