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