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