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