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: 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    let instance = &*(ptr as *mut T::Instance);
172    let imp = instance.imp();
173
174    gst::panic_to_error!(imp, ptr::null_mut(), {
175        match imp.update_caps(&from_glib_borrow(caps)) {
176            Ok(caps) => caps.into_glib_ptr(),
177            Err(err) => {
178                err.log_with_imp(imp);
179                ptr::null_mut()
180            }
181        }
182    })
183}
184
185unsafe extern "C" fn video_aggregator_aggregate_frames<T: VideoAggregatorImpl>(
186    ptr: *mut ffi::GstVideoAggregator,
187    outbuf: *mut *mut gst::ffi::GstBuffer,
188) -> gst::ffi::GstFlowReturn {
189    let instance = &*(ptr as *mut T::Instance);
190    let imp = instance.imp();
191
192    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
193        let instance = imp.obj();
194        let instance = instance.unsafe_cast_ref::<VideoAggregator>();
195        let token = AggregateFramesToken(instance);
196
197        imp.aggregate_frames(
198            &token,
199            gst::BufferRef::from_mut_ptr(
200                // Wrong pointer type
201                outbuf as *mut gst::ffi::GstBuffer,
202            ),
203        )
204        .into()
205    })
206    .into_glib()
207}
208
209unsafe extern "C" fn video_aggregator_create_output_buffer<T: VideoAggregatorImpl>(
210    ptr: *mut ffi::GstVideoAggregator,
211    outbuf: *mut *mut gst::ffi::GstBuffer,
212) -> gst::ffi::GstFlowReturn {
213    let instance = &*(ptr as *mut T::Instance);
214    let imp = instance.imp();
215
216    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
217        match imp.create_output_buffer() {
218            Ok(buffer) => {
219                *outbuf = buffer.map(|b| b.into_glib_ptr()).unwrap_or(ptr::null_mut());
220                Ok(gst::FlowSuccess::Ok)
221            }
222            Err(err) => {
223                *outbuf = ptr::null_mut();
224                Err(err)
225            }
226        }
227        .into()
228    })
229    .into_glib()
230}
231
232unsafe extern "C" fn video_aggregator_find_best_format<T: VideoAggregatorImpl>(
233    ptr: *mut ffi::GstVideoAggregator,
234    downstream_caps: *mut gst::ffi::GstCaps,
235    best_info: *mut ffi::GstVideoInfo,
236    at_least_one_alpha: *mut glib::ffi::gboolean,
237) {
238    let instance = &*(ptr as *mut T::Instance);
239    let imp = instance.imp();
240
241    gst::panic_to_error!(imp, (), {
242        match imp.find_best_format(&from_glib_borrow(downstream_caps)) {
243            None => (),
244            Some((info, alpha)) => {
245                *best_info = *info.to_glib_none().0;
246                *at_least_one_alpha = alpha.into_glib();
247            }
248        }
249    })
250}