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::{ffi, prelude::*, BaseParse, BaseParseFrame};
9
10pub trait BaseParseImpl: BaseParseImplExt + ElementImpl {
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
62mod sealed {
63    pub trait Sealed {}
64    impl<T: super::BaseParseImplExt> Sealed for T {}
65}
66
67pub trait BaseParseImplExt: sealed::Sealed + ObjectSubclass {
68    fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
69        unsafe {
70            let data = Self::type_data();
71            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
72            (*parent_class)
73                .start
74                .map(|f| {
75                    if from_glib(f(self
76                        .obj()
77                        .unsafe_cast_ref::<BaseParse>()
78                        .to_glib_none()
79                        .0))
80                    {
81                        Ok(())
82                    } else {
83                        Err(gst::error_msg!(
84                            gst::CoreError::StateChange,
85                            ["Parent function `start` failed"]
86                        ))
87                    }
88                })
89                .unwrap_or(Ok(()))
90        }
91    }
92
93    fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
94        unsafe {
95            let data = Self::type_data();
96            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
97            (*parent_class)
98                .stop
99                .map(|f| {
100                    if from_glib(f(self
101                        .obj()
102                        .unsafe_cast_ref::<BaseParse>()
103                        .to_glib_none()
104                        .0))
105                    {
106                        Ok(())
107                    } else {
108                        Err(gst::error_msg!(
109                            gst::CoreError::StateChange,
110                            ["Parent function `stop` failed"]
111                        ))
112                    }
113                })
114                .unwrap_or(Ok(()))
115        }
116    }
117
118    fn parent_set_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
119        unsafe {
120            let data = Self::type_data();
121            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
122            (*parent_class)
123                .set_sink_caps
124                .map(|f| {
125                    gst::result_from_gboolean!(
126                        f(
127                            self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
128                            caps.to_glib_none().0,
129                        ),
130                        gst::CAT_RUST,
131                        "Parent function `set_sink_caps` failed",
132                    )
133                })
134                .unwrap_or(Ok(()))
135        }
136    }
137
138    fn parent_handle_frame(
139        &self,
140        frame: BaseParseFrame,
141    ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> {
142        unsafe {
143            let data = Self::type_data();
144            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
145            let mut skipsize = 0;
146            (*parent_class)
147                .handle_frame
148                .map(|f| {
149                    let res = try_from_glib(f(
150                        self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
151                        frame.to_glib_none().0,
152                        &mut skipsize,
153                    ));
154                    (res.unwrap(), skipsize as u32)
155                })
156                .ok_or(gst::FlowError::Error)
157        }
158    }
159
160    fn parent_convert(
161        &self,
162        src_val: impl gst::format::FormattedValue,
163        dest_format: gst::Format,
164    ) -> Option<gst::GenericFormattedValue> {
165        unsafe {
166            let data = Self::type_data();
167            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseParseClass;
168            let res = (*parent_class).convert.map(|f| {
169                let mut dest_val = mem::MaybeUninit::uninit();
170
171                let res = from_glib(f(
172                    self.obj().unsafe_cast_ref::<BaseParse>().to_glib_none().0,
173                    src_val.format().into_glib(),
174                    src_val.into_raw_value(),
175                    dest_format.into_glib(),
176                    dest_val.as_mut_ptr(),
177                ));
178                (res, dest_val)
179            });
180
181            match res {
182                Some((true, dest_val)) => Some(gst::GenericFormattedValue::new(
183                    dest_format,
184                    dest_val.assume_init(),
185                )),
186                _ => None,
187            }
188        }
189    }
190}
191
192impl<T: BaseParseImpl> BaseParseImplExt for T {}
193
194unsafe impl<T: BaseParseImpl> IsSubclassable<T> for BaseParse {
195    fn class_init(klass: &mut glib::Class<Self>) {
196        Self::parent_class_init::<T>(klass);
197        let klass = klass.as_mut();
198        klass.start = Some(base_parse_start::<T>);
199        klass.stop = Some(base_parse_stop::<T>);
200        klass.set_sink_caps = Some(base_parse_set_sink_caps::<T>);
201        klass.handle_frame = Some(base_parse_handle_frame::<T>);
202        klass.convert = Some(base_parse_convert::<T>);
203    }
204}
205
206unsafe extern "C" fn base_parse_start<T: BaseParseImpl>(
207    ptr: *mut ffi::GstBaseParse,
208) -> glib::ffi::gboolean {
209    let instance = &*(ptr as *mut T::Instance);
210    let imp = instance.imp();
211
212    gst::panic_to_error!(imp, false, {
213        match imp.start() {
214            Ok(()) => true,
215            Err(err) => {
216                imp.post_error_message(err);
217                false
218            }
219        }
220    })
221    .into_glib()
222}
223
224unsafe extern "C" fn base_parse_stop<T: BaseParseImpl>(
225    ptr: *mut ffi::GstBaseParse,
226) -> glib::ffi::gboolean {
227    let instance = &*(ptr as *mut T::Instance);
228    let imp = instance.imp();
229
230    gst::panic_to_error!(imp, false, {
231        match imp.stop() {
232            Ok(()) => true,
233            Err(err) => {
234                imp.post_error_message(err);
235                false
236            }
237        }
238    })
239    .into_glib()
240}
241
242unsafe extern "C" fn base_parse_set_sink_caps<T: BaseParseImpl>(
243    ptr: *mut ffi::GstBaseParse,
244    caps: *mut gst::ffi::GstCaps,
245) -> glib::ffi::gboolean {
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
262unsafe extern "C" fn base_parse_handle_frame<T: BaseParseImpl>(
263    ptr: *mut ffi::GstBaseParse,
264    frame: *mut ffi::GstBaseParseFrame,
265    skipsize: *mut i32,
266) -> gst::ffi::GstFlowReturn {
267    let instance = &*(ptr as *mut T::Instance);
268    let imp = instance.imp();
269    let instance = imp.obj();
270    let instance = instance.unsafe_cast_ref::<BaseParse>();
271    let wrap_frame = BaseParseFrame::new(frame, instance);
272
273    let res = gst::panic_to_error!(imp, Err(gst::FlowError::Error), {
274        imp.handle_frame(wrap_frame)
275    });
276
277    match res {
278        Ok((flow, skip)) => {
279            *skipsize = i32::try_from(skip).expect("skip is higher than i32::MAX");
280            gst::FlowReturn::from_ok(flow)
281        }
282        Err(flow) => gst::FlowReturn::from_error(flow),
283    }
284    .into_glib()
285}
286
287unsafe extern "C" fn base_parse_convert<T: BaseParseImpl>(
288    ptr: *mut ffi::GstBaseParse,
289    source_format: gst::ffi::GstFormat,
290    source_value: i64,
291    dest_format: gst::ffi::GstFormat,
292    dest_value: *mut i64,
293) -> glib::ffi::gboolean {
294    let instance = &*(ptr as *mut T::Instance);
295    let imp = instance.imp();
296    let source = gst::GenericFormattedValue::new(from_glib(source_format), source_value);
297
298    let res = gst::panic_to_error!(imp, None, { imp.convert(source, from_glib(dest_format)) });
299
300    match res {
301        Some(dest) => {
302            *dest_value = dest.into_raw_value();
303            true
304        }
305        _ => false,
306    }
307    .into_glib()
308}