Skip to main content

gstreamer_base/subclass/
base_parse.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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    /// Optional.
12    ///  Called when the element starts processing.
13    ///  Allows opening external resources.
14    fn start(&self) -> Result<(), gst::ErrorMessage> {
15        self.parent_start()
16    }
17
18    /// Optional.
19    ///  Called when the element stops processing.
20    ///  Allows closing external resources.
21    fn stop(&self) -> Result<(), gst::ErrorMessage> {
22        self.parent_stop()
23    }
24
25    /// Optional.
26    ///  Allows the subclass to do its own sink get caps if needed.
27    fn sink_caps(&self, filter: Option<&gst::Caps>) -> gst::Caps {
28        self.parent_sink_caps(filter)
29    }
30
31    /// Optional.
32    ///  Allows the subclass to be notified of the actual caps set.
33    fn set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
34        self.parent_set_sink_caps(caps)
35    }
36
37    /// Parses the input data into valid frames as defined by subclass
38    /// which should be passed to [`BaseParseExtManual::finish_frame()`][crate::prelude::BaseParseExtManual::finish_frame()].
39    /// The frame's input buffer is guaranteed writable,
40    /// whereas the input frame ownership is held by caller
41    /// (so subclass should make a copy if it needs to hang on).
42    /// Input buffer (data) is provided by baseclass with as much
43    /// metadata set as possible by baseclass according to upstream
44    /// information and/or subclass settings,
45    /// though subclass may still set buffer timestamp and duration
46    /// if desired.
47    ///
48    /// # Returns
49    ///
50    fn handle_frame(
51        &self,
52        frame: BaseParseFrame,
53    ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
54        self.parent_handle_frame(frame)
55    }
56
57    /// Optional.
58    ///  Convert between formats.
59    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}