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>(class:klass);
171 let klass: &mut GstGLFilterClass = 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: &::Instance = &*(ptr as *mut T::Instance);
199 let imp: &T = instance.imp();
200
201 gstbool::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: &::Instance = &*(ptr as *mut T::Instance);
219 let imp: &T = instance.imp();
220
221 gstbool::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: &::Instance = &*(ptr as *mut T::Instance);
235 let imp: &T = instance.imp();
236
237 gstbool::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: &::Instance = &*(ptr as *mut T::Instance);
255 let imp: &T = instance.imp();
256
257 gstbool::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: &::Instance = &*(ptr as *mut T::Instance);
276 let imp: &T = 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(default:std::ptr::null_mut())
289}
290