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