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