gstreamer_video/subclass/
video_aggregator.rs
1use 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> {
17 self.parent_update_caps(caps)
18 }
19
20 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 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 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 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}