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