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