gstreamer_base/subclass/
base_sink.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, translate::*};
6use gst::subclass::prelude::*;
7
8use crate::{ffi, BaseSink};
9
10pub trait BaseSinkImpl: BaseSinkImplExt + ElementImpl {
11    fn start(&self) -> Result<(), gst::ErrorMessage> {
12        self.parent_start()
13    }
14
15    fn stop(&self) -> Result<(), gst::ErrorMessage> {
16        self.parent_stop()
17    }
18
19    fn render(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
20        self.parent_render(buffer)
21    }
22
23    fn prepare(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
24        self.parent_prepare(buffer)
25    }
26
27    fn render_list(&self, list: &gst::BufferList) -> Result<gst::FlowSuccess, gst::FlowError> {
28        self.parent_render_list(list)
29    }
30
31    fn prepare_list(&self, list: &gst::BufferList) -> Result<gst::FlowSuccess, gst::FlowError> {
32        self.parent_prepare_list(list)
33    }
34
35    fn query(&self, query: &mut gst::QueryRef) -> bool {
36        BaseSinkImplExt::parent_query(self, query)
37    }
38
39    fn event(&self, event: gst::Event) -> bool {
40        self.parent_event(event)
41    }
42
43    fn caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> {
44        self.parent_caps(filter)
45    }
46
47    fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
48        self.parent_set_caps(caps)
49    }
50
51    fn fixate(&self, caps: gst::Caps) -> gst::Caps {
52        self.parent_fixate(caps)
53    }
54
55    fn unlock(&self) -> Result<(), gst::ErrorMessage> {
56        self.parent_unlock()
57    }
58
59    fn unlock_stop(&self) -> Result<(), gst::ErrorMessage> {
60        self.parent_unlock_stop()
61    }
62
63    fn propose_allocation(
64        &self,
65        query: &mut gst::query::Allocation,
66    ) -> Result<(), gst::LoggableError> {
67        self.parent_propose_allocation(query)
68    }
69}
70
71mod sealed {
72    pub trait Sealed {}
73    impl<T: super::BaseSinkImplExt> Sealed for T {}
74}
75
76pub trait BaseSinkImplExt: sealed::Sealed + ObjectSubclass {
77    fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
78        unsafe {
79            let data = Self::type_data();
80            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
81            (*parent_class)
82                .start
83                .map(|f| {
84                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) {
85                        Ok(())
86                    } else {
87                        Err(gst::error_msg!(
88                            gst::CoreError::StateChange,
89                            ["Parent function `start` failed"]
90                        ))
91                    }
92                })
93                .unwrap_or(Ok(()))
94        }
95    }
96
97    fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
98        unsafe {
99            let data = Self::type_data();
100            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
101            (*parent_class)
102                .stop
103                .map(|f| {
104                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) {
105                        Ok(())
106                    } else {
107                        Err(gst::error_msg!(
108                            gst::CoreError::StateChange,
109                            ["Parent function `stop` failed"]
110                        ))
111                    }
112                })
113                .unwrap_or(Ok(()))
114        }
115    }
116
117    fn parent_render(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
118        unsafe {
119            let data = Self::type_data();
120            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
121            (*parent_class)
122                .render
123                .map(|f| {
124                    try_from_glib(f(
125                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
126                        buffer.to_glib_none().0,
127                    ))
128                })
129                .unwrap_or(Ok(gst::FlowSuccess::Ok))
130        }
131    }
132
133    fn parent_prepare(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
134        unsafe {
135            let data = Self::type_data();
136            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
137            (*parent_class)
138                .prepare
139                .map(|f| {
140                    try_from_glib(f(
141                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
142                        buffer.to_glib_none().0,
143                    ))
144                })
145                .unwrap_or(Ok(gst::FlowSuccess::Ok))
146        }
147    }
148
149    fn parent_render_list(
150        &self,
151        list: &gst::BufferList,
152    ) -> Result<gst::FlowSuccess, gst::FlowError>;
153
154    fn parent_prepare_list(
155        &self,
156        list: &gst::BufferList,
157    ) -> Result<gst::FlowSuccess, gst::FlowError>;
158
159    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
160        unsafe {
161            let data = Self::type_data();
162            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
163            (*parent_class)
164                .query
165                .map(|f| {
166                    from_glib(f(
167                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
168                        query.as_mut_ptr(),
169                    ))
170                })
171                .unwrap_or(false)
172        }
173    }
174
175    fn parent_event(&self, event: gst::Event) -> bool {
176        unsafe {
177            let data = Self::type_data();
178            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
179            (*parent_class)
180                .event
181                .map(|f| {
182                    from_glib(f(
183                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
184                        event.into_glib_ptr(),
185                    ))
186                })
187                .unwrap_or(true)
188        }
189    }
190
191    fn parent_caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> {
192        unsafe {
193            let data = Self::type_data();
194            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
195
196            (*parent_class)
197                .get_caps
198                .map(|f| {
199                    from_glib_full(f(
200                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
201                        filter.to_glib_none().0,
202                    ))
203                })
204                .unwrap_or(None)
205        }
206    }
207
208    fn parent_set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
209        unsafe {
210            let data = Self::type_data();
211            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
212            (*parent_class)
213                .set_caps
214                .map(|f| {
215                    gst::result_from_gboolean!(
216                        f(
217                            self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
218                            caps.to_glib_none().0
219                        ),
220                        gst::CAT_RUST,
221                        "Parent function `set_caps` failed"
222                    )
223                })
224                .unwrap_or(Ok(()))
225        }
226    }
227
228    fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps {
229        unsafe {
230            let data = Self::type_data();
231            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
232
233            match (*parent_class).fixate {
234                Some(fixate) => from_glib_full(fixate(
235                    self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
236                    caps.into_glib_ptr(),
237                )),
238                None => caps,
239            }
240        }
241    }
242
243    fn parent_unlock(&self) -> Result<(), gst::ErrorMessage> {
244        unsafe {
245            let data = Self::type_data();
246            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
247            (*parent_class)
248                .unlock
249                .map(|f| {
250                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) {
251                        Ok(())
252                    } else {
253                        Err(gst::error_msg!(
254                            gst::CoreError::Failed,
255                            ["Parent function `unlock` failed"]
256                        ))
257                    }
258                })
259                .unwrap_or(Ok(()))
260        }
261    }
262
263    fn parent_unlock_stop(&self) -> Result<(), gst::ErrorMessage> {
264        unsafe {
265            let data = Self::type_data();
266            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
267            (*parent_class)
268                .unlock_stop
269                .map(|f| {
270                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) {
271                        Ok(())
272                    } else {
273                        Err(gst::error_msg!(
274                            gst::CoreError::Failed,
275                            ["Parent function `unlock_stop` failed"]
276                        ))
277                    }
278                })
279                .unwrap_or(Ok(()))
280        }
281    }
282
283    fn parent_propose_allocation(
284        &self,
285        query: &mut gst::query::Allocation,
286    ) -> Result<(), gst::LoggableError> {
287        unsafe {
288            let data = Self::type_data();
289            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
290            (*parent_class)
291                .propose_allocation
292                .map(|f| {
293                    gst::result_from_gboolean!(
294                        f(
295                            self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
296                            query.as_mut_ptr(),
297                        ),
298                        gst::CAT_RUST,
299                        "Parent function `propose_allocation` failed",
300                    )
301                })
302                .unwrap_or(Ok(()))
303        }
304    }
305}
306
307impl<T: BaseSinkImpl> BaseSinkImplExt for T {
308    fn parent_render_list(
309        &self,
310        list: &gst::BufferList,
311    ) -> Result<gst::FlowSuccess, gst::FlowError> {
312        unsafe {
313            let data = Self::type_data();
314            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
315            (*parent_class)
316                .render_list
317                .map(|f| {
318                    try_from_glib(f(
319                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
320                        list.to_glib_none().0,
321                    ))
322                })
323                .unwrap_or_else(|| {
324                    for buffer in list.iter() {
325                        self.render(&from_glib_borrow(buffer.as_ptr()))?;
326                    }
327                    Ok(gst::FlowSuccess::Ok)
328                })
329        }
330    }
331
332    fn parent_prepare_list(
333        &self,
334        list: &gst::BufferList,
335    ) -> Result<gst::FlowSuccess, gst::FlowError> {
336        unsafe {
337            let data = Self::type_data();
338            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass;
339            (*parent_class)
340                .prepare_list
341                .map(|f| {
342                    try_from_glib(f(
343                        self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0,
344                        list.to_glib_none().0,
345                    ))
346                })
347                .unwrap_or_else(|| {
348                    for buffer in list.iter() {
349                        self.prepare(&from_glib_borrow(buffer.as_ptr()))?;
350                    }
351                    Ok(gst::FlowSuccess::Ok)
352                })
353        }
354    }
355}
356
357unsafe impl<T: BaseSinkImpl> IsSubclassable<T> for BaseSink {
358    fn class_init(klass: &mut glib::Class<Self>) {
359        Self::parent_class_init::<T>(klass);
360        let klass = klass.as_mut();
361        klass.start = Some(base_sink_start::<T>);
362        klass.stop = Some(base_sink_stop::<T>);
363        klass.render = Some(base_sink_render::<T>);
364        klass.render_list = Some(base_sink_render_list::<T>);
365        klass.prepare = Some(base_sink_prepare::<T>);
366        klass.prepare_list = Some(base_sink_prepare_list::<T>);
367        klass.query = Some(base_sink_query::<T>);
368        klass.event = Some(base_sink_event::<T>);
369        klass.get_caps = Some(base_sink_get_caps::<T>);
370        klass.set_caps = Some(base_sink_set_caps::<T>);
371        klass.fixate = Some(base_sink_fixate::<T>);
372        klass.unlock = Some(base_sink_unlock::<T>);
373        klass.unlock_stop = Some(base_sink_unlock_stop::<T>);
374        klass.propose_allocation = Some(base_sink_propose_allocation::<T>);
375    }
376}
377
378unsafe extern "C" fn base_sink_start<T: BaseSinkImpl>(
379    ptr: *mut ffi::GstBaseSink,
380) -> glib::ffi::gboolean {
381    let instance = &*(ptr as *mut T::Instance);
382    let imp = instance.imp();
383
384    gst::panic_to_error!(imp, false, {
385        match imp.start() {
386            Ok(()) => true,
387            Err(err) => {
388                imp.post_error_message(err);
389                false
390            }
391        }
392    })
393    .into_glib()
394}
395
396unsafe extern "C" fn base_sink_stop<T: BaseSinkImpl>(
397    ptr: *mut ffi::GstBaseSink,
398) -> glib::ffi::gboolean {
399    let instance = &*(ptr as *mut T::Instance);
400    let imp = instance.imp();
401
402    gst::panic_to_error!(imp, false, {
403        match imp.stop() {
404            Ok(()) => true,
405            Err(err) => {
406                imp.post_error_message(err);
407                false
408            }
409        }
410    })
411    .into_glib()
412}
413
414unsafe extern "C" fn base_sink_render<T: BaseSinkImpl>(
415    ptr: *mut ffi::GstBaseSink,
416    buffer: *mut gst::ffi::GstBuffer,
417) -> gst::ffi::GstFlowReturn {
418    let instance = &*(ptr as *mut T::Instance);
419    let imp = instance.imp();
420    let buffer = from_glib_borrow(buffer);
421
422    gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.render(&buffer).into() }).into_glib()
423}
424
425unsafe extern "C" fn base_sink_prepare<T: BaseSinkImpl>(
426    ptr: *mut ffi::GstBaseSink,
427    buffer: *mut gst::ffi::GstBuffer,
428) -> gst::ffi::GstFlowReturn {
429    let instance = &*(ptr as *mut T::Instance);
430    let imp = instance.imp();
431    let buffer = from_glib_borrow(buffer);
432
433    gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.prepare(&buffer).into() }).into_glib()
434}
435
436unsafe extern "C" fn base_sink_render_list<T: BaseSinkImpl>(
437    ptr: *mut ffi::GstBaseSink,
438    list: *mut gst::ffi::GstBufferList,
439) -> gst::ffi::GstFlowReturn {
440    let instance = &*(ptr as *mut T::Instance);
441    let imp = instance.imp();
442    let list = from_glib_borrow(list);
443
444    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
445        imp.render_list(&list).into()
446    })
447    .into_glib()
448}
449
450unsafe extern "C" fn base_sink_prepare_list<T: BaseSinkImpl>(
451    ptr: *mut ffi::GstBaseSink,
452    list: *mut gst::ffi::GstBufferList,
453) -> gst::ffi::GstFlowReturn {
454    let instance = &*(ptr as *mut T::Instance);
455    let imp = instance.imp();
456    let list = from_glib_borrow(list);
457
458    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
459        imp.prepare_list(&list).into()
460    })
461    .into_glib()
462}
463
464unsafe extern "C" fn base_sink_query<T: BaseSinkImpl>(
465    ptr: *mut ffi::GstBaseSink,
466    query_ptr: *mut gst::ffi::GstQuery,
467) -> glib::ffi::gboolean {
468    let instance = &*(ptr as *mut T::Instance);
469    let imp = instance.imp();
470    let query = gst::QueryRef::from_mut_ptr(query_ptr);
471
472    gst::panic_to_error!(imp, false, { BaseSinkImpl::query(imp, query) }).into_glib()
473}
474
475unsafe extern "C" fn base_sink_event<T: BaseSinkImpl>(
476    ptr: *mut ffi::GstBaseSink,
477    event_ptr: *mut gst::ffi::GstEvent,
478) -> glib::ffi::gboolean {
479    let instance = &*(ptr as *mut T::Instance);
480    let imp = instance.imp();
481
482    gst::panic_to_error!(imp, false, { imp.event(from_glib_full(event_ptr)) }).into_glib()
483}
484
485unsafe extern "C" fn base_sink_get_caps<T: BaseSinkImpl>(
486    ptr: *mut ffi::GstBaseSink,
487    filter: *mut gst::ffi::GstCaps,
488) -> *mut gst::ffi::GstCaps {
489    let instance = &*(ptr as *mut T::Instance);
490    let imp = instance.imp();
491    let filter = Option::<gst::Caps>::from_glib_borrow(filter);
492
493    gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) })
494        .map(|caps| caps.into_glib_ptr())
495        .unwrap_or(ptr::null_mut())
496}
497
498unsafe extern "C" fn base_sink_set_caps<T: BaseSinkImpl>(
499    ptr: *mut ffi::GstBaseSink,
500    caps: *mut gst::ffi::GstCaps,
501) -> glib::ffi::gboolean {
502    let instance = &*(ptr as *mut T::Instance);
503    let imp = instance.imp();
504    let caps = from_glib_borrow(caps);
505
506    gst::panic_to_error!(imp, false, {
507        match imp.set_caps(&caps) {
508            Ok(()) => true,
509            Err(err) => {
510                err.log_with_imp(imp);
511                false
512            }
513        }
514    })
515    .into_glib()
516}
517
518unsafe extern "C" fn base_sink_fixate<T: BaseSinkImpl>(
519    ptr: *mut ffi::GstBaseSink,
520    caps: *mut gst::ffi::GstCaps,
521) -> *mut gst::ffi::GstCaps {
522    let instance = &*(ptr as *mut T::Instance);
523    let imp = instance.imp();
524    let caps = from_glib_full(caps);
525
526    gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr()
527}
528
529unsafe extern "C" fn base_sink_unlock<T: BaseSinkImpl>(
530    ptr: *mut ffi::GstBaseSink,
531) -> glib::ffi::gboolean {
532    let instance = &*(ptr as *mut T::Instance);
533    let imp = instance.imp();
534
535    gst::panic_to_error!(imp, false, {
536        match imp.unlock() {
537            Ok(()) => true,
538            Err(err) => {
539                imp.post_error_message(err);
540                false
541            }
542        }
543    })
544    .into_glib()
545}
546
547unsafe extern "C" fn base_sink_unlock_stop<T: BaseSinkImpl>(
548    ptr: *mut ffi::GstBaseSink,
549) -> glib::ffi::gboolean {
550    let instance = &*(ptr as *mut T::Instance);
551    let imp = instance.imp();
552
553    gst::panic_to_error!(imp, false, {
554        match imp.unlock_stop() {
555            Ok(()) => true,
556            Err(err) => {
557                imp.post_error_message(err);
558                false
559            }
560        }
561    })
562    .into_glib()
563}
564
565unsafe extern "C" fn base_sink_propose_allocation<T: BaseSinkImpl>(
566    ptr: *mut ffi::GstBaseSink,
567    query: *mut gst::ffi::GstQuery,
568) -> glib::ffi::gboolean {
569    let instance = &*(ptr as *mut T::Instance);
570    let imp = instance.imp();
571    let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
572        gst::QueryViewMut::Allocation(allocation) => allocation,
573        _ => unreachable!(),
574    };
575
576    gst::panic_to_error!(imp, false, {
577        match imp.propose_allocation(query) {
578            Ok(()) => true,
579            Err(err) => {
580                err.log_with_imp_and_level(imp, gst::DebugLevel::Info);
581                false
582            }
583        }
584    })
585    .into_glib()
586}