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