gstreamer_pbutils/subclass/
audio_visualizer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, translate::*};
4use gst::{result_from_gboolean, subclass::prelude::*, LoggableError, CAT_RUST};
5
6use crate::{ffi, AudioVisualizer};
7
8pub struct AudioVisualizerSetupToken<'a>(pub(crate) &'a AudioVisualizer);
9
10pub trait AudioVisualizerImpl: AudioVisualizerImplExt + ElementImpl {
11    fn setup(&self, token: &AudioVisualizerSetupToken) -> Result<(), LoggableError> {
12        self.parent_setup(token)
13    }
14
15    fn render(
16        &self,
17        audio_buffer: &gst::BufferRef,
18        video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
19    ) -> Result<(), LoggableError> {
20        self.parent_render(audio_buffer, video_frame)
21    }
22
23    fn decide_allocation(
24        &self,
25        query: &mut gst::query::Allocation,
26    ) -> Result<(), gst::LoggableError> {
27        self.parent_decide_allocation(query)
28    }
29}
30
31mod sealed {
32    pub trait Sealed {}
33    impl<T: super::AudioVisualizerImplExt> Sealed for T {}
34}
35
36pub trait AudioVisualizerImplExt: sealed::Sealed + ObjectSubclass {
37    fn parent_setup(&self, token: &AudioVisualizerSetupToken) -> Result<(), LoggableError> {
38        assert_eq!(
39            self.obj().as_ptr() as *mut ffi::GstAudioVisualizer,
40            token.0.as_ptr()
41        );
42
43        unsafe {
44            let data = Self::type_data();
45            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
46            (*parent_class)
47                .setup
48                .map(|f| {
49                    result_from_gboolean!(
50                        f(self
51                            .obj()
52                            .unsafe_cast_ref::<AudioVisualizer>()
53                            .to_glib_none()
54                            .0,),
55                        CAT_RUST,
56                        "Parent function `setup` failed",
57                    )
58                })
59                .unwrap_or(Ok(()))
60        }
61    }
62
63    fn parent_render(
64        &self,
65        audio_buffer: &gst::BufferRef,
66        video_frame: &mut gst_video::VideoFrameRef<&mut gst::BufferRef>,
67    ) -> Result<(), LoggableError> {
68        unsafe {
69            let data = Self::type_data();
70            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
71            (*parent_class)
72                .render
73                .map(|f| {
74                    result_from_gboolean!(
75                        f(
76                            self.obj()
77                                .unsafe_cast_ref::<AudioVisualizer>()
78                                .to_glib_none()
79                                .0,
80                            audio_buffer.as_mut_ptr(),
81                            video_frame.as_mut_ptr(),
82                        ),
83                        CAT_RUST,
84                        "Parent function `render` failed",
85                    )
86                })
87                .unwrap_or(Ok(()))
88        }
89    }
90
91    fn parent_decide_allocation(
92        &self,
93        query: &mut gst::query::Allocation,
94    ) -> Result<(), gst::LoggableError> {
95        unsafe {
96            let data = Self::type_data();
97            let parent_class = data.as_ref().parent_class() as *mut ffi::GstAudioVisualizerClass;
98            (*parent_class)
99                .decide_allocation
100                .map(|f| {
101                    gst::result_from_gboolean!(
102                        f(
103                            self.obj()
104                                .unsafe_cast_ref::<AudioVisualizer>()
105                                .to_glib_none()
106                                .0,
107                            query.as_mut_ptr(),
108                        ),
109                        gst::CAT_RUST,
110                        "Parent function `decide_allocation` failed",
111                    )
112                })
113                .unwrap_or(Ok(()))
114        }
115    }
116}
117
118impl<T: AudioVisualizerImpl> AudioVisualizerImplExt for T {}
119
120unsafe impl<T: AudioVisualizerImpl> IsSubclassable<T> for AudioVisualizer {
121    fn class_init(klass: &mut glib::Class<Self>) {
122        Self::parent_class_init::<T>(klass);
123        let klass = klass.as_mut();
124        klass.setup = Some(audio_visualizer_setup::<T>);
125        klass.render = Some(audio_visualizer_render::<T>);
126        klass.decide_allocation = Some(audio_visualizer_decide_allocation::<T>);
127    }
128}
129
130unsafe extern "C" fn audio_visualizer_setup<T: AudioVisualizerImpl>(
131    ptr: *mut ffi::GstAudioVisualizer,
132) -> gst::ffi::GstFlowReturn {
133    let instance = &*(ptr as *mut T::Instance);
134    let imp = instance.imp();
135
136    gst::panic_to_error!(imp, false, {
137        let instance = imp.obj();
138        let instance = instance.unsafe_cast_ref::<AudioVisualizer>();
139        let token = AudioVisualizerSetupToken(instance);
140
141        match imp.setup(&token) {
142            Ok(()) => true,
143            Err(err) => {
144                err.log_with_imp(imp);
145                false
146            }
147        }
148    })
149    .into_glib()
150}
151
152unsafe extern "C" fn audio_visualizer_render<T: AudioVisualizerImpl>(
153    ptr: *mut ffi::GstAudioVisualizer,
154    audio_buffer: *mut gst::ffi::GstBuffer,
155    video_frame: *mut gst_video::ffi::GstVideoFrame,
156) -> gst::ffi::GstFlowReturn {
157    let instance = &*(ptr as *mut T::Instance);
158    let imp = instance.imp();
159    let buffer = gst::BufferRef::from_ptr(audio_buffer);
160
161    gst::panic_to_error!(imp, false, {
162        match imp.render(
163            buffer,
164            &mut gst_video::VideoFrameRef::from_glib_borrow_mut(video_frame),
165        ) {
166            Ok(()) => true,
167            Err(err) => {
168                err.log_with_imp(imp);
169                false
170            }
171        }
172    })
173    .into_glib()
174}
175
176unsafe extern "C" fn audio_visualizer_decide_allocation<T: AudioVisualizerImpl>(
177    ptr: *mut ffi::GstAudioVisualizer,
178    query: *mut gst::ffi::GstQuery,
179) -> gst::ffi::GstFlowReturn {
180    let instance = &*(ptr as *mut T::Instance);
181    let imp = instance.imp();
182    let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
183        gst::QueryViewMut::Allocation(allocation) => allocation,
184        _ => unreachable!(),
185    };
186
187    gst::panic_to_error!(imp, false, {
188        match imp.decide_allocation(query) {
189            Ok(()) => true,
190            Err(err) => {
191                err.log_with_imp(imp);
192                false
193            }
194        }
195    })
196    .into_glib()
197}