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