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 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}