gstreamer_video/subclass/
video_aggregator.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ptr};
4
5use glib::translate::*;
6use gst_base::{prelude::*, subclass::prelude::*};
7
8use crate::{ffi, VideoAggregator};
9
10pub struct AggregateFramesToken<'a>(pub(crate) &'a VideoAggregator);
11
12pub trait VideoAggregatorImpl: VideoAggregatorImplExt + AggregatorImpl {
13    fn update_caps(&self, caps: &gst::Caps) -> Result<gst::Caps, gst::LoggableError> {
14        self.parent_update_caps(caps)
15    }
16
17    fn aggregate_frames(
18        &self,
19        token: &AggregateFramesToken,
20        outbuf: &mut gst::BufferRef,
21    ) -> Result<gst::FlowSuccess, gst::FlowError> {
22        self.parent_aggregate_frames(token, outbuf)
23    }
24
25    fn create_output_buffer(&self) -> Result<Option<gst::Buffer>, gst::FlowError> {
26        self.parent_create_output_buffer()
27    }
28
29    fn find_best_format(&self, downstream_caps: &gst::Caps) -> Option<(crate::VideoInfo, bool)> {
30        self.parent_find_best_format(downstream_caps)
31    }
32}
33mod sealed {
34    pub trait Sealed {}
35    impl<T: super::VideoAggregatorImplExt> Sealed for T {}
36}
37
38pub trait VideoAggregatorImplExt: sealed::Sealed + ObjectSubclass {
39    fn parent_update_caps(&self, caps: &gst::Caps) -> Result<gst::Caps, gst::LoggableError> {
40        unsafe {
41            let data = Self::type_data();
42            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
43            let f = (*parent_class)
44                .update_caps
45                .expect("Missing parent function `update_caps`");
46
47            Option::<_>::from_glib_full(f(
48                self.obj()
49                    .unsafe_cast_ref::<VideoAggregator>()
50                    .to_glib_none()
51                    .0,
52                caps.as_mut_ptr(),
53            ))
54            .ok_or_else(|| {
55                gst::loggable_error!(gst::CAT_RUST, "Parent function `update_caps` failed")
56            })
57        }
58    }
59
60    fn parent_aggregate_frames(
61        &self,
62        token: &AggregateFramesToken,
63        outbuf: &mut gst::BufferRef,
64    ) -> Result<gst::FlowSuccess, gst::FlowError> {
65        assert_eq!(
66            self.obj().as_ptr() as *mut ffi::GstVideoAggregator,
67            token.0.as_ptr()
68        );
69
70        unsafe {
71            let data = Self::type_data();
72            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
73            let f = (*parent_class)
74                .aggregate_frames
75                .expect("Missing parent function `aggregate_frames`");
76
77            try_from_glib(f(
78                self.obj()
79                    .unsafe_cast_ref::<VideoAggregator>()
80                    .to_glib_none()
81                    .0,
82                // FIXME: Wrong pointer type
83                outbuf.as_mut_ptr() as *mut *mut gst::ffi::GstBuffer,
84            ))
85        }
86    }
87
88    fn parent_create_output_buffer(&self) -> Result<Option<gst::Buffer>, gst::FlowError> {
89        unsafe {
90            let data = Self::type_data();
91            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
92            let f = (*parent_class)
93                .create_output_buffer
94                .expect("Missing parent function `create_output_buffer`");
95
96            let mut buffer = ptr::null_mut();
97            try_from_glib(f(
98                self.obj()
99                    .unsafe_cast_ref::<VideoAggregator>()
100                    .to_glib_none()
101                    .0,
102                &mut buffer,
103            ))
104            .map(|_: gst::FlowSuccess| from_glib_full(buffer))
105        }
106    }
107
108    fn parent_find_best_format(
109        &self,
110        downstream_caps: &gst::Caps,
111    ) -> Option<(crate::VideoInfo, bool)> {
112        unsafe {
113            let data = Self::type_data();
114            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
115            (*parent_class).find_best_format.and_then(|f| {
116                let mut info = mem::MaybeUninit::uninit();
117                ffi::gst_video_info_init(info.as_mut_ptr());
118                let mut info = info.assume_init();
119
120                let mut at_least_one_alpha = glib::ffi::GFALSE;
121
122                f(
123                    self.obj()
124                        .unsafe_cast_ref::<VideoAggregator>()
125                        .to_glib_none()
126                        .0,
127                    downstream_caps.as_mut_ptr(),
128                    &mut info,
129                    &mut at_least_one_alpha,
130                );
131
132                if info.finfo.is_null() {
133                    None
134                } else {
135                    Some((
136                        from_glib_none(&info as *const ffi::GstVideoInfo),
137                        from_glib(at_least_one_alpha),
138                    ))
139                }
140            })
141        }
142    }
143}
144
145impl<T: VideoAggregatorImpl> VideoAggregatorImplExt for T {}
146
147unsafe impl<T: VideoAggregatorImpl> IsSubclassable<T> for VideoAggregator {
148    fn class_init(klass: &mut glib::Class<Self>) {
149        Self::parent_class_init::<T>(klass);
150
151        let klass = klass.as_mut();
152        klass.update_caps = Some(video_aggregator_update_caps::<T>);
153        klass.aggregate_frames = Some(video_aggregator_aggregate_frames::<T>);
154        klass.create_output_buffer = Some(video_aggregator_create_output_buffer::<T>);
155        klass.find_best_format = Some(video_aggregator_find_best_format::<T>);
156    }
157}
158
159unsafe extern "C" fn video_aggregator_update_caps<T: VideoAggregatorImpl>(
160    ptr: *mut ffi::GstVideoAggregator,
161    caps: *mut gst::ffi::GstCaps,
162) -> *mut gst::ffi::GstCaps {
163    let instance = &*(ptr as *mut T::Instance);
164    let imp = instance.imp();
165
166    gst::panic_to_error!(imp, ptr::null_mut(), {
167        match imp.update_caps(&from_glib_borrow(caps)) {
168            Ok(caps) => caps.into_glib_ptr(),
169            Err(err) => {
170                err.log_with_imp(imp);
171                ptr::null_mut()
172            }
173        }
174    })
175}
176
177unsafe extern "C" fn video_aggregator_aggregate_frames<T: VideoAggregatorImpl>(
178    ptr: *mut ffi::GstVideoAggregator,
179    outbuf: *mut *mut gst::ffi::GstBuffer,
180) -> gst::ffi::GstFlowReturn {
181    let instance = &*(ptr as *mut T::Instance);
182    let imp = instance.imp();
183
184    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
185        let instance = imp.obj();
186        let instance = instance.unsafe_cast_ref::<VideoAggregator>();
187        let token = AggregateFramesToken(instance);
188
189        imp.aggregate_frames(
190            &token,
191            gst::BufferRef::from_mut_ptr(
192                // Wrong pointer type
193                outbuf as *mut gst::ffi::GstBuffer,
194            ),
195        )
196        .into()
197    })
198    .into_glib()
199}
200
201unsafe extern "C" fn video_aggregator_create_output_buffer<T: VideoAggregatorImpl>(
202    ptr: *mut ffi::GstVideoAggregator,
203    outbuf: *mut *mut gst::ffi::GstBuffer,
204) -> gst::ffi::GstFlowReturn {
205    let instance = &*(ptr as *mut T::Instance);
206    let imp = instance.imp();
207
208    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
209        match imp.create_output_buffer() {
210            Ok(buffer) => {
211                *outbuf = buffer.map(|b| b.into_glib_ptr()).unwrap_or(ptr::null_mut());
212                Ok(gst::FlowSuccess::Ok)
213            }
214            Err(err) => {
215                *outbuf = ptr::null_mut();
216                Err(err)
217            }
218        }
219        .into()
220    })
221    .into_glib()
222}
223
224unsafe extern "C" fn video_aggregator_find_best_format<T: VideoAggregatorImpl>(
225    ptr: *mut ffi::GstVideoAggregator,
226    downstream_caps: *mut gst::ffi::GstCaps,
227    best_info: *mut ffi::GstVideoInfo,
228    at_least_one_alpha: *mut glib::ffi::gboolean,
229) {
230    let instance = &*(ptr as *mut T::Instance);
231    let imp = instance.imp();
232
233    gst::panic_to_error!(imp, (), {
234        match imp.find_best_format(&from_glib_borrow(downstream_caps)) {
235            None => (),
236            Some((info, alpha)) => {
237                *best_info = *info.to_glib_none().0;
238                *at_least_one_alpha = alpha.into_glib();
239            }
240        }
241    })
242}