gstreamer_video/subclass/
video_filter.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4use gst_base::{prelude::*, subclass::prelude::*};
5
6use crate::{ffi, VideoFilter, VideoFrameExt, VideoFrameRef, VideoInfo};
7
8pub 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
42mod sealed {
43    pub trait Sealed {}
44    impl<T: super::VideoFilterImplExt> Sealed for T {}
45}
46
47pub 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
174impl<T: VideoFilterImpl> VideoFilterImplExt for T {}
175
176unsafe 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
202unsafe 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 = &*(ptr as *mut T::Instance);
210    let imp = instance.imp();
211
212    gst::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
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    let instance = &*(ptr as *mut T::Instance);
235    let imp = instance.imp();
236
237    gst::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
247unsafe 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 = &*(ptr as *mut T::Instance);
252    let imp = instance.imp();
253
254    gst::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}