gstreamer_base/subclass/
base_src.rs

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