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