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    /// Optional.
14    ///  Lets subclasses update the [`gst::Caps`][crate::gst::Caps] representing
15    ///  the src pad caps before usage. Return [`None`] to indicate failure.
16    fn update_caps(&self, caps: &gst::Caps) -> Result<gst::Caps, gst::LoggableError> {
17        self.parent_update_caps(caps)
18    }
19
20    /// Lets subclasses aggregate frames that are ready. Subclasses
21    ///  should iterate the GstElement.sinkpads and use the already
22    ///  mapped [`VideoFrame`][crate::VideoFrame] from [`VideoAggregatorPadExtManual::prepared_frame()`][crate::prelude::VideoAggregatorPadExtManual::prepared_frame()]
23    ///  or directly use the [`gst::Buffer`][crate::gst::Buffer] from [`VideoAggregatorPadExtManual::current_buffer()`][crate::prelude::VideoAggregatorPadExtManual::current_buffer()]
24    ///  if it needs to map the buffer in a special way. The result of the
25    ///  aggregation should land in `outbuffer`.
26    fn aggregate_frames(
27        &self,
28        token: &AggregateFramesToken,
29        outbuf: &mut gst::BufferRef,
30    ) -> Result<gst::FlowSuccess, gst::FlowError> {
31        self.parent_aggregate_frames(token, outbuf)
32    }
33
34    /// Optional.
35    ///  Lets subclasses provide a [`gst::Buffer`][crate::gst::Buffer] to be used as `outbuffer` of
36    ///  the `aggregate_frames` vmethod.
37    fn create_output_buffer(&self) -> Result<Option<gst::Buffer>, gst::FlowError> {
38        self.parent_create_output_buffer()
39    }
40
41    fn find_best_format(&self, downstream_caps: &gst::Caps) -> Option<(crate::VideoInfo, bool)> {
42        self.parent_find_best_format(downstream_caps)
43    }
44}
45
46pub trait VideoAggregatorImplExt: VideoAggregatorImpl {
47    fn parent_update_caps(&self, caps: &gst::Caps) -> Result<gst::Caps, gst::LoggableError> {
48        unsafe {
49            let data = Self::type_data();
50            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
51            let f = (*parent_class)
52                .update_caps
53                .expect("Missing parent function `update_caps`");
54
55            Option::<_>::from_glib_full(f(
56                self.obj()
57                    .unsafe_cast_ref::<VideoAggregator>()
58                    .to_glib_none()
59                    .0,
60                caps.as_mut_ptr(),
61            ))
62            .ok_or_else(|| {
63                gst::loggable_error!(gst::CAT_RUST, "Parent function `update_caps` failed")
64            })
65        }
66    }
67
68    fn parent_aggregate_frames(
69        &self,
70        token: &AggregateFramesToken,
71        outbuf: &mut gst::BufferRef,
72    ) -> Result<gst::FlowSuccess, gst::FlowError> {
73        assert_eq!(
74            self.obj().as_ptr() as *mut ffi::GstVideoAggregator,
75            token.0.as_ptr()
76        );
77
78        unsafe {
79            let data = Self::type_data();
80            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
81            let f = (*parent_class)
82                .aggregate_frames
83                .expect("Missing parent function `aggregate_frames`");
84
85            try_from_glib(f(
86                self.obj()
87                    .unsafe_cast_ref::<VideoAggregator>()
88                    .to_glib_none()
89                    .0,
90                // FIXME: Wrong pointer type
91                outbuf.as_mut_ptr() as *mut *mut gst::ffi::GstBuffer,
92            ))
93        }
94    }
95
96    fn parent_create_output_buffer(&self) -> Result<Option<gst::Buffer>, gst::FlowError> {
97        unsafe {
98            let data = Self::type_data();
99            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
100            let f = (*parent_class)
101                .create_output_buffer
102                .expect("Missing parent function `create_output_buffer`");
103
104            let mut buffer = ptr::null_mut();
105            try_from_glib(f(
106                self.obj()
107                    .unsafe_cast_ref::<VideoAggregator>()
108                    .to_glib_none()
109                    .0,
110                &mut buffer,
111            ))
112            .map(|_: gst::FlowSuccess| from_glib_full(buffer))
113        }
114    }
115
116    fn parent_find_best_format(
117        &self,
118        downstream_caps: &gst::Caps,
119    ) -> Option<(crate::VideoInfo, bool)> {
120        unsafe {
121            let data = Self::type_data();
122            let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoAggregatorClass;
123            (*parent_class).find_best_format.and_then(|f| {
124                let mut info = mem::MaybeUninit::uninit();
125                ffi::gst_video_info_init(info.as_mut_ptr());
126                let mut info = info.assume_init();
127
128                let mut at_least_one_alpha = glib::ffi::GFALSE;
129
130                f(
131                    self.obj()
132                        .unsafe_cast_ref::<VideoAggregator>()
133                        .to_glib_none()
134                        .0,
135                    downstream_caps.as_mut_ptr(),
136                    &mut info,
137                    &mut at_least_one_alpha,
138                );
139
140                if info.finfo.is_null() {
141                    None
142                } else {
143                    Some((
144                        from_glib_none(&info as *const ffi::GstVideoInfo),
145                        from_glib(at_least_one_alpha),
146                    ))
147                }
148            })
149        }
150    }
151}
152
153impl<T: VideoAggregatorImpl> VideoAggregatorImplExt for T {}
154
155unsafe impl<T: VideoAggregatorImpl> IsSubclassable<T> for VideoAggregator {
156    fn class_init(klass: &mut glib::Class<Self>) {
157        Self::parent_class_init::<T>(klass);
158
159        let klass = klass.as_mut();
160        klass.update_caps = Some(video_aggregator_update_caps::<T>);
161        klass.aggregate_frames = Some(video_aggregator_aggregate_frames::<T>);
162        klass.create_output_buffer = Some(video_aggregator_create_output_buffer::<T>);
163        klass.find_best_format = Some(video_aggregator_find_best_format::<T>);
164    }
165}
166
167unsafe extern "C" fn video_aggregator_update_caps<T: VideoAggregatorImpl>(
168    ptr: *mut ffi::GstVideoAggregator,
169    caps: *mut gst::ffi::GstCaps,
170) -> *mut gst::ffi::GstCaps {
171    unsafe {
172        let instance = &*(ptr as *mut T::Instance);
173        let imp = instance.imp();
174
175        gst::panic_to_error!(imp, ptr::null_mut(), {
176            match imp.update_caps(&from_glib_borrow(caps)) {
177                Ok(caps) => caps.into_glib_ptr(),
178                Err(err) => {
179                    err.log_with_imp(imp);
180                    ptr::null_mut()
181                }
182            }
183        })
184    }
185}
186
187unsafe extern "C" fn video_aggregator_aggregate_frames<T: VideoAggregatorImpl>(
188    ptr: *mut ffi::GstVideoAggregator,
189    outbuf: *mut *mut gst::ffi::GstBuffer,
190) -> gst::ffi::GstFlowReturn {
191    unsafe {
192        let instance = &*(ptr as *mut T::Instance);
193        let imp = instance.imp();
194
195        gst::panic_to_error!(imp, gst::FlowReturn::Error, {
196            let instance = imp.obj();
197            let instance = instance.unsafe_cast_ref::<VideoAggregator>();
198            let token = AggregateFramesToken(instance);
199
200            imp.aggregate_frames(
201                &token,
202                gst::BufferRef::from_mut_ptr(
203                    // Wrong pointer type
204                    outbuf as *mut gst::ffi::GstBuffer,
205                ),
206            )
207            .into()
208        })
209        .into_glib()
210    }
211}
212
213unsafe extern "C" fn video_aggregator_create_output_buffer<T: VideoAggregatorImpl>(
214    ptr: *mut ffi::GstVideoAggregator,
215    outbuf: *mut *mut gst::ffi::GstBuffer,
216) -> gst::ffi::GstFlowReturn {
217    unsafe {
218        let instance = &*(ptr as *mut T::Instance);
219        let imp = instance.imp();
220
221        gst::panic_to_error!(imp, gst::FlowReturn::Error, {
222            match imp.create_output_buffer() {
223                Ok(buffer) => {
224                    *outbuf = buffer.map(|b| b.into_glib_ptr()).unwrap_or(ptr::null_mut());
225                    Ok(gst::FlowSuccess::Ok)
226                }
227                Err(err) => {
228                    *outbuf = ptr::null_mut();
229                    Err(err)
230                }
231            }
232            .into()
233        })
234        .into_glib()
235    }
236}
237
238unsafe extern "C" fn video_aggregator_find_best_format<T: VideoAggregatorImpl>(
239    ptr: *mut ffi::GstVideoAggregator,
240    downstream_caps: *mut gst::ffi::GstCaps,
241    best_info: *mut ffi::GstVideoInfo,
242    at_least_one_alpha: *mut glib::ffi::gboolean,
243) {
244    unsafe {
245        let instance = &*(ptr as *mut T::Instance);
246        let imp = instance.imp();
247
248        gst::panic_to_error!(imp, (), {
249            match imp.find_best_format(&from_glib_borrow(downstream_caps)) {
250                None => (),
251                Some((info, alpha)) => {
252                    *best_info = *info.to_glib_none().0;
253                    *at_least_one_alpha = alpha.into_glib();
254                }
255            }
256        })
257    }
258}