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