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: 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    let instance = &*(ptr as *mut T::Instance);
205    let imp = instance.imp();
206
207    gst::panic_to_error!(imp, false, {
208        match imp.start() {
209            Ok(()) => true,
210            Err(err) => {
211                imp.post_error_message(err);
212                false
213            }
214        }
215    })
216    .into_glib()
217}
218
219unsafe extern "C" fn base_parse_stop<T: BaseParseImpl>(
220    ptr: *mut ffi::GstBaseParse,
221) -> glib::ffi::gboolean {
222    let instance = &*(ptr as *mut T::Instance);
223    let imp = instance.imp();
224
225    gst::panic_to_error!(imp, false, {
226        match imp.stop() {
227            Ok(()) => true,
228            Err(err) => {
229                imp.post_error_message(err);
230                false
231            }
232        }
233    })
234    .into_glib()
235}
236
237unsafe extern "C" fn base_parse_set_sink_caps<T: BaseParseImpl>(
238    ptr: *mut ffi::GstBaseParse,
239    caps: *mut gst::ffi::GstCaps,
240) -> glib::ffi::gboolean {
241    let instance = &*(ptr as *mut T::Instance);
242    let imp = instance.imp();
243    let caps: Borrowed<gst::Caps> = from_glib_borrow(caps);
244
245    gst::panic_to_error!(imp, false, {
246        match imp.set_sink_caps(&caps) {
247            Ok(()) => true,
248            Err(err) => {
249                err.log_with_imp(imp);
250                false
251            }
252        }
253    })
254    .into_glib()
255}
256
257unsafe extern "C" fn base_parse_handle_frame<T: BaseParseImpl>(
258    ptr: *mut ffi::GstBaseParse,
259    frame: *mut ffi::GstBaseParseFrame,
260    skipsize: *mut i32,
261) -> gst::ffi::GstFlowReturn {
262    let instance = &*(ptr as *mut T::Instance);
263    let imp = instance.imp();
264    let instance = imp.obj();
265    let instance = instance.unsafe_cast_ref::<BaseParse>();
266    let wrap_frame = BaseParseFrame::new(frame, instance);
267
268    let res = gst::panic_to_error!(imp, Err(gst::FlowError::Error), {
269        imp.handle_frame(wrap_frame)
270    });
271
272    match res {
273        Ok((flow, skip)) => {
274            *skipsize = i32::try_from(skip).expect("skip is higher than i32::MAX");
275            gst::FlowReturn::from_ok(flow)
276        }
277        Err(flow) => gst::FlowReturn::from_error(flow),
278    }
279    .into_glib()
280}
281
282unsafe extern "C" fn base_parse_convert<T: BaseParseImpl>(
283    ptr: *mut ffi::GstBaseParse,
284    source_format: gst::ffi::GstFormat,
285    source_value: i64,
286    dest_format: gst::ffi::GstFormat,
287    dest_value: *mut i64,
288) -> glib::ffi::gboolean {
289    let instance = &*(ptr as *mut T::Instance);
290    let imp = instance.imp();
291    let source = gst::GenericFormattedValue::new(from_glib(source_format), source_value);
292
293    let res = gst::panic_to_error!(imp, None, { imp.convert(source, from_glib(dest_format)) });
294
295    match res {
296        Some(dest) => {
297            *dest_value = dest.into_raw_value();
298            true
299        }
300        _ => false,
301    }
302    .into_glib()
303}