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