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: 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    let instance = &*(ptr as *mut T::Instance);
194    let imp = instance.imp();
195
196    gst::panic_to_error!(imp, false, {
197        match imp.filter(&from_glib_borrow(input), &from_glib_borrow(output)) {
198            Ok(()) => true,
199            Err(err) => {
200                err.log_with_imp(imp);
201                false
202            }
203        }
204    })
205    .into_glib()
206}
207
208unsafe extern "C" fn filter_texture<T: GLFilterImpl>(
209    ptr: *mut GstGLFilter,
210    input: *mut GstGLMemory,
211    output: *mut GstGLMemory,
212) -> glib::ffi::gboolean {
213    let instance = &*(ptr as *mut T::Instance);
214    let imp = instance.imp();
215
216    gst::panic_to_error!(imp, false, {
217        match imp.filter_texture(&from_glib_borrow(input), &from_glib_borrow(output)) {
218            Ok(()) => true,
219            Err(err) => {
220                err.log_with_imp(imp);
221                false
222            }
223        }
224    })
225    .into_glib()
226}
227
228unsafe extern "C" fn init_fbo<T: GLFilterImpl>(ptr: *mut GstGLFilter) -> glib::ffi::gboolean {
229    let instance = &*(ptr as *mut T::Instance);
230    let imp = instance.imp();
231
232    gst::panic_to_error!(imp, false, {
233        match imp.init_fbo() {
234            Ok(()) => true,
235            Err(err) => {
236                err.log_with_imp(imp);
237                false
238            }
239        }
240    })
241    .into_glib()
242}
243
244unsafe extern "C" fn set_caps<T: GLFilterImpl>(
245    ptr: *mut GstGLFilter,
246    incaps: *mut gst::ffi::GstCaps,
247    outcaps: *mut gst::ffi::GstCaps,
248) -> glib::ffi::gboolean {
249    let instance = &*(ptr as *mut T::Instance);
250    let imp = instance.imp();
251
252    gst::panic_to_error!(imp, false, {
253        match GLFilterImpl::set_caps(imp, &from_glib_borrow(incaps), &from_glib_borrow(outcaps)) {
254            Ok(()) => true,
255            Err(err) => {
256                err.log_with_imp(imp);
257                false
258            }
259        }
260    })
261    .into_glib()
262}
263
264unsafe extern "C" fn transform_internal_caps<T: GLFilterImpl>(
265    ptr: *mut GstGLFilter,
266    direction: gst::ffi::GstPadDirection,
267    caps: *mut gst::ffi::GstCaps,
268    filter_caps: *mut gst::ffi::GstCaps,
269) -> *mut gst::ffi::GstCaps {
270    let instance = &*(ptr as *mut T::Instance);
271    let imp = instance.imp();
272
273    gst::panic_to_error!(imp, None, {
274        let filter_caps: Borrowed<Option<Caps>> = from_glib_borrow(filter_caps);
275
276        imp.transform_internal_caps(
277            from_glib(direction),
278            &from_glib_borrow(caps),
279            filter_caps.as_ref().as_ref(),
280        )
281    })
282    .map(|caps| caps.into_glib_ptr())
283    .unwrap_or(std::ptr::null_mut())
284}