Skip to main content

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::{BaseSrc, ffi, prelude::*};
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    unsafe {
593        let instance = &*(ptr as *mut T::Instance);
594        let imp = instance.imp();
595
596        gst::panic_to_error!(imp, false, {
597            match imp.start() {
598                Ok(()) => true,
599                Err(err) => {
600                    imp.post_error_message(err);
601                    false
602                }
603            }
604        })
605        .into_glib()
606    }
607}
608
609unsafe extern "C" fn base_src_stop<T: BaseSrcImpl>(
610    ptr: *mut ffi::GstBaseSrc,
611) -> glib::ffi::gboolean {
612    unsafe {
613        let instance = &*(ptr as *mut T::Instance);
614        let imp = instance.imp();
615
616        gst::panic_to_error!(imp, false, {
617            match imp.stop() {
618                Ok(()) => true,
619                Err(err) => {
620                    imp.post_error_message(err);
621                    false
622                }
623            }
624        })
625        .into_glib()
626    }
627}
628
629unsafe extern "C" fn base_src_is_seekable<T: BaseSrcImpl>(
630    ptr: *mut ffi::GstBaseSrc,
631) -> glib::ffi::gboolean {
632    unsafe {
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}
639
640unsafe extern "C" fn base_src_get_size<T: BaseSrcImpl>(
641    ptr: *mut ffi::GstBaseSrc,
642    size: *mut u64,
643) -> glib::ffi::gboolean {
644    unsafe {
645        let instance = &*(ptr as *mut T::Instance);
646        let imp = instance.imp();
647
648        gst::panic_to_error!(imp, false, {
649            match imp.size() {
650                Some(s) => {
651                    *size = s;
652                    true
653                }
654                None => false,
655            }
656        })
657        .into_glib()
658    }
659}
660
661unsafe extern "C" fn base_src_get_times<T: BaseSrcImpl>(
662    ptr: *mut ffi::GstBaseSrc,
663    buffer: *mut gst::ffi::GstBuffer,
664    start: *mut gst::ffi::GstClockTime,
665    stop: *mut gst::ffi::GstClockTime,
666) {
667    unsafe {
668        let instance = &*(ptr as *mut T::Instance);
669        let imp = instance.imp();
670        let buffer = gst::BufferRef::from_ptr(buffer);
671
672        *start = gst::ffi::GST_CLOCK_TIME_NONE;
673        *stop = gst::ffi::GST_CLOCK_TIME_NONE;
674
675        gst::panic_to_error!(imp, (), {
676            let (start_, stop_) = imp.times(buffer);
677            *start = start_.into_glib();
678            *stop = stop_.into_glib();
679        });
680    }
681}
682
683unsafe extern "C" fn base_src_fill<T: BaseSrcImpl>(
684    ptr: *mut ffi::GstBaseSrc,
685    offset: u64,
686    length: u32,
687    buffer: *mut gst::ffi::GstBuffer,
688) -> gst::ffi::GstFlowReturn {
689    unsafe {
690        let instance = &*(ptr as *mut T::Instance);
691        let imp = instance.imp();
692        let buffer = gst::BufferRef::from_mut_ptr(buffer);
693
694        gst::panic_to_error!(imp, gst::FlowReturn::Error, {
695            imp.fill(offset, length, buffer).into()
696        })
697        .into_glib()
698    }
699}
700
701unsafe extern "C" fn base_src_alloc<T: BaseSrcImpl>(
702    ptr: *mut ffi::GstBaseSrc,
703    offset: u64,
704    length: u32,
705    buffer_ptr: *mut gst::ffi::GstBuffer,
706) -> gst::ffi::GstFlowReturn {
707    unsafe {
708        let instance = &*(ptr as *mut T::Instance);
709        let imp = instance.imp();
710        // FIXME: Wrong signature in -sys bindings
711        // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
712        let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
713
714        gst::panic_to_error!(imp, gst::FlowReturn::Error, {
715            match imp.alloc(offset, length) {
716                Ok(buffer) => {
717                    *buffer_ptr = buffer.into_glib_ptr();
718                    gst::FlowReturn::Ok
719                }
720                Err(err) => gst::FlowReturn::from(err),
721            }
722        })
723        .into_glib()
724    }
725}
726
727#[allow(clippy::needless_option_as_deref)]
728unsafe extern "C" fn base_src_create<T: BaseSrcImpl>(
729    ptr: *mut ffi::GstBaseSrc,
730    offset: u64,
731    length: u32,
732    buffer_ptr: *mut gst::ffi::GstBuffer,
733) -> gst::ffi::GstFlowReturn {
734    unsafe {
735        let instance = &*(ptr as *mut T::Instance);
736        let imp = instance.imp();
737        let instance = imp.obj();
738        let instance = instance.unsafe_cast_ref::<BaseSrc>();
739        // FIXME: Wrong signature in -sys bindings
740        // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
741        let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer;
742
743        let mut buffer = if (*buffer_ptr).is_null() {
744            None
745        } else {
746            Some(gst::BufferRef::from_mut_ptr(*buffer_ptr))
747        };
748
749        let instance_data = imp
750            .instance_data::<InstanceData>(BaseSrc::static_type())
751            .unwrap();
752
753        // If there is a pending buffer list at this point then unset it.
754        if instance.type_() == T::Type::static_type() {
755            *instance_data.pending_buffer_list.borrow_mut() = None;
756        }
757
758        let res = gst::panic_to_error!(imp, gst::FlowReturn::Error, {
759            match imp.create(offset, buffer.as_deref_mut(), length) {
760                Ok(CreateSuccess::NewBuffer(new_buffer)) => {
761                    if let Some(passed_buffer) = buffer {
762                        if passed_buffer.as_ptr() != new_buffer.as_ptr() {
763                            gst::debug!(
764                            gst::CAT_PERFORMANCE,
765                            obj = instance,
766                            "Returned new buffer from create function, copying into passed buffer"
767                        );
768
769                            let mut map = match passed_buffer.map_writable() {
770                                Ok(map) => map,
771                                Err(_) => {
772                                    gst::error!(
773                                        gst::CAT_RUST,
774                                        obj = instance,
775                                        "Failed to map passed buffer writable"
776                                    );
777                                    return gst::FlowReturn::Error;
778                                }
779                            };
780
781                            let copied_size = new_buffer.copy_to_slice(0, &mut map);
782                            drop(map);
783
784                            if let Err(copied_size) = copied_size {
785                                passed_buffer.set_size(copied_size);
786                            }
787
788                            match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..)
789                            {
790                                Ok(_) => gst::FlowReturn::Ok,
791                                Err(_) => {
792                                    gst::error!(
793                                        gst::CAT_RUST,
794                                        obj = instance,
795                                        "Failed to copy buffer metadata"
796                                    );
797
798                                    gst::FlowReturn::Error
799                                }
800                            }
801                        } else {
802                            gst::FlowReturn::Ok
803                        }
804                    } else {
805                        *buffer_ptr = new_buffer.into_glib_ptr();
806                        gst::FlowReturn::Ok
807                    }
808                }
809                Ok(CreateSuccess::NewBufferList(new_buffer_list)) => {
810                    if buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull {
811                        panic!("Buffer lists can only be returned in push mode");
812                    }
813
814                    *buffer_ptr = ptr::null_mut();
815
816                    // If this is the final type then submit the buffer list. This can only be done
817                    // once so can only really be done here.
818                    // FIXME: This won't work if a non-Rust subclass of a Rust subclass is created.
819                    if instance.type_() == T::Type::static_type() {
820                        ffi::gst_base_src_submit_buffer_list(
821                            instance.to_glib_none().0,
822                            new_buffer_list.into_glib_ptr(),
823                        );
824                    } else {
825                        *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list);
826                    }
827
828                    gst::FlowReturn::Ok
829                }
830                Ok(CreateSuccess::FilledBuffer) => gst::FlowReturn::Ok,
831                Err(err) => gst::FlowReturn::from(err),
832            }
833        })
834        .into_glib();
835
836        // If there is a pending buffer list at this point then unset it.
837        if instance.type_() == T::Type::static_type() {
838            *instance_data.pending_buffer_list.borrow_mut() = None;
839        }
840
841        res
842    }
843}
844
845unsafe extern "C" fn base_src_do_seek<T: BaseSrcImpl>(
846    ptr: *mut ffi::GstBaseSrc,
847    segment: *mut gst::ffi::GstSegment,
848) -> glib::ffi::gboolean {
849    unsafe {
850        let instance = &*(ptr as *mut T::Instance);
851        let imp = instance.imp();
852
853        gst::panic_to_error!(imp, false, {
854            let mut s = from_glib_none(segment);
855            let res = imp.do_seek(&mut s);
856            ptr::write(segment, *(s.to_glib_none().0));
857
858            res
859        })
860        .into_glib()
861    }
862}
863
864unsafe extern "C" fn base_src_query<T: BaseSrcImpl>(
865    ptr: *mut ffi::GstBaseSrc,
866    query_ptr: *mut gst::ffi::GstQuery,
867) -> glib::ffi::gboolean {
868    unsafe {
869        let instance = &*(ptr as *mut T::Instance);
870        let imp = instance.imp();
871        let query = gst::QueryRef::from_mut_ptr(query_ptr);
872
873        gst::panic_to_error!(imp, false, { BaseSrcImpl::query(imp, query) }).into_glib()
874    }
875}
876
877unsafe extern "C" fn base_src_event<T: BaseSrcImpl>(
878    ptr: *mut ffi::GstBaseSrc,
879    event_ptr: *mut gst::ffi::GstEvent,
880) -> glib::ffi::gboolean {
881    unsafe {
882        let instance = &*(ptr as *mut T::Instance);
883        let imp = instance.imp();
884
885        gst::panic_to_error!(imp, false, { imp.event(&from_glib_borrow(event_ptr)) }).into_glib()
886    }
887}
888
889unsafe extern "C" fn base_src_get_caps<T: BaseSrcImpl>(
890    ptr: *mut ffi::GstBaseSrc,
891    filter: *mut gst::ffi::GstCaps,
892) -> *mut gst::ffi::GstCaps {
893    unsafe {
894        let instance = &*(ptr as *mut T::Instance);
895        let imp = instance.imp();
896        let filter = Option::<gst::Caps>::from_glib_borrow(filter);
897
898        gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) })
899            .map(|caps| caps.into_glib_ptr())
900            .unwrap_or(ptr::null_mut())
901    }
902}
903
904unsafe extern "C" fn base_src_negotiate<T: BaseSrcImpl>(
905    ptr: *mut ffi::GstBaseSrc,
906) -> glib::ffi::gboolean {
907    unsafe {
908        let instance = &*(ptr as *mut T::Instance);
909        let imp = instance.imp();
910
911        gst::panic_to_error!(imp, false, {
912            match imp.negotiate() {
913                Ok(()) => true,
914                Err(err) => {
915                    err.log_with_imp(imp);
916                    false
917                }
918            }
919        })
920        .into_glib()
921    }
922}
923
924unsafe extern "C" fn base_src_set_caps<T: BaseSrcImpl>(
925    ptr: *mut ffi::GstBaseSrc,
926    caps: *mut gst::ffi::GstCaps,
927) -> glib::ffi::gboolean {
928    unsafe {
929        let instance = &*(ptr as *mut T::Instance);
930        let imp = instance.imp();
931        let caps = from_glib_borrow(caps);
932
933        gst::panic_to_error!(imp, false, {
934            match imp.set_caps(&caps) {
935                Ok(()) => true,
936                Err(err) => {
937                    err.log_with_imp(imp);
938                    false
939                }
940            }
941        })
942        .into_glib()
943    }
944}
945
946unsafe extern "C" fn base_src_fixate<T: BaseSrcImpl>(
947    ptr: *mut ffi::GstBaseSrc,
948    caps: *mut gst::ffi::GstCaps,
949) -> *mut gst::ffi::GstCaps {
950    unsafe {
951        let instance = &*(ptr as *mut T::Instance);
952        let imp = instance.imp();
953        let caps = from_glib_full(caps);
954
955        gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr()
956    }
957}
958
959unsafe extern "C" fn base_src_unlock<T: BaseSrcImpl>(
960    ptr: *mut ffi::GstBaseSrc,
961) -> glib::ffi::gboolean {
962    unsafe {
963        let instance = &*(ptr as *mut T::Instance);
964        let imp = instance.imp();
965
966        gst::panic_to_error!(imp, false, {
967            match imp.unlock() {
968                Ok(()) => true,
969                Err(err) => {
970                    imp.post_error_message(err);
971                    false
972                }
973            }
974        })
975        .into_glib()
976    }
977}
978
979unsafe extern "C" fn base_src_unlock_stop<T: BaseSrcImpl>(
980    ptr: *mut ffi::GstBaseSrc,
981) -> glib::ffi::gboolean {
982    unsafe {
983        let instance = &*(ptr as *mut T::Instance);
984        let imp = instance.imp();
985
986        gst::panic_to_error!(imp, false, {
987            match imp.unlock_stop() {
988                Ok(()) => true,
989                Err(err) => {
990                    imp.post_error_message(err);
991                    false
992                }
993            }
994        })
995        .into_glib()
996    }
997}
998
999unsafe extern "C" fn base_src_decide_allocation<T: BaseSrcImpl>(
1000    ptr: *mut ffi::GstBaseSrc,
1001    query: *mut gst::ffi::GstQuery,
1002) -> glib::ffi::gboolean {
1003    unsafe {
1004        let instance = &*(ptr as *mut T::Instance);
1005        let imp = instance.imp();
1006        let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
1007            gst::QueryViewMut::Allocation(allocation) => allocation,
1008            _ => unreachable!(),
1009        };
1010
1011        gst::panic_to_error!(imp, false, {
1012            match imp.decide_allocation(query) {
1013                Ok(()) => true,
1014                Err(err) => {
1015                    err.log_with_imp(imp);
1016                    false
1017                }
1018            }
1019        })
1020        .into_glib()
1021    }
1022}