use glib::{prelude::*, translate::*};
use gst::{result_from_gboolean, subclass::prelude::*, LoggableError, CAT_RUST};
use crate::{ffi, AudioVisualizer};
pub struct AudioVisualizerSetupToken<'a>(pub(crate) &'a AudioVisualizer);
pub trait AudioVisualizerImpl: AudioVisualizerImplExt + ElementImpl {
fn setup(&self, token: &AudioVisualizerSetupToken) -> Result<(), LoggableError> {
self.parent_setup(token)
}
fn render(
&self,
audio_buffer: &gst::BufferRef,
video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
) -> Result<(), LoggableError> {
self.parent_render(audio_buffer, video_frame)
}
fn decide_allocation(
&self,
query: &mut gst::query::Allocation,
) -> Result<(), gst::LoggableError> {
self.parent_decide_allocation(query)
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::AudioVisualizerImplExt> Sealed for T {}
}
pub trait AudioVisualizerImplExt: sealed::Sealed + ObjectSubclass {
fn parent_setup(&self, token: &AudioVisualizerSetupToken) -> Result<(), LoggableError> {
assert_eq!(
self.obj().as_ptr() as *mut ffi::GstAudioVisualizer,
token.0.as_ptr()
);
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(self
.obj()
.unsafe_cast_ref::<AudioVisualizer>()
.to_glib_none()
.0,),
CAT_RUST,
"Parent function `setup` failed",
)
})
.unwrap_or(Ok(()))
}
}
fn parent_render(
&self,
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(
self.obj()
.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,
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(
self.obj()
.unsafe_cast_ref::<AudioVisualizer>()
.to_glib_none()
.0,
query.as_mut_ptr(),
),
gst::CAT_RUST,
"Parent function `decide_allocation` failed",
)
})
.unwrap_or(Ok(()))
}
}
}
impl<T: AudioVisualizerImpl> AudioVisualizerImplExt for T {}
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();
gst::panic_to_error!(imp, false, {
let instance = imp.obj();
let instance = instance.unsafe_cast_ref::<AudioVisualizer>();
let token = AudioVisualizerSetupToken(instance);
match imp.setup(&token) {
Ok(()) => true,
Err(err) => {
err.log_with_imp(imp);
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 buffer = gst::BufferRef::from_ptr(audio_buffer);
gst::panic_to_error!(imp, false, {
match imp.render(
buffer,
&mut gst_video::VideoFrameRef::from_glib_borrow_mut(video_frame),
) {
Ok(()) => true,
Err(err) => {
err.log_with_imp(imp);
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 query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
gst::QueryViewMut::Allocation(allocation) => allocation,
_ => unreachable!(),
};
gst::panic_to_error!(imp, false, {
match imp.decide_allocation(query) {
Ok(()) => true,
Err(err) => {
err.log_with_imp(imp);
false
}
}
})
.into_glib()
}