1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4 mem,
5 num::NonZeroU64,
6 ops::ControlFlow,
7 panic::{self, AssertUnwindSafe},
8 ptr,
9};
10
11use glib::{ffi::gpointer, prelude::*, translate::*};
12
13use crate::{
14 format::{FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic},
15 prelude::*,
16 Buffer, BufferList, Event, FlowError, FlowReturn, FlowSuccess, Format, GenericFormattedValue,
17 LoggableError, Pad, PadFlags, PadProbeReturn, PadProbeType, Query, QueryRef, StaticPadTemplate,
18};
19
20#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
21pub struct PadProbeId(NonZeroU64);
22
23impl IntoGlib for PadProbeId {
24 type GlibType = libc::c_ulong;
25
26 #[inline]
27 fn into_glib(self) -> libc::c_ulong {
28 self.0.get() as libc::c_ulong
29 }
30}
31
32impl FromGlib<libc::c_ulong> for PadProbeId {
33 #[inline]
34 unsafe fn from_glib(val: libc::c_ulong) -> PadProbeId {
35 skip_assert_initialized!();
36 debug_assert_ne!(val, 0);
37 PadProbeId(NonZeroU64::new_unchecked(val as _))
38 }
39}
40
41impl PadProbeId {
42 #[inline]
43 pub fn as_raw(&self) -> libc::c_ulong {
44 self.0.get() as libc::c_ulong
45 }
46}
47
48#[doc(alias = "GstPadProbeInfo")]
49#[derive(Debug)]
50pub struct PadProbeInfo<'a> {
51 pub mask: PadProbeType,
52 pub id: Option<PadProbeId>,
53 pub offset: u64,
54 pub size: u32,
55 pub data: Option<PadProbeData<'a>>,
56 pub flow_res: Result<FlowSuccess, FlowError>,
57}
58
59impl<'a> PadProbeInfo<'a> {
60 pub fn buffer(&self) -> Option<&Buffer> {
61 match self.data {
62 Some(PadProbeData::Buffer(ref buffer)) => Some(buffer),
63 _ => None,
64 }
65 }
66
67 pub fn buffer_mut(&mut self) -> Option<&mut Buffer> {
68 match self.data {
69 Some(PadProbeData::Buffer(ref mut buffer)) => Some(buffer),
70 _ => None,
71 }
72 }
73
74 pub fn buffer_list(&self) -> Option<&BufferList> {
75 match self.data {
76 Some(PadProbeData::BufferList(ref buffer_list)) => Some(buffer_list),
77 _ => None,
78 }
79 }
80
81 pub fn buffer_list_mut(&mut self) -> Option<&mut BufferList> {
82 match self.data {
83 Some(PadProbeData::BufferList(ref mut buffer_list)) => Some(buffer_list),
84 _ => None,
85 }
86 }
87
88 pub fn query(&self) -> Option<&QueryRef> {
89 match self.data {
90 Some(PadProbeData::Query(ref query)) => Some(*query),
91 _ => None,
92 }
93 }
94
95 pub fn query_mut(&mut self) -> Option<&mut QueryRef> {
96 match self.data {
97 Some(PadProbeData::Query(ref mut query)) => Some(*query),
98 _ => None,
99 }
100 }
101
102 pub fn event(&self) -> Option<&Event> {
103 match self.data {
104 Some(PadProbeData::Event(ref event)) => Some(event),
105 _ => None,
106 }
107 }
108
109 pub fn event_mut(&mut self) -> Option<&mut Event> {
110 match self.data {
111 Some(PadProbeData::Event(ref mut event)) => Some(event),
112 _ => None,
113 }
114 }
115}
116
117#[derive(Debug)]
118pub enum PadProbeData<'a> {
119 Buffer(Buffer),
120 BufferList(BufferList),
121 Query(&'a mut QueryRef),
122 Event(Event),
123 #[doc(hidden)]
124 __Unknown(*mut ffi::GstMiniObject),
125}
126
127unsafe impl<'a> Send for PadProbeData<'a> {}
128unsafe impl<'a> Sync for PadProbeData<'a> {}
129
130#[derive(Debug)]
131#[must_use = "if unused the StreamLock will immediately unlock"]
132pub struct StreamLock<'a>(&'a Pad);
133impl<'a> Drop for StreamLock<'a> {
134 #[inline]
135 fn drop(&mut self) {
136 unsafe {
137 let pad: *mut ffi::GstPad = self.0.to_glib_none().0;
138 glib::ffi::g_rec_mutex_unlock(&mut (*pad).stream_rec_lock);
139 }
140 }
141}
142
143#[derive(Debug)]
144pub enum PadGetRangeSuccess {
145 FilledBuffer,
146 NewBuffer(crate::Buffer),
147}
148
149#[derive(Debug)]
150pub enum EventForeachAction {
151 Keep,
152 Remove,
153 Replace(Event),
154}
155
156mod sealed {
157 pub trait Sealed {}
158 impl<T: super::IsA<super::Pad>> Sealed for T {}
159}
160
161pub trait PadExtManual: sealed::Sealed + IsA<Pad> + 'static {
162 #[doc(alias = "gst_pad_add_probe")]
163 fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
164 where
165 F: Fn(&Self, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
166 {
167 unsafe {
168 let func_box: Box<F> = Box::new(func);
169 let id = ffi::gst_pad_add_probe(
170 self.as_ref().to_glib_none().0,
171 mask.into_glib(),
172 Some(trampoline_pad_probe::<Self, F>),
173 Box::into_raw(func_box) as gpointer,
174 Some(destroy_closure::<F>),
175 );
176
177 if id == 0 {
178 None
179 } else {
180 Some(from_glib(id))
181 }
182 }
183 }
184
185 #[doc(alias = "gst_pad_remove_probe")]
186 fn remove_probe(&self, id: PadProbeId) {
187 unsafe {
188 ffi::gst_pad_remove_probe(self.as_ref().to_glib_none().0, id.into_glib());
189 }
190 }
191
192 #[doc(alias = "gst_pad_pull_range")]
193 fn pull_range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
194 unsafe {
195 let mut buffer = ptr::null_mut();
196 FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
197 self.as_ref().to_glib_none().0,
198 offset,
199 size,
200 &mut buffer,
201 ))
202 .map(|_| from_glib_full(buffer))
203 }
204 }
205
206 fn pull_range_fill(
207 &self,
208 offset: u64,
209 buffer: &mut crate::BufferRef,
210 size: u32,
211 ) -> Result<(), FlowError> {
212 assert!(buffer.size() >= size as usize);
213
214 unsafe {
215 let mut buffer_ref = buffer.as_mut_ptr();
216 FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
217 self.as_ref().to_glib_none().0,
218 offset,
219 size,
220 &mut buffer_ref,
221 ))
222 .and_then(|_| {
223 if buffer.as_mut_ptr() != buffer_ref {
224 ffi::gst_mini_object_unref(buffer_ref as *mut _);
225 Err(crate::FlowError::Error)
226 } else {
227 Ok(())
228 }
229 })
230 }
231 }
232
233 #[doc(alias = "get_range")]
234 #[doc(alias = "gst_pad_get_range")]
235 fn range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
236 unsafe {
237 let mut buffer = ptr::null_mut();
238 FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
239 self.as_ref().to_glib_none().0,
240 offset,
241 size,
242 &mut buffer,
243 ))
244 .map(|_| from_glib_full(buffer))
245 }
246 }
247
248 #[doc(alias = "get_range_fill")]
249 fn range_fill(
250 &self,
251 offset: u64,
252 buffer: &mut crate::BufferRef,
253 size: u32,
254 ) -> Result<(), FlowError> {
255 assert!(buffer.size() >= size as usize);
256
257 unsafe {
258 let mut buffer_ref = buffer.as_mut_ptr();
259 FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
260 self.as_ref().to_glib_none().0,
261 offset,
262 size,
263 &mut buffer_ref,
264 ))
265 .and_then(|_| {
266 if buffer.as_mut_ptr() != buffer_ref {
267 ffi::gst_mini_object_unref(buffer_ref as *mut _);
268 Err(crate::FlowError::Error)
269 } else {
270 Ok(())
271 }
272 })
273 }
274 }
275
276 #[doc(alias = "gst_pad_peer_query")]
277 fn peer_query(&self, query: &mut QueryRef) -> bool {
278 unsafe {
279 from_glib(ffi::gst_pad_peer_query(
280 self.as_ref().to_glib_none().0,
281 query.as_mut_ptr(),
282 ))
283 }
284 }
285
286 #[doc(alias = "gst_pad_query")]
287 fn query(&self, query: &mut QueryRef) -> bool {
288 unsafe {
289 from_glib(ffi::gst_pad_query(
290 self.as_ref().to_glib_none().0,
291 query.as_mut_ptr(),
292 ))
293 }
294 }
295
296 fn proxy_query_caps(&self, query: &mut QueryRef) -> bool {
297 unsafe {
298 from_glib(ffi::gst_pad_proxy_query_accept_caps(
299 self.as_ref().to_glib_none().0,
300 query.as_mut_ptr(),
301 ))
302 }
303 }
304
305 #[doc(alias = "gst_pad_proxy_query_accept_caps")]
306 fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool {
307 unsafe {
308 from_glib(ffi::gst_pad_proxy_query_accept_caps(
309 self.as_ref().to_glib_none().0,
310 query.as_mut_ptr(),
311 ))
312 }
313 }
314
315 #[doc(alias = "gst_pad_push_event")]
316 fn push_event(&self, event: impl Into<Event>) -> bool {
317 unsafe {
318 from_glib(ffi::gst_pad_push_event(
319 self.as_ref().to_glib_none().0,
320 event.into().into_glib_ptr(),
321 ))
322 }
323 }
324
325 #[doc(alias = "gst_pad_send_event")]
326 fn send_event(&self, event: impl Into<Event>) -> bool {
327 unsafe {
328 from_glib(ffi::gst_pad_send_event(
329 self.as_ref().to_glib_none().0,
330 event.into().into_glib_ptr(),
331 ))
332 }
333 }
334
335 #[doc(alias = "gst_pad_iterate_internal_links")]
336 fn iterate_internal_links(&self) -> crate::Iterator<Pad> {
337 unsafe {
338 from_glib_full(ffi::gst_pad_iterate_internal_links(
339 self.as_ref().to_glib_none().0,
340 ))
341 }
342 }
343
344 fn stream_lock(&self) -> StreamLock {
345 unsafe {
346 let ptr: &mut ffi::GstPad = &mut *(self.as_ptr() as *mut _);
347 glib::ffi::g_rec_mutex_lock(&mut ptr.stream_rec_lock);
348 StreamLock(self.upcast_ref())
349 }
350 }
351
352 #[doc(alias = "gst_pad_set_activate_function")]
353 #[doc(alias = "gst_pad_set_activate_function_full")]
354 unsafe fn set_activate_function<F>(&self, func: F)
355 where
356 F: Fn(&Self, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
357 {
358 let func_box: Box<F> = Box::new(func);
359 ffi::gst_pad_set_activate_function_full(
360 self.as_ref().to_glib_none().0,
361 Some(trampoline_activate_function::<Self, F>),
362 Box::into_raw(func_box) as gpointer,
363 Some(destroy_closure::<F>),
364 );
365 }
366
367 #[doc(alias = "gst_pad_set_activatemode_function")]
368 #[doc(alias = "gst_pad_set_activatemode_function_full")]
369 unsafe fn set_activatemode_function<F>(&self, func: F)
370 where
371 F: Fn(&Self, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
372 + Send
373 + Sync
374 + 'static,
375 {
376 let func_box: Box<F> = Box::new(func);
377 ffi::gst_pad_set_activatemode_function_full(
378 self.as_ref().to_glib_none().0,
379 Some(trampoline_activatemode_function::<Self, F>),
380 Box::into_raw(func_box) as gpointer,
381 Some(destroy_closure::<F>),
382 );
383 }
384
385 #[doc(alias = "gst_pad_set_chain_function")]
386 #[doc(alias = "gst_pad_set_chain_function_full")]
387 unsafe fn set_chain_function<F>(&self, func: F)
388 where
389 F: Fn(&Self, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
390 + Send
391 + Sync
392 + 'static,
393 {
394 let func_box: Box<F> = Box::new(func);
395 ffi::gst_pad_set_chain_function_full(
396 self.as_ref().to_glib_none().0,
397 Some(trampoline_chain_function::<Self, F>),
398 Box::into_raw(func_box) as gpointer,
399 Some(destroy_closure::<F>),
400 );
401 }
402
403 #[doc(alias = "gst_pad_set_chain_list_function")]
404 #[doc(alias = "gst_pad_set_chain_list_function_full")]
405 unsafe fn set_chain_list_function<F>(&self, func: F)
406 where
407 F: Fn(&Self, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
408 + Send
409 + Sync
410 + 'static,
411 {
412 let func_box: Box<F> = Box::new(func);
413 ffi::gst_pad_set_chain_list_function_full(
414 self.as_ref().to_glib_none().0,
415 Some(trampoline_chain_list_function::<Self, F>),
416 Box::into_raw(func_box) as gpointer,
417 Some(destroy_closure::<F>),
418 );
419 }
420
421 #[doc(alias = "gst_pad_set_event_function")]
422 #[doc(alias = "gst_pad_set_event_function_full")]
423 unsafe fn set_event_function<F>(&self, func: F)
424 where
425 F: Fn(&Self, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
426 {
427 let func_box: Box<F> = Box::new(func);
428 ffi::gst_pad_set_event_function_full(
429 self.as_ref().to_glib_none().0,
430 Some(trampoline_event_function::<Self, F>),
431 Box::into_raw(func_box) as gpointer,
432 Some(destroy_closure::<F>),
433 );
434 }
435
436 #[doc(alias = "gst_pad_set_event_full_function")]
437 #[doc(alias = "gst_pad_set_event_full_function_full")]
438 unsafe fn set_event_full_function<F>(&self, func: F)
439 where
440 F: Fn(&Self, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
441 + Send
442 + Sync
443 + 'static,
444 {
445 let func_box: Box<F> = Box::new(func);
446 ffi::gst_pad_set_event_full_function_full(
447 self.as_ref().to_glib_none().0,
448 Some(trampoline_event_full_function::<Self, F>),
449 Box::into_raw(func_box) as gpointer,
450 Some(destroy_closure::<F>),
451 );
452 }
453
454 #[doc(alias = "gst_pad_set_getrange_function")]
455 #[doc(alias = "gst_pad_set_getrange_function_full")]
456 unsafe fn set_getrange_function<F>(&self, func: F)
457 where
458 F: Fn(
459 &Self,
460 Option<&crate::Object>,
461 u64,
462 Option<&mut crate::BufferRef>,
463 u32,
464 ) -> Result<PadGetRangeSuccess, crate::FlowError>
465 + Send
466 + Sync
467 + 'static,
468 {
469 let func_box: Box<F> = Box::new(func);
470 ffi::gst_pad_set_getrange_function_full(
471 self.as_ref().to_glib_none().0,
472 Some(trampoline_getrange_function::<Self, F>),
473 Box::into_raw(func_box) as gpointer,
474 Some(destroy_closure::<F>),
475 );
476 }
477
478 #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
479 #[doc(alias = "gst_pad_set_iterate_internal_links_function_full")]
480 unsafe fn set_iterate_internal_links_function<F>(&self, func: F)
481 where
482 F: Fn(&Self, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
483 {
484 let func_box: Box<F> = Box::new(func);
485 ffi::gst_pad_set_iterate_internal_links_function_full(
486 self.as_ref().to_glib_none().0,
487 Some(trampoline_iterate_internal_links_function::<Self, F>),
488 Box::into_raw(func_box) as gpointer,
489 Some(destroy_closure::<F>),
490 );
491 }
492
493 #[doc(alias = "gst_pad_set_link_function")]
494 #[doc(alias = "gst_pad_set_link_function_full")]
495 unsafe fn set_link_function<F>(&self, func: F)
496 where
497 F: Fn(
498 &Self,
499 Option<&crate::Object>,
500 &Pad,
501 ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
502 + Send
503 + Sync
504 + 'static,
505 {
506 let func_box: Box<F> = Box::new(func);
507 ffi::gst_pad_set_link_function_full(
508 self.as_ref().to_glib_none().0,
509 Some(trampoline_link_function::<Self, F>),
510 Box::into_raw(func_box) as gpointer,
511 Some(destroy_closure::<F>),
512 );
513 }
514
515 #[doc(alias = "gst_pad_set_query_function")]
516 #[doc(alias = "gst_pad_set_query_function_full")]
517 unsafe fn set_query_function<F>(&self, func: F)
518 where
519 F: Fn(&Self, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
520 {
521 let func_box: Box<F> = Box::new(func);
522 ffi::gst_pad_set_query_function_full(
523 self.as_ref().to_glib_none().0,
524 Some(trampoline_query_function::<Self, F>),
525 Box::into_raw(func_box) as gpointer,
526 Some(destroy_closure::<F>),
527 );
528 }
529
530 #[doc(alias = "gst_pad_set_unlink_function")]
531 #[doc(alias = "gst_pad_set_unlink_function_full")]
532 unsafe fn set_unlink_function<F>(&self, func: F)
533 where
534 F: Fn(&Self, Option<&crate::Object>) + Send + Sync + 'static,
535 {
536 let func_box: Box<F> = Box::new(func);
537 ffi::gst_pad_set_unlink_function_full(
538 self.as_ref().to_glib_none().0,
539 Some(trampoline_unlink_function::<Self, F>),
540 Box::into_raw(func_box) as gpointer,
541 Some(destroy_closure::<F>),
542 );
543 }
544
545 #[doc(alias = "gst_pad_start_task")]
546 fn start_task<F: FnMut() + Send + 'static>(&self, func: F) -> Result<(), glib::BoolError> {
547 unsafe extern "C" fn trampoline_pad_task<F: FnMut() + Send + 'static>(func: gpointer) {
548 let (func, pad) = &mut *(func as *mut (F, *mut ffi::GstPad));
549 let pad = Pad::from_glib_borrow(*pad);
550 let result = panic::catch_unwind(AssertUnwindSafe(func));
551
552 if let Err(err) = result {
553 let element = match pad.parent_element() {
554 Some(element) => element,
555 None => panic::resume_unwind(err),
556 };
557
558 if pad.pause_task().is_err() {
559 crate::error!(crate::CAT_RUST, "could not stop pad task on panic");
560 }
561
562 crate::subclass::post_panic_error_message(&element, pad.upcast_ref(), Some(err));
563 }
564 }
565
566 fn into_raw_pad_task<F: FnMut() + Send + 'static>(
567 func: F,
568 pad: *mut ffi::GstPad,
569 ) -> gpointer {
570 #[allow(clippy::type_complexity)]
571 let func: Box<(F, *mut ffi::GstPad)> = Box::new((func, pad));
572 Box::into_raw(func) as gpointer
573 }
574
575 unsafe extern "C" fn destroy_closure_pad_task<F>(ptr: gpointer) {
576 let _ = Box::<(F, *mut ffi::GstPad)>::from_raw(ptr as *mut _);
577 }
578
579 unsafe {
580 glib::result_from_gboolean!(
581 ffi::gst_pad_start_task(
582 self.as_ref().to_glib_none().0,
583 Some(trampoline_pad_task::<F>),
584 into_raw_pad_task(func, self.upcast_ref().as_ptr()),
585 Some(destroy_closure_pad_task::<F>),
586 ),
587 "Failed to start pad task",
588 )
589 }
590 }
591 #[doc(alias = "gst_pad_peer_query_convert")]
592 fn peer_query_convert<U: SpecificFormattedValueFullRange>(
593 &self,
594 src_val: impl FormattedValue,
595 ) -> Option<U> {
596 unsafe {
597 let mut dest_val = mem::MaybeUninit::uninit();
598 let ret = from_glib(ffi::gst_pad_peer_query_convert(
599 self.as_ref().to_glib_none().0,
600 src_val.format().into_glib(),
601 src_val.into_raw_value(),
602 U::default_format().into_glib(),
603 dest_val.as_mut_ptr(),
604 ));
605 if ret {
606 Some(U::from_raw(U::default_format(), dest_val.assume_init()))
607 } else {
608 None
609 }
610 }
611 }
612
613 #[doc(alias = "gst_pad_peer_query_convert")]
614 fn peer_query_convert_generic(
615 &self,
616 src_val: impl FormattedValue,
617 dest_format: Format,
618 ) -> Option<GenericFormattedValue> {
619 unsafe {
620 let mut dest_val = mem::MaybeUninit::uninit();
621 let ret = from_glib(ffi::gst_pad_peer_query_convert(
622 self.as_ref().to_glib_none().0,
623 src_val.format().into_glib(),
624 src_val.into_raw_value(),
625 dest_format.into_glib(),
626 dest_val.as_mut_ptr(),
627 ));
628 if ret {
629 Some(GenericFormattedValue::new(
630 dest_format,
631 dest_val.assume_init(),
632 ))
633 } else {
634 None
635 }
636 }
637 }
638
639 #[doc(alias = "gst_pad_peer_query_duration")]
640 fn peer_query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
641 unsafe {
642 let mut duration = mem::MaybeUninit::uninit();
643 let ret = from_glib(ffi::gst_pad_peer_query_duration(
644 self.as_ref().to_glib_none().0,
645 T::default_format().into_glib(),
646 duration.as_mut_ptr(),
647 ));
648 if ret {
649 try_from_glib(duration.assume_init()).ok()
650 } else {
651 None
652 }
653 }
654 }
655
656 #[doc(alias = "gst_pad_peer_query_duration")]
657 fn peer_query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
658 unsafe {
659 let mut duration = mem::MaybeUninit::uninit();
660 let ret = from_glib(ffi::gst_pad_peer_query_duration(
661 self.as_ref().to_glib_none().0,
662 format.into_glib(),
663 duration.as_mut_ptr(),
664 ));
665 if ret {
666 Some(GenericFormattedValue::new(format, duration.assume_init()))
667 } else {
668 None
669 }
670 }
671 }
672
673 #[doc(alias = "gst_pad_peer_query_position")]
674 fn peer_query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
675 unsafe {
676 let mut cur = mem::MaybeUninit::uninit();
677 let ret = from_glib(ffi::gst_pad_peer_query_position(
678 self.as_ref().to_glib_none().0,
679 T::default_format().into_glib(),
680 cur.as_mut_ptr(),
681 ));
682 if ret {
683 try_from_glib(cur.assume_init()).ok()
684 } else {
685 None
686 }
687 }
688 }
689
690 #[doc(alias = "gst_pad_peer_query_position")]
691 fn peer_query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
692 unsafe {
693 let mut cur = mem::MaybeUninit::uninit();
694 let ret = from_glib(ffi::gst_pad_peer_query_position(
695 self.as_ref().to_glib_none().0,
696 format.into_glib(),
697 cur.as_mut_ptr(),
698 ));
699 if ret {
700 Some(GenericFormattedValue::new(format, cur.assume_init()))
701 } else {
702 None
703 }
704 }
705 }
706
707 #[doc(alias = "gst_pad_query_convert")]
708 fn query_convert<U: SpecificFormattedValueFullRange>(
709 &self,
710 src_val: impl FormattedValue,
711 ) -> Option<U> {
712 unsafe {
713 let mut dest_val = mem::MaybeUninit::uninit();
714 let ret = from_glib(ffi::gst_pad_query_convert(
715 self.as_ref().to_glib_none().0,
716 src_val.format().into_glib(),
717 src_val.into_raw_value(),
718 U::default_format().into_glib(),
719 dest_val.as_mut_ptr(),
720 ));
721 if ret {
722 Some(U::from_raw(U::default_format(), dest_val.assume_init()))
723 } else {
724 None
725 }
726 }
727 }
728
729 #[doc(alias = "gst_pad_query_convert")]
730 fn query_convert_generic(
731 &self,
732 src_val: impl FormattedValue,
733 dest_format: Format,
734 ) -> Option<GenericFormattedValue> {
735 unsafe {
736 let mut dest_val = mem::MaybeUninit::uninit();
737 let ret = from_glib(ffi::gst_pad_query_convert(
738 self.as_ref().to_glib_none().0,
739 src_val.format().into_glib(),
740 src_val.into_raw_value(),
741 dest_format.into_glib(),
742 dest_val.as_mut_ptr(),
743 ));
744 if ret {
745 Some(GenericFormattedValue::new(
746 dest_format,
747 dest_val.assume_init(),
748 ))
749 } else {
750 None
751 }
752 }
753 }
754
755 #[doc(alias = "gst_pad_query_duration")]
756 fn query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
757 unsafe {
758 let mut duration = mem::MaybeUninit::uninit();
759 let ret = from_glib(ffi::gst_pad_query_duration(
760 self.as_ref().to_glib_none().0,
761 T::default_format().into_glib(),
762 duration.as_mut_ptr(),
763 ));
764 if ret {
765 try_from_glib(duration.assume_init()).ok()
766 } else {
767 None
768 }
769 }
770 }
771
772 #[doc(alias = "gst_pad_query_duration")]
773 fn query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
774 unsafe {
775 let mut duration = mem::MaybeUninit::uninit();
776 let ret = from_glib(ffi::gst_pad_query_duration(
777 self.as_ref().to_glib_none().0,
778 format.into_glib(),
779 duration.as_mut_ptr(),
780 ));
781 if ret {
782 Some(GenericFormattedValue::new(format, duration.assume_init()))
783 } else {
784 None
785 }
786 }
787 }
788
789 #[doc(alias = "gst_pad_query_position")]
790 fn query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
791 unsafe {
792 let mut cur = mem::MaybeUninit::uninit();
793 let ret = from_glib(ffi::gst_pad_query_position(
794 self.as_ref().to_glib_none().0,
795 T::default_format().into_glib(),
796 cur.as_mut_ptr(),
797 ));
798 if ret {
799 try_from_glib(cur.assume_init()).ok()
800 } else {
801 None
802 }
803 }
804 }
805
806 #[doc(alias = "gst_pad_query_position")]
807 fn query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
808 unsafe {
809 let mut cur = mem::MaybeUninit::uninit();
810 let ret = from_glib(ffi::gst_pad_query_position(
811 self.as_ref().to_glib_none().0,
812 format.into_glib(),
813 cur.as_mut_ptr(),
814 ));
815 if ret {
816 Some(GenericFormattedValue::new(format, cur.assume_init()))
817 } else {
818 None
819 }
820 }
821 }
822
823 #[doc(alias = "get_mode")]
824 #[doc(alias = "GST_PAD_MODE")]
825 fn mode(&self) -> crate::PadMode {
826 unsafe {
827 let ptr: &ffi::GstPad = &*(self.as_ptr() as *const _);
828 from_glib(ptr.mode)
829 }
830 }
831
832 #[doc(alias = "gst_pad_sticky_events_foreach")]
833 fn sticky_events_foreach<
834 F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
835 >(
836 &self,
837 func: F,
838 ) {
839 unsafe extern "C" fn trampoline<
840 F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
841 >(
842 _pad: *mut ffi::GstPad,
843 event: *mut *mut ffi::GstEvent,
844 user_data: glib::ffi::gpointer,
845 ) -> glib::ffi::gboolean {
846 let func = user_data as *mut F;
847 let res = (*func)(&from_glib_borrow(*event));
848
849 let (do_continue, ev_action) = match res {
850 ControlFlow::Continue(ev_action) => (glib::ffi::GTRUE, ev_action),
851 ControlFlow::Break(ev_action) => (glib::ffi::GFALSE, ev_action),
852 };
853
854 use EventForeachAction::*;
855
856 match ev_action {
857 Keep => (), // do nothing
858 Remove => {
859 ffi::gst_mini_object_unref(*event as *mut _);
860 *event = ptr::null_mut();
861 }
862 Replace(ev) => {
863 ffi::gst_mini_object_unref(*event as *mut _);
864 *event = ev.into_glib_ptr();
865 }
866 }
867
868 do_continue
869 }
870
871 unsafe {
872 let mut func = func;
873 let func_ptr = &mut func as *mut F as glib::ffi::gpointer;
874
875 ffi::gst_pad_sticky_events_foreach(
876 self.as_ref().to_glib_none().0,
877 Some(trampoline::<F>),
878 func_ptr,
879 );
880 }
881 }
882
883 #[doc(alias = "gst_pad_get_sticky_event")]
884 #[doc(alias = "get_sticky_event")]
885 fn sticky_event<T: crate::event::StickyEventType>(&self, idx: u32) -> Option<T::Owned> {
886 unsafe {
887 let ptr = ffi::gst_pad_get_sticky_event(
888 self.as_ref().to_glib_none().0,
889 T::TYPE.into_glib(),
890 idx,
891 );
892
893 if ptr.is_null() {
894 None
895 } else {
896 Some(T::from_event(from_glib_full(ptr)))
897 }
898 }
899 }
900
901 fn set_pad_flags(&self, flags: PadFlags) {
902 unsafe {
903 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
904 let _guard = self.as_ref().object_lock();
905 (*ptr).flags |= flags.into_glib();
906 }
907 }
908
909 fn unset_pad_flags(&self, flags: PadFlags) {
910 unsafe {
911 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
912 let _guard = self.as_ref().object_lock();
913 (*ptr).flags &= !flags.into_glib();
914 }
915 }
916
917 #[doc(alias = "get_pad_flags")]
918 fn pad_flags(&self) -> PadFlags {
919 unsafe {
920 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
921 let _guard = self.as_ref().object_lock();
922 from_glib((*ptr).flags)
923 }
924 }
925}
926
927impl<O: IsA<Pad>> PadExtManual for O {}
928
929unsafe fn create_probe_info<'a>(
930 info: *mut ffi::GstPadProbeInfo,
931) -> (PadProbeInfo<'a>, Option<glib::Type>) {
932 let mut data_type = None;
933 let flow_res = try_from_glib((*info).ABI.abi.flow_ret);
934 let info = PadProbeInfo {
935 mask: from_glib((*info).type_),
936 id: Some(PadProbeId(NonZeroU64::new_unchecked((*info).id as _))),
937 offset: (*info).offset,
938 size: (*info).size,
939 data: if (*info).data.is_null() {
940 None
941 } else {
942 let data = (*info).data as *mut ffi::GstMiniObject;
943 (*info).data = ptr::null_mut();
944 if (*data).type_ == Buffer::static_type().into_glib() {
945 data_type = Some(Buffer::static_type());
946 Some(PadProbeData::Buffer(from_glib_full(
947 data as *const ffi::GstBuffer,
948 )))
949 } else if (*data).type_ == BufferList::static_type().into_glib() {
950 data_type = Some(BufferList::static_type());
951 Some(PadProbeData::BufferList(from_glib_full(
952 data as *const ffi::GstBufferList,
953 )))
954 } else if (*data).type_ == Query::static_type().into_glib() {
955 data_type = Some(Query::static_type());
956 Some(PadProbeData::Query(QueryRef::from_mut_ptr(
957 data as *mut ffi::GstQuery,
958 )))
959 } else if (*data).type_ == Event::static_type().into_glib() {
960 data_type = Some(Event::static_type());
961 Some(PadProbeData::Event(from_glib_full(
962 data as *const ffi::GstEvent,
963 )))
964 } else {
965 Some(PadProbeData::__Unknown(data))
966 }
967 },
968 flow_res,
969 };
970 (info, data_type)
971}
972
973unsafe fn update_probe_info(
974 ret: PadProbeReturn,
975 probe_info: PadProbeInfo,
976 data_type: Option<glib::Type>,
977 info: *mut ffi::GstPadProbeInfo,
978) {
979 if ret == PadProbeReturn::Handled {
980 // Handled queries need to be returned
981 // Handled buffers and buffer lists are consumed
982 // No other types can safely be used here
983
984 match probe_info.data {
985 Some(PadProbeData::Query(query)) => {
986 assert_eq!(data_type, Some(Query::static_type()));
987 (*info).data = query.as_mut_ptr() as *mut libc::c_void;
988 }
989 Some(PadProbeData::Buffer(_)) => {
990 assert_eq!(data_type, Some(Buffer::static_type()));
991 // Buffer not consumed by probe; consume it here
992 }
993 Some(PadProbeData::BufferList(_)) => {
994 assert_eq!(data_type, Some(BufferList::static_type()));
995 // BufferList not consumed by probe; consume it here
996 }
997 Some(PadProbeData::Event(_)) => {
998 assert_eq!(data_type, Some(Event::static_type()));
999 // Event not consumed by probe; consume it here
1000 }
1001 None if data_type == Some(Buffer::static_type())
1002 || data_type == Some(BufferList::static_type())
1003 || data_type == Some(Event::static_type()) =>
1004 {
1005 // Buffer or Event consumed by probe
1006 }
1007 other => panic!("Bad data for {data_type:?} pad probe returning Handled: {other:?}"),
1008 }
1009 } else {
1010 match probe_info.data {
1011 Some(PadProbeData::Buffer(buffer)) => {
1012 assert_eq!(data_type, Some(Buffer::static_type()));
1013 (*info).data = buffer.into_glib_ptr() as *mut libc::c_void;
1014 }
1015 Some(PadProbeData::BufferList(bufferlist)) => {
1016 assert_eq!(data_type, Some(BufferList::static_type()));
1017 (*info).data = bufferlist.into_glib_ptr() as *mut libc::c_void;
1018 }
1019 Some(PadProbeData::Event(event)) => {
1020 assert_eq!(data_type, Some(Event::static_type()));
1021 (*info).data = event.into_glib_ptr() as *mut libc::c_void;
1022 }
1023 Some(PadProbeData::Query(query)) => {
1024 assert_eq!(data_type, Some(Query::static_type()));
1025 (*info).data = query.as_mut_ptr() as *mut libc::c_void;
1026 }
1027 Some(PadProbeData::__Unknown(ptr)) => {
1028 assert_eq!(data_type, None);
1029 (*info).data = ptr as *mut libc::c_void;
1030 }
1031 None => {
1032 assert_eq!(data_type, None);
1033 }
1034 }
1035 }
1036
1037 let flow_ret: FlowReturn = probe_info.flow_res.into();
1038 (*info).ABI.abi.flow_ret = flow_ret.into_glib();
1039}
1040
1041unsafe extern "C" fn trampoline_pad_probe<
1042 T,
1043 F: Fn(&T, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
1044>(
1045 pad: *mut ffi::GstPad,
1046 info: *mut ffi::GstPadProbeInfo,
1047 func: gpointer,
1048) -> ffi::GstPadProbeReturn
1049where
1050 T: IsA<Pad>,
1051{
1052 let func: &F = &*(func as *const F);
1053
1054 let (mut probe_info: PadProbeInfo<'_>, data_type: Option) = create_probe_info(info);
1055
1056 let ret: PadProbeReturn = func(
1057 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1058 &mut probe_info,
1059 );
1060
1061 update_probe_info(ret, probe_info, data_type, info);
1062
1063 ret.into_glib()
1064}
1065
1066unsafe extern "C" fn trampoline_activate_function<
1067 T,
1068 F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1069>(
1070 pad: *mut ffi::GstPad,
1071 parent: *mut ffi::GstObject,
1072) -> glib::ffi::gboolean
1073where
1074 T: IsA<Pad>,
1075{
1076 let func: &F = &*((*pad).activatedata as *const F);
1077
1078 matchbool func(
1079 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1080 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1081 .as_ref()
1082 .as_ref(),
1083 ) {
1084 Ok(()) => true,
1085 Err(err: LoggableError) => {
1086 err.log_with_object(&*Pad::from_glib_borrow(_ptr:pad));
1087 false
1088 }
1089 }
1090 .into_glib()
1091}
1092
1093unsafe extern "C" fn trampoline_activatemode_function<
1094 T,
1095 F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1096 + Send
1097 + Sync
1098 + 'static,
1099>(
1100 pad: *mut ffi::GstPad,
1101 parent: *mut ffi::GstObject,
1102 mode: ffi::GstPadMode,
1103 active: glib::ffi::gboolean,
1104) -> glib::ffi::gboolean
1105where
1106 T: IsA<Pad>,
1107{
1108 let func: &F = &*((*pad).activatemodedata as *const F);
1109
1110 matchbool func(
1111 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1112 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1113 .as_ref()
1114 .as_ref(),
1115 from_glib(val:mode),
1116 from_glib(val:active),
1117 ) {
1118 Ok(()) => true,
1119 Err(err: LoggableError) => {
1120 err.log_with_object(&*Pad::from_glib_borrow(_ptr:pad));
1121 false
1122 }
1123 }
1124 .into_glib()
1125}
1126
1127unsafe extern "C" fn trampoline_chain_function<
1128 T,
1129 F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1130 + Send
1131 + Sync
1132 + 'static,
1133>(
1134 pad: *mut ffi::GstPad,
1135 parent: *mut ffi::GstObject,
1136 buffer: *mut ffi::GstBuffer,
1137) -> ffi::GstFlowReturn
1138where
1139 T: IsA<Pad>,
1140{
1141 let func: &F = &*((*pad).chaindata as *const F);
1142
1143 let res: FlowReturn = funcResult(
1144 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1145 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1146 .as_ref()
1147 .as_ref(),
1148 from_glib_full(ptr:buffer),
1149 )
1150 .into();
1151 res.into_glib()
1152}
1153
1154unsafe extern "C" fn trampoline_chain_list_function<
1155 T,
1156 F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1157 + Send
1158 + Sync
1159 + 'static,
1160>(
1161 pad: *mut ffi::GstPad,
1162 parent: *mut ffi::GstObject,
1163 list: *mut ffi::GstBufferList,
1164) -> ffi::GstFlowReturn
1165where
1166 T: IsA<Pad>,
1167{
1168 let func: &F = &*((*pad).chainlistdata as *const F);
1169
1170 let res: FlowReturn = funcResult(
1171 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1172 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1173 .as_ref()
1174 .as_ref(),
1175 from_glib_full(ptr:list),
1176 )
1177 .into();
1178 res.into_glib()
1179}
1180
1181unsafe extern "C" fn trampoline_event_function<
1182 T,
1183 F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1184>(
1185 pad: *mut ffi::GstPad,
1186 parent: *mut ffi::GstObject,
1187 event: *mut ffi::GstEvent,
1188) -> glib::ffi::gboolean
1189where
1190 T: IsA<Pad>,
1191{
1192 let func: &F = &*((*pad).eventdata as *const F);
1193
1194 funcbool(
1195 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1196 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1197 .as_ref()
1198 .as_ref(),
1199 from_glib_full(ptr:event),
1200 )
1201 .into_glib()
1202}
1203
1204unsafe extern "C" fn trampoline_event_full_function<
1205 T,
1206 F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1207 + Send
1208 + Sync
1209 + 'static,
1210>(
1211 pad: *mut ffi::GstPad,
1212 parent: *mut ffi::GstObject,
1213 event: *mut ffi::GstEvent,
1214) -> ffi::GstFlowReturn
1215where
1216 T: IsA<Pad>,
1217{
1218 let func: &F = &*((*pad).eventdata as *const F);
1219
1220 let res: FlowReturn = funcResult(
1221 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1222 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1223 .as_ref()
1224 .as_ref(),
1225 from_glib_full(ptr:event),
1226 )
1227 .into();
1228 res.into_glib()
1229}
1230
1231#[allow(clippy::needless_option_as_deref)]
1232unsafe extern "C" fn trampoline_getrange_function<
1233 T,
1234 F: Fn(
1235 &T,
1236 Option<&crate::Object>,
1237 u64,
1238 Option<&mut crate::BufferRef>,
1239 u32,
1240 ) -> Result<PadGetRangeSuccess, crate::FlowError>
1241 + Send
1242 + Sync
1243 + 'static,
1244>(
1245 pad: *mut ffi::GstPad,
1246 parent: *mut ffi::GstObject,
1247 offset: u64,
1248 length: u32,
1249 buffer: *mut *mut ffi::GstBuffer,
1250) -> ffi::GstFlowReturn
1251where
1252 T: IsA<Pad>,
1253{
1254 let func: &F = &*((*pad).getrangedata as *const F);
1255
1256 debug_assert!(!buffer.is_null());
1257
1258 let pad = Pad::from_glib_borrow(pad);
1259 let pad = pad.unsafe_cast_ref();
1260 let mut passed_buffer = if (*buffer).is_null() {
1261 None
1262 } else {
1263 Some(crate::BufferRef::from_mut_ptr(*buffer))
1264 };
1265
1266 match func(
1267 pad,
1268 Option::<crate::Object>::from_glib_borrow(parent)
1269 .as_ref()
1270 .as_ref(),
1271 offset,
1272 passed_buffer.as_deref_mut(),
1273 length,
1274 ) {
1275 Ok(PadGetRangeSuccess::NewBuffer(new_buffer)) => {
1276 if let Some(passed_buffer) = passed_buffer {
1277 crate::debug!(
1278 crate::CAT_PERFORMANCE,
1279 obj: pad.unsafe_cast_ref::<glib::Object>(),
1280 "Returned new buffer from getrange function, copying into passed buffer"
1281 );
1282
1283 let mut map = match passed_buffer.map_writable() {
1284 Ok(map) => map,
1285 Err(_) => {
1286 crate::error!(
1287 crate::CAT_RUST,
1288 obj: pad.unsafe_cast_ref::<glib::Object>(),
1289 "Failed to map passed buffer writable"
1290 );
1291 return ffi::GST_FLOW_ERROR;
1292 }
1293 };
1294
1295 let copied_size = new_buffer.copy_to_slice(0, &mut map);
1296 drop(map);
1297
1298 if let Err(copied_size) = copied_size {
1299 passed_buffer.set_size(copied_size);
1300 }
1301
1302 match new_buffer.copy_into(passed_buffer, crate::BUFFER_COPY_METADATA, 0, None) {
1303 Ok(_) => FlowReturn::Ok.into_glib(),
1304 Err(_) => {
1305 crate::error!(
1306 crate::CAT_RUST,
1307 obj: pad.unsafe_cast_ref::<glib::Object>(),
1308 "Failed to copy buffer metadata"
1309 );
1310
1311 FlowReturn::Error.into_glib()
1312 }
1313 }
1314 } else {
1315 *buffer = new_buffer.into_glib_ptr();
1316 FlowReturn::Ok.into_glib()
1317 }
1318 }
1319 Ok(PadGetRangeSuccess::FilledBuffer) => {
1320 assert!(passed_buffer.is_some());
1321 FlowReturn::Ok.into_glib()
1322 }
1323 Err(ret) => FlowReturn::from_error(ret).into_glib(),
1324 }
1325}
1326
1327unsafe extern "C" fn trampoline_iterate_internal_links_function<
1328 T,
1329 F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1330>(
1331 pad: *mut ffi::GstPad,
1332 parent: *mut ffi::GstObject,
1333) -> *mut ffi::GstIterator
1334where
1335 T: IsA<Pad>,
1336{
1337 let func: &F = &*((*pad).iterintlinkdata as *const F);
1338
1339 // Steal the iterator and return it
1340 let ret: Iterator = func(
1341 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1342 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1343 .as_ref()
1344 .as_ref(),
1345 );
1346
1347 ret.into_glib_ptr()
1348}
1349
1350unsafe extern "C" fn trampoline_link_function<
1351 T,
1352 F: Fn(
1353 &T,
1354 Option<&crate::Object>,
1355 &crate::Pad,
1356 ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
1357 + Send
1358 + Sync
1359 + 'static,
1360>(
1361 pad: *mut ffi::GstPad,
1362 parent: *mut ffi::GstObject,
1363 peer: *mut ffi::GstPad,
1364) -> ffi::GstPadLinkReturn
1365where
1366 T: IsA<Pad>,
1367{
1368 let func: &F = &*((*pad).linkdata as *const F);
1369
1370 let res: crate::PadLinkReturn = funcResult(
1371 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1372 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1373 .as_ref()
1374 .as_ref(),
1375 &from_glib_borrow(ptr:peer),
1376 )
1377 .into();
1378 res.into_glib()
1379}
1380
1381unsafe extern "C" fn trampoline_query_function<
1382 T,
1383 F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
1384>(
1385 pad: *mut ffi::GstPad,
1386 parent: *mut ffi::GstObject,
1387 query: *mut ffi::GstQuery,
1388) -> glib::ffi::gboolean
1389where
1390 T: IsA<Pad>,
1391{
1392 let func: &F = &*((*pad).querydata as *const F);
1393
1394 funcbool(
1395 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1396 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1397 .as_ref()
1398 .as_ref(),
1399 crate::QueryRef::from_mut_ptr(query),
1400 )
1401 .into_glib()
1402}
1403
1404unsafe extern "C" fn trampoline_unlink_function<
1405 T,
1406 F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
1407>(
1408 pad: *mut ffi::GstPad,
1409 parent: *mut ffi::GstObject,
1410) where
1411 T: IsA<Pad>,
1412{
1413 let func: &F = &*((*pad).unlinkdata as *const F);
1414
1415 func(
1416 Pad::from_glib_borrow(_ptr:pad).unsafe_cast_ref(),
1417 Option&Option::<crate::Object>::from_glib_borrow(_ptr:parent)
1418 .as_ref()
1419 .as_ref(),
1420 )
1421}
1422
1423unsafe extern "C" fn destroy_closure<F>(ptr: gpointer) {
1424 let _ = Box::<F>::from_raw(ptr as *mut _);
1425}
1426
1427impl Pad {
1428 // rustdoc-stripper-ignore-next
1429 /// Creates a new [`Pad`] with the specified [`PadDirection`](crate::PadDirection).
1430 ///
1431 /// An automatically generated name will be assigned.
1432 ///
1433 /// Use [`Pad::builder()`] to get a [`PadBuilder`] and define options.
1434 #[doc(alias = "gst_pad_new")]
1435 pub fn new(direction: crate::PadDirection) -> Self {
1436 skip_assert_initialized!();
1437 Self::builder(direction).build()
1438 }
1439
1440 // rustdoc-stripper-ignore-next
1441 /// Creates a [`PadBuilder`] with the specified [`PadDirection`](crate::PadDirection).
1442 ///
1443 /// An automatically generated name will be assigned.
1444 #[doc(alias = "gst_pad_new")]
1445 pub fn builder(direction: crate::PadDirection) -> PadBuilder<Self> {
1446 skip_assert_initialized!();
1447 PadBuilder::new(direction)
1448 }
1449
1450 // rustdoc-stripper-ignore-next
1451 /// Creates a new [`Pad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1452 ///
1453 /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1454 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1455 /// the `Pad` will automatically be named after the `name_template`.
1456 ///
1457 /// # Panics
1458 ///
1459 /// Panics if the `name_template` is a wildcard-name.
1460 ///
1461 /// Use [`Pad::builder_from_static_template()`] to get a [`PadBuilder`] and define options.
1462 #[doc(alias = "gst_pad_new_from_static_template")]
1463 pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
1464 skip_assert_initialized!();
1465 Self::builder_from_static_template(templ).build()
1466 }
1467
1468 // rustdoc-stripper-ignore-next
1469 /// Creates a new [`PadBuilder`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1470 ///
1471 /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1472 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1473 /// the `Pad` will automatically be named after the `name_template`.
1474 ///
1475 /// Use [`PadBuilder::name`] or [`PadBuilder::maybe_name`] to specify a different name.
1476 #[doc(alias = "gst_pad_new_from_static_template")]
1477 pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder<Self> {
1478 skip_assert_initialized!();
1479 PadBuilder::from_static_template(templ)
1480 }
1481
1482 // rustdoc-stripper-ignore-next
1483 /// Creates a new [`Pad`] from the [`PadTemplate`](crate::PadTemplate).
1484 ///
1485 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1486 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1487 /// the `Pad` will automatically be named after the `name_template`.
1488 ///
1489 /// # Panics
1490 ///
1491 /// Panics if the `name_template` is a wildcard-name.
1492 ///
1493 /// Use [`Pad::builder_from_template()`] to get a [`PadBuilder`] and define options.
1494 #[doc(alias = "gst_pad_new_from_template")]
1495 pub fn from_template(templ: &crate::PadTemplate) -> Self {
1496 skip_assert_initialized!();
1497 Self::builder_from_template(templ).build()
1498 }
1499
1500 // rustdoc-stripper-ignore-next
1501 /// Creates a new [`PadBuilder`] from the [`PadTemplate`](crate::PadTemplate).
1502 ///
1503 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1504 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1505 /// the `Pad` will automatically be named after the `name_template`.
1506 ///
1507 /// Use [`PadBuilder::name`] or [`PadBuilder::maybe_name`] to specify a different name.
1508 #[doc(alias = "gst_pad_new_from_template")]
1509 pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder<Self> {
1510 skip_assert_initialized!();
1511 PadBuilder::from_template(templ)
1512 }
1513
1514 #[doc(alias = "gst_pad_query_default")]
1515 pub fn query_default<O: IsA<Pad>>(
1516 pad: &O,
1517 parent: Option<&impl IsA<crate::Object>>,
1518 query: &mut QueryRef,
1519 ) -> bool {
1520 skip_assert_initialized!();
1521 unsafe {
1522 from_glib(ffi::gst_pad_query_default(
1523 pad.as_ref().to_glib_none().0,
1524 parent.map(|p| p.as_ref()).to_glib_none().0,
1525 query.as_mut_ptr(),
1526 ))
1527 }
1528 }
1529
1530 #[doc(alias = "gst_pad_event_default")]
1531 pub fn event_default<O: IsA<Pad>>(
1532 pad: &O,
1533 parent: Option<&impl IsA<crate::Object>>,
1534 event: impl Into<Event>,
1535 ) -> bool {
1536 skip_assert_initialized!();
1537 unsafe {
1538 from_glib(ffi::gst_pad_event_default(
1539 pad.as_ref().to_glib_none().0,
1540 parent.map(|p| p.as_ref()).to_glib_none().0,
1541 event.into().into_glib_ptr(),
1542 ))
1543 }
1544 }
1545
1546 #[doc(alias = "gst_pad_iterate_internal_links_default")]
1547 pub fn iterate_internal_links_default<O: IsA<Pad>>(
1548 pad: &O,
1549 parent: Option<&impl IsA<crate::Object>>,
1550 ) -> crate::Iterator<Pad> {
1551 skip_assert_initialized!();
1552 unsafe {
1553 from_glib_full(ffi::gst_pad_iterate_internal_links_default(
1554 pad.as_ref().to_glib_none().0,
1555 parent.map(|p| p.as_ref()).to_glib_none().0,
1556 ))
1557 }
1558 }
1559}
1560
1561#[must_use = "The builder must be built to be used"]
1562pub struct PadBuilder<T> {
1563 pub(crate) pad: T,
1564 pub(crate) needs_specific_name: bool,
1565}
1566
1567impl<T: IsA<Pad> + IsA<glib::Object> + glib::object::IsClass> PadBuilder<T> {
1568 // rustdoc-stripper-ignore-next
1569 /// Creates a `PadBuilder` with the specified [`PadDirection`](crate::PadDirection).
1570 ///
1571 /// An automatically generated name will be assigned. Use [`PadBuilder::name`] or
1572 /// [`PadBuilder::maybe_name`] to define a specific name.
1573 pub fn new(direction: crate::PadDirection) -> Self {
1574 assert_initialized_main_thread!();
1575
1576 let pad = glib::Object::builder::<T>()
1577 .property("direction", direction)
1578 .build();
1579
1580 // Ghost pads are a bit special
1581 if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
1582 unsafe {
1583 let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
1584 // This can't really fail...
1585 debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
1586 }
1587 }
1588
1589 PadBuilder {
1590 pad,
1591 needs_specific_name: false,
1592 }
1593 }
1594
1595 // rustdoc-stripper-ignore-next
1596 /// Creates a `PadBuilder` from the specified [`StaticPadTemplate`](crate::StaticPadTemplate).
1597 ///
1598 /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1599 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1600 /// the `Pad` will automatically be named after the `name_template`.
1601 ///
1602 /// Use [`PadBuilder::name`] or [`PadBuilder::maybe_name`] to specify a different name.
1603 pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
1604 skip_assert_initialized!();
1605
1606 let templ = templ.get();
1607 Self::from_template(&templ)
1608 }
1609
1610 // rustdoc-stripper-ignore-next
1611 /// Creates a `PadBuilder` from the specified [`PadTemplate`](crate::PadTemplate).
1612 ///
1613 /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1614 /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1615 /// the `Pad` will automatically be named after the `name_template`.
1616 ///
1617 /// Use [`PadBuilder::name`] or [`PadBuilder::maybe_name`] to specify a different name.
1618 pub fn from_template(templ: &crate::PadTemplate) -> Self {
1619 assert_initialized_main_thread!();
1620
1621 let mut type_ = T::static_type();
1622
1623 // Since 1.14 templates can keep a pad GType with them, so we need to do some
1624 // additional checks here now
1625 if templ.has_property("gtype", Some(glib::Type::static_type())) {
1626 let gtype = templ.property::<glib::Type>("gtype");
1627
1628 if gtype == glib::Type::UNIT {
1629 // Nothing to be done, we can create any kind of pad
1630 } else if gtype.is_a(type_) {
1631 // We were asked to create a parent type of the template type, e.g. a gst::Pad for
1632 // a template that wants a gst_base::AggregatorPad. Not a problem: update the type
1633 type_ = gtype;
1634 } else {
1635 // Otherwise the requested type must be a subclass of the template pad type
1636 assert!(type_.is_a(gtype));
1637 }
1638 }
1639
1640 let mut properties = [
1641 ("direction", templ.direction().into()),
1642 ("template", templ.into()),
1643 ];
1644
1645 let pad =
1646 unsafe { glib::Object::with_mut_values(type_, &mut properties).unsafe_cast::<T>() };
1647
1648 // Ghost pads are a bit special
1649 if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
1650 unsafe {
1651 let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
1652 // This can't really fail...
1653 debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
1654 }
1655 }
1656
1657 let needs_specific_name = if templ.name().find('%').is_some() {
1658 // Pad needs a specific name
1659 true
1660 } else {
1661 pad.set_property("name", templ.name());
1662 false
1663 };
1664
1665 PadBuilder {
1666 pad,
1667 needs_specific_name,
1668 }
1669 }
1670
1671 // rustdoc-stripper-ignore-next
1672 /// Sets the name of the Pad.
1673 pub fn name(mut self, name: impl glib::IntoGStr) -> Self {
1674 name.run_with_gstr(|name| self.pad.set_property("name", name));
1675 self.needs_specific_name = false;
1676
1677 self
1678 }
1679
1680 // rustdoc-stripper-ignore-next
1681 /// Optionally sets the name of the Pad.
1682 ///
1683 /// This method is convenient when the `name` is provided as an `Option`.
1684 /// If the `name` is `None`, this has no effect.
1685 pub fn maybe_name<N: glib::IntoGStr>(self, name: Option<N>) -> Self {
1686 if let Some(name) = name {
1687 self.name(name)
1688 } else {
1689 self
1690 }
1691 }
1692
1693 #[doc(alias = "gst_pad_set_activate_function")]
1694 pub fn activate_function<F>(self, func: F) -> Self
1695 where
1696 F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1697 {
1698 unsafe {
1699 self.pad.set_activate_function(func);
1700 }
1701
1702 self
1703 }
1704
1705 #[doc(alias = "gst_pad_set_activatemode_function")]
1706 pub fn activatemode_function<F>(self, func: F) -> Self
1707 where
1708 F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1709 + Send
1710 + Sync
1711 + 'static,
1712 {
1713 unsafe {
1714 self.pad.set_activatemode_function(func);
1715 }
1716
1717 self
1718 }
1719
1720 #[doc(alias = "gst_pad_set_chain_function")]
1721 pub fn chain_function<F>(self, func: F) -> Self
1722 where
1723 F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1724 + Send
1725 + Sync
1726 + 'static,
1727 {
1728 unsafe {
1729 self.pad.set_chain_function(func);
1730 }
1731
1732 self
1733 }
1734
1735 #[doc(alias = "gst_pad_set_chain_list_function")]
1736 pub fn chain_list_function<F>(self, func: F) -> Self
1737 where
1738 F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1739 + Send
1740 + Sync
1741 + 'static,
1742 {
1743 unsafe {
1744 self.pad.set_chain_list_function(func);
1745 }
1746
1747 self
1748 }
1749
1750 #[doc(alias = "gst_pad_set_event_function")]
1751 pub fn event_function<F>(self, func: F) -> Self
1752 where
1753 F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1754 {
1755 unsafe {
1756 self.pad.set_event_function(func);
1757 }
1758
1759 self
1760 }
1761
1762 #[doc(alias = "gst_pad_set_event_full_function")]
1763 pub fn event_full_function<F>(self, func: F) -> Self
1764 where
1765 F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1766 + Send
1767 + Sync
1768 + 'static,
1769 {
1770 unsafe {
1771 self.pad.set_event_full_function(func);
1772 }
1773
1774 self
1775 }
1776
1777 #[doc(alias = "gst_pad_set_getrange_function")]
1778 pub fn getrange_function<F>(self, func: F) -> Self
1779 where
1780 F: Fn(
1781 &T,
1782 Option<&crate::Object>,
1783 u64,
1784 Option<&mut crate::BufferRef>,
1785 u32,
1786 ) -> Result<PadGetRangeSuccess, crate::FlowError>
1787 + Send
1788 + Sync
1789 + 'static,
1790 {
1791 unsafe {
1792 self.pad.set_getrange_function(func);
1793 }
1794
1795 self
1796 }
1797
1798 #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
1799 pub fn iterate_internal_links_function<F>(self, func: F) -> Self
1800 where
1801 F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1802 {
1803 unsafe {
1804 self.pad.set_iterate_internal_links_function(func);
1805 }
1806
1807 self
1808 }
1809
1810 #[doc(alias = "gst_pad_set_link_function")]
1811 pub fn link_function<F>(self, func: F) -> Self
1812 where
1813 F: Fn(
1814 &T,
1815 Option<&crate::Object>,
1816 &Pad,
1817 ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
1818 + Send
1819 + Sync
1820 + 'static,
1821 {
1822 unsafe {
1823 self.pad.set_link_function(func);
1824 }
1825
1826 self
1827 }
1828
1829 #[doc(alias = "gst_pad_set_query_function")]
1830 pub fn query_function<F>(self, func: F) -> Self
1831 where
1832 F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
1833 {
1834 unsafe {
1835 self.pad.set_query_function(func);
1836 }
1837
1838 self
1839 }
1840
1841 #[doc(alias = "gst_pad_set_unlink_function")]
1842 pub fn unlink_function<F>(self, func: F) -> Self
1843 where
1844 F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
1845 {
1846 unsafe {
1847 self.pad.set_unlink_function(func);
1848 }
1849
1850 self
1851 }
1852
1853 pub fn flags(self, flags: PadFlags) -> Self {
1854 self.pad.set_pad_flags(flags);
1855
1856 self
1857 }
1858
1859 // rustdoc-stripper-ignore-next
1860 /// Builds the [`Pad`].
1861 ///
1862 /// # Panics
1863 ///
1864 /// Panics if the [`Pad`] was built from a [`PadTemplate`](crate::PadTemplate)
1865 /// with a wildcard-name `name_template` (i.e. containing `%u`, `%s` or `%d`)
1866 /// and no specific `name` was provided using [`PadBuilder::name`]
1867 /// or [`PadBuilder::maybe_name`], or for [`GhostPad`s](crate::GhostPad),
1868 /// by defining a `target`.
1869 #[must_use = "Building the pad without using it has no effect"]
1870 #[track_caller]
1871 pub fn build(self) -> T {
1872 if self.needs_specific_name {
1873 panic!(concat!(
1874 "Attempt to build a Pad from a wildcard-name template",
1875 " or with a target Pad with an incompatible name.",
1876 " Make sure to define a specific name using PadBuilder.",
1877 ));
1878 }
1879
1880 self.pad
1881 }
1882}
1883
1884#[cfg(test)]
1885mod tests {
1886 use std::sync::{atomic::AtomicUsize, mpsc::channel, Arc, Mutex};
1887
1888 use super::*;
1889
1890 #[test]
1891 fn test_event_chain_functions() {
1892 crate::init().unwrap();
1893
1894 let events = Arc::new(Mutex::new(Vec::new()));
1895 let events_clone = events.clone();
1896 let buffers = Arc::new(Mutex::new(Vec::new()));
1897 let buffers_clone = buffers.clone();
1898 let pad = crate::Pad::builder(crate::PadDirection::Sink)
1899 .name("sink")
1900 .event_function(move |_, _, event| {
1901 let mut events = events_clone.lock().unwrap();
1902 events.push(event);
1903
1904 true
1905 })
1906 .chain_function(move |_, _, buffer| {
1907 let mut buffers = buffers_clone.lock().unwrap();
1908 buffers.push(buffer);
1909
1910 Ok(FlowSuccess::Ok)
1911 })
1912 .build();
1913
1914 pad.set_active(true).unwrap();
1915
1916 assert!(pad.send_event(crate::event::StreamStart::new("test")));
1917 let segment = crate::FormattedSegment::<crate::ClockTime>::new();
1918 assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
1919
1920 assert_eq!(pad.chain(crate::Buffer::new()), Ok(FlowSuccess::Ok));
1921
1922 let events = events.lock().unwrap();
1923 let buffers = buffers.lock().unwrap();
1924 assert_eq!(events.len(), 2);
1925 assert_eq!(buffers.len(), 1);
1926
1927 match events[0].view() {
1928 crate::EventView::StreamStart(..) => (),
1929 _ => unreachable!(),
1930 }
1931
1932 match events[1].view() {
1933 crate::EventView::Segment(..) => (),
1934 _ => unreachable!(),
1935 }
1936 }
1937
1938 #[test]
1939 fn test_getrange_function() {
1940 crate::init().unwrap();
1941
1942 let pad = crate::Pad::builder(crate::PadDirection::Src)
1943 .name("src")
1944 .activate_function(|pad, _parent| {
1945 pad.activate_mode(crate::PadMode::Pull, true)
1946 .map_err(|err| err.into())
1947 })
1948 .getrange_function(|_pad, _parent, offset, _buffer, size| {
1949 assert_eq!(offset, 0);
1950 assert_eq!(size, 5);
1951 let buffer = crate::Buffer::from_slice(b"abcde");
1952 Ok(PadGetRangeSuccess::NewBuffer(buffer))
1953 })
1954 .build();
1955 pad.set_active(true).unwrap();
1956
1957 let buffer = pad.range(0, 5).unwrap();
1958 let map = buffer.map_readable().unwrap();
1959 assert_eq!(&*map, b"abcde");
1960
1961 let mut buffer = crate::Buffer::with_size(5).unwrap();
1962 pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
1963 let map = buffer.map_readable().unwrap();
1964 assert_eq!(&*map, b"abcde");
1965
1966 pad.set_active(false).unwrap();
1967 drop(pad);
1968
1969 let pad = crate::Pad::builder(crate::PadDirection::Src)
1970 .name("src")
1971 .activate_function(|pad, _parent| {
1972 pad.activate_mode(crate::PadMode::Pull, true)
1973 .map_err(|err| err.into())
1974 })
1975 .getrange_function(|_pad, _parent, offset, buffer, size| {
1976 assert_eq!(offset, 0);
1977 assert_eq!(size, 5);
1978 if let Some(buffer) = buffer {
1979 buffer.copy_from_slice(0, b"fghij").unwrap();
1980 Ok(PadGetRangeSuccess::FilledBuffer)
1981 } else {
1982 let buffer = crate::Buffer::from_slice(b"abcde");
1983 Ok(PadGetRangeSuccess::NewBuffer(buffer))
1984 }
1985 })
1986 .build();
1987 pad.set_active(true).unwrap();
1988
1989 let buffer = pad.range(0, 5).unwrap();
1990 let map = buffer.map_readable().unwrap();
1991 assert_eq!(&*map, b"abcde");
1992
1993 let mut buffer = crate::Buffer::with_size(5).unwrap();
1994 pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
1995 let map = buffer.map_readable().unwrap();
1996 assert_eq!(&*map, b"fghij");
1997 }
1998
1999 #[test]
2000 fn test_task() {
2001 crate::init().unwrap();
2002
2003 let pad = crate::Pad::builder(crate::PadDirection::Sink)
2004 .name("sink")
2005 .build();
2006 let (sender, receiver) = channel();
2007
2008 let mut i = 0;
2009 let pad_clone = pad.clone();
2010 pad.start_task(move || {
2011 i += 1;
2012 if i == 3 {
2013 sender.send(i).unwrap();
2014 pad_clone.pause_task().unwrap();
2015 }
2016 })
2017 .unwrap();
2018
2019 assert_eq!(receiver.recv().unwrap(), 3);
2020 }
2021
2022 #[test]
2023 fn test_remove_probe_from_probe() {
2024 crate::init().unwrap();
2025
2026 let src_pad = crate::Pad::builder(crate::PadDirection::Src)
2027 .name("src")
2028 .build();
2029 let sink_pad = crate::Pad::builder(crate::PadDirection::Sink)
2030 .name("sink")
2031 .chain_function(|_pad, _parent, _buffer| Ok(crate::FlowSuccess::Ok))
2032 .build();
2033
2034 src_pad.link(&sink_pad).unwrap();
2035
2036 let counter = Arc::new(AtomicUsize::new(0));
2037 let counter_clone = counter.clone();
2038 src_pad.add_probe(crate::PadProbeType::BUFFER, move |pad, info| {
2039 if let Some(PadProbeData::Buffer(_)) = info.data {
2040 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
2041 pad.remove_probe(info.id.take().expect("no pad probe id"));
2042 } else {
2043 unreachable!();
2044 }
2045 crate::PadProbeReturn::Handled
2046 });
2047
2048 sink_pad.set_active(true).unwrap();
2049 src_pad.set_active(true).unwrap();
2050
2051 assert!(src_pad.push_event(crate::event::StreamStart::new("test")));
2052 let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2053 assert!(src_pad.push_event(crate::event::Segment::new(segment.as_ref())));
2054
2055 assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2056 assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2057
2058 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
2059 }
2060
2061 #[test]
2062 fn test_probe() {
2063 crate::init().unwrap();
2064
2065 let (major, minor, micro, _) = crate::version();
2066 let pad = crate::Pad::builder(crate::PadDirection::Src)
2067 .name("src")
2068 .build();
2069 let events = Arc::new(Mutex::new(Vec::new()));
2070 let buffers = Arc::new(Mutex::new(Vec::new()));
2071
2072 let flow_override = if (major, minor, micro) >= (1, 16, 1) {
2073 Err(FlowError::Eos)
2074 } else {
2075 // Broken on 1.16.0
2076 // https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/151
2077 Ok(FlowSuccess::Ok)
2078 };
2079
2080 {
2081 let events = events.clone();
2082 pad.add_probe(crate::PadProbeType::EVENT_DOWNSTREAM, move |_, info| {
2083 if let Some(PadProbeData::Event(event)) = &info.data {
2084 let mut events = events.lock().unwrap();
2085 events.push(event.clone());
2086 } else {
2087 unreachable!();
2088 }
2089 crate::PadProbeReturn::Ok
2090 });
2091 }
2092
2093 {
2094 let events = events.clone();
2095 pad.add_probe(crate::PadProbeType::EVENT_UPSTREAM, move |_, info| {
2096 if let Some(PadProbeData::Event(event)) = info.data.take() {
2097 let mut events = events.lock().unwrap();
2098 events.push(event);
2099 } else {
2100 unreachable!();
2101 }
2102 crate::PadProbeReturn::Handled
2103 });
2104 }
2105
2106 {
2107 let buffers = buffers.clone();
2108 pad.add_probe(crate::PadProbeType::BUFFER, move |_, info| {
2109 if let Some(PadProbeData::Buffer(buffer)) = info.data.take() {
2110 let mut buffers = buffers.lock().unwrap();
2111 info.flow_res = if buffers.is_empty() {
2112 Ok(FlowSuccess::Ok)
2113 } else {
2114 flow_override
2115 };
2116 buffers.push(buffer);
2117 } else {
2118 unreachable!();
2119 }
2120 crate::PadProbeReturn::Handled
2121 });
2122 }
2123
2124 pad.set_active(true).unwrap();
2125
2126 assert!(
2127 pad.send_event(crate::event::Latency::new(crate::ClockTime::from_nseconds(
2128 10
2129 )))
2130 );
2131 assert!(pad.push_event(crate::event::StreamStart::new("test")));
2132 let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2133 assert!(pad.push_event(crate::event::Segment::new(segment.as_ref())));
2134
2135 assert_eq!(pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2136 assert_eq!(pad.push(crate::Buffer::new()), flow_override);
2137
2138 let events = events.lock().unwrap();
2139 let buffers = buffers.lock().unwrap();
2140 assert_eq!(events.len(), 3);
2141 assert_eq!(buffers.len(), 2);
2142
2143 assert_eq!(events[0].type_(), crate::EventType::Latency);
2144 assert_eq!(events[1].type_(), crate::EventType::StreamStart);
2145 assert_eq!(events[2].type_(), crate::EventType::Segment);
2146
2147 assert!(
2148 buffers.iter().all(|b| b.is_writable()),
2149 "A buffer ref leaked!"
2150 );
2151
2152 drop(pad); // Need to drop the pad first to unref sticky events
2153 assert!(
2154 events.iter().all(|e| e.is_writable()),
2155 "An event ref leaked!"
2156 );
2157 }
2158
2159 #[test]
2160 fn test_sticky_events() {
2161 crate::init().unwrap();
2162
2163 let pad = crate::Pad::builder(crate::PadDirection::Sink)
2164 .name("sink")
2165 .build();
2166 pad.set_active(true).unwrap();
2167
2168 // Send some sticky events
2169 assert!(pad.send_event(crate::event::StreamStart::new("test")));
2170
2171 let caps = crate::Caps::builder("some/x-caps").build();
2172 assert!(pad.send_event(crate::event::Caps::new(&caps)));
2173
2174 let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2175 assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2176
2177 let stream_start = pad.sticky_event::<crate::event::StreamStart>(0).unwrap();
2178 assert_eq!(stream_start.stream_id(), "test");
2179
2180 let caps2 = pad.sticky_event::<crate::event::Caps>(0).unwrap();
2181 assert_eq!(&*caps, caps2.caps());
2182
2183 let segment = pad.sticky_event::<crate::event::Segment>(0).unwrap();
2184 assert_eq!(segment.segment().format(), crate::Format::Time);
2185 }
2186
2187 #[test]
2188 fn test_sticky_events_foreach() {
2189 crate::init().unwrap();
2190
2191 let pad = crate::Pad::builder(crate::PadDirection::Sink)
2192 .name("sink")
2193 .build();
2194 pad.set_active(true).unwrap();
2195
2196 // Send some sticky events
2197 assert!(pad.send_event(crate::event::StreamStart::new("test")));
2198
2199 let caps = crate::Caps::builder("some/x-caps").build();
2200 assert!(pad.send_event(crate::event::Caps::new(&caps)));
2201
2202 let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2203 assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2204
2205 let mut sticky_events = Vec::new();
2206 pad.sticky_events_foreach(|event| {
2207 sticky_events.push(event.clone());
2208 ControlFlow::Continue(EventForeachAction::Keep)
2209 });
2210 assert_eq!(sticky_events.len(), 3);
2211
2212 // Test early exit from foreach loop
2213 let mut sticky_events2 = Vec::new();
2214 pad.sticky_events_foreach(|event| {
2215 sticky_events2.push(event.clone());
2216 if event.type_() == crate::EventType::Caps {
2217 ControlFlow::Break(EventForeachAction::Keep)
2218 } else {
2219 ControlFlow::Continue(EventForeachAction::Keep)
2220 }
2221 });
2222 assert_eq!(sticky_events2.len(), 2);
2223
2224 let mut sticky_events3 = Vec::new();
2225 pad.sticky_events_foreach(|event| {
2226 sticky_events3.push(event.clone());
2227 ControlFlow::Continue(EventForeachAction::Keep)
2228 });
2229 assert_eq!(sticky_events3.len(), 3);
2230
2231 for (e1, e2) in sticky_events.iter().zip(sticky_events3.iter()) {
2232 assert_eq!(e1.as_ref() as *const _, e2.as_ref() as *const _);
2233 }
2234
2235 // Replace segment event
2236 pad.sticky_events_foreach(|event| {
2237 let action = if event.type_() == crate::EventType::Segment {
2238 let byte_segment = crate::FormattedSegment::<crate::format::Bytes>::new();
2239 EventForeachAction::Replace(crate::event::Segment::new(&byte_segment))
2240 } else {
2241 EventForeachAction::Keep
2242 };
2243 ControlFlow::Continue(action)
2244 });
2245
2246 // Check that segment event is different now
2247 let mut sticky_events4 = Vec::new();
2248 pad.sticky_events_foreach(|event| {
2249 sticky_events4.push(event.clone());
2250 ControlFlow::Continue(EventForeachAction::Keep)
2251 });
2252 assert_eq!(sticky_events4.len(), 3);
2253 assert_eq!(
2254 sticky_events[0].as_ref() as *const _,
2255 sticky_events4[0].as_ref() as *const _
2256 );
2257 assert_eq!(
2258 sticky_events[1].as_ref() as *const _,
2259 sticky_events4[1].as_ref() as *const _
2260 );
2261 assert_ne!(
2262 sticky_events[2].as_ref() as *const _,
2263 sticky_events4[2].as_ref() as *const _
2264 );
2265
2266 // Drop caps event
2267 pad.sticky_events_foreach(|event| {
2268 let action = if event.type_() == crate::EventType::Caps {
2269 EventForeachAction::Remove
2270 } else {
2271 EventForeachAction::Keep
2272 };
2273 ControlFlow::Continue(action)
2274 });
2275
2276 // Check that caps event actually got removed
2277 let mut sticky_events5 = Vec::new();
2278 pad.sticky_events_foreach(|event| {
2279 sticky_events5.push(event.clone());
2280 ControlFlow::Continue(EventForeachAction::Keep)
2281 });
2282 assert_eq!(sticky_events5.len(), 2);
2283 assert_eq!(
2284 sticky_events4[0].as_ref() as *const _,
2285 sticky_events5[0].as_ref() as *const _
2286 );
2287 assert_eq!(
2288 sticky_events4[2].as_ref() as *const _,
2289 sticky_events5[1].as_ref() as *const _
2290 );
2291 }
2292
2293 #[test]
2294 fn naming() {
2295 crate::init().unwrap();
2296
2297 let pad = crate::Pad::builder(crate::PadDirection::Sink).build();
2298 assert!(pad.name().starts_with("pad"));
2299
2300 let pad = crate::Pad::builder(crate::PadDirection::Src).build();
2301 assert!(pad.name().starts_with("pad"));
2302
2303 let pad = crate::Pad::builder(crate::PadDirection::Unknown).build();
2304 assert!(pad.name().starts_with("pad"));
2305
2306 let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2307 .maybe_name(None::<&str>)
2308 .build();
2309 assert!(pad.name().starts_with("pad"));
2310
2311 let pad = crate::Pad::builder(crate::PadDirection::Sink)
2312 .name("sink_0")
2313 .build();
2314 assert_eq!(pad.name(), "sink_0");
2315
2316 let pad = crate::Pad::builder(crate::PadDirection::Src)
2317 .name("src_0")
2318 .build();
2319 assert_eq!(pad.name(), "src_0");
2320
2321 let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2322 .name("test")
2323 .build();
2324 assert_eq!(pad.name(), "test");
2325
2326 let pad = crate::Pad::builder(crate::PadDirection::Unknown)
2327 .maybe_name(Some("test"))
2328 .build();
2329 assert_eq!(pad.name(), "test");
2330
2331 let caps = crate::Caps::new_any();
2332 let templ = crate::PadTemplate::new(
2333 "sink",
2334 crate::PadDirection::Sink,
2335 crate::PadPresence::Always,
2336 &caps,
2337 )
2338 .unwrap();
2339
2340 let pad = Pad::from_template(&templ);
2341 assert!(pad.name().starts_with("sink"));
2342
2343 let pad = Pad::builder_from_template(&templ)
2344 .name("audio_sink")
2345 .build();
2346 assert!(pad.name().starts_with("audio_sink"));
2347
2348 let templ = crate::PadTemplate::new(
2349 "audio_%u",
2350 crate::PadDirection::Sink,
2351 crate::PadPresence::Request,
2352 &caps,
2353 )
2354 .unwrap();
2355
2356 let pad = Pad::builder_from_template(&templ).name("audio_0").build();
2357 assert!(pad.name().starts_with("audio_0"));
2358 }
2359
2360 #[test]
2361 #[should_panic]
2362 fn missing_name() {
2363 crate::init().unwrap();
2364
2365 let caps = crate::Caps::new_any();
2366 let templ = crate::PadTemplate::new(
2367 "audio_%u",
2368 crate::PadDirection::Sink,
2369 crate::PadPresence::Request,
2370 &caps,
2371 )
2372 .unwrap();
2373
2374 // Panic: attempt to build from a wildcard-named template
2375 // without providing a name.
2376 let _pad = Pad::from_template(&templ);
2377 }
2378}
2379