Skip to main content

gstreamer_gl/subclass/
gl_filter.rs

1use ffi::{GstGLFilter, GstGLFilterClass, GstGLMemory};
2use glib::translate::*;
3use gst::{
4    Buffer, CAT_RUST, Caps, LoggableError, PadDirection, ffi::GstBuffer, result_from_gboolean,
5};
6
7use super::prelude::*;
8use crate::{GLFilter, GLMemory, ffi, prelude::*};
9
10#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub enum GLFilterMode {
12    Buffer,
13    Texture,
14}
15
16pub trait GLFilterImpl: GLBaseFilterImpl + ObjectSubclass<Type: IsA<GLFilter>> {
17    const MODE: GLFilterMode;
18    // rustdoc-stripper-ignore-next
19    /// Calls [`add_rgba_pad_templates`](ffi::gst_gl_filter_add_rgba_pad_templates)
20    /// in [`GLFilter::class_init`] if [`true`].
21    const ADD_RGBA_PAD_TEMPLATES: bool = true;
22
23    fn set_caps(&self, incaps: &Caps, outcaps: &Caps) -> Result<(), LoggableError> {
24        GLFilterImplExt::parent_set_caps(self, incaps, outcaps)
25    }
26
27    fn filter(&self, input: &Buffer, output: &Buffer) -> Result<(), LoggableError> {
28        self.parent_filter(input, output)
29    }
30
31    fn filter_texture(&self, input: &GLMemory, output: &GLMemory) -> Result<(), LoggableError> {
32        self.parent_filter_texture(input, output)
33    }
34
35    fn init_fbo(&self) -> Result<(), LoggableError> {
36        self.parent_init_fbo()
37    }
38
39    fn transform_internal_caps(
40        &self,
41        direction: PadDirection,
42        caps: &Caps,
43        filter_caps: Option<&Caps>,
44    ) -> Option<Caps> {
45        self.parent_transform_internal_caps(direction, caps, filter_caps)
46    }
47}
48
49pub trait GLFilterImplExt: GLFilterImpl {
50    fn parent_set_caps(&self, incaps: &Caps, outcaps: &Caps) -> Result<(), LoggableError> {
51        unsafe {
52            let data = Self::type_data();
53            let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass;
54
55            (*parent_class)
56                .set_caps
57                .map(|f| {
58                    result_from_gboolean!(
59                        f(
60                            self.obj().unsafe_cast_ref::<GLFilter>().to_glib_none().0,
61                            incaps.to_glib_none().0,
62                            outcaps.to_glib_none().0,
63                        ),
64                        CAT_RUST,
65                        "Parent function `set_caps` failed"
66                    )
67                })
68                .unwrap_or(Ok(()))
69        }
70    }
71
72    fn parent_filter(&self, input: &Buffer, output: &Buffer) -> Result<(), LoggableError> {
73        unsafe {
74            let data = Self::type_data();
75            let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass;
76
77            (*parent_class)
78                .filter
79                .map(|f| {
80                    result_from_gboolean!(
81                        f(
82                            self.obj().unsafe_cast_ref::<GLFilter>().to_glib_none().0,
83                            input.to_glib_none().0,
84                            output.to_glib_none().0,
85                        ),
86                        CAT_RUST,
87                        "Parent function `filter` failed"
88                    )
89                })
90                .unwrap_or(Ok(()))
91        }
92    }
93
94    fn parent_filter_texture(
95        &self,
96        input: &GLMemory,
97        output: &GLMemory,
98    ) -> Result<(), LoggableError> {
99        unsafe {
100            let data = Self::type_data();
101            let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass;
102
103            (*parent_class)
104                .filter_texture
105                .map(|f| {
106                    result_from_gboolean!(
107                        f(
108                            self.obj().unsafe_cast_ref::<GLFilter>().to_glib_none().0,
109                            input.to_glib_none().0,
110                            output.to_glib_none().0,
111                        ),
112                        CAT_RUST,
113                        "Parent function `filter_texture` failed"
114                    )
115                })
116                .unwrap_or(Ok(()))
117        }
118    }
119
120    fn parent_init_fbo(&self) -> Result<(), LoggableError> {
121        unsafe {
122            let data = Self::type_data();
123            let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass;
124
125            (*parent_class)
126                .init_fbo
127                .map(|f| {
128                    result_from_gboolean!(
129                        f(self.obj().unsafe_cast_ref::<GLFilter>().to_glib_none().0),
130                        CAT_RUST,
131                        "Parent function `init_fbo` failed"
132                    )
133                })
134                .unwrap_or(Ok(()))
135        }
136    }
137    fn parent_transform_internal_caps(
138        &self,
139        direction: PadDirection,
140        caps: &Caps,
141        filter_caps: Option<&Caps>,
142    ) -> Option<Caps> {
143        unsafe {
144            let data = Self::type_data();
145            let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass;
146
147            let f = (*parent_class)
148                .transform_internal_caps
149                .expect("Missing parent function `transform_internal_caps`");
150
151            from_glib_full(f(
152                self.obj().unsafe_cast_ref::<GLFilter>().to_glib_none().0,
153                direction.into_glib(),
154                caps.to_glib_none().0,
155                filter_caps.to_glib_none().0,
156            ))
157        }
158    }
159}
160
161impl<T: GLFilterImpl> GLFilterImplExt for T {}
162
163unsafe impl<T: GLFilterImpl> IsSubclassable<T> for GLFilter {
164    fn class_init(klass: &mut glib::Class<Self>) {
165        Self::parent_class_init::<T>(klass);
166        let klass = klass.as_mut();
167        klass.set_caps = Some(set_caps::<T>);
168        klass.init_fbo = Some(init_fbo::<T>);
169        klass.transform_internal_caps = Some(transform_internal_caps::<T>);
170
171        match <T as GLFilterImpl>::MODE {
172            GLFilterMode::Buffer => {
173                klass.filter = Some(filter::<T>);
174                klass.filter_texture = None;
175            }
176            GLFilterMode::Texture => {
177                klass.filter = None;
178                klass.filter_texture = Some(filter_texture::<T>);
179            }
180        }
181
182        if <T as GLFilterImpl>::ADD_RGBA_PAD_TEMPLATES {
183            unsafe { ffi::gst_gl_filter_add_rgba_pad_templates(klass) }
184        }
185    }
186}
187
188unsafe extern "C" fn filter<T: GLFilterImpl>(
189    ptr: *mut GstGLFilter,
190    input: *mut GstBuffer,
191    output: *mut GstBuffer,
192) -> glib::ffi::gboolean {
193    unsafe {
194        let instance = &*(ptr as *mut T::Instance);
195        let imp = instance.imp();
196
197        gst::panic_to_error!(imp, false, {
198            match imp.filter(&from_glib_borrow(input), &from_glib_borrow(output)) {
199                Ok(()) => true,
200                Err(err) => {
201                    err.log_with_imp(imp);
202                    false
203                }
204            }
205        })
206        .into_glib()
207    }
208}
209
210unsafe extern "C" fn filter_texture<T: GLFilterImpl>(
211    ptr: *mut GstGLFilter,
212    input: *mut GstGLMemory,
213    output: *mut GstGLMemory,
214) -> glib::ffi::gboolean {
215    unsafe {
216        let instance = &*(ptr as *mut T::Instance);
217        let imp = instance.imp();
218
219        gst::panic_to_error!(imp, false, {
220            match imp.filter_texture(&from_glib_borrow(input), &from_glib_borrow(output)) {
221                Ok(()) => true,
222                Err(err) => {
223                    err.log_with_imp(imp);
224                    false
225                }
226            }
227        })
228        .into_glib()
229    }
230}
231
232unsafe extern "C" fn init_fbo<T: GLFilterImpl>(ptr: *mut GstGLFilter) -> glib::ffi::gboolean {
233    unsafe {
234        let instance = &*(ptr as *mut T::Instance);
235        let imp = instance.imp();
236
237        gst::panic_to_error!(imp, false, {
238            match imp.init_fbo() {
239                Ok(()) => true,
240                Err(err) => {
241                    err.log_with_imp(imp);
242                    false
243                }
244            }
245        })
246        .into_glib()
247    }
248}
249
250unsafe extern "C" fn set_caps<T: GLFilterImpl>(
251    ptr: *mut GstGLFilter,
252    incaps: *mut gst::ffi::GstCaps,
253    outcaps: *mut gst::ffi::GstCaps,
254) -> glib::ffi::gboolean {
255    unsafe {
256        let instance = &*(ptr as *mut T::Instance);
257        let imp = instance.imp();
258
259        gst::panic_to_error!(imp, false, {
260            match GLFilterImpl::set_caps(imp, &from_glib_borrow(incaps), &from_glib_borrow(outcaps))
261            {
262                Ok(()) => true,
263                Err(err) => {
264                    err.log_with_imp(imp);
265                    false
266                }
267            }
268        })
269        .into_glib()
270    }
271}
272
273unsafe extern "C" fn transform_internal_caps<T: GLFilterImpl>(
274    ptr: *mut GstGLFilter,
275    direction: gst::ffi::GstPadDirection,
276    caps: *mut gst::ffi::GstCaps,
277    filter_caps: *mut gst::ffi::GstCaps,
278) -> *mut gst::ffi::GstCaps {
279    unsafe {
280        let instance = &*(ptr as *mut T::Instance);
281        let imp = instance.imp();
282
283        gst::panic_to_error!(imp, None, {
284            let filter_caps: Borrowed<Option<Caps>> = from_glib_borrow(filter_caps);
285
286            imp.transform_internal_caps(
287                from_glib(direction),
288                &from_glib_borrow(caps),
289                filter_caps.as_ref().as_ref(),
290            )
291        })
292        .map(|caps| caps.into_glib_ptr())
293        .unwrap_or(std::ptr::null_mut())
294    }
295}