Skip to main content

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