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