gstreamer_base/subclass/
base_src.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ptr};
4
5use atomic_refcell::AtomicRefCell;
6use glib::{prelude::*, translate::*};
7use gst::{prelude::*, subclass::prelude::*};
8
9use crate::{ffi, prelude::*, BaseSrc};
10
11#[derive(Default)]
12pub(super) struct InstanceData {
13    pub(super) pending_buffer_list: AtomicRefCell<Option<gst::BufferList>>,
14}
15
16#[derive(Debug)]
17pub enum CreateSuccess {
18    FilledBuffer,
19    NewBuffer(gst::Buffer),
20    NewBufferList(gst::BufferList),
21}
22
23pub trait BaseSrcImpl: BaseSrcImplExt + ElementImpl {
24    fn start(&self) -> Result<(), gst::ErrorMessage> {
25        self.parent_start()
26    }
27
28    fn stop(&self) -> Result<(), gst::ErrorMessage> {
29        self.parent_stop()
30    }
31
32    fn is_seekable(&self) -> bool {
33        self.parent_is_seekable()
34    }
35
36    fn size(&self) -> Option<u64> {
37        self.parent_size()
38    }
39
40    #[doc(alias = "get_times")]
41    fn times(&self, buffer: &gst::BufferRef) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) {
42        self.parent_times(buffer)
43    }
44
45    fn fill(
46        &self,
47        offset: u64,
48        length: u32,
49        buffer: &mut gst::BufferRef,
50    ) -> Result<gst::FlowSuccess, gst::FlowError> {
51        self.parent_fill(offset, length, buffer)
52    }
53
54    fn alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> {
55        self.parent_alloc(offset, length)
56    }
57
58    fn create(
59        &self,
60        offset: u64,
61        buffer: Option<&mut gst::BufferRef>,
62        length: u32,
63    ) -> Result<CreateSuccess, gst::FlowError> {
64        self.parent_create(offset, buffer, length)
65    }
66
67    fn do_seek(&self, segment: &mut gst::Segment) -> bool {
68        self.parent_do_seek(segment)
69    }
70
71    fn query(&self, query: &mut gst::QueryRef) -> bool {
72        BaseSrcImplExt::parent_query(self, query)
73    }
74
75    fn event(&self, event: &gst::Event) -> bool {
76        self.parent_event(event)
77    }
78
79    fn caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> {
80        self.parent_caps(filter)
81    }
82
83    fn negotiate(&self) -> Result<(), gst::LoggableError> {
84        self.parent_negotiate()
85    }
86
87    fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
88        self.parent_set_caps(caps)
89    }
90
91    fn fixate(&self, caps: gst::Caps) -> gst::Caps {
92        self.parent_fixate(caps)
93    }
94
95    fn unlock(&self) -> Result<(), gst::ErrorMessage> {
96        self.parent_unlock()
97    }
98
99    fn unlock_stop(&self) -> Result<(), gst::ErrorMessage> {
100        self.parent_unlock_stop()
101    }
102
103    fn decide_allocation(
104        &self,
105        query: &mut gst::query::Allocation,
106    ) -> Result<(), gst::LoggableError> {
107        self.parent_decide_allocation(query)
108    }
109}
110
111mod sealed {
112    pub trait Sealed {}
113    impl<T: super::BaseSrcImplExt> Sealed for T {}
114}
115
116pub trait BaseSrcImplExt: sealed::Sealed + ObjectSubclass {
117    fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
118        unsafe {
119            let data = Self::type_data();
120            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
121            (*parent_class)
122                .start
123                .map(|f| {
124                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) {
125                        Ok(())
126                    } else {
127                        Err(gst::error_msg!(
128                            gst::CoreError::StateChange,
129                            ["Parent function `start` failed"]
130                        ))
131                    }
132                })
133                .unwrap_or(Ok(()))
134        }
135    }
136
137    fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
138        unsafe {
139            let data = Self::type_data();
140            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
141            (*parent_class)
142                .stop
143                .map(|f| {
144                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) {
145                        Ok(())
146                    } else {
147                        Err(gst::error_msg!(
148                            gst::CoreError::StateChange,
149                            ["Parent function `stop` failed"]
150                        ))
151                    }
152                })
153                .unwrap_or(Ok(()))
154        }
155    }
156
157    fn parent_is_seekable(&self) -> bool {
158        unsafe {
159            let data = Self::type_data();
160            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
161            (*parent_class)
162                .is_seekable
163                .map(|f| from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)))
164                .unwrap_or(false)
165        }
166    }
167
168    fn parent_size(&self) -> Option<u64> {
169        unsafe {
170            let data = Self::type_data();
171            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
172            (*parent_class)
173                .get_size
174                .map(|f| {
175                    let mut size = mem::MaybeUninit::uninit();
176                    if from_glib(f(
177                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
178                        size.as_mut_ptr(),
179                    )) {
180                        Some(size.assume_init())
181                    } else {
182                        None
183                    }
184                })
185                .unwrap_or(None)
186        }
187    }
188
189    fn parent_times(
190        &self,
191        buffer: &gst::BufferRef,
192    ) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) {
193        unsafe {
194            let data = Self::type_data();
195            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
196            (*parent_class)
197                .get_times
198                .map(|f| {
199                    let mut start = mem::MaybeUninit::uninit();
200                    let mut stop = mem::MaybeUninit::uninit();
201                    f(
202                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
203                        buffer.as_mut_ptr(),
204                        start.as_mut_ptr(),
205                        stop.as_mut_ptr(),
206                    );
207                    (
208                        from_glib(start.assume_init()),
209                        from_glib(stop.assume_init()),
210                    )
211                })
212                .unwrap_or((gst::ClockTime::NONE, gst::ClockTime::NONE))
213        }
214    }
215
216    fn parent_fill(
217        &self,
218        offset: u64,
219        length: u32,
220        buffer: &mut gst::BufferRef,
221    ) -> Result<gst::FlowSuccess, gst::FlowError> {
222        unsafe {
223            let data = Self::type_data();
224            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
225            (*parent_class)
226                .fill
227                .map(|f| {
228                    try_from_glib(f(
229                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
230                        offset,
231                        length,
232                        buffer.as_mut_ptr(),
233                    ))
234                })
235                .unwrap_or(Err(gst::FlowError::NotSupported))
236        }
237    }
238
239    fn parent_alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> {
240        unsafe {
241            let data = Self::type_data();
242            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
243            (*parent_class)
244                .alloc
245                .map(|f| {
246                    let mut buffer_ptr: *mut gst::ffi::GstBuffer = ptr::null_mut();
247
248                    // FIXME: Wrong signature in -sys bindings
249                    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
250                    let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer;
251
252                    gst::FlowSuccess::try_from_glib(f(
253                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
254                        offset,
255                        length,
256                        buffer_ref,
257                    ))
258                    .map(|_| from_glib_full(buffer_ptr))
259                })
260                .unwrap_or(Err(gst::FlowError::NotSupported))
261        }
262    }
263
264    fn parent_create(
265        &self,
266        offset: u64,
267        mut buffer: Option<&mut gst::BufferRef>,
268        length: u32,
269    ) -> Result<CreateSuccess, gst::FlowError> {
270        unsafe {
271            let data = Self::type_data();
272            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
273            (*parent_class)
274                .create
275                .map(|f| {
276                    let instance = self.obj();
277                    let instance = instance.unsafe_cast_ref::<BaseSrc>();
278                    let orig_buffer_ptr = buffer
279                        .as_mut()
280                        .map(|b| b.as_mut_ptr())
281                        .unwrap_or(ptr::null_mut());
282                    let mut buffer_ptr = orig_buffer_ptr;
283
284                    // FIXME: Wrong signature in -sys bindings
285                    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
286                    let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer;
287
288                    let instance_data = self.instance_data::<InstanceData>(BaseSrc::static_type()).unwrap();
289
290                    if let Err(err) = gst::FlowSuccess::try_from_glib(
291                        f(
292                            instance.to_glib_none().0,
293                            offset,
294                            length,
295                            buffer_ref,
296                        )
297                    ) {
298                        *instance_data.pending_buffer_list.borrow_mut() = None;
299                        return Err(err);
300                    }
301
302                    let pending_buffer_list = instance_data.pending_buffer_list.borrow_mut().take();
303                    if pending_buffer_list.is_some() &&
304                        (buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull) {
305                        panic!("Buffer lists can only be returned in push mode");
306                    }
307
308                    if buffer_ptr.is_null() && pending_buffer_list.is_none() {
309                        gst::error!(
310                            gst::CAT_RUST,
311                            obj = instance,
312                            "No buffer and no buffer list returned"
313                        );
314                        return Err(gst::FlowError::Error);
315                    }
316
317                    if !buffer_ptr.is_null() && pending_buffer_list.is_some() {
318                        gst::error!(
319                            gst::CAT_RUST,
320                            obj = instance,
321                            "Both buffer and buffer list returned"
322                        );
323                        return Err(gst::FlowError::Error);
324                    }
325
326                    if let Some(passed_buffer) = buffer {
327                        if buffer_ptr != orig_buffer_ptr {
328                            let new_buffer = gst::Buffer::from_glib_full(buffer_ptr);
329
330                            gst::debug!(
331                                gst::CAT_PERFORMANCE,
332                                obj = instance,
333                                "Returned new buffer from parent create function, copying into passed buffer"
334                            );
335
336                            let mut map = match passed_buffer.map_writable() {
337                                Ok(map) => map,
338                                Err(_) => {
339                                    gst::error!(
340                                        gst::CAT_RUST,
341                                        obj = instance,
342                                        "Failed to map passed buffer writable"
343                                    );
344                                    return Err(gst::FlowError::Error);
345                                }
346                            };
347
348                            let copied_size = new_buffer.copy_to_slice(0, &mut map);
349                            drop(map);
350
351                            if let Err(copied_size) = copied_size {
352                                passed_buffer.set_size(copied_size);
353                            }
354
355                            match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) {
356                                Ok(_) => Ok(CreateSuccess::FilledBuffer),
357                                Err(_) => {
358                                    gst::error!(
359                                        gst::CAT_RUST,
360                                        obj = instance,
361                                        "Failed to copy buffer metadata"
362                                    );
363
364                                    Err(gst::FlowError::Error)
365                                }
366                            }
367                        } else {
368                            Ok(CreateSuccess::FilledBuffer)
369                        }
370                    } else if let Some(buffer_list) = pending_buffer_list {
371                        Ok(CreateSuccess::NewBufferList(buffer_list))
372                    } else {
373                        Ok(CreateSuccess::NewBuffer(from_glib_full(buffer_ptr)))
374                    }
375                })
376                .unwrap_or(Err(gst::FlowError::NotSupported))
377        }
378    }
379
380    fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool {
381        unsafe {
382            let data = Self::type_data();
383            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
384            (*parent_class)
385                .do_seek
386                .map(|f| {
387                    from_glib(f(
388                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
389                        segment.to_glib_none_mut().0,
390                    ))
391                })
392                .unwrap_or(false)
393        }
394    }
395
396    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
397        unsafe {
398            let data = Self::type_data();
399            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
400            (*parent_class)
401                .query
402                .map(|f| {
403                    from_glib(f(
404                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
405                        query.as_mut_ptr(),
406                    ))
407                })
408                .unwrap_or(false)
409        }
410    }
411
412    fn parent_event(&self, event: &gst::Event) -> bool {
413        unsafe {
414            let data = Self::type_data();
415            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
416            (*parent_class)
417                .event
418                .map(|f| {
419                    from_glib(f(
420                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
421                        event.to_glib_none().0,
422                    ))
423                })
424                .unwrap_or(false)
425        }
426    }
427
428    fn parent_caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> {
429        unsafe {
430            let data = Self::type_data();
431            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
432
433            (*parent_class)
434                .get_caps
435                .map(|f| {
436                    from_glib_full(f(
437                        self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
438                        filter.to_glib_none().0,
439                    ))
440                })
441                .unwrap_or(None)
442        }
443    }
444
445    fn parent_negotiate(&self) -> Result<(), gst::LoggableError> {
446        unsafe {
447            let data = Self::type_data();
448            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
449            (*parent_class)
450                .negotiate
451                .map(|f| {
452                    gst::result_from_gboolean!(
453                        f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0),
454                        gst::CAT_RUST,
455                        "Parent function `negotiate` failed"
456                    )
457                })
458                .unwrap_or(Ok(()))
459        }
460    }
461
462    fn parent_set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
463        unsafe {
464            let data = Self::type_data();
465            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
466            (*parent_class)
467                .set_caps
468                .map(|f| {
469                    gst::result_from_gboolean!(
470                        f(
471                            self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
472                            caps.to_glib_none().0
473                        ),
474                        gst::CAT_RUST,
475                        "Parent function `set_caps` failed"
476                    )
477                })
478                .unwrap_or(Ok(()))
479        }
480    }
481
482    fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps {
483        unsafe {
484            let data = Self::type_data();
485            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
486
487            match (*parent_class).fixate {
488                Some(fixate) => from_glib_full(fixate(
489                    self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
490                    caps.into_glib_ptr(),
491                )),
492                None => caps,
493            }
494        }
495    }
496
497    fn parent_unlock(&self) -> Result<(), gst::ErrorMessage> {
498        unsafe {
499            let data = Self::type_data();
500            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
501            (*parent_class)
502                .unlock
503                .map(|f| {
504                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) {
505                        Ok(())
506                    } else {
507                        Err(gst::error_msg!(
508                            gst::CoreError::Failed,
509                            ["Parent function `unlock` failed"]
510                        ))
511                    }
512                })
513                .unwrap_or(Ok(()))
514        }
515    }
516
517    fn parent_unlock_stop(&self) -> Result<(), gst::ErrorMessage> {
518        unsafe {
519            let data = Self::type_data();
520            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
521            (*parent_class)
522                .unlock_stop
523                .map(|f| {
524                    if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) {
525                        Ok(())
526                    } else {
527                        Err(gst::error_msg!(
528                            gst::CoreError::Failed,
529                            ["Parent function `unlock_stop` failed"]
530                        ))
531                    }
532                })
533                .unwrap_or(Ok(()))
534        }
535    }
536
537    fn parent_decide_allocation(
538        &self,
539        query: &mut gst::query::Allocation,
540    ) -> Result<(), gst::LoggableError> {
541        unsafe {
542            let data = Self::type_data();
543            let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass;
544            (*parent_class)
545                .decide_allocation
546                .map(|f| {
547                    gst::result_from_gboolean!(
548                        f(
549                            self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0,
550                            query.as_mut_ptr(),
551                        ),
552                        gst::CAT_RUST,
553                        "Parent function `decide_allocation` failed",
554                    )
555                })
556                .unwrap_or(Ok(()))
557        }
558    }
559}
560
561impl<T: BaseSrcImpl> BaseSrcImplExt for T {}
562
563unsafe impl<T: BaseSrcImpl> IsSubclassable<T> for BaseSrc {
564    fn class_init(klass: &mut glib::Class<Self>) {
565        Self::parent_class_init::<T>(klass);
566        let klass = klass.as_mut();
567        klass.start = Some(base_src_start::<T>);
568        klass.stop = Some(base_src_stop::<T>);
569        klass.is_seekable = Some(base_src_is_seekable::<T>);
570        klass.get_size = Some(base_src_get_size::<T>);
571        klass.get_times = Some(base_src_get_times::<T>);
572        klass.fill = Some(base_src_fill::<T>);
573        klass.alloc = Some(base_src_alloc::<T>);
574        klass.create = Some(base_src_create::<T>);
575        klass.do_seek = Some(base_src_do_seek::<T>);
576        klass.query = Some(base_src_query::<T>);
577        klass.event = Some(base_src_event::<T>);
578        klass.get_caps = Some(base_src_get_caps::<T>);
579        klass.negotiate = Some(base_src_negotiate::<T>);
580        klass.set_caps = Some(base_src_set_caps::<T>);
581        klass.fixate = Some(base_src_fixate::<T>);
582        klass.unlock = Some(base_src_unlock::<T>);
583        klass.unlock_stop = Some(base_src_unlock_stop::<T>);
584        klass.decide_allocation = Some(base_src_decide_allocation::<T>);
585    }
586
587    fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) {
588        Self::parent_instance_init(instance);
589
590        instance.set_instance_data(BaseSrc::static_type(), InstanceData::default());
591    }
592}
593
594unsafe extern "C" fn base_src_start<T: BaseSrcImpl>(
595    ptr: *mut ffi::GstBaseSrc,
596) -> glib::ffi::gboolean {
597    let instance = &*(ptr as *mut T::Instance);
598    let imp = instance.imp();
599
600    gst::panic_to_error!(imp, false, {
601        match imp.start() {
602            Ok(()) => true,
603            Err(err) => {
604                imp.post_error_message(err);
605                false
606            }
607        }
608    })
609    .into_glib()
610}
611
612unsafe extern "C" fn base_src_stop<T: BaseSrcImpl>(
613    ptr: *mut ffi::GstBaseSrc,
614) -> glib::ffi::gboolean {
615    let instance = &*(ptr as *mut T::Instance);
616    let imp = instance.imp();
617
618    gst::panic_to_error!(imp, false, {
619        match imp.stop() {
620            Ok(()) => true,
621            Err(err) => {
622                imp.post_error_message(err);
623                false
624            }
625        }
626    })
627    .into_glib()
628}
629
630unsafe extern "C" fn base_src_is_seekable<T: BaseSrcImpl>(
631    ptr: *mut ffi::GstBaseSrc,
632) -> glib::ffi::gboolean {
633    let instance = &*(ptr as *mut T::Instance);
634    let imp = instance.imp();
635
636    gst::panic_to_error!(imp, false, { imp.is_seekable() }).into_glib()
637}
638
639unsafe extern "C" fn base_src_get_size<T: BaseSrcImpl>(
640    ptr: *mut ffi::GstBaseSrc,
641    size: *mut u64,
642) -> glib::ffi::gboolean {
643    let instance = &*(ptr as *mut T::Instance);
644    let imp = instance.imp();
645
646    gst::panic_to_error!(imp, false, {
647        match imp.size() {
648            Some(s) => {
649                *size = s;
650                true
651            }
652            None => false,
653        }
654    })
655    .into_glib()
656}
657
658unsafe extern "C" fn base_src_get_times<T: BaseSrcImpl>(
659    ptr: *mut ffi::GstBaseSrc,
660    buffer: *mut gst::ffi::GstBuffer,
661    start: *mut gst::ffi::GstClockTime,
662    stop: *mut gst::ffi::GstClockTime,
663) {
664    let instance = &*(ptr as *mut T::Instance);
665    let imp = instance.imp();
666    let buffer = gst::BufferRef::from_ptr(buffer);
667
668    *start = gst::ffi::GST_CLOCK_TIME_NONE;
669    *stop = gst::ffi::GST_CLOCK_TIME_NONE;
670
671    gst::panic_to_error!(imp, (), {
672        let (start_, stop_) = imp.times(buffer);
673        *start = start_.into_glib();
674        *stop = stop_.into_glib();
675    });
676}
677
678unsafe extern "C" fn base_src_fill<T: BaseSrcImpl>(
679    ptr: *mut ffi::GstBaseSrc,
680    offset: u64,
681    length: u32,
682    buffer: *mut gst::ffi::GstBuffer,
683) -> gst::ffi::GstFlowReturn {
684    let instance = &*(ptr as *mut T::Instance);
685    let imp = instance.imp();
686    let buffer = gst::BufferRef::from_mut_ptr(buffer);
687
688    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
689        imp.fill(offset, length, buffer).into()
690    })
691    .into_glib()
692}
693
694unsafe extern "C" fn base_src_alloc<T: BaseSrcImpl>(
695    ptr: *mut ffi::GstBaseSrc,
696    offset: u64,
697    length: u32,
698    buffer_ptr: *mut gst::ffi::GstBuffer,
699) -> gst::ffi::GstFlowReturn {
700    let instance = &*(ptr as *mut T::Instance);
701    let imp = instance.imp();
702    // FIXME: Wrong signature in -sys bindings
703    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
704    let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
705
706    gst::panic_to_error!(imp, gst::FlowReturn::Error, {
707        match imp.alloc(offset, length) {
708            Ok(buffer) => {
709                *buffer_ptr = buffer.into_glib_ptr();
710                gst::FlowReturn::Ok
711            }
712            Err(err) => gst::FlowReturn::from(err),
713        }
714    })
715    .into_glib()
716}
717
718#[allow(clippy::needless_option_as_deref)]
719unsafe extern "C" fn base_src_create<T: BaseSrcImpl>(
720    ptr: *mut ffi::GstBaseSrc,
721    offset: u64,
722    length: u32,
723    buffer_ptr: *mut gst::ffi::GstBuffer,
724) -> gst::ffi::GstFlowReturn {
725    let instance = &*(ptr as *mut T::Instance);
726    let imp = instance.imp();
727    let instance = imp.obj();
728    let instance = instance.unsafe_cast_ref::<BaseSrc>();
729    // FIXME: Wrong signature in -sys bindings
730    // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
731    let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
732
733    let mut buffer = if (*buffer_ptr).is_null() {
734        None
735    } else {
736        Some(gst::BufferRef::from_mut_ptr(*buffer_ptr))
737    };
738
739    let instance_data = imp
740        .instance_data::<InstanceData>(BaseSrc::static_type())
741        .unwrap();
742
743    // If there is a pending buffer list at this point then unset it.
744    if instance.type_() == T::Type::static_type() {
745        *instance_data.pending_buffer_list.borrow_mut() = None;
746    }
747
748    let res = gst::panic_to_error!(imp, gst::FlowReturn::Error, {
749        match imp.create(offset, buffer.as_deref_mut(), length) {
750            Ok(CreateSuccess::NewBuffer(new_buffer)) => {
751                if let Some(passed_buffer) = buffer {
752                    if passed_buffer.as_ptr() != new_buffer.as_ptr() {
753                        gst::debug!(
754                            gst::CAT_PERFORMANCE,
755                            obj = instance,
756                            "Returned new buffer from create function, copying into passed buffer"
757                        );
758
759                        let mut map = match passed_buffer.map_writable() {
760                            Ok(map) => map,
761                            Err(_) => {
762                                gst::error!(
763                                    gst::CAT_RUST,
764                                    obj = instance,
765                                    "Failed to map passed buffer writable"
766                                );
767                                return gst::FlowReturn::Error;
768                            }
769                        };
770
771                        let copied_size = new_buffer.copy_to_slice(0, &mut map);
772                        drop(map);
773
774                        if let Err(copied_size) = copied_size {
775                            passed_buffer.set_size(copied_size);
776                        }
777
778                        match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) {
779                            Ok(_) => gst::FlowReturn::Ok,
780                            Err(_) => {
781                                gst::error!(
782                                    gst::CAT_RUST,
783                                    obj = instance,
784                                    "Failed to copy buffer metadata"
785                                );
786
787                                gst::FlowReturn::Error
788                            }
789                        }
790                    } else {
791                        gst::FlowReturn::Ok
792                    }
793                } else {
794                    *buffer_ptr = new_buffer.into_glib_ptr();
795                    gst::FlowReturn::Ok
796                }
797            }
798            Ok(CreateSuccess::NewBufferList(new_buffer_list)) => {
799                if buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull {
800                    panic!("Buffer lists can only be returned in push mode");
801                }
802
803                *buffer_ptr = ptr::null_mut();
804
805                // If this is the final type then submit the buffer list. This can only be done
806                // once so can only really be done here.
807                // FIXME: This won't work if a non-Rust subclass of a Rust subclass is created.
808                if instance.type_() == T::Type::static_type() {
809                    ffi::gst_base_src_submit_buffer_list(
810                        instance.to_glib_none().0,
811                        new_buffer_list.into_glib_ptr(),
812                    );
813                } else {
814                    *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list);
815                }
816
817                gst::FlowReturn::Ok
818            }
819            Ok(CreateSuccess::FilledBuffer) => gst::FlowReturn::Ok,
820            Err(err) => gst::FlowReturn::from(err),
821        }
822    })
823    .into_glib();
824
825    // If there is a pending buffer list at this point then unset it.
826    if instance.type_() == T::Type::static_type() {
827        *instance_data.pending_buffer_list.borrow_mut() = None;
828    }
829
830    res
831}
832
833unsafe extern "C" fn base_src_do_seek<T: BaseSrcImpl>(
834    ptr: *mut ffi::GstBaseSrc,
835    segment: *mut gst::ffi::GstSegment,
836) -> glib::ffi::gboolean {
837    let instance = &*(ptr as *mut T::Instance);
838    let imp = instance.imp();
839
840    gst::panic_to_error!(imp, false, {
841        let mut s = from_glib_none(segment);
842        let res = imp.do_seek(&mut s);
843        ptr::write(segment, *(s.to_glib_none().0));
844
845        res
846    })
847    .into_glib()
848}
849
850unsafe extern "C" fn base_src_query<T: BaseSrcImpl>(
851    ptr: *mut ffi::GstBaseSrc,
852    query_ptr: *mut gst::ffi::GstQuery,
853) -> glib::ffi::gboolean {
854    let instance = &*(ptr as *mut T::Instance);
855    let imp = instance.imp();
856    let query = gst::QueryRef::from_mut_ptr(query_ptr);
857
858    gst::panic_to_error!(imp, false, { BaseSrcImpl::query(imp, query) }).into_glib()
859}
860
861unsafe extern "C" fn base_src_event<T: BaseSrcImpl>(
862    ptr: *mut ffi::GstBaseSrc,
863    event_ptr: *mut gst::ffi::GstEvent,
864) -> glib::ffi::gboolean {
865    let instance = &*(ptr as *mut T::Instance);
866    let imp = instance.imp();
867
868    gst::panic_to_error!(imp, false, { imp.event(&from_glib_borrow(event_ptr)) }).into_glib()
869}
870
871unsafe extern "C" fn base_src_get_caps<T: BaseSrcImpl>(
872    ptr: *mut ffi::GstBaseSrc,
873    filter: *mut gst::ffi::GstCaps,
874) -> *mut gst::ffi::GstCaps {
875    let instance = &*(ptr as *mut T::Instance);
876    let imp = instance.imp();
877    let filter = Option::<gst::Caps>::from_glib_borrow(filter);
878
879    gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) })
880        .map(|caps| caps.into_glib_ptr())
881        .unwrap_or(ptr::null_mut())
882}
883
884unsafe extern "C" fn base_src_negotiate<T: BaseSrcImpl>(
885    ptr: *mut ffi::GstBaseSrc,
886) -> glib::ffi::gboolean {
887    let instance = &*(ptr as *mut T::Instance);
888    let imp = instance.imp();
889
890    gst::panic_to_error!(imp, false, {
891        match imp.negotiate() {
892            Ok(()) => true,
893            Err(err) => {
894                err.log_with_imp(imp);
895                false
896            }
897        }
898    })
899    .into_glib()
900}
901
902unsafe extern "C" fn base_src_set_caps<T: BaseSrcImpl>(
903    ptr: *mut ffi::GstBaseSrc,
904    caps: *mut gst::ffi::GstCaps,
905) -> glib::ffi::gboolean {
906    let instance = &*(ptr as *mut T::Instance);
907    let imp = instance.imp();
908    let caps = from_glib_borrow(caps);
909
910    gst::panic_to_error!(imp, false, {
911        match imp.set_caps(&caps) {
912            Ok(()) => true,
913            Err(err) => {
914                err.log_with_imp(imp);
915                false
916            }
917        }
918    })
919    .into_glib()
920}
921
922unsafe extern "C" fn base_src_fixate<T: BaseSrcImpl>(
923    ptr: *mut ffi::GstBaseSrc,
924    caps: *mut gst::ffi::GstCaps,
925) -> *mut gst::ffi::GstCaps {
926    let instance = &*(ptr as *mut T::Instance);
927    let imp = instance.imp();
928    let caps = from_glib_full(caps);
929
930    gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr()
931}
932
933unsafe extern "C" fn base_src_unlock<T: BaseSrcImpl>(
934    ptr: *mut ffi::GstBaseSrc,
935) -> glib::ffi::gboolean {
936    let instance = &*(ptr as *mut T::Instance);
937    let imp = instance.imp();
938
939    gst::panic_to_error!(imp, false, {
940        match imp.unlock() {
941            Ok(()) => true,
942            Err(err) => {
943                imp.post_error_message(err);
944                false
945            }
946        }
947    })
948    .into_glib()
949}
950
951unsafe extern "C" fn base_src_unlock_stop<T: BaseSrcImpl>(
952    ptr: *mut ffi::GstBaseSrc,
953) -> glib::ffi::gboolean {
954    let instance = &*(ptr as *mut T::Instance);
955    let imp = instance.imp();
956
957    gst::panic_to_error!(imp, false, {
958        match imp.unlock_stop() {
959            Ok(()) => true,
960            Err(err) => {
961                imp.post_error_message(err);
962                false
963            }
964        }
965    })
966    .into_glib()
967}
968
969unsafe extern "C" fn base_src_decide_allocation<T: BaseSrcImpl>(
970    ptr: *mut ffi::GstBaseSrc,
971    query: *mut gst::ffi::GstQuery,
972) -> glib::ffi::gboolean {
973    let instance = &*(ptr as *mut T::Instance);
974    let imp = instance.imp();
975    let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
976        gst::QueryViewMut::Allocation(allocation) => allocation,
977        _ => unreachable!(),
978    };
979
980    gst::panic_to_error!(imp, false, {
981        match imp.decide_allocation(query) {
982            Ok(()) => true,
983            Err(err) => {
984                err.log_with_imp(imp);
985                false
986            }
987        }
988    })
989    .into_glib()
990}