1use std::mem;
4
5use glib::translate::*;
6use gst::subclass::prelude::*;
7
8use crate::{BaseParse, BaseParseFrame, ffi, prelude::*};
9
10pub trait BaseParseImpl: ElementImpl + ObjectSubclass<Type: IsA<BaseParse>> {
11 fn start(&self) -> Result<(), gst::ErrorMessage> {
15 self.parent_start()
16 }
17
18 fn stop(&self) -> Result<(), gst::ErrorMessage> {
22 self.parent_stop()
23 }
24
25 fn sink_caps(&self, filter: Option<&gst::Caps>) -> gst::Caps {
28 self.parent_sink_caps(filter)
29 }
30
31 fn set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
34 self.parent_set_sink_caps(caps)
35 }
36
37 fn handle_frame(
51 &self,
52 frame: BaseParseFrame,
53 ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
54 self.parent_handle_frame(frame)
55 }
56
57 fn convert(
60 &self,
61 src_val: impl gst::format::FormattedValue,
62 dest_format: gst::Format,
63 ) -> Option<gst::GenericFormattedValue> {
64 self.parent_convert(src_val, dest_format)
65 }
66}
67
68pub trait BaseParseImplExt: BaseParseImpl {
69 fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
70 unsafe {
71 let data = Self::type_data();
72 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
73 (*parent_class)
74 .start
75 .map(|f| {
76 if from_glib(f(self
77 .obj()
78 .unsafe_cast_ref::<BaseParse>()
79 .to_glib_none()
80 .0))
81 {
82 Ok(())
83 } else {
84 Err(gst::error_msg!(
85 gst::CoreError::StateChange,
86 ["Parent function `start` failed"]
87 ))
88 }
89 })
90 .unwrap_or(Ok(()))
91 }
92 }
93
94 fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
95 unsafe {
96 let data = Self::type_data();
97 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
98 (*parent_class)
99 .stop
100 .map(|f| {
101 if from_glib(f(self
102 .obj()
103 .unsafe_cast_ref::<BaseParse>()
104 .to_glib_none()
105 .0))
106 {
107 Ok(())
108 } else {
109 Err(gst::error_msg!(
110 gst::CoreError::StateChange,
111 ["Parent function `stop` failed"]
112 ))
113 }
114 })
115 .unwrap_or(Ok(()))
116 }
117 }
118
119 fn parent_sink_caps(&self, filter: Option<&gst::Caps>) -> gst::Caps {
120 unsafe {
121 let data = Self::type_data();
122 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
123 if let Some(f) = (*parent_class).get_sink_caps {
124 from_glib_full(f(
125 self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
126 filter.to_glib_none().0,
127 ))
128 } else {
129 let templ_caps = self.obj().sink_pad().pad_template_caps();
130 if let Some(filter) = filter {
131 filter.intersect_with_mode(&templ_caps, gst::CapsIntersectMode::First)
132 } else {
133 templ_caps
134 }
135 }
136 }
137 }
138
139 fn parent_set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
140 unsafe {
141 let data = Self::type_data();
142 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
143 (*parent_class)
144 .set_sink_caps
145 .map(|f| {
146 gst::result_from_gboolean!(
147 f(
148 self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
149 caps.to_glib_none().0,
150 ),
151 gst::CAT_RUST,
152 "Parent function `set_sink_caps` failed",
153 )
154 })
155 .unwrap_or(Ok(()))
156 }
157 }
158
159 fn parent_handle_frame(
160 &self,
161 frame: BaseParseFrame,
162 ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
163 unsafe {
164 let data = Self::type_data();
165 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
166 let mut skipsize = 0;
167 (*parent_class)
168 .handle_frame
169 .map(|f| {
170 let res = try_from_glib(f(
171 self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
172 frame.to_glib_none().0,
173 &mut skipsize,
174 ));
175 (res.unwrap(), skipsize as u32)
176 })
177 .ok_or(gst::FlowError::Error)
178 }
179 }
180
181 fn parent_convert(
182 &self,
183 src_val: impl gst::format::FormattedValue,
184 dest_format: gst::Format,
185 ) -> Option<gst::GenericFormattedValue> {
186 unsafe {
187 let data = Self::type_data();
188 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
189 let res = (*parent_class).convert.map(|f| {
190 let mut dest_val = mem::MaybeUninit::uninit();
191
192 let res = from_glib(f(
193 self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
194 src_val.format().into_glib(),
195 src_val.into_raw_value(),
196 dest_format.into_glib(),
197 dest_val.as_mut_ptr(),
198 ));
199 (res, dest_val)
200 });
201
202 match res {
203 Some((true, dest_val)) => Some(gst::GenericFormattedValue::new(
204 dest_format,
205 dest_val.assume_init(),
206 )),
207 _ => None,
208 }
209 }
210 }
211}
212
213impl<T: BaseParseImpl> BaseParseImplExt for T {}
214
215unsafe impl<T: BaseParseImpl> IsSubclassable<T> for BaseParse {
216 fn class_init(klass: &mut glib::Class<Self>) {
217 Self::parent_class_init::<T>(klass);
218 let klass = klass.as_mut();
219 klass.start = Some(base_parse_start::<T>);
220 klass.stop = Some(base_parse_stop::<T>);
221 klass.set_sink_caps = Some(base_parse_set_sink_caps::<T>);
222 klass.get_sink_caps = Some(base_parse_get_sink_caps::<T>);
223 klass.handle_frame = Some(base_parse_handle_frame::<T>);
224 klass.convert = Some(base_parse_convert::<T>);
225 }
226}
227
228unsafe extern "C" fn base_parse_start<T: BaseParseImpl>(
229 ptr: *mut ffi::GstBaseParse,
230) -> glib::ffi::gboolean {
231 unsafe {
232 let instance = &*(ptr as *mut T::Instance);
233 let imp = instance.imp();
234
235 gst::panic_to_error!(imp, false, {
236 match imp.start() {
237 Ok(()) => true,
238 Err(err) => {
239 imp.post_error_message(err);
240 false
241 }
242 }
243 })
244 .into_glib()
245 }
246}
247
248unsafe extern "C" fn base_parse_stop<T: BaseParseImpl>(
249 ptr: *mut ffi::GstBaseParse,
250) -> glib::ffi::gboolean {
251 unsafe {
252 let instance = &*(ptr as *mut T::Instance);
253 let imp = instance.imp();
254
255 gst::panic_to_error!(imp, false, {
256 match imp.stop() {
257 Ok(()) => true,
258 Err(err) => {
259 imp.post_error_message(err);
260 false
261 }
262 }
263 })
264 .into_glib()
265 }
266}
267
268unsafe extern "C" fn base_parse_set_sink_caps<T: BaseParseImpl>(
269 ptr: *mut ffi::GstBaseParse,
270 caps: *mut gst::ffi::GstCaps,
271) -> glib::ffi::gboolean {
272 unsafe {
273 let instance = &*(ptr as *mut T::Instance);
274 let imp = instance.imp();
275 let caps: Borrowed<gst::Caps> = from_glib_borrow(caps);
276
277 gst::panic_to_error!(imp, false, {
278 match imp.set_sink_caps(&caps) {
279 Ok(()) => true,
280 Err(err) => {
281 err.log_with_imp(imp);
282 false
283 }
284 }
285 })
286 .into_glib()
287 }
288}
289
290unsafe extern "C" fn base_parse_get_sink_caps<T: BaseParseImpl>(
291 ptr: *mut ffi::GstBaseParse,
292 filter: *mut gst::ffi::GstCaps,
293) -> *mut gst::ffi::GstCaps {
294 unsafe {
295 let instance = &*(ptr as *mut T::Instance);
296 let imp = instance.imp();
297 let filter: Borrowed<Option<gst::Caps>> = from_glib_borrow(filter);
298
299 gst::panic_to_error!(imp, gst::Caps::new_empty(), {
300 imp.sink_caps(filter.as_ref().as_ref())
301 })
302 .into_glib_ptr()
303 }
304}
305
306unsafe extern "C" fn base_parse_handle_frame<T: BaseParseImpl>(
307 ptr: *mut ffi::GstBaseParse,
308 frame: *mut ffi::GstBaseParseFrame,
309 skipsize: *mut i32,
310) -> gst::ffi::GstFlowReturn {
311 unsafe {
312 let instance = &*(ptr as *mut T::Instance);
313 let imp = instance.imp();
314 let instance = imp.obj();
315 let instance = instance.unsafe_cast_ref::<BaseParse>();
316 let wrap_frame = BaseParseFrame::new(frame, instance);
317
318 let res = gst::panic_to_error!(imp, Err(gst::FlowError::Error), {
319 imp.handle_frame(wrap_frame)
320 });
321
322 match res {
323 Ok((flow, skip)) => {
324 *skipsize = i32::try_from(skip).expect("skip is higher than i32::MAX");
325 gst::FlowReturn::from_ok(flow)
326 }
327 Err(flow) => gst::FlowReturn::from_error(flow),
328 }
329 .into_glib()
330 }
331}
332
333unsafe extern "C" fn base_parse_convert<T: BaseParseImpl>(
334 ptr: *mut ffi::GstBaseParse,
335 source_format: gst::ffi::GstFormat,
336 source_value: i64,
337 dest_format: gst::ffi::GstFormat,
338 dest_value: *mut i64,
339) -> glib::ffi::gboolean {
340 unsafe {
341 let instance = &*(ptr as *mut T::Instance);
342 let imp = instance.imp();
343 let source = gst::GenericFormattedValue::new(from_glib(source_format), source_value);
344
345 let res = gst::panic_to_error!(imp, None, { imp.convert(source, from_glib(dest_format)) });
346
347 match res {
348 Some(dest) => {
349 *dest_value = dest.into_raw_value();
350 true
351 }
352 _ => false,
353 }
354 .into_glib()
355 }
356}