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 be notified of the actual caps set.
27    fn set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
28        self.parent_set_sink_caps(caps)
29    }
30
31    /// Parses the input data into valid frames as defined by subclass
32    /// which should be passed to [`BaseParseExtManual::finish_frame()`][crate::prelude::BaseParseExtManual::finish_frame()].
33    /// The frame's input buffer is guaranteed writable,
34    /// whereas the input frame ownership is held by caller
35    /// (so subclass should make a copy if it needs to hang on).
36    /// Input buffer (data) is provided by baseclass with as much
37    /// metadata set as possible by baseclass according to upstream
38    /// information and/or subclass settings,
39    /// though subclass may still set buffer timestamp and duration
40    /// if desired.
41    ///
42    /// # Returns
43    ///
44    fn handle_frame(
45        &self,
46        frame: BaseParseFrame,
47    ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
48        self.parent_handle_frame(frame)
49    }
50
51    /// Optional.
52    ///  Convert between formats.
53    fn convert(
54        &self,
55        src_val: impl gst::format::FormattedValue,
56        dest_format: gst::Format,
57    ) -> Option<gst::GenericFormattedValue> {
58        self.parent_convert(src_val, dest_format)
59    }
60}
61
62pub trait BaseParseImplExt: BaseParseImpl {
63    fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
64        unsafe {
65            let data = Self::type_data();
66            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
67            (*parent_class)
68                .start
69                .map(|f| {
70                    if from_glib(f(self
71                        .obj()
72                        .unsafe_cast_ref::<BaseParse>()
73                        .to_glib_none()
74                        .0))
75                    {
76                        Ok(())
77                    } else {
78                        Err(gst::error_msg!(
79                            gst::CoreError::StateChange,
80                            ["Parent function `start` failed"]
81                        ))
82                    }
83                })
84                .unwrap_or(Ok(()))
85        }
86    }
87
88    fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
89        unsafe {
90            let data = Self::type_data();
91            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
92            (*parent_class)
93                .stop
94                .map(|f| {
95                    if from_glib(f(self
96                        .obj()
97                        .unsafe_cast_ref::<BaseParse>()
98                        .to_glib_none()
99                        .0))
100                    {
101                        Ok(())
102                    } else {
103                        Err(gst::error_msg!(
104                            gst::CoreError::StateChange,
105                            ["Parent function `stop` failed"]
106                        ))
107                    }
108                })
109                .unwrap_or(Ok(()))
110        }
111    }
112
113    fn parent_set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
114        unsafe {
115            let data = Self::type_data();
116            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
117            (*parent_class)
118                .set_sink_caps
119                .map(|f| {
120                    gst::result_from_gboolean!(
121                        f(
122                            self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
123                            caps.to_glib_none().0,
124                        ),
125                        gst::CAT_RUST,
126                        "Parent function `set_sink_caps` failed",
127                    )
128                })
129                .unwrap_or(Ok(()))
130        }
131    }
132
133    fn parent_handle_frame(
134        &self,
135        frame: BaseParseFrame,
136    ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
137        unsafe {
138            let data = Self::type_data();
139            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
140            let mut skipsize = 0;
141            (*parent_class)
142                .handle_frame
143                .map(|f| {
144                    let res = try_from_glib(f(
145                        self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
146                        frame.to_glib_none().0,
147                        &mut skipsize,
148                    ));
149                    (res.unwrap(), skipsize as u32)
150                })
151                .ok_or(gst::FlowError::Error)
152        }
153    }
154
155    fn parent_convert(
156        &self,
157        src_val: impl gst::format::FormattedValue,
158        dest_format: gst::Format,
159    ) -> Option<gst::GenericFormattedValue> {
160        unsafe {
161            let data = Self::type_data();
162            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
163            let res = (*parent_class).convert.map(|f| {
164                let mut dest_val = mem::MaybeUninit::uninit();
165
166                let res = from_glib(f(
167                    self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
168                    src_val.format().into_glib(),
169                    src_val.into_raw_value(),
170                    dest_format.into_glib(),
171                    dest_val.as_mut_ptr(),
172                ));
173                (res, dest_val)
174            });
175
176            match res {
177                Some((true, dest_val)) => Some(gst::GenericFormattedValue::new(
178                    dest_format,
179                    dest_val.assume_init(),
180                )),
181                _ => None,
182            }
183        }
184    }
185}
186
187impl<T: BaseParseImpl> BaseParseImplExt for T {}
188
189unsafe impl<T: BaseParseImpl> IsSubclassable<T> for BaseParse {
190    fn class_init(klass: &mut glib::Class<Self>) {
191        Self::parent_class_init::<T>(klass);
192        let klass = klass.as_mut();
193        klass.start = Some(base_parse_start::<T>);
194        klass.stop = Some(base_parse_stop::<T>);
195        klass.set_sink_caps = Some(base_parse_set_sink_caps::<T>);
196        klass.handle_frame = Some(base_parse_handle_frame::<T>);
197        klass.convert = Some(base_parse_convert::<T>);
198    }
199}
200
201unsafe extern "C" fn base_parse_start<T: BaseParseImpl>(
202    ptr: *mut ffi::GstBaseParse,
203) -> glib::ffi::gboolean {
204    unsafe {
205        let instance = &*(ptr as *mut T::Instance);
206        let imp = instance.imp();
207
208        gst::panic_to_error!(imp, false, {
209            match imp.start() {
210                Ok(()) => true,
211                Err(err) => {
212                    imp.post_error_message(err);
213                    false
214                }
215            }
216        })
217        .into_glib()
218    }
219}
220
221unsafe extern "C" fn base_parse_stop<T: BaseParseImpl>(
222    ptr: *mut ffi::GstBaseParse,
223) -> glib::ffi::gboolean {
224    unsafe {
225        let instance = &*(ptr as *mut T::Instance);
226        let imp = instance.imp();
227
228        gst::panic_to_error!(imp, false, {
229            match imp.stop() {
230                Ok(()) => true,
231                Err(err) => {
232                    imp.post_error_message(err);
233                    false
234                }
235            }
236        })
237        .into_glib()
238    }
239}
240
241unsafe extern "C" fn base_parse_set_sink_caps<T: BaseParseImpl>(
242    ptr: *mut ffi::GstBaseParse,
243    caps: *mut gst::ffi::GstCaps,
244) -> glib::ffi::gboolean {
245    unsafe {
246        let instance = &*(ptr as *mut T::Instance);
247        let imp = instance.imp();
248        let caps: Borrowed<gst::Caps> = from_glib_borrow(caps);
249
250        gst::panic_to_error!(imp, false, {
251            match imp.set_sink_caps(&caps) {
252                Ok(()) => true,
253                Err(err) => {
254                    err.log_with_imp(imp);
255                    false
256                }
257            }
258        })
259        .into_glib()
260    }
261}
262
263unsafe extern "C" fn base_parse_handle_frame<T: BaseParseImpl>(
264    ptr: *mut ffi::GstBaseParse,
265    frame: *mut ffi::GstBaseParseFrame,
266    skipsize: *mut i32,
267) -> gst::ffi::GstFlowReturn {
268    unsafe {
269        let instance = &*(ptr as *mut T::Instance);
270        let imp = instance.imp();
271        let instance = imp.obj();
272        let instance = instance.unsafe_cast_ref::<BaseParse>();
273        let wrap_frame = BaseParseFrame::new(frame, instance);
274
275        let res = gst::panic_to_error!(imp, Err(gst::FlowError::Error), {
276            imp.handle_frame(wrap_frame)
277        });
278
279        match res {
280            Ok((flow, skip)) => {
281                *skipsize = i32::try_from(skip).expect("skip is higher than i32::MAX");
282                gst::FlowReturn::from_ok(flow)
283            }
284            Err(flow) => gst::FlowReturn::from_error(flow),
285        }
286        .into_glib()
287    }
288}
289
290unsafe extern "C" fn base_parse_convert<T: BaseParseImpl>(
291    ptr: *mut ffi::GstBaseParse,
292    source_format: gst::ffi::GstFormat,
293    source_value: i64,
294    dest_format: gst::ffi::GstFormat,
295    dest_value: *mut i64,
296) -> glib::ffi::gboolean {
297    unsafe {
298        let instance = &*(ptr as *mut T::Instance);
299        let imp = instance.imp();
300        let source = gst::GenericFormattedValue::new(from_glib(source_format), source_value);
301
302        let res = gst::panic_to_error!(imp, None, { imp.convert(source, from_glib(dest_format)) });
303
304        match res {
305            Some(dest) => {
306                *dest_value = dest.into_raw_value();
307                true
308            }
309            _ => false,
310        }
311        .into_glib()
312    }
313}