1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use glib::translate::*;
4 
5 use gst_base::prelude::*;
6 use gst_base::subclass::prelude::*;
7 
8 use crate::VideoFilter;
9 use crate::VideoFrameRef;
10 use crate::VideoInfo;
11 
12 pub trait VideoFilterImpl: VideoFilterImplExt + BaseTransformImpl {
set_info( &self, element: &Self::Type, incaps: &gst::Caps, in_info: &VideoInfo, outcaps: &gst::Caps, out_info: &VideoInfo, ) -> Result<(), gst::LoggableError>13     fn set_info(
14         &self,
15         element: &Self::Type,
16         incaps: &gst::Caps,
17         in_info: &VideoInfo,
18         outcaps: &gst::Caps,
19         out_info: &VideoInfo,
20     ) -> Result<(), gst::LoggableError> {
21         self.parent_set_info(element, incaps, in_info, outcaps, out_info)
22     }
23 
transform_frame( &self, element: &Self::Type, inframe: &VideoFrameRef<&gst::BufferRef>, outframe: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>24     fn transform_frame(
25         &self,
26         element: &Self::Type,
27         inframe: &VideoFrameRef<&gst::BufferRef>,
28         outframe: &mut VideoFrameRef<&mut gst::BufferRef>,
29     ) -> Result<gst::FlowSuccess, gst::FlowError> {
30         self.parent_transform_frame(element, inframe, outframe)
31     }
32 
transform_frame_ip( &self, element: &Self::Type, frame: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>33     fn transform_frame_ip(
34         &self,
35         element: &Self::Type,
36         frame: &mut VideoFrameRef<&mut gst::BufferRef>,
37     ) -> Result<gst::FlowSuccess, gst::FlowError> {
38         self.parent_transform_frame_ip(element, frame)
39     }
40 
transform_frame_ip_passthrough( &self, element: &Self::Type, frame: &VideoFrameRef<&gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>41     fn transform_frame_ip_passthrough(
42         &self,
43         element: &Self::Type,
44         frame: &VideoFrameRef<&gst::BufferRef>,
45     ) -> Result<gst::FlowSuccess, gst::FlowError> {
46         self.parent_transform_frame_ip_passthrough(element, frame)
47     }
48 }
49 
50 pub trait VideoFilterImplExt: ObjectSubclass {
parent_set_info( &self, element: &Self::Type, incaps: &gst::Caps, in_info: &VideoInfo, outcaps: &gst::Caps, out_info: &VideoInfo, ) -> Result<(), gst::LoggableError>51     fn parent_set_info(
52         &self,
53         element: &Self::Type,
54         incaps: &gst::Caps,
55         in_info: &VideoInfo,
56         outcaps: &gst::Caps,
57         out_info: &VideoInfo,
58     ) -> Result<(), gst::LoggableError>;
59 
parent_transform_frame( &self, element: &Self::Type, inframe: &VideoFrameRef<&gst::BufferRef>, outframe: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>60     fn parent_transform_frame(
61         &self,
62         element: &Self::Type,
63         inframe: &VideoFrameRef<&gst::BufferRef>,
64         outframe: &mut VideoFrameRef<&mut gst::BufferRef>,
65     ) -> Result<gst::FlowSuccess, gst::FlowError>;
66 
parent_transform_frame_ip( &self, element: &Self::Type, frame: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>67     fn parent_transform_frame_ip(
68         &self,
69         element: &Self::Type,
70         frame: &mut VideoFrameRef<&mut gst::BufferRef>,
71     ) -> Result<gst::FlowSuccess, gst::FlowError>;
72 
parent_transform_frame_ip_passthrough( &self, element: &Self::Type, frame: &VideoFrameRef<&gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>73     fn parent_transform_frame_ip_passthrough(
74         &self,
75         element: &Self::Type,
76         frame: &VideoFrameRef<&gst::BufferRef>,
77     ) -> Result<gst::FlowSuccess, gst::FlowError>;
78 }
79 
80 impl<T: VideoFilterImpl> VideoFilterImplExt for T {
parent_set_info( &self, element: &Self::Type, incaps: &gst::Caps, in_info: &VideoInfo, outcaps: &gst::Caps, out_info: &VideoInfo, ) -> Result<(), gst::LoggableError>81     fn parent_set_info(
82         &self,
83         element: &Self::Type,
84         incaps: &gst::Caps,
85         in_info: &VideoInfo,
86         outcaps: &gst::Caps,
87         out_info: &VideoInfo,
88     ) -> Result<(), gst::LoggableError> {
89         unsafe {
90             let data = Self::type_data();
91             let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoFilterClass;
92             (*parent_class)
93                 .set_info
94                 .map(|f| {
95                     gst::result_from_gboolean!(
96                         f(
97                             element.unsafe_cast_ref::<VideoFilter>().to_glib_none().0,
98                             incaps.to_glib_none().0,
99                             mut_override(in_info.to_glib_none().0),
100                             outcaps.to_glib_none().0,
101                             mut_override(out_info.to_glib_none().0),
102                         ),
103                         gst::CAT_RUST,
104                         "Parent function `set_info` failed"
105                     )
106                 })
107                 .unwrap_or(Ok(()))
108         }
109     }
110 
parent_transform_frame( &self, element: &Self::Type, inframe: &VideoFrameRef<&gst::BufferRef>, outframe: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>111     fn parent_transform_frame(
112         &self,
113         element: &Self::Type,
114         inframe: &VideoFrameRef<&gst::BufferRef>,
115         outframe: &mut VideoFrameRef<&mut gst::BufferRef>,
116     ) -> Result<gst::FlowSuccess, gst::FlowError> {
117         unsafe {
118             let data = Self::type_data();
119             let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoFilterClass;
120             (*parent_class)
121                 .transform_frame
122                 .map(|f| {
123                     try_from_glib(f(
124                         element.unsafe_cast_ref::<VideoFilter>().to_glib_none().0,
125                         mut_override(inframe.as_ptr()),
126                         outframe.as_mut_ptr(),
127                     ))
128                 })
129                 .unwrap_or_else(|| {
130                     if !element
131                         .unsafe_cast_ref::<gst_base::BaseTransform>()
132                         .is_in_place()
133                     {
134                         Err(gst::FlowError::NotSupported)
135                     } else {
136                         unreachable!(concat!(
137                             "parent `transform_frame` called ",
138                             "while transform element operates in-place"
139                         ));
140                     }
141                 })
142         }
143     }
144 
parent_transform_frame_ip( &self, element: &Self::Type, frame: &mut VideoFrameRef<&mut gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>145     fn parent_transform_frame_ip(
146         &self,
147         element: &Self::Type,
148         frame: &mut VideoFrameRef<&mut gst::BufferRef>,
149     ) -> Result<gst::FlowSuccess, gst::FlowError> {
150         unsafe {
151             let data = Self::type_data();
152             let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoFilterClass;
153             let f = (*parent_class).transform_frame_ip.unwrap_or_else(|| {
154                 if element
155                     .unsafe_cast_ref::<gst_base::BaseTransform>()
156                     .is_in_place()
157                 {
158                     panic!(concat!(
159                         "Missing parent function `transform_frame_ip`. Required because ",
160                         "transform element operates in-place"
161                     ));
162                 } else {
163                     unreachable!(concat!(
164                         "parent `transform_frame` called ",
165                         "while transform element doesn't operate in-place"
166                     ));
167                 }
168             });
169 
170             try_from_glib(f(
171                 element.unsafe_cast_ref::<VideoFilter>().to_glib_none().0,
172                 frame.as_mut_ptr(),
173             ))
174         }
175     }
176 
parent_transform_frame_ip_passthrough( &self, element: &Self::Type, frame: &VideoFrameRef<&gst::BufferRef>, ) -> Result<gst::FlowSuccess, gst::FlowError>177     fn parent_transform_frame_ip_passthrough(
178         &self,
179         element: &Self::Type,
180         frame: &VideoFrameRef<&gst::BufferRef>,
181     ) -> Result<gst::FlowSuccess, gst::FlowError> {
182         unsafe {
183             let data = Self::type_data();
184             let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoFilterClass;
185             let f = (*parent_class).transform_frame_ip.unwrap_or_else(|| {
186                 if element
187                     .unsafe_cast_ref::<gst_base::BaseTransform>()
188                     .is_in_place()
189                 {
190                     panic!(concat!(
191                         "Missing parent function `transform_frame_ip`. Required because ",
192                         "transform element operates in-place (passthrough mode)"
193                     ));
194                 } else {
195                     unreachable!(concat!(
196                         "parent `transform_frame_ip` called ",
197                         "while transform element doesn't operate in-place (passthrough mode)"
198                     ));
199                 }
200             });
201 
202             try_from_glib(f(
203                 element.unsafe_cast_ref::<VideoFilter>().to_glib_none().0,
204                 mut_override(frame.as_ptr()),
205             ))
206         }
207     }
208 }
209 
210 unsafe impl<T: VideoFilterImpl> IsSubclassable<T> for VideoFilter {
class_init(klass: &mut glib::Class<Self>)211     fn class_init(klass: &mut glib::Class<Self>) {
212         use gst_base::subclass::base_transform::BaseTransformMode;
213 
214         <gst_base::BaseTransform as IsSubclassable<T>>::class_init(klass);
215         let klass = klass.as_mut();
216         klass.set_info = Some(video_filter_set_info::<T>);
217 
218         match T::MODE {
219             BaseTransformMode::AlwaysInPlace => {
220                 klass.transform_frame = None;
221                 klass.transform_frame_ip = Some(video_filter_transform_frame_ip::<T>);
222             }
223             BaseTransformMode::NeverInPlace => {
224                 klass.transform_frame = Some(video_filter_transform_frame::<T>);
225                 klass.transform_frame_ip = None;
226             }
227             BaseTransformMode::Both => {
228                 klass.transform_frame = Some(video_filter_transform_frame::<T>);
229                 klass.transform_frame_ip = Some(video_filter_transform_frame_ip::<T>);
230             }
231         }
232     }
233 
instance_init(instance: &mut glib::subclass::InitializingObject<T>)234     fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) {
235         <gst_base::BaseTransform as IsSubclassable<T>>::instance_init(instance);
236     }
237 }
238 
video_filter_set_info<T: VideoFilterImpl>( ptr: *mut ffi::GstVideoFilter, incaps: *mut gst::ffi::GstCaps, in_info: *mut ffi::GstVideoInfo, outcaps: *mut gst::ffi::GstCaps, out_info: *mut ffi::GstVideoInfo, ) -> glib::ffi::gboolean239 unsafe extern "C" fn video_filter_set_info<T: VideoFilterImpl>(
240     ptr: *mut ffi::GstVideoFilter,
241     incaps: *mut gst::ffi::GstCaps,
242     in_info: *mut ffi::GstVideoInfo,
243     outcaps: *mut gst::ffi::GstCaps,
244     out_info: *mut ffi::GstVideoInfo,
245 ) -> glib::ffi::gboolean {
246     let instance = &*(ptr as *mut T::Instance);
247     let imp = instance.impl_();
248     let wrap: Borrowed<VideoFilter> = from_glib_borrow(ptr);
249 
250     gst::panic_to_error!(&wrap, imp.panicked(), false, {
251         match imp.set_info(
252             wrap.unsafe_cast_ref(),
253             &from_glib_borrow(incaps),
254             &from_glib_none(in_info),
255             &from_glib_borrow(outcaps),
256             &from_glib_none(out_info),
257         ) {
258             Ok(()) => true,
259             Err(err) => {
260                 err.log_with_object(&*wrap);
261                 false
262             }
263         }
264     })
265     .into_glib()
266 }
267 
video_filter_transform_frame<T: VideoFilterImpl>( ptr: *mut ffi::GstVideoFilter, inframe: *mut ffi::GstVideoFrame, outframe: *mut ffi::GstVideoFrame, ) -> gst::ffi::GstFlowReturn268 unsafe extern "C" fn video_filter_transform_frame<T: VideoFilterImpl>(
269     ptr: *mut ffi::GstVideoFilter,
270     inframe: *mut ffi::GstVideoFrame,
271     outframe: *mut ffi::GstVideoFrame,
272 ) -> gst::ffi::GstFlowReturn {
273     let instance = &*(ptr as *mut T::Instance);
274     let imp = instance.impl_();
275     let wrap: Borrowed<VideoFilter> = from_glib_borrow(ptr);
276 
277     gst::panic_to_error!(&wrap, imp.panicked(), gst::FlowReturn::Error, {
278         imp.transform_frame(
279             wrap.unsafe_cast_ref(),
280             &VideoFrameRef::from_glib_borrow(inframe),
281             &mut VideoFrameRef::from_glib_borrow_mut(outframe),
282         )
283         .into()
284     })
285     .into_glib()
286 }
287 
video_filter_transform_frame_ip<T: VideoFilterImpl>( ptr: *mut ffi::GstVideoFilter, frame: *mut ffi::GstVideoFrame, ) -> gst::ffi::GstFlowReturn288 unsafe extern "C" fn video_filter_transform_frame_ip<T: VideoFilterImpl>(
289     ptr: *mut ffi::GstVideoFilter,
290     frame: *mut ffi::GstVideoFrame,
291 ) -> gst::ffi::GstFlowReturn {
292     let instance = &*(ptr as *mut T::Instance);
293     let imp = instance.impl_();
294     let wrap: Borrowed<VideoFilter> = from_glib_borrow(ptr);
295 
296     gst::panic_to_error!(&wrap, imp.panicked(), gst::FlowReturn::Error, {
297         if from_glib(gst_base::ffi::gst_base_transform_is_passthrough(
298             ptr as *mut gst_base::ffi::GstBaseTransform,
299         )) {
300             imp.transform_frame_ip_passthrough(
301                 wrap.unsafe_cast_ref(),
302                 &VideoFrameRef::from_glib_borrow(frame),
303             )
304             .into()
305         } else {
306             imp.transform_frame_ip(
307                 wrap.unsafe_cast_ref(),
308                 &mut VideoFrameRef::from_glib_borrow_mut(frame),
309             )
310             .into()
311         }
312     })
313     .into_glib()
314 }
315