gstreamer_gl/subclass/
gl_filter.rs

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