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