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