gstreamer/
pad.rs

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    ffi,
15    format::{FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic},
16    prelude::*,
17    Buffer, BufferList, Event, FlowError, FlowReturn, FlowSuccess, Format, GenericFormattedValue,
18    LoggableError, Pad, PadFlags, PadProbeReturn, PadProbeType, Query, QueryRef, StaticPadTemplate,
19};
20
21#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct PadProbeId(NonZeroU64);
23
24impl IntoGlib for PadProbeId {
25    type GlibType = libc::c_ulong;
26
27    #[inline]
28    fn into_glib(self) -> libc::c_ulong {
29        self.0.get() as libc::c_ulong
30    }
31}
32
33impl FromGlib<libc::c_ulong> for PadProbeId {
34    #[inline]
35    unsafe fn from_glib(val: libc::c_ulong) -> PadProbeId {
36        skip_assert_initialized!();
37        debug_assert_ne!(val, 0);
38        PadProbeId(NonZeroU64::new_unchecked(val as _))
39    }
40}
41
42impl PadProbeId {
43    #[inline]
44    pub fn as_raw(&self) -> libc::c_ulong {
45        self.0.get() as libc::c_ulong
46    }
47}
48
49#[doc(alias = "GstPadProbeInfo")]
50#[derive(Debug)]
51pub struct PadProbeInfo<'a> {
52    pub mask: PadProbeType,
53    pub id: Option<PadProbeId>,
54    pub offset: u64,
55    pub size: u32,
56    pub data: Option<PadProbeData<'a>>,
57    pub flow_res: Result<FlowSuccess, FlowError>,
58}
59
60impl PadProbeInfo<'_> {
61    pub fn buffer(&self) -> Option<&Buffer> {
62        match self.data {
63            Some(PadProbeData::Buffer(ref buffer)) => Some(buffer),
64            _ => None,
65        }
66    }
67
68    pub fn buffer_mut(&mut self) -> Option<&mut Buffer> {
69        match self.data {
70            Some(PadProbeData::Buffer(ref mut buffer)) => Some(buffer),
71            _ => None,
72        }
73    }
74
75    pub fn buffer_list(&self) -> Option<&BufferList> {
76        match self.data {
77            Some(PadProbeData::BufferList(ref buffer_list)) => Some(buffer_list),
78            _ => None,
79        }
80    }
81
82    pub fn buffer_list_mut(&mut self) -> Option<&mut BufferList> {
83        match self.data {
84            Some(PadProbeData::BufferList(ref mut buffer_list)) => Some(buffer_list),
85            _ => None,
86        }
87    }
88
89    pub fn query(&self) -> Option<&QueryRef> {
90        match self.data {
91            Some(PadProbeData::Query(ref query)) => Some(*query),
92            _ => None,
93        }
94    }
95
96    pub fn query_mut(&mut self) -> Option<&mut QueryRef> {
97        match self.data {
98            Some(PadProbeData::Query(ref mut query)) => Some(*query),
99            _ => None,
100        }
101    }
102
103    pub fn event(&self) -> Option<&Event> {
104        match self.data {
105            Some(PadProbeData::Event(ref event)) => Some(event),
106            _ => None,
107        }
108    }
109
110    pub fn event_mut(&mut self) -> Option<&mut Event> {
111        match self.data {
112            Some(PadProbeData::Event(ref mut event)) => Some(event),
113            _ => None,
114        }
115    }
116
117    // rustdoc-stripper-ignore-next
118    /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the
119    /// probe will be considered dropped after this point.
120    pub fn take_buffer(&mut self) -> Option<Buffer> {
121        if matches!(self.data, Some(PadProbeData::Buffer(..))) {
122            match self.data.take() {
123                Some(PadProbeData::Buffer(b)) => Some(b),
124                _ => unreachable!(),
125            }
126        } else {
127            None
128        }
129    }
130
131    // rustdoc-stripper-ignore-next
132    /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the
133    /// probe will be considered dropped after this point.
134    pub fn take_buffer_list(&mut self) -> Option<BufferList> {
135        if matches!(self.data, Some(PadProbeData::BufferList(..))) {
136            match self.data.take() {
137                Some(PadProbeData::BufferList(b)) => Some(b),
138                _ => unreachable!(),
139            }
140        } else {
141            None
142        }
143    }
144    // rustdoc-stripper-ignore-next
145    /// Takes over the event in the probe info. As the data is no longer valid for the caller, the
146    /// probe will be considered dropped after this point.
147    pub fn take_event(&mut self) -> Option<Event> {
148        if matches!(self.data, Some(PadProbeData::Event(..))) {
149            match self.data.take() {
150                Some(PadProbeData::Event(e)) => Some(e),
151                _ => unreachable!(),
152            }
153        } else {
154            None
155        }
156    }
157}
158
159#[derive(Debug)]
160pub enum PadProbeData<'a> {
161    Buffer(Buffer),
162    BufferList(BufferList),
163    Query(&'a mut QueryRef),
164    Event(Event),
165    #[doc(hidden)]
166    __Unknown(*mut ffi::GstMiniObject),
167}
168
169unsafe impl Send for PadProbeData<'_> {}
170unsafe impl Sync for PadProbeData<'_> {}
171
172#[derive(Debug)]
173#[must_use = "if unused the StreamLock will immediately unlock"]
174pub struct StreamLock<'a>(&'a Pad);
175impl Drop for StreamLock<'_> {
176    #[inline]
177    fn drop(&mut self) {
178        unsafe {
179            let pad: *mut ffi::GstPad = self.0.to_glib_none().0;
180            glib::ffi::g_rec_mutex_unlock(&mut (*pad).stream_rec_lock);
181        }
182    }
183}
184
185#[derive(Debug)]
186pub enum PadGetRangeSuccess {
187    FilledBuffer,
188    NewBuffer(crate::Buffer),
189}
190
191#[derive(Debug)]
192pub enum EventForeachAction {
193    Keep,
194    Remove,
195    Replace(Event),
196}
197
198mod sealed {
199    pub trait Sealed {}
200    impl<T: super::IsA<super::Pad>> Sealed for T {}
201}
202
203pub trait PadExtManual: sealed::Sealed + IsA<Pad> + 'static {
204    /// Be notified of different states of pads. The provided callback is called for
205    /// every state that matches `mask`.
206    ///
207    /// Probes are called in groups: First GST_PAD_PROBE_TYPE_BLOCK probes are
208    /// called, then others, then finally GST_PAD_PROBE_TYPE_IDLE. The only
209    /// exception here are GST_PAD_PROBE_TYPE_IDLE probes that are called
210    /// immediately if the pad is already idle while calling [`add_probe()`][Self::add_probe()].
211    /// In each of the groups, probes are called in the order in which they were
212    /// added.
213    /// ## `mask`
214    /// the probe mask
215    /// ## `callback`
216    /// `GstPadProbeCallback` that will be called with
217    ///  notifications of the pad state
218    /// ## `destroy_data`
219    /// `GDestroyNotify` for user_data
220    ///
221    /// # Returns
222    ///
223    /// an id or 0 if no probe is pending. The id can be used to remove the
224    /// probe with [`remove_probe()`][Self::remove_probe()]. When using GST_PAD_PROBE_TYPE_IDLE it can
225    /// happen that the probe can be run immediately and if the probe returns
226    /// GST_PAD_PROBE_REMOVE this functions returns 0.
227    ///
228    /// MT safe.
229    #[doc(alias = "gst_pad_add_probe")]
230    fn add_probe<F>(&self, mask: PadProbeType, func: F) -> Option<PadProbeId>
231    where
232        F: Fn(&Self, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
233    {
234        unsafe {
235            let func_box: Box<F> = Box::new(func);
236            let id = ffi::gst_pad_add_probe(
237                self.as_ref().to_glib_none().0,
238                mask.into_glib(),
239                Some(trampoline_pad_probe::<Self, F>),
240                Box::into_raw(func_box) as gpointer,
241                Some(destroy_closure::<F>),
242            );
243
244            if id == 0 {
245                None
246            } else {
247                Some(from_glib(id))
248            }
249        }
250    }
251
252    /// Remove the probe with `id` from `self`.
253    ///
254    /// MT safe.
255    /// ## `id`
256    /// the probe id to remove
257    #[doc(alias = "gst_pad_remove_probe")]
258    fn remove_probe(&self, id: PadProbeId) {
259        unsafe {
260            ffi::gst_pad_remove_probe(self.as_ref().to_glib_none().0, id.into_glib());
261        }
262    }
263
264    /// Pulls a `buffer` from the peer pad or fills up a provided buffer.
265    ///
266    /// This function will first trigger the pad block signal if it was
267    /// installed.
268    ///
269    /// When `self` is not linked [`FlowReturn::NotLinked`][crate::FlowReturn::NotLinked] is returned else this
270    /// function returns the result of [`range()`][Self::range()] on the peer pad.
271    /// See [`range()`][Self::range()] for a list of return values and for the
272    /// semantics of the arguments of this function.
273    ///
274    /// If `buffer` points to a variable holding [`None`], a valid new [`Buffer`][crate::Buffer] will be
275    /// placed in `buffer` when this function returns [`FlowReturn::Ok`][crate::FlowReturn::Ok]. The new buffer
276    /// must be freed with `gst_buffer_unref()` after usage. When this function
277    /// returns any other result value, `buffer` will still point to [`None`].
278    ///
279    /// When `buffer` points to a variable that points to a valid [`Buffer`][crate::Buffer], the
280    /// buffer will be filled with the result data when this function returns
281    /// [`FlowReturn::Ok`][crate::FlowReturn::Ok]. When this function returns any other result value,
282    /// `buffer` will be unchanged. If the provided buffer is larger than `size`, only
283    /// `size` bytes will be filled in the result buffer and its size will be updated
284    /// accordingly.
285    ///
286    /// Note that less than `size` bytes can be returned in `buffer` when, for example,
287    /// an EOS condition is near or when `buffer` is not large enough to hold `size`
288    /// bytes. The caller should check the result buffer size to get the result size.
289    /// ## `offset`
290    /// The start offset of the buffer
291    /// ## `size`
292    /// The length of the buffer
293    ///
294    /// # Returns
295    ///
296    /// a [`FlowReturn`][crate::FlowReturn] from the peer pad.
297    ///
298    /// MT safe.
299    ///
300    /// ## `buffer`
301    /// a pointer to hold the [`Buffer`][crate::Buffer], returns
302    ///  GST_FLOW_ERROR if [`None`].
303    #[doc(alias = "gst_pad_pull_range")]
304    fn pull_range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
305        unsafe {
306            let mut buffer = ptr::null_mut();
307            FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
308                self.as_ref().to_glib_none().0,
309                offset,
310                size,
311                &mut buffer,
312            ))
313            .map(|_| from_glib_full(buffer))
314        }
315    }
316
317    fn pull_range_fill(
318        &self,
319        offset: u64,
320        buffer: &mut crate::BufferRef,
321        size: u32,
322    ) -> Result<(), FlowError> {
323        assert!(buffer.size() >= size as usize);
324
325        unsafe {
326            let mut buffer_ref = buffer.as_mut_ptr();
327            FlowSuccess::try_from_glib(ffi::gst_pad_pull_range(
328                self.as_ref().to_glib_none().0,
329                offset,
330                size,
331                &mut buffer_ref,
332            ))
333            .and_then(|_| {
334                if buffer.as_mut_ptr() != buffer_ref {
335                    ffi::gst_mini_object_unref(buffer_ref as *mut _);
336                    Err(crate::FlowError::Error)
337                } else {
338                    Ok(())
339                }
340            })
341        }
342    }
343
344    /// When `self` is flushing this function returns [`FlowReturn::Flushing`][crate::FlowReturn::Flushing]
345    /// immediately and `buffer` is [`None`].
346    ///
347    /// Calls the getrange function of `self`, see `GstPadGetRangeFunction` for a
348    /// description of a getrange function. If `self` has no getrange function
349    /// installed (see `gst_pad_set_getrange_function()`) this function returns
350    /// [`FlowReturn::NotSupported`][crate::FlowReturn::NotSupported].
351    ///
352    /// If `buffer` points to a variable holding [`None`], a valid new [`Buffer`][crate::Buffer] will be
353    /// placed in `buffer` when this function returns [`FlowReturn::Ok`][crate::FlowReturn::Ok]. The new buffer
354    /// must be freed with `gst_buffer_unref()` after usage.
355    ///
356    /// When `buffer` points to a variable that points to a valid [`Buffer`][crate::Buffer], the
357    /// buffer will be filled with the result data when this function returns
358    /// [`FlowReturn::Ok`][crate::FlowReturn::Ok]. If the provided buffer is larger than `size`, only
359    /// `size` bytes will be filled in the result buffer and its size will be updated
360    /// accordingly.
361    ///
362    /// Note that less than `size` bytes can be returned in `buffer` when, for example,
363    /// an EOS condition is near or when `buffer` is not large enough to hold `size`
364    /// bytes. The caller should check the result buffer size to get the result size.
365    ///
366    /// When this function returns any other result value than [`FlowReturn::Ok`][crate::FlowReturn::Ok], `buffer`
367    /// will be unchanged.
368    ///
369    /// This is a lowlevel function. Usually [`pull_range()`][Self::pull_range()] is used.
370    /// ## `offset`
371    /// The start offset of the buffer
372    /// ## `size`
373    /// The length of the buffer
374    ///
375    /// # Returns
376    ///
377    /// a [`FlowReturn`][crate::FlowReturn] from the pad.
378    ///
379    /// MT safe.
380    ///
381    /// ## `buffer`
382    /// a pointer to hold the [`Buffer`][crate::Buffer],
383    ///  returns [`FlowReturn::Error`][crate::FlowReturn::Error] if [`None`].
384    #[doc(alias = "get_range")]
385    #[doc(alias = "gst_pad_get_range")]
386    fn range(&self, offset: u64, size: u32) -> Result<Buffer, FlowError> {
387        unsafe {
388            let mut buffer = ptr::null_mut();
389            FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
390                self.as_ref().to_glib_none().0,
391                offset,
392                size,
393                &mut buffer,
394            ))
395            .map(|_| from_glib_full(buffer))
396        }
397    }
398
399    #[doc(alias = "get_range_fill")]
400    fn range_fill(
401        &self,
402        offset: u64,
403        buffer: &mut crate::BufferRef,
404        size: u32,
405    ) -> Result<(), FlowError> {
406        assert!(buffer.size() >= size as usize);
407
408        unsafe {
409            let mut buffer_ref = buffer.as_mut_ptr();
410            FlowSuccess::try_from_glib(ffi::gst_pad_get_range(
411                self.as_ref().to_glib_none().0,
412                offset,
413                size,
414                &mut buffer_ref,
415            ))
416            .and_then(|_| {
417                if buffer.as_mut_ptr() != buffer_ref {
418                    ffi::gst_mini_object_unref(buffer_ref as *mut _);
419                    Err(crate::FlowError::Error)
420                } else {
421                    Ok(())
422                }
423            })
424        }
425    }
426
427    /// Performs [`query()`][Self::query()] on the peer of `self`.
428    ///
429    /// The caller is responsible for both the allocation and deallocation of
430    /// the query structure.
431    /// ## `query`
432    /// the [`Query`][crate::Query] to perform.
433    ///
434    /// # Returns
435    ///
436    /// [`true`] if the query could be performed. This function returns [`false`]
437    /// if `self` has no peer.
438    #[doc(alias = "gst_pad_peer_query")]
439    fn peer_query(&self, query: &mut QueryRef) -> bool {
440        unsafe {
441            from_glib(ffi::gst_pad_peer_query(
442                self.as_ref().to_glib_none().0,
443                query.as_mut_ptr(),
444            ))
445        }
446    }
447
448    /// Dispatches a query to a pad. The query should have been allocated by the
449    /// caller via one of the type-specific allocation functions. The element that
450    /// the pad belongs to is responsible for filling the query with an appropriate
451    /// response, which should then be parsed with a type-specific query parsing
452    /// function.
453    ///
454    /// Again, the caller is responsible for both the allocation and deallocation of
455    /// the query structure.
456    ///
457    /// Please also note that some queries might need a running pipeline to work.
458    /// ## `query`
459    /// the [`Query`][crate::Query] to perform.
460    ///
461    /// # Returns
462    ///
463    /// [`true`] if the query could be performed.
464    #[doc(alias = "gst_pad_query")]
465    fn query(&self, query: &mut QueryRef) -> bool {
466        unsafe {
467            from_glib(ffi::gst_pad_query(
468                self.as_ref().to_glib_none().0,
469                query.as_mut_ptr(),
470            ))
471        }
472    }
473
474    /// Calls [`PadExt::query_caps()`][crate::prelude::PadExt::query_caps()] for all internally linked pads of `self` and returns
475    /// the intersection of the results.
476    ///
477    /// This function is useful as a default caps query function for an element
478    /// that can handle any stream format, but requires all its pads to have
479    /// the same caps. Two such elements are tee and adder.
480    /// ## `query`
481    /// a CAPS [`Query`][crate::Query].
482    ///
483    /// # Returns
484    ///
485    /// [`true`] if `query` could be executed
486    #[doc(alias = "gst_pad_proxy_query_caps")]
487    fn proxy_query_caps(&self, query: &mut QueryRef) -> bool {
488        unsafe {
489            from_glib(ffi::gst_pad_proxy_query_caps(
490                self.as_ref().to_glib_none().0,
491                query.as_mut_ptr(),
492            ))
493        }
494    }
495
496    /// Checks if all internally linked pads of `self` accepts the caps in `query` and
497    /// returns the intersection of the results.
498    ///
499    /// This function is useful as a default accept caps query function for an element
500    /// that can handle any stream format, but requires caps that are acceptable for
501    /// all opposite pads.
502    /// ## `query`
503    /// an ACCEPT_CAPS [`Query`][crate::Query].
504    ///
505    /// # Returns
506    ///
507    /// [`true`] if `query` could be executed
508    #[doc(alias = "gst_pad_proxy_query_accept_caps")]
509    fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool {
510        unsafe {
511            from_glib(ffi::gst_pad_proxy_query_accept_caps(
512                self.as_ref().to_glib_none().0,
513                query.as_mut_ptr(),
514            ))
515        }
516    }
517
518    /// Sends the event to the peer of the given pad. This function is
519    /// mainly used by elements to send events to their peer
520    /// elements.
521    ///
522    /// This function takes ownership of the provided event so you should
523    /// `gst_event_ref()` it if you want to reuse the event after this call.
524    /// ## `event`
525    /// the [`Event`][crate::Event] to send to the pad.
526    ///
527    /// # Returns
528    ///
529    /// [`true`] if the event was handled.
530    ///
531    /// MT safe.
532    #[doc(alias = "gst_pad_push_event")]
533    fn push_event(&self, event: impl Into<Event>) -> bool {
534        unsafe {
535            from_glib(ffi::gst_pad_push_event(
536                self.as_ref().to_glib_none().0,
537                event.into().into_glib_ptr(),
538            ))
539        }
540    }
541
542    /// Sends the event to the pad. This function can be used
543    /// by applications to send events in the pipeline.
544    ///
545    /// If `self` is a source pad, `event` should be an upstream event. If `self` is a
546    /// sink pad, `event` should be a downstream event. For example, you would not
547    /// send a [`EventType::Eos`][crate::EventType::Eos] on a src pad; EOS events only propagate downstream.
548    /// Furthermore, some downstream events have to be serialized with data flow,
549    /// like EOS, while some can travel out-of-band, like [`EventType::FlushStart`][crate::EventType::FlushStart]. If
550    /// the event needs to be serialized with data flow, this function will take the
551    /// pad's stream lock while calling its event function.
552    ///
553    /// To find out whether an event type is upstream, downstream, or downstream and
554    /// serialized, see [`EventTypeFlags`][crate::EventTypeFlags], [`EventType::flags()`][crate::EventType::flags()],
555    /// `GST_EVENT_IS_UPSTREAM`, `GST_EVENT_IS_DOWNSTREAM`, and
556    /// `GST_EVENT_IS_SERIALIZED`. Note that in practice that an application or
557    /// plugin doesn't need to bother itself with this information; the core handles
558    /// all necessary locks and checks.
559    ///
560    /// This function takes ownership of the provided event so you should
561    /// `gst_event_ref()` it if you want to reuse the event after this call.
562    /// ## `event`
563    /// the [`Event`][crate::Event] to send to the pad.
564    ///
565    /// # Returns
566    ///
567    /// [`true`] if the event was handled.
568    #[doc(alias = "gst_pad_send_event")]
569    fn send_event(&self, event: impl Into<Event>) -> bool {
570        unsafe {
571            from_glib(ffi::gst_pad_send_event(
572                self.as_ref().to_glib_none().0,
573                event.into().into_glib_ptr(),
574            ))
575        }
576    }
577
578    #[doc(alias = "gst_pad_iterate_internal_links")]
579    fn iterate_internal_links(&self) -> crate::Iterator<Pad> {
580        unsafe {
581            from_glib_full(ffi::gst_pad_iterate_internal_links(
582                self.as_ref().to_glib_none().0,
583            ))
584        }
585    }
586
587    fn stream_lock(&self) -> StreamLock {
588        unsafe {
589            let ptr: &mut ffi::GstPad = &mut *(self.as_ptr() as *mut _);
590            glib::ffi::g_rec_mutex_lock(&mut ptr.stream_rec_lock);
591            StreamLock(self.upcast_ref())
592        }
593    }
594
595    #[doc(alias = "gst_pad_set_activate_function")]
596    #[doc(alias = "gst_pad_set_activate_function_full")]
597    unsafe fn set_activate_function<F>(&self, func: F)
598    where
599        F: Fn(&Self, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
600    {
601        let func_box: Box<F> = Box::new(func);
602        ffi::gst_pad_set_activate_function_full(
603            self.as_ref().to_glib_none().0,
604            Some(trampoline_activate_function::<Self, F>),
605            Box::into_raw(func_box) as gpointer,
606            Some(destroy_closure::<F>),
607        );
608    }
609
610    #[doc(alias = "gst_pad_set_activatemode_function")]
611    #[doc(alias = "gst_pad_set_activatemode_function_full")]
612    unsafe fn set_activatemode_function<F>(&self, func: F)
613    where
614        F: Fn(&Self, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
615            + Send
616            + Sync
617            + 'static,
618    {
619        let func_box: Box<F> = Box::new(func);
620        ffi::gst_pad_set_activatemode_function_full(
621            self.as_ref().to_glib_none().0,
622            Some(trampoline_activatemode_function::<Self, F>),
623            Box::into_raw(func_box) as gpointer,
624            Some(destroy_closure::<F>),
625        );
626    }
627
628    #[doc(alias = "gst_pad_set_chain_function")]
629    #[doc(alias = "gst_pad_set_chain_function_full")]
630    unsafe fn set_chain_function<F>(&self, func: F)
631    where
632        F: Fn(&Self, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
633            + Send
634            + Sync
635            + 'static,
636    {
637        let func_box: Box<F> = Box::new(func);
638        ffi::gst_pad_set_chain_function_full(
639            self.as_ref().to_glib_none().0,
640            Some(trampoline_chain_function::<Self, F>),
641            Box::into_raw(func_box) as gpointer,
642            Some(destroy_closure::<F>),
643        );
644    }
645
646    #[doc(alias = "gst_pad_set_chain_list_function")]
647    #[doc(alias = "gst_pad_set_chain_list_function_full")]
648    unsafe fn set_chain_list_function<F>(&self, func: F)
649    where
650        F: Fn(&Self, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
651            + Send
652            + Sync
653            + 'static,
654    {
655        let func_box: Box<F> = Box::new(func);
656        ffi::gst_pad_set_chain_list_function_full(
657            self.as_ref().to_glib_none().0,
658            Some(trampoline_chain_list_function::<Self, F>),
659            Box::into_raw(func_box) as gpointer,
660            Some(destroy_closure::<F>),
661        );
662    }
663
664    #[doc(alias = "gst_pad_set_event_function")]
665    #[doc(alias = "gst_pad_set_event_function_full")]
666    unsafe fn set_event_function<F>(&self, func: F)
667    where
668        F: Fn(&Self, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
669    {
670        let func_box: Box<F> = Box::new(func);
671        ffi::gst_pad_set_event_function_full(
672            self.as_ref().to_glib_none().0,
673            Some(trampoline_event_function::<Self, F>),
674            Box::into_raw(func_box) as gpointer,
675            Some(destroy_closure::<F>),
676        );
677    }
678
679    #[doc(alias = "gst_pad_set_event_full_function")]
680    #[doc(alias = "gst_pad_set_event_full_function_full")]
681    unsafe fn set_event_full_function<F>(&self, func: F)
682    where
683        F: Fn(&Self, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
684            + Send
685            + Sync
686            + 'static,
687    {
688        let func_box: Box<F> = Box::new(func);
689        ffi::gst_pad_set_event_full_function_full(
690            self.as_ref().to_glib_none().0,
691            Some(trampoline_event_full_function::<Self, F>),
692            Box::into_raw(func_box) as gpointer,
693            Some(destroy_closure::<F>),
694        );
695    }
696
697    #[doc(alias = "gst_pad_set_getrange_function")]
698    #[doc(alias = "gst_pad_set_getrange_function_full")]
699    unsafe fn set_getrange_function<F>(&self, func: F)
700    where
701        F: Fn(
702                &Self,
703                Option<&crate::Object>,
704                u64,
705                Option<&mut crate::BufferRef>,
706                u32,
707            ) -> Result<PadGetRangeSuccess, crate::FlowError>
708            + Send
709            + Sync
710            + 'static,
711    {
712        let func_box: Box<F> = Box::new(func);
713        ffi::gst_pad_set_getrange_function_full(
714            self.as_ref().to_glib_none().0,
715            Some(trampoline_getrange_function::<Self, F>),
716            Box::into_raw(func_box) as gpointer,
717            Some(destroy_closure::<F>),
718        );
719    }
720
721    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
722    #[doc(alias = "gst_pad_set_iterate_internal_links_function_full")]
723    unsafe fn set_iterate_internal_links_function<F>(&self, func: F)
724    where
725        F: Fn(&Self, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
726    {
727        let func_box: Box<F> = Box::new(func);
728        ffi::gst_pad_set_iterate_internal_links_function_full(
729            self.as_ref().to_glib_none().0,
730            Some(trampoline_iterate_internal_links_function::<Self, F>),
731            Box::into_raw(func_box) as gpointer,
732            Some(destroy_closure::<F>),
733        );
734    }
735
736    #[doc(alias = "gst_pad_set_link_function")]
737    #[doc(alias = "gst_pad_set_link_function_full")]
738    unsafe fn set_link_function<F>(&self, func: F)
739    where
740        F: Fn(
741                &Self,
742                Option<&crate::Object>,
743                &Pad,
744            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
745            + Send
746            + Sync
747            + 'static,
748    {
749        let func_box: Box<F> = Box::new(func);
750        ffi::gst_pad_set_link_function_full(
751            self.as_ref().to_glib_none().0,
752            Some(trampoline_link_function::<Self, F>),
753            Box::into_raw(func_box) as gpointer,
754            Some(destroy_closure::<F>),
755        );
756    }
757
758    #[doc(alias = "gst_pad_set_query_function")]
759    #[doc(alias = "gst_pad_set_query_function_full")]
760    unsafe fn set_query_function<F>(&self, func: F)
761    where
762        F: Fn(&Self, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
763    {
764        let func_box: Box<F> = Box::new(func);
765        ffi::gst_pad_set_query_function_full(
766            self.as_ref().to_glib_none().0,
767            Some(trampoline_query_function::<Self, F>),
768            Box::into_raw(func_box) as gpointer,
769            Some(destroy_closure::<F>),
770        );
771    }
772
773    #[doc(alias = "gst_pad_set_unlink_function")]
774    #[doc(alias = "gst_pad_set_unlink_function_full")]
775    unsafe fn set_unlink_function<F>(&self, func: F)
776    where
777        F: Fn(&Self, Option<&crate::Object>) + Send + Sync + 'static,
778    {
779        let func_box: Box<F> = Box::new(func);
780        ffi::gst_pad_set_unlink_function_full(
781            self.as_ref().to_glib_none().0,
782            Some(trampoline_unlink_function::<Self, F>),
783            Box::into_raw(func_box) as gpointer,
784            Some(destroy_closure::<F>),
785        );
786    }
787
788    /// Starts a task that repeatedly calls `func` with `user_data`. This function
789    /// is mostly used in pad activation functions to start the dataflow.
790    /// The `GST_PAD_STREAM_LOCK` of `self` will automatically be acquired
791    /// before `func` is called.
792    /// ## `func`
793    /// the task function to call
794    /// ## `notify`
795    /// called when `user_data` is no longer referenced
796    ///
797    /// # Returns
798    ///
799    /// a [`true`] if the task could be started.
800    #[doc(alias = "gst_pad_start_task")]
801    fn start_task<F: FnMut() + Send + 'static>(&self, func: F) -> Result<(), glib::BoolError> {
802        unsafe extern "C" fn trampoline_pad_task<F: FnMut() + Send + 'static>(func: gpointer) {
803            let (func, pad) = &mut *(func as *mut (F, *mut ffi::GstPad));
804            let pad = Pad::from_glib_borrow(*pad);
805            let result = panic::catch_unwind(AssertUnwindSafe(func));
806
807            if let Err(err) = result {
808                let element = match pad.parent_element() {
809                    Some(element) => element,
810                    None => panic::resume_unwind(err),
811                };
812
813                if pad.pause_task().is_err() {
814                    crate::error!(crate::CAT_RUST, "could not stop pad task on panic");
815                }
816
817                crate::subclass::post_panic_error_message(&element, pad.upcast_ref(), Some(err));
818            }
819        }
820
821        fn into_raw_pad_task<F: FnMut() + Send + 'static>(
822            func: F,
823            pad: *mut ffi::GstPad,
824        ) -> gpointer {
825            #[allow(clippy::type_complexity)]
826            let func: Box<(F, *mut ffi::GstPad)> = Box::new((func, pad));
827            Box::into_raw(func) as gpointer
828        }
829
830        unsafe extern "C" fn destroy_closure_pad_task<F>(ptr: gpointer) {
831            let _ = Box::<(F, *mut ffi::GstPad)>::from_raw(ptr as *mut _);
832        }
833
834        unsafe {
835            glib::result_from_gboolean!(
836                ffi::gst_pad_start_task(
837                    self.as_ref().to_glib_none().0,
838                    Some(trampoline_pad_task::<F>),
839                    into_raw_pad_task(func, self.upcast_ref().as_ptr()),
840                    Some(destroy_closure_pad_task::<F>),
841                ),
842                "Failed to start pad task",
843            )
844        }
845    }
846    /// Queries the peer pad of a given sink pad to convert `src_val` in `src_format`
847    /// to `dest_format`.
848    /// ## `src_format`
849    /// a [`Format`][crate::Format] to convert from.
850    /// ## `src_val`
851    /// a value to convert.
852    /// ## `dest_format`
853    /// the [`Format`][crate::Format] to convert to.
854    ///
855    /// # Returns
856    ///
857    /// [`true`] if the query could be performed.
858    ///
859    /// ## `dest_val`
860    /// a pointer to the result.
861    #[doc(alias = "gst_pad_peer_query_convert")]
862    fn peer_query_convert<U: SpecificFormattedValueFullRange>(
863        &self,
864        src_val: impl FormattedValue,
865    ) -> Option<U> {
866        unsafe {
867            let mut dest_val = mem::MaybeUninit::uninit();
868            let ret = from_glib(ffi::gst_pad_peer_query_convert(
869                self.as_ref().to_glib_none().0,
870                src_val.format().into_glib(),
871                src_val.into_raw_value(),
872                U::default_format().into_glib(),
873                dest_val.as_mut_ptr(),
874            ));
875            if ret {
876                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
877            } else {
878                None
879            }
880        }
881    }
882
883    #[doc(alias = "gst_pad_peer_query_convert")]
884    fn peer_query_convert_generic(
885        &self,
886        src_val: impl FormattedValue,
887        dest_format: Format,
888    ) -> Option<GenericFormattedValue> {
889        unsafe {
890            let mut dest_val = mem::MaybeUninit::uninit();
891            let ret = from_glib(ffi::gst_pad_peer_query_convert(
892                self.as_ref().to_glib_none().0,
893                src_val.format().into_glib(),
894                src_val.into_raw_value(),
895                dest_format.into_glib(),
896                dest_val.as_mut_ptr(),
897            ));
898            if ret {
899                Some(GenericFormattedValue::new(
900                    dest_format,
901                    dest_val.assume_init(),
902                ))
903            } else {
904                None
905            }
906        }
907    }
908
909    /// Queries the peer pad of a given sink pad for the total stream duration.
910    /// ## `format`
911    /// the [`Format`][crate::Format] requested
912    ///
913    /// # Returns
914    ///
915    /// [`true`] if the query could be performed.
916    ///
917    /// ## `duration`
918    /// a location in which to store the total
919    ///  duration, or [`None`].
920    #[doc(alias = "gst_pad_peer_query_duration")]
921    fn peer_query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
922        unsafe {
923            let mut duration = mem::MaybeUninit::uninit();
924            let ret = from_glib(ffi::gst_pad_peer_query_duration(
925                self.as_ref().to_glib_none().0,
926                T::default_format().into_glib(),
927                duration.as_mut_ptr(),
928            ));
929            if ret {
930                try_from_glib(duration.assume_init()).ok()
931            } else {
932                None
933            }
934        }
935    }
936
937    #[doc(alias = "gst_pad_peer_query_duration")]
938    fn peer_query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
939        unsafe {
940            let mut duration = mem::MaybeUninit::uninit();
941            let ret = from_glib(ffi::gst_pad_peer_query_duration(
942                self.as_ref().to_glib_none().0,
943                format.into_glib(),
944                duration.as_mut_ptr(),
945            ));
946            if ret {
947                Some(GenericFormattedValue::new(format, duration.assume_init()))
948            } else {
949                None
950            }
951        }
952    }
953
954    /// Queries the peer of a given sink pad for the stream position.
955    /// ## `format`
956    /// the [`Format`][crate::Format] requested
957    ///
958    /// # Returns
959    ///
960    /// [`true`] if the query could be performed.
961    ///
962    /// ## `cur`
963    /// a location in which to store the current
964    ///  position, or [`None`].
965    #[doc(alias = "gst_pad_peer_query_position")]
966    fn peer_query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
967        unsafe {
968            let mut cur = mem::MaybeUninit::uninit();
969            let ret = from_glib(ffi::gst_pad_peer_query_position(
970                self.as_ref().to_glib_none().0,
971                T::default_format().into_glib(),
972                cur.as_mut_ptr(),
973            ));
974            if ret {
975                try_from_glib(cur.assume_init()).ok()
976            } else {
977                None
978            }
979        }
980    }
981
982    #[doc(alias = "gst_pad_peer_query_position")]
983    fn peer_query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
984        unsafe {
985            let mut cur = mem::MaybeUninit::uninit();
986            let ret = from_glib(ffi::gst_pad_peer_query_position(
987                self.as_ref().to_glib_none().0,
988                format.into_glib(),
989                cur.as_mut_ptr(),
990            ));
991            if ret {
992                Some(GenericFormattedValue::new(format, cur.assume_init()))
993            } else {
994                None
995            }
996        }
997    }
998
999    /// Queries a pad to convert `src_val` in `src_format` to `dest_format`.
1000    /// ## `src_format`
1001    /// a [`Format`][crate::Format] to convert from.
1002    /// ## `src_val`
1003    /// a value to convert.
1004    /// ## `dest_format`
1005    /// the [`Format`][crate::Format] to convert to.
1006    ///
1007    /// # Returns
1008    ///
1009    /// [`true`] if the query could be performed.
1010    ///
1011    /// ## `dest_val`
1012    /// a pointer to the result.
1013    #[doc(alias = "gst_pad_query_convert")]
1014    fn query_convert<U: SpecificFormattedValueFullRange>(
1015        &self,
1016        src_val: impl FormattedValue,
1017    ) -> Option<U> {
1018        unsafe {
1019            let mut dest_val = mem::MaybeUninit::uninit();
1020            let ret = from_glib(ffi::gst_pad_query_convert(
1021                self.as_ref().to_glib_none().0,
1022                src_val.format().into_glib(),
1023                src_val.into_raw_value(),
1024                U::default_format().into_glib(),
1025                dest_val.as_mut_ptr(),
1026            ));
1027            if ret {
1028                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
1029            } else {
1030                None
1031            }
1032        }
1033    }
1034
1035    #[doc(alias = "gst_pad_query_convert")]
1036    fn query_convert_generic(
1037        &self,
1038        src_val: impl FormattedValue,
1039        dest_format: Format,
1040    ) -> Option<GenericFormattedValue> {
1041        unsafe {
1042            let mut dest_val = mem::MaybeUninit::uninit();
1043            let ret = from_glib(ffi::gst_pad_query_convert(
1044                self.as_ref().to_glib_none().0,
1045                src_val.format().into_glib(),
1046                src_val.into_raw_value(),
1047                dest_format.into_glib(),
1048                dest_val.as_mut_ptr(),
1049            ));
1050            if ret {
1051                Some(GenericFormattedValue::new(
1052                    dest_format,
1053                    dest_val.assume_init(),
1054                ))
1055            } else {
1056                None
1057            }
1058        }
1059    }
1060
1061    /// Queries a pad for the total stream duration.
1062    /// ## `format`
1063    /// the [`Format`][crate::Format] requested
1064    ///
1065    /// # Returns
1066    ///
1067    /// [`true`] if the query could be performed.
1068    ///
1069    /// ## `duration`
1070    /// a location in which to store the total
1071    ///  duration, or [`None`].
1072    #[doc(alias = "gst_pad_query_duration")]
1073    fn query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
1074        unsafe {
1075            let mut duration = mem::MaybeUninit::uninit();
1076            let ret = from_glib(ffi::gst_pad_query_duration(
1077                self.as_ref().to_glib_none().0,
1078                T::default_format().into_glib(),
1079                duration.as_mut_ptr(),
1080            ));
1081            if ret {
1082                try_from_glib(duration.assume_init()).ok()
1083            } else {
1084                None
1085            }
1086        }
1087    }
1088
1089    #[doc(alias = "gst_pad_query_duration")]
1090    fn query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
1091        unsafe {
1092            let mut duration = mem::MaybeUninit::uninit();
1093            let ret = from_glib(ffi::gst_pad_query_duration(
1094                self.as_ref().to_glib_none().0,
1095                format.into_glib(),
1096                duration.as_mut_ptr(),
1097            ));
1098            if ret {
1099                Some(GenericFormattedValue::new(format, duration.assume_init()))
1100            } else {
1101                None
1102            }
1103        }
1104    }
1105
1106    /// Queries a pad for the stream position.
1107    /// ## `format`
1108    /// the [`Format`][crate::Format] requested
1109    ///
1110    /// # Returns
1111    ///
1112    /// [`true`] if the query could be performed.
1113    ///
1114    /// ## `cur`
1115    /// A location in which to store the current position, or [`None`].
1116    #[doc(alias = "gst_pad_query_position")]
1117    fn query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
1118        unsafe {
1119            let mut cur = mem::MaybeUninit::uninit();
1120            let ret = from_glib(ffi::gst_pad_query_position(
1121                self.as_ref().to_glib_none().0,
1122                T::default_format().into_glib(),
1123                cur.as_mut_ptr(),
1124            ));
1125            if ret {
1126                try_from_glib(cur.assume_init()).ok()
1127            } else {
1128                None
1129            }
1130        }
1131    }
1132
1133    #[doc(alias = "gst_pad_query_position")]
1134    fn query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
1135        unsafe {
1136            let mut cur = mem::MaybeUninit::uninit();
1137            let ret = from_glib(ffi::gst_pad_query_position(
1138                self.as_ref().to_glib_none().0,
1139                format.into_glib(),
1140                cur.as_mut_ptr(),
1141            ));
1142            if ret {
1143                Some(GenericFormattedValue::new(format, cur.assume_init()))
1144            } else {
1145                None
1146            }
1147        }
1148    }
1149
1150    #[doc(alias = "get_mode")]
1151    #[doc(alias = "GST_PAD_MODE")]
1152    fn mode(&self) -> crate::PadMode {
1153        unsafe {
1154            let ptr: &ffi::GstPad = &*(self.as_ptr() as *const _);
1155            from_glib(ptr.mode)
1156        }
1157    }
1158
1159    /// Iterates all sticky events on `self` and calls `foreach_func` for every
1160    /// event. If `foreach_func` returns [`false`] the iteration is immediately stopped.
1161    /// ## `foreach_func`
1162    /// the
1163    ///  `GstPadStickyEventsForeachFunction` that should be called for every event.
1164    #[doc(alias = "gst_pad_sticky_events_foreach")]
1165    fn sticky_events_foreach<
1166        F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
1167    >(
1168        &self,
1169        func: F,
1170    ) {
1171        unsafe extern "C" fn trampoline<
1172            F: FnMut(&Event) -> ControlFlow<EventForeachAction, EventForeachAction>,
1173        >(
1174            _pad: *mut ffi::GstPad,
1175            event: *mut *mut ffi::GstEvent,
1176            user_data: glib::ffi::gpointer,
1177        ) -> glib::ffi::gboolean {
1178            let func = user_data as *mut F;
1179            let res = (*func)(&from_glib_borrow(*event));
1180
1181            let (do_continue, ev_action) = match res {
1182                ControlFlow::Continue(ev_action) => (glib::ffi::GTRUE, ev_action),
1183                ControlFlow::Break(ev_action) => (glib::ffi::GFALSE, ev_action),
1184            };
1185
1186            use EventForeachAction::*;
1187
1188            match ev_action {
1189                Keep => (), // do nothing
1190                Remove => {
1191                    ffi::gst_mini_object_unref(*event as *mut _);
1192                    *event = ptr::null_mut();
1193                }
1194                Replace(ev) => {
1195                    ffi::gst_mini_object_unref(*event as *mut _);
1196                    *event = ev.into_glib_ptr();
1197                }
1198            }
1199
1200            do_continue
1201        }
1202
1203        unsafe {
1204            let mut func = func;
1205            let func_ptr = &mut func as *mut F as glib::ffi::gpointer;
1206
1207            ffi::gst_pad_sticky_events_foreach(
1208                self.as_ref().to_glib_none().0,
1209                Some(trampoline::<F>),
1210                func_ptr,
1211            );
1212        }
1213    }
1214
1215    /// Returns a new reference of the sticky event of type `event_type`
1216    /// from the event.
1217    /// ## `event_type`
1218    /// the [`EventType`][crate::EventType] that should be retrieved.
1219    /// ## `idx`
1220    /// the index of the event
1221    ///
1222    /// # Returns
1223    ///
1224    /// a [`Event`][crate::Event] of type
1225    /// `event_type` or [`None`] when no event of `event_type` was on
1226    /// `self`. Unref after usage.
1227    #[doc(alias = "gst_pad_get_sticky_event")]
1228    #[doc(alias = "get_sticky_event")]
1229    fn sticky_event<T: crate::event::StickyEventType>(&self, idx: u32) -> Option<T::Owned> {
1230        unsafe {
1231            let ptr = ffi::gst_pad_get_sticky_event(
1232                self.as_ref().to_glib_none().0,
1233                T::TYPE.into_glib(),
1234                idx,
1235            );
1236
1237            if ptr.is_null() {
1238                None
1239            } else {
1240                Some(T::from_event(from_glib_full(ptr)))
1241            }
1242        }
1243    }
1244
1245    fn set_pad_flags(&self, flags: PadFlags) {
1246        unsafe {
1247            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
1248            let _guard = self.as_ref().object_lock();
1249            (*ptr).flags |= flags.into_glib();
1250        }
1251    }
1252
1253    fn unset_pad_flags(&self, flags: PadFlags) {
1254        unsafe {
1255            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
1256            let _guard = self.as_ref().object_lock();
1257            (*ptr).flags &= !flags.into_glib();
1258        }
1259    }
1260
1261    #[doc(alias = "get_pad_flags")]
1262    fn pad_flags(&self) -> PadFlags {
1263        unsafe {
1264            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
1265            let _guard = self.as_ref().object_lock();
1266            from_glib((*ptr).flags)
1267        }
1268    }
1269}
1270
1271impl<O: IsA<Pad>> PadExtManual for O {}
1272
1273unsafe fn create_probe_info<'a>(
1274    info: *mut ffi::GstPadProbeInfo,
1275) -> (PadProbeInfo<'a>, Option<glib::Type>) {
1276    let mut data_type = None;
1277    let flow_res = try_from_glib((*info).ABI.abi.flow_ret);
1278    let info = PadProbeInfo {
1279        mask: from_glib((*info).type_),
1280        id: Some(PadProbeId(NonZeroU64::new_unchecked((*info).id as _))),
1281        offset: (*info).offset,
1282        size: (*info).size,
1283        data: if (*info).data.is_null() {
1284            None
1285        } else {
1286            let data = (*info).data as *mut ffi::GstMiniObject;
1287            (*info).data = ptr::null_mut();
1288            if (*data).type_ == Buffer::static_type().into_glib() {
1289                data_type = Some(Buffer::static_type());
1290                Some(PadProbeData::Buffer(from_glib_full(
1291                    data as *const ffi::GstBuffer,
1292                )))
1293            } else if (*data).type_ == BufferList::static_type().into_glib() {
1294                data_type = Some(BufferList::static_type());
1295                Some(PadProbeData::BufferList(from_glib_full(
1296                    data as *const ffi::GstBufferList,
1297                )))
1298            } else if (*data).type_ == Query::static_type().into_glib() {
1299                data_type = Some(Query::static_type());
1300                Some(PadProbeData::Query(QueryRef::from_mut_ptr(
1301                    data as *mut ffi::GstQuery,
1302                )))
1303            } else if (*data).type_ == Event::static_type().into_glib() {
1304                data_type = Some(Event::static_type());
1305                Some(PadProbeData::Event(from_glib_full(
1306                    data as *const ffi::GstEvent,
1307                )))
1308            } else {
1309                Some(PadProbeData::__Unknown(data))
1310            }
1311        },
1312        flow_res,
1313    };
1314    (info, data_type)
1315}
1316
1317unsafe fn update_probe_info(
1318    ret: PadProbeReturn,
1319    probe_info: PadProbeInfo,
1320    data_type: Option<glib::Type>,
1321    info: *mut ffi::GstPadProbeInfo,
1322) {
1323    if ret == PadProbeReturn::Handled {
1324        // Handled queries need to be returned
1325        // Handled buffers and buffer lists are consumed
1326        // No other types can safely be used here
1327
1328        match probe_info.data {
1329            Some(PadProbeData::Query(query)) => {
1330                assert_eq!(data_type, Some(Query::static_type()));
1331                (*info).data = query.as_mut_ptr() as *mut libc::c_void;
1332            }
1333            Some(PadProbeData::Buffer(_)) => {
1334                assert_eq!(data_type, Some(Buffer::static_type()));
1335                // Buffer not consumed by probe; consume it here
1336            }
1337            Some(PadProbeData::BufferList(_)) => {
1338                assert_eq!(data_type, Some(BufferList::static_type()));
1339                // BufferList not consumed by probe; consume it here
1340            }
1341            Some(PadProbeData::Event(_)) => {
1342                assert_eq!(data_type, Some(Event::static_type()));
1343                // Event not consumed by probe; consume it here
1344            }
1345            None if data_type == Some(Buffer::static_type())
1346                || data_type == Some(BufferList::static_type())
1347                || data_type == Some(Event::static_type()) =>
1348            {
1349                // Buffer or Event consumed by probe
1350                (*info).data = ptr::null_mut();
1351            }
1352            other => panic!("Bad data for {data_type:?} pad probe returning Handled: {other:?}"),
1353        }
1354    } else if ret == PadProbeReturn::Drop {
1355        // We may have consumed the object via PadProbeInfo::take_*() functions
1356        match probe_info.data {
1357            None if data_type == Some(Buffer::static_type())
1358                || data_type == Some(BufferList::static_type())
1359                || data_type == Some(Event::static_type()) =>
1360            {
1361                (*info).data = ptr::null_mut();
1362            }
1363            _ => {
1364                // Nothing to do, it's going to be dropped
1365            }
1366        }
1367    } else {
1368        match probe_info.data {
1369            Some(PadProbeData::Buffer(buffer)) => {
1370                assert_eq!(data_type, Some(Buffer::static_type()));
1371                (*info).data = buffer.into_glib_ptr() as *mut libc::c_void;
1372            }
1373            Some(PadProbeData::BufferList(bufferlist)) => {
1374                assert_eq!(data_type, Some(BufferList::static_type()));
1375                (*info).data = bufferlist.into_glib_ptr() as *mut libc::c_void;
1376            }
1377            Some(PadProbeData::Event(event)) => {
1378                assert_eq!(data_type, Some(Event::static_type()));
1379                (*info).data = event.into_glib_ptr() as *mut libc::c_void;
1380            }
1381            Some(PadProbeData::Query(query)) => {
1382                assert_eq!(data_type, Some(Query::static_type()));
1383                (*info).data = query.as_mut_ptr() as *mut libc::c_void;
1384            }
1385            Some(PadProbeData::__Unknown(ptr)) => {
1386                assert_eq!(data_type, None);
1387                (*info).data = ptr as *mut libc::c_void;
1388            }
1389            None => {
1390                assert_eq!(data_type, None);
1391            }
1392        }
1393    }
1394
1395    let flow_ret: FlowReturn = probe_info.flow_res.into();
1396    (*info).ABI.abi.flow_ret = flow_ret.into_glib();
1397}
1398
1399unsafe extern "C" fn trampoline_pad_probe<
1400    T,
1401    F: Fn(&T, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static,
1402>(
1403    pad: *mut ffi::GstPad,
1404    info: *mut ffi::GstPadProbeInfo,
1405    func: gpointer,
1406) -> ffi::GstPadProbeReturn
1407where
1408    T: IsA<Pad>,
1409{
1410    let func: &F = &*(func as *const F);
1411
1412    let (mut probe_info, data_type) = create_probe_info(info);
1413
1414    let ret = func(
1415        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1416        &mut probe_info,
1417    );
1418
1419    update_probe_info(ret, probe_info, data_type, info);
1420
1421    ret.into_glib()
1422}
1423
1424unsafe extern "C" fn trampoline_activate_function<
1425    T,
1426    F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
1427>(
1428    pad: *mut ffi::GstPad,
1429    parent: *mut ffi::GstObject,
1430) -> glib::ffi::gboolean
1431where
1432    T: IsA<Pad>,
1433{
1434    let func: &F = &*((*pad).activatedata as *const F);
1435
1436    match func(
1437        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1438        Option::<crate::Object>::from_glib_borrow(parent)
1439            .as_ref()
1440            .as_ref(),
1441    ) {
1442        Ok(()) => true,
1443        Err(err) => {
1444            err.log_with_object(&*Pad::from_glib_borrow(pad));
1445            false
1446        }
1447    }
1448    .into_glib()
1449}
1450
1451unsafe extern "C" fn trampoline_activatemode_function<
1452    T,
1453    F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
1454        + Send
1455        + Sync
1456        + 'static,
1457>(
1458    pad: *mut ffi::GstPad,
1459    parent: *mut ffi::GstObject,
1460    mode: ffi::GstPadMode,
1461    active: glib::ffi::gboolean,
1462) -> glib::ffi::gboolean
1463where
1464    T: IsA<Pad>,
1465{
1466    let func: &F = &*((*pad).activatemodedata as *const F);
1467
1468    match func(
1469        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1470        Option::<crate::Object>::from_glib_borrow(parent)
1471            .as_ref()
1472            .as_ref(),
1473        from_glib(mode),
1474        from_glib(active),
1475    ) {
1476        Ok(()) => true,
1477        Err(err) => {
1478            err.log_with_object(&*Pad::from_glib_borrow(pad));
1479            false
1480        }
1481    }
1482    .into_glib()
1483}
1484
1485unsafe extern "C" fn trampoline_chain_function<
1486    T,
1487    F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
1488        + Send
1489        + Sync
1490        + 'static,
1491>(
1492    pad: *mut ffi::GstPad,
1493    parent: *mut ffi::GstObject,
1494    buffer: *mut ffi::GstBuffer,
1495) -> ffi::GstFlowReturn
1496where
1497    T: IsA<Pad>,
1498{
1499    let func: &F = &*((*pad).chaindata as *const F);
1500
1501    let res: FlowReturn = func(
1502        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1503        Option::<crate::Object>::from_glib_borrow(parent)
1504            .as_ref()
1505            .as_ref(),
1506        from_glib_full(buffer),
1507    )
1508    .into();
1509    res.into_glib()
1510}
1511
1512unsafe extern "C" fn trampoline_chain_list_function<
1513    T,
1514    F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
1515        + Send
1516        + Sync
1517        + 'static,
1518>(
1519    pad: *mut ffi::GstPad,
1520    parent: *mut ffi::GstObject,
1521    list: *mut ffi::GstBufferList,
1522) -> ffi::GstFlowReturn
1523where
1524    T: IsA<Pad>,
1525{
1526    let func: &F = &*((*pad).chainlistdata as *const F);
1527
1528    let res: FlowReturn = func(
1529        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1530        Option::<crate::Object>::from_glib_borrow(parent)
1531            .as_ref()
1532            .as_ref(),
1533        from_glib_full(list),
1534    )
1535    .into();
1536    res.into_glib()
1537}
1538
1539unsafe extern "C" fn trampoline_event_function<
1540    T,
1541    F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
1542>(
1543    pad: *mut ffi::GstPad,
1544    parent: *mut ffi::GstObject,
1545    event: *mut ffi::GstEvent,
1546) -> glib::ffi::gboolean
1547where
1548    T: IsA<Pad>,
1549{
1550    let func: &F = &*((*pad).eventdata as *const F);
1551
1552    func(
1553        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1554        Option::<crate::Object>::from_glib_borrow(parent)
1555            .as_ref()
1556            .as_ref(),
1557        from_glib_full(event),
1558    )
1559    .into_glib()
1560}
1561
1562unsafe extern "C" fn trampoline_event_full_function<
1563    T,
1564    F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
1565        + Send
1566        + Sync
1567        + 'static,
1568>(
1569    pad: *mut ffi::GstPad,
1570    parent: *mut ffi::GstObject,
1571    event: *mut ffi::GstEvent,
1572) -> ffi::GstFlowReturn
1573where
1574    T: IsA<Pad>,
1575{
1576    let func: &F = &*((*pad).eventdata as *const F);
1577
1578    let res: FlowReturn = func(
1579        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1580        Option::<crate::Object>::from_glib_borrow(parent)
1581            .as_ref()
1582            .as_ref(),
1583        from_glib_full(event),
1584    )
1585    .into();
1586    res.into_glib()
1587}
1588
1589#[allow(clippy::needless_option_as_deref)]
1590unsafe extern "C" fn trampoline_getrange_function<
1591    T,
1592    F: Fn(
1593            &T,
1594            Option<&crate::Object>,
1595            u64,
1596            Option<&mut crate::BufferRef>,
1597            u32,
1598        ) -> Result<PadGetRangeSuccess, crate::FlowError>
1599        + Send
1600        + Sync
1601        + 'static,
1602>(
1603    pad: *mut ffi::GstPad,
1604    parent: *mut ffi::GstObject,
1605    offset: u64,
1606    length: u32,
1607    buffer: *mut *mut ffi::GstBuffer,
1608) -> ffi::GstFlowReturn
1609where
1610    T: IsA<Pad>,
1611{
1612    let func: &F = &*((*pad).getrangedata as *const F);
1613
1614    debug_assert!(!buffer.is_null());
1615
1616    let pad = Pad::from_glib_borrow(pad);
1617    let pad = pad.unsafe_cast_ref();
1618    let mut passed_buffer = if (*buffer).is_null() {
1619        None
1620    } else {
1621        Some(crate::BufferRef::from_mut_ptr(*buffer))
1622    };
1623
1624    match func(
1625        pad,
1626        Option::<crate::Object>::from_glib_borrow(parent)
1627            .as_ref()
1628            .as_ref(),
1629        offset,
1630        passed_buffer.as_deref_mut(),
1631        length,
1632    ) {
1633        Ok(PadGetRangeSuccess::NewBuffer(new_buffer)) => {
1634            if let Some(passed_buffer) = passed_buffer {
1635                crate::debug!(
1636                    crate::CAT_PERFORMANCE,
1637                    obj = pad.unsafe_cast_ref::<glib::Object>(),
1638                    "Returned new buffer from getrange function, copying into passed buffer"
1639                );
1640
1641                let mut map = match passed_buffer.map_writable() {
1642                    Ok(map) => map,
1643                    Err(_) => {
1644                        crate::error!(
1645                            crate::CAT_RUST,
1646                            obj = pad.unsafe_cast_ref::<glib::Object>(),
1647                            "Failed to map passed buffer writable"
1648                        );
1649                        return ffi::GST_FLOW_ERROR;
1650                    }
1651                };
1652
1653                let copied_size = new_buffer.copy_to_slice(0, &mut map);
1654                drop(map);
1655
1656                if let Err(copied_size) = copied_size {
1657                    passed_buffer.set_size(copied_size);
1658                }
1659
1660                match new_buffer.copy_into(passed_buffer, crate::BUFFER_COPY_METADATA, ..) {
1661                    Ok(_) => FlowReturn::Ok.into_glib(),
1662                    Err(_) => {
1663                        crate::error!(
1664                            crate::CAT_RUST,
1665                            obj = pad.unsafe_cast_ref::<glib::Object>(),
1666                            "Failed to copy buffer metadata"
1667                        );
1668
1669                        FlowReturn::Error.into_glib()
1670                    }
1671                }
1672            } else {
1673                *buffer = new_buffer.into_glib_ptr();
1674                FlowReturn::Ok.into_glib()
1675            }
1676        }
1677        Ok(PadGetRangeSuccess::FilledBuffer) => {
1678            assert!(passed_buffer.is_some());
1679            FlowReturn::Ok.into_glib()
1680        }
1681        Err(ret) => FlowReturn::from_error(ret).into_glib(),
1682    }
1683}
1684
1685unsafe extern "C" fn trampoline_iterate_internal_links_function<
1686    T,
1687    F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
1688>(
1689    pad: *mut ffi::GstPad,
1690    parent: *mut ffi::GstObject,
1691) -> *mut ffi::GstIterator
1692where
1693    T: IsA<Pad>,
1694{
1695    let func: &F = &*((*pad).iterintlinkdata as *const F);
1696
1697    // Steal the iterator and return it
1698    let ret = func(
1699        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1700        Option::<crate::Object>::from_glib_borrow(parent)
1701            .as_ref()
1702            .as_ref(),
1703    );
1704
1705    ret.into_glib_ptr()
1706}
1707
1708unsafe extern "C" fn trampoline_link_function<
1709    T,
1710    F: Fn(
1711            &T,
1712            Option<&crate::Object>,
1713            &crate::Pad,
1714        ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
1715        + Send
1716        + Sync
1717        + 'static,
1718>(
1719    pad: *mut ffi::GstPad,
1720    parent: *mut ffi::GstObject,
1721    peer: *mut ffi::GstPad,
1722) -> ffi::GstPadLinkReturn
1723where
1724    T: IsA<Pad>,
1725{
1726    let func: &F = &*((*pad).linkdata as *const F);
1727
1728    let res: crate::PadLinkReturn = func(
1729        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1730        Option::<crate::Object>::from_glib_borrow(parent)
1731            .as_ref()
1732            .as_ref(),
1733        &from_glib_borrow(peer),
1734    )
1735    .into();
1736    res.into_glib()
1737}
1738
1739unsafe extern "C" fn trampoline_query_function<
1740    T,
1741    F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
1742>(
1743    pad: *mut ffi::GstPad,
1744    parent: *mut ffi::GstObject,
1745    query: *mut ffi::GstQuery,
1746) -> glib::ffi::gboolean
1747where
1748    T: IsA<Pad>,
1749{
1750    let func: &F = &*((*pad).querydata as *const F);
1751
1752    func(
1753        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1754        Option::<crate::Object>::from_glib_borrow(parent)
1755            .as_ref()
1756            .as_ref(),
1757        crate::QueryRef::from_mut_ptr(query),
1758    )
1759    .into_glib()
1760}
1761
1762unsafe extern "C" fn trampoline_unlink_function<
1763    T,
1764    F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
1765>(
1766    pad: *mut ffi::GstPad,
1767    parent: *mut ffi::GstObject,
1768) where
1769    T: IsA<Pad>,
1770{
1771    let func: &F = &*((*pad).unlinkdata as *const F);
1772
1773    func(
1774        Pad::from_glib_borrow(pad).unsafe_cast_ref(),
1775        Option::<crate::Object>::from_glib_borrow(parent)
1776            .as_ref()
1777            .as_ref(),
1778    )
1779}
1780
1781unsafe extern "C" fn destroy_closure<F>(ptr: gpointer) {
1782    let _ = Box::<F>::from_raw(ptr as *mut _);
1783}
1784
1785impl Pad {
1786    // rustdoc-stripper-ignore-next
1787    /// Creates a new [`Pad`] with the specified [`PadDirection`](crate::PadDirection).
1788    ///
1789    /// The [`Pad`] will be assigned the usual `gst::Object` generated unique name.
1790    ///
1791    /// Use [`Pad::builder()`] to get a [`PadBuilder`] and define options.
1792    // rustdoc-stripper-ignore-next-stop
1793    /// Creates a new pad with the given name in the given direction.
1794    /// If name is [`None`], a guaranteed unique name (across all pads)
1795    /// will be assigned.
1796    /// This function makes a copy of the name so you can safely free the name.
1797    /// ## `name`
1798    /// the name of the new pad.
1799    /// ## `direction`
1800    /// the [`PadDirection`][crate::PadDirection] of the pad.
1801    ///
1802    /// # Returns
1803    ///
1804    /// a new [`Pad`][crate::Pad].
1805    ///
1806    /// MT safe.
1807    #[doc(alias = "gst_pad_new")]
1808    pub fn new(direction: crate::PadDirection) -> Self {
1809        skip_assert_initialized!();
1810        Self::builder(direction).build()
1811    }
1812
1813    // rustdoc-stripper-ignore-next
1814    /// Creates a [`PadBuilder`] with the specified [`PadDirection`](crate::PadDirection).
1815    #[doc(alias = "gst_pad_new")]
1816    pub fn builder(direction: crate::PadDirection) -> PadBuilder<Self> {
1817        skip_assert_initialized!();
1818        PadBuilder::new(direction)
1819    }
1820
1821    // rustdoc-stripper-ignore-next
1822    /// Creates a new [`Pad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1823    ///
1824    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1825    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1826    /// the `Pad` will automatically be named after the `name_template`.
1827    ///
1828    /// Use [`Pad::builder_from_static_template()`] to get a [`PadBuilder`] and define options.
1829    ///
1830    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1831    /// automatically generated unique name.
1832    ///
1833    /// # Panics
1834    ///
1835    /// Panics if the `name_template` is a wildcard-name.
1836    // rustdoc-stripper-ignore-next-stop
1837    /// Creates a new pad with the given name from the given static template.
1838    /// If name is [`None`], a guaranteed unique name (across all pads)
1839    /// will be assigned.
1840    /// This function makes a copy of the name so you can safely free the name.
1841    /// ## `templ`
1842    /// the [`StaticPadTemplate`][crate::StaticPadTemplate] to use
1843    /// ## `name`
1844    /// the name of the pad
1845    ///
1846    /// # Returns
1847    ///
1848    /// a new [`Pad`][crate::Pad].
1849    #[doc(alias = "gst_pad_new_from_static_template")]
1850    pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
1851        skip_assert_initialized!();
1852        Self::builder_from_static_template(templ).build()
1853    }
1854
1855    // rustdoc-stripper-ignore-next
1856    /// Creates a new [`PadBuilder`] from the [`StaticPadTemplate`](crate::StaticPadTemplate).
1857    ///
1858    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
1859    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1860    /// the `Pad` will automatically be named after the `name_template`.
1861    ///
1862    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1863    /// automatically generated unique name.
1864    #[doc(alias = "gst_pad_new_from_static_template")]
1865    pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder<Self> {
1866        skip_assert_initialized!();
1867        PadBuilder::from_static_template(templ)
1868    }
1869
1870    // rustdoc-stripper-ignore-next
1871    /// Creates a new [`Pad`] from the [`PadTemplate`](crate::PadTemplate).
1872    ///
1873    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1874    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1875    /// the `Pad` will automatically be named after the `name_template`.
1876    ///
1877    /// Use [`Pad::builder_from_template()`] to get a [`PadBuilder`] and define options.
1878    ///
1879    /// # Panics
1880    ///
1881    /// Panics if the `name_template` is a wildcard-name.
1882    // rustdoc-stripper-ignore-next-stop
1883    /// Creates a new pad with the given name from the given template.
1884    /// If name is [`None`], a guaranteed unique name (across all pads)
1885    /// will be assigned.
1886    /// This function makes a copy of the name so you can safely free the name.
1887    /// ## `templ`
1888    /// the pad template to use
1889    /// ## `name`
1890    /// the name of the pad
1891    ///
1892    /// # Returns
1893    ///
1894    /// a new [`Pad`][crate::Pad].
1895    #[doc(alias = "gst_pad_new_from_template")]
1896    pub fn from_template(templ: &crate::PadTemplate) -> Self {
1897        skip_assert_initialized!();
1898        Self::builder_from_template(templ).build()
1899    }
1900
1901    // rustdoc-stripper-ignore-next
1902    /// Creates a new [`PadBuilder`] from the [`PadTemplate`](crate::PadTemplate).
1903    ///
1904    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
1905    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
1906    /// the `Pad` will automatically be named after the `name_template`.
1907    ///
1908    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
1909    /// automatically generated unique name.
1910    #[doc(alias = "gst_pad_new_from_template")]
1911    pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder<Self> {
1912        skip_assert_initialized!();
1913        PadBuilder::from_template(templ)
1914    }
1915
1916    #[doc(alias = "gst_pad_query_default")]
1917    pub fn query_default<O: IsA<Pad>>(
1918        pad: &O,
1919        parent: Option<&impl IsA<crate::Object>>,
1920        query: &mut QueryRef,
1921    ) -> bool {
1922        skip_assert_initialized!();
1923        unsafe {
1924            from_glib(ffi::gst_pad_query_default(
1925                pad.as_ref().to_glib_none().0,
1926                parent.map(|p| p.as_ref()).to_glib_none().0,
1927                query.as_mut_ptr(),
1928            ))
1929        }
1930    }
1931
1932    #[doc(alias = "gst_pad_event_default")]
1933    pub fn event_default<O: IsA<Pad>>(
1934        pad: &O,
1935        parent: Option<&impl IsA<crate::Object>>,
1936        event: impl Into<Event>,
1937    ) -> bool {
1938        skip_assert_initialized!();
1939        unsafe {
1940            from_glib(ffi::gst_pad_event_default(
1941                pad.as_ref().to_glib_none().0,
1942                parent.map(|p| p.as_ref()).to_glib_none().0,
1943                event.into().into_glib_ptr(),
1944            ))
1945        }
1946    }
1947
1948    #[doc(alias = "gst_pad_iterate_internal_links_default")]
1949    pub fn iterate_internal_links_default<O: IsA<Pad>>(
1950        pad: &O,
1951        parent: Option<&impl IsA<crate::Object>>,
1952    ) -> crate::Iterator<Pad> {
1953        skip_assert_initialized!();
1954        unsafe {
1955            from_glib_full(ffi::gst_pad_iterate_internal_links_default(
1956                pad.as_ref().to_glib_none().0,
1957                parent.map(|p| p.as_ref()).to_glib_none().0,
1958            ))
1959        }
1960    }
1961}
1962
1963pub(crate) enum PadBuilderName {
1964    Undefined,
1965    KeepGenerated,
1966    UserDefined(String),
1967    CandidateForWildcardTemplate(String),
1968}
1969
1970#[must_use = "The builder must be built to be used"]
1971pub struct PadBuilder<T> {
1972    pub(crate) pad: T,
1973    pub(crate) name: PadBuilderName,
1974}
1975
1976impl<T: IsA<Pad> + IsA<glib::Object> + glib::object::IsClass> PadBuilder<T> {
1977    // rustdoc-stripper-ignore-next
1978    /// Creates a `PadBuilder` with the specified [`PadDirection`](crate::PadDirection).
1979    pub fn new(direction: crate::PadDirection) -> Self {
1980        assert_initialized_main_thread!();
1981
1982        let pad = glib::Object::builder::<T>()
1983            .property("direction", direction)
1984            .build();
1985
1986        // Ghost pads are a bit special
1987        if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
1988            unsafe {
1989                let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
1990                // This can't really fail...
1991                debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
1992            }
1993        }
1994
1995        PadBuilder {
1996            pad,
1997            name: PadBuilderName::Undefined,
1998        }
1999    }
2000
2001    // rustdoc-stripper-ignore-next
2002    /// Creates a `PadBuilder` from the specified [`StaticPadTemplate`](crate::StaticPadTemplate).
2003    ///
2004    /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`,
2005    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
2006    /// the `Pad` will automatically be named after the `name_template`.
2007    ///
2008    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
2009    /// automatically generated unique name.
2010    pub fn from_static_template(templ: &StaticPadTemplate) -> Self {
2011        skip_assert_initialized!();
2012
2013        let templ = templ.get();
2014        Self::from_template(&templ)
2015    }
2016
2017    // rustdoc-stripper-ignore-next
2018    /// Creates a `PadBuilder` from the specified [`PadTemplate`](crate::PadTemplate).
2019    ///
2020    /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`,
2021    /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`,
2022    /// the `Pad` will automatically be named after the `name_template`.
2023    ///
2024    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
2025    /// automatically generated unique name.
2026    pub fn from_template(templ: &crate::PadTemplate) -> Self {
2027        assert_initialized_main_thread!();
2028
2029        let mut type_ = T::static_type();
2030        let gtype = templ.gtype();
2031
2032        if gtype == glib::Type::UNIT {
2033            // Nothing to be done, we can create any kind of pad
2034        } else if gtype.is_a(type_) {
2035            // We were asked to create a parent type of the template type, e.g. a gst::Pad for
2036            // a template that wants a gst_base::AggregatorPad. Not a problem: update the type
2037            type_ = gtype;
2038        } else {
2039            // Otherwise the requested type must be a subclass of the template pad type
2040            assert!(type_.is_a(gtype));
2041        }
2042
2043        let mut properties = [
2044            ("direction", templ.direction().into()),
2045            ("template", templ.into()),
2046        ];
2047
2048        let pad =
2049            unsafe { glib::Object::with_mut_values(type_, &mut properties).unsafe_cast::<T>() };
2050
2051        // Ghost pads are a bit special
2052        if let Some(pad) = pad.dynamic_cast_ref::<crate::GhostPad>() {
2053            unsafe {
2054                let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0);
2055                // This can't really fail...
2056                debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad");
2057            }
2058        }
2059
2060        PadBuilder {
2061            pad,
2062            name: PadBuilderName::Undefined,
2063        }
2064    }
2065
2066    // rustdoc-stripper-ignore-next
2067    /// Uses the `gst::Object` generated unique name.
2068    pub fn generated_name(mut self) -> Self {
2069        self.name = PadBuilderName::KeepGenerated;
2070        self
2071    }
2072
2073    // rustdoc-stripper-ignore-next
2074    /// Sets the name of the Pad.
2075    pub fn name(mut self, name: impl Into<String>) -> Self {
2076        self.name = PadBuilderName::UserDefined(name.into());
2077
2078        self
2079    }
2080
2081    // rustdoc-stripper-ignore-next
2082    /// Optionally sets the name of the Pad.
2083    ///
2084    /// This method is convenient when the `name` is provided as an `Option`.
2085    /// If the `name` is `None`, this has no effect.
2086    #[deprecated = "use `name_if_some()` instead"]
2087    pub fn maybe_name<N: Into<String>>(self, name: Option<N>) -> Self {
2088        if let Some(name) = name {
2089            self.name(name)
2090        } else {
2091            self
2092        }
2093    }
2094
2095    // rustdoc-stripper-ignore-next
2096    /// Optionally sets the name of the Pad.
2097    ///
2098    /// This method is convenient when the `name` is provided as an `Option`.
2099    /// If the `name` is `None`, this has no effect.
2100    pub fn name_if_some<N: Into<String>>(self, name: Option<N>) -> Self {
2101        if let Some(name) = name {
2102            self.name(name)
2103        } else {
2104            self
2105        }
2106    }
2107
2108    #[doc(alias = "gst_pad_set_activate_function")]
2109    pub fn activate_function<F>(self, func: F) -> Self
2110    where
2111        F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
2112    {
2113        unsafe {
2114            self.pad.set_activate_function(func);
2115        }
2116
2117        self
2118    }
2119
2120    #[doc(alias = "gst_pad_set_activate_function")]
2121    pub fn activate_function_if_some<F>(self, func: Option<F>) -> Self
2122    where
2123        F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static,
2124    {
2125        if let Some(func) = func {
2126            self.activate_function(func)
2127        } else {
2128            self
2129        }
2130    }
2131
2132    #[doc(alias = "gst_pad_set_activatemode_function")]
2133    pub fn activatemode_function<F>(self, func: F) -> Self
2134    where
2135        F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
2136            + Send
2137            + Sync
2138            + 'static,
2139    {
2140        unsafe {
2141            self.pad.set_activatemode_function(func);
2142        }
2143
2144        self
2145    }
2146
2147    #[doc(alias = "gst_pad_set_activatemode_function")]
2148    pub fn activatemode_function_if_some<F>(self, func: Option<F>) -> Self
2149    where
2150        F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError>
2151            + Send
2152            + Sync
2153            + 'static,
2154    {
2155        if let Some(func) = func {
2156            self.activatemode_function(func)
2157        } else {
2158            self
2159        }
2160    }
2161
2162    #[doc(alias = "gst_pad_set_chain_function")]
2163    pub fn chain_function<F>(self, func: F) -> Self
2164    where
2165        F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
2166            + Send
2167            + Sync
2168            + 'static,
2169    {
2170        unsafe {
2171            self.pad.set_chain_function(func);
2172        }
2173
2174        self
2175    }
2176
2177    #[doc(alias = "gst_pad_set_chain_function")]
2178    pub fn chain_function_if_some<F>(self, func: Option<F>) -> Self
2179    where
2180        F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result<FlowSuccess, FlowError>
2181            + Send
2182            + Sync
2183            + 'static,
2184    {
2185        if let Some(func) = func {
2186            self.chain_function(func)
2187        } else {
2188            self
2189        }
2190    }
2191
2192    #[doc(alias = "gst_pad_set_chain_list_function")]
2193    pub fn chain_list_function<F>(self, func: F) -> Self
2194    where
2195        F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
2196            + Send
2197            + Sync
2198            + 'static,
2199    {
2200        unsafe {
2201            self.pad.set_chain_list_function(func);
2202        }
2203
2204        self
2205    }
2206
2207    #[doc(alias = "gst_pad_set_chain_list_function")]
2208    pub fn chain_list_function_if_some<F>(self, func: Option<F>) -> Self
2209    where
2210        F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result<FlowSuccess, FlowError>
2211            + Send
2212            + Sync
2213            + 'static,
2214    {
2215        if let Some(func) = func {
2216            self.chain_list_function(func)
2217        } else {
2218            self
2219        }
2220    }
2221
2222    #[doc(alias = "gst_pad_set_event_function")]
2223    pub fn event_function<F>(self, func: F) -> Self
2224    where
2225        F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
2226    {
2227        unsafe {
2228            self.pad.set_event_function(func);
2229        }
2230
2231        self
2232    }
2233
2234    #[doc(alias = "gst_pad_set_event_function")]
2235    pub fn event_function_if_some<F>(self, func: Option<F>) -> Self
2236    where
2237        F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static,
2238    {
2239        if let Some(func) = func {
2240            self.event_function(func)
2241        } else {
2242            self
2243        }
2244    }
2245
2246    #[doc(alias = "gst_pad_set_event_full_function")]
2247    pub fn event_full_function<F>(self, func: F) -> Self
2248    where
2249        F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
2250            + Send
2251            + Sync
2252            + 'static,
2253    {
2254        unsafe {
2255            self.pad.set_event_full_function(func);
2256        }
2257
2258        self
2259    }
2260
2261    #[doc(alias = "gst_pad_set_event_full_function")]
2262    pub fn event_full_function_if_some<F>(self, func: Option<F>) -> Self
2263    where
2264        F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result<FlowSuccess, FlowError>
2265            + Send
2266            + Sync
2267            + 'static,
2268    {
2269        if let Some(func) = func {
2270            self.event_full_function(func)
2271        } else {
2272            self
2273        }
2274    }
2275
2276    #[doc(alias = "gst_pad_set_getrange_function")]
2277    pub fn getrange_function<F>(self, func: F) -> Self
2278    where
2279        F: Fn(
2280                &T,
2281                Option<&crate::Object>,
2282                u64,
2283                Option<&mut crate::BufferRef>,
2284                u32,
2285            ) -> Result<PadGetRangeSuccess, crate::FlowError>
2286            + Send
2287            + Sync
2288            + 'static,
2289    {
2290        unsafe {
2291            self.pad.set_getrange_function(func);
2292        }
2293
2294        self
2295    }
2296
2297    #[doc(alias = "gst_pad_set_getrange_function")]
2298    pub fn getrange_function_if_some<F>(self, func: Option<F>) -> Self
2299    where
2300        F: Fn(
2301                &T,
2302                Option<&crate::Object>,
2303                u64,
2304                Option<&mut crate::BufferRef>,
2305                u32,
2306            ) -> Result<PadGetRangeSuccess, crate::FlowError>
2307            + Send
2308            + Sync
2309            + 'static,
2310    {
2311        if let Some(func) = func {
2312            self.getrange_function(func)
2313        } else {
2314            self
2315        }
2316    }
2317
2318    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
2319    pub fn iterate_internal_links_function<F>(self, func: F) -> Self
2320    where
2321        F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
2322    {
2323        unsafe {
2324            self.pad.set_iterate_internal_links_function(func);
2325        }
2326
2327        self
2328    }
2329
2330    #[doc(alias = "gst_pad_set_iterate_internal_links_function")]
2331    pub fn iterate_internal_links_function_if_some<F>(self, func: Option<F>) -> Self
2332    where
2333        F: Fn(&T, Option<&crate::Object>) -> crate::Iterator<Pad> + Send + Sync + 'static,
2334    {
2335        if let Some(func) = func {
2336            self.iterate_internal_links_function(func)
2337        } else {
2338            self
2339        }
2340    }
2341
2342    #[doc(alias = "gst_pad_set_link_function")]
2343    pub fn link_function<F>(self, func: F) -> Self
2344    where
2345        F: Fn(
2346                &T,
2347                Option<&crate::Object>,
2348                &Pad,
2349            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
2350            + Send
2351            + Sync
2352            + 'static,
2353    {
2354        unsafe {
2355            self.pad.set_link_function(func);
2356        }
2357
2358        self
2359    }
2360
2361    #[doc(alias = "gst_pad_set_link_function")]
2362    pub fn link_function_if_some<F>(self, func: Option<F>) -> Self
2363    where
2364        F: Fn(
2365                &T,
2366                Option<&crate::Object>,
2367                &Pad,
2368            ) -> Result<crate::PadLinkSuccess, crate::PadLinkError>
2369            + Send
2370            + Sync
2371            + 'static,
2372    {
2373        if let Some(func) = func {
2374            self.link_function(func)
2375        } else {
2376            self
2377        }
2378    }
2379
2380    #[doc(alias = "gst_pad_set_query_function")]
2381    pub fn query_function<F>(self, func: F) -> Self
2382    where
2383        F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
2384    {
2385        unsafe {
2386            self.pad.set_query_function(func);
2387        }
2388
2389        self
2390    }
2391
2392    #[doc(alias = "gst_pad_set_query_function")]
2393    pub fn query_function_if_some<F>(self, func: Option<F>) -> Self
2394    where
2395        F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static,
2396    {
2397        if let Some(func) = func {
2398            self.query_function(func)
2399        } else {
2400            self
2401        }
2402    }
2403
2404    #[doc(alias = "gst_pad_set_unlink_function")]
2405    pub fn unlink_function<F>(self, func: F) -> Self
2406    where
2407        F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
2408    {
2409        unsafe {
2410            self.pad.set_unlink_function(func);
2411        }
2412
2413        self
2414    }
2415
2416    #[doc(alias = "gst_pad_set_unlink_function")]
2417    pub fn unlink_function_if_some<F>(self, func: Option<F>) -> Self
2418    where
2419        F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static,
2420    {
2421        if let Some(func) = func {
2422            self.unlink_function(func)
2423        } else {
2424            self
2425        }
2426    }
2427
2428    pub fn flags(self, flags: PadFlags) -> Self {
2429        self.pad.set_pad_flags(flags);
2430
2431        self
2432    }
2433
2434    pub fn flags_if_some(self, flags: Option<PadFlags>) -> Self {
2435        if let Some(flags) = flags {
2436            self.flags(flags)
2437        } else {
2438            self
2439        }
2440    }
2441
2442    // rustdoc-stripper-ignore-next
2443    /// Builds the [`Pad`].
2444    ///
2445    /// # Panics
2446    ///
2447    /// Panics if the [`Pad`] was built from a [`PadTemplate`](crate::PadTemplate)
2448    /// with a wildcard-name `name_template` (i.e. containing `%u`, `%s` or `%d`)
2449    /// and no specific `name` was provided using [`PadBuilder::name`]
2450    /// or [`PadBuilder::name_if_some`], or for [`GhostPad`s](crate::GhostPad),
2451    /// by defining a `target`.
2452    ///
2453    /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object`
2454    /// automatically generated unique name.
2455    #[must_use = "Building the pad without using it has no effect"]
2456    #[track_caller]
2457    pub fn build(self) -> T {
2458        let Self { pad, name } = self;
2459
2460        let templ = pad.pad_template();
2461
2462        use PadBuilderName::*;
2463        match (name, templ) {
2464            (KeepGenerated, _) => (),
2465            (Undefined, None) => (),
2466            (Undefined, Some(templ)) => {
2467                if templ.name().find('%').is_some() {
2468                    panic!(concat!(
2469                        "Attempt to build a Pad from a wildcard-name template",
2470                        " or with a target Pad with an incompatible name.",
2471                        " Make sure to define a specific name using PadBuilder",
2472                        " or opt-in to keep the automatically generated name.",
2473                    ));
2474                } else {
2475                    pad.set_property("name", templ.name());
2476                }
2477            }
2478            (UserDefined(name), _) | (CandidateForWildcardTemplate(name), None) => {
2479                pad.set_property("name", name);
2480            }
2481            (CandidateForWildcardTemplate(name), Some(templ)) => {
2482                if templ.name().find('%').is_none() {
2483                    // Not a widlcard template
2484                    pad.set_property("name", templ.name());
2485                } else {
2486                    let mut can_assign_name = true;
2487
2488                    if templ.presence() == crate::PadPresence::Request {
2489                        // Check if the name is compatible with the name template.
2490                        use crate::CAT_RUST;
2491
2492                        let mut name_parts = name.split('_');
2493                        for templ_part in templ.name_template().split('_') {
2494                            let Some(name_part) = name_parts.next() else {
2495                                crate::debug!(
2496                                CAT_RUST,
2497                                "Not using Pad name '{name}': not enough parts compared to template '{}'",
2498                                templ.name_template(),
2499                            );
2500                                can_assign_name = false;
2501                                break;
2502                            };
2503
2504                            if let Some(conv_spec_start) = templ_part.find('%') {
2505                                if conv_spec_start > 0
2506                                    && !name_part.starts_with(&templ_part[..conv_spec_start])
2507                                {
2508                                    crate::debug!(
2509                                    CAT_RUST,
2510                                    "Not using Pad name '{name}': mismatch template '{}' prefix",
2511                                    templ.name_template(),
2512                                );
2513                                    can_assign_name = false;
2514                                    break;
2515                                }
2516
2517                                let conv_spec_pos = conv_spec_start + 1;
2518                                match templ_part.get(conv_spec_pos..=conv_spec_pos) {
2519                                    Some("s") => {
2520                                        // *There can be only one* %s
2521                                        break;
2522                                    }
2523                                    Some("u") => {
2524                                        if name_part
2525                                            .get(conv_spec_start..)
2526                                            .map_or(true, |s| s.parse::<u32>().is_err())
2527                                        {
2528                                            crate::debug!(
2529                                            CAT_RUST,
2530                                            "Not using Pad name '{name}': can't parse '%u' from '{name_part}' (template '{}')",
2531                                            templ.name_template(),
2532                                        );
2533
2534                                            can_assign_name = false;
2535                                            break;
2536                                        }
2537                                    }
2538                                    Some("d") => {
2539                                        if name_part
2540                                            .get(conv_spec_start..)
2541                                            .map_or(true, |s| s.parse::<i32>().is_err())
2542                                        {
2543                                            crate::debug!(
2544                                            CAT_RUST,
2545                                            "Not using target Pad name '{name}': can't parse '%i' from '{name_part}' (template '{}')",
2546                                            templ.name_template(),
2547                                        );
2548
2549                                            can_assign_name = false;
2550                                            break;
2551                                        }
2552                                    }
2553                                    other => {
2554                                        unreachable!("Unexpected conversion specifier {other:?}")
2555                                    }
2556                                }
2557                            } else if name_part != templ_part {
2558                                can_assign_name = false;
2559                            }
2560                        }
2561                    }
2562
2563                    if can_assign_name {
2564                        pad.set_property("name", name);
2565                    } else {
2566                        panic!(concat!(
2567                            "Attempt to build a Pad from a wildcard-name template",
2568                            " with a target Pad with an incompatible name.",
2569                            " Make sure to define a specific name using PadBuilder",
2570                            " or opt-in to keep the automatically generated name.",
2571                        ));
2572                    }
2573                }
2574            }
2575        }
2576
2577        pad
2578    }
2579}
2580
2581#[cfg(test)]
2582mod tests {
2583    use std::sync::{atomic::AtomicUsize, mpsc::channel, Arc, Mutex};
2584
2585    use super::*;
2586
2587    #[test]
2588    fn test_event_chain_functions() {
2589        crate::init().unwrap();
2590
2591        let events = Arc::new(Mutex::new(Vec::new()));
2592        let events_clone = events.clone();
2593        let buffers = Arc::new(Mutex::new(Vec::new()));
2594        let buffers_clone = buffers.clone();
2595        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2596            .name("sink")
2597            .event_function(move |_, _, event| {
2598                let mut events = events_clone.lock().unwrap();
2599                events.push(event);
2600
2601                true
2602            })
2603            .chain_function(move |_, _, buffer| {
2604                let mut buffers = buffers_clone.lock().unwrap();
2605                buffers.push(buffer);
2606
2607                Ok(FlowSuccess::Ok)
2608            })
2609            .build();
2610
2611        pad.set_active(true).unwrap();
2612
2613        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2614        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2615        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2616
2617        assert_eq!(pad.chain(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2618
2619        let events = events.lock().unwrap();
2620        let buffers = buffers.lock().unwrap();
2621        assert_eq!(events.len(), 2);
2622        assert_eq!(buffers.len(), 1);
2623
2624        match events[0].view() {
2625            crate::EventView::StreamStart(..) => (),
2626            _ => unreachable!(),
2627        }
2628
2629        match events[1].view() {
2630            crate::EventView::Segment(..) => (),
2631            _ => unreachable!(),
2632        }
2633    }
2634
2635    #[test]
2636    fn test_getrange_function() {
2637        crate::init().unwrap();
2638
2639        let pad = crate::Pad::builder(crate::PadDirection::Src)
2640            .name("src")
2641            .activate_function(|pad, _parent| {
2642                pad.activate_mode(crate::PadMode::Pull, true)
2643                    .map_err(|err| err.into())
2644            })
2645            .getrange_function(|_pad, _parent, offset, _buffer, size| {
2646                assert_eq!(offset, 0);
2647                assert_eq!(size, 5);
2648                let buffer = crate::Buffer::from_slice(b"abcde");
2649                Ok(PadGetRangeSuccess::NewBuffer(buffer))
2650            })
2651            .build();
2652        pad.set_active(true).unwrap();
2653
2654        let buffer = pad.range(0, 5).unwrap();
2655        let map = buffer.map_readable().unwrap();
2656        assert_eq!(&*map, b"abcde");
2657
2658        let mut buffer = crate::Buffer::with_size(5).unwrap();
2659        pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
2660        let map = buffer.map_readable().unwrap();
2661        assert_eq!(&*map, b"abcde");
2662
2663        pad.set_active(false).unwrap();
2664        drop(pad);
2665
2666        let pad = crate::Pad::builder(crate::PadDirection::Src)
2667            .name("src")
2668            .activate_function(|pad, _parent| {
2669                pad.activate_mode(crate::PadMode::Pull, true)
2670                    .map_err(|err| err.into())
2671            })
2672            .getrange_function(|_pad, _parent, offset, buffer, size| {
2673                assert_eq!(offset, 0);
2674                assert_eq!(size, 5);
2675                if let Some(buffer) = buffer {
2676                    buffer.copy_from_slice(0, b"fghij").unwrap();
2677                    Ok(PadGetRangeSuccess::FilledBuffer)
2678                } else {
2679                    let buffer = crate::Buffer::from_slice(b"abcde");
2680                    Ok(PadGetRangeSuccess::NewBuffer(buffer))
2681                }
2682            })
2683            .build();
2684        pad.set_active(true).unwrap();
2685
2686        let buffer = pad.range(0, 5).unwrap();
2687        let map = buffer.map_readable().unwrap();
2688        assert_eq!(&*map, b"abcde");
2689
2690        let mut buffer = crate::Buffer::with_size(5).unwrap();
2691        pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap();
2692        let map = buffer.map_readable().unwrap();
2693        assert_eq!(&*map, b"fghij");
2694    }
2695
2696    #[test]
2697    fn test_task() {
2698        crate::init().unwrap();
2699
2700        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2701            .name("sink")
2702            .build();
2703        let (sender, receiver) = channel();
2704
2705        let mut i = 0;
2706        let pad_clone = pad.clone();
2707        pad.start_task(move || {
2708            i += 1;
2709            if i == 3 {
2710                sender.send(i).unwrap();
2711                pad_clone.pause_task().unwrap();
2712            }
2713        })
2714        .unwrap();
2715
2716        assert_eq!(receiver.recv().unwrap(), 3);
2717    }
2718
2719    #[test]
2720    fn test_remove_probe_from_probe() {
2721        crate::init().unwrap();
2722
2723        let src_pad = crate::Pad::builder(crate::PadDirection::Src)
2724            .name("src")
2725            .build();
2726        let sink_pad = crate::Pad::builder(crate::PadDirection::Sink)
2727            .name("sink")
2728            .chain_function(|_pad, _parent, _buffer| Ok(crate::FlowSuccess::Ok))
2729            .build();
2730
2731        src_pad.link(&sink_pad).unwrap();
2732
2733        let counter = Arc::new(AtomicUsize::new(0));
2734        let counter_clone = counter.clone();
2735        src_pad.add_probe(crate::PadProbeType::BUFFER, move |pad, info| {
2736            if let Some(PadProbeData::Buffer(_)) = info.data {
2737                counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
2738                pad.remove_probe(info.id.take().expect("no pad probe id"));
2739            } else {
2740                unreachable!();
2741            }
2742            crate::PadProbeReturn::Handled
2743        });
2744
2745        sink_pad.set_active(true).unwrap();
2746        src_pad.set_active(true).unwrap();
2747
2748        assert!(src_pad.push_event(crate::event::StreamStart::new("test")));
2749        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2750        assert!(src_pad.push_event(crate::event::Segment::new(segment.as_ref())));
2751
2752        assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2753        assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2754
2755        assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
2756    }
2757
2758    fn do_probe_with_return(probe_return: crate::PadProbeReturn) {
2759        skip_assert_initialized!();
2760        crate::init().unwrap();
2761
2762        let (major, minor, micro, _) = crate::version();
2763        let pad = crate::Pad::builder(crate::PadDirection::Src)
2764            .name("src")
2765            .build();
2766        let events = Arc::new(Mutex::new(Vec::new()));
2767        let buffers = Arc::new(Mutex::new(Vec::new()));
2768
2769        let flow_override = if (major, minor, micro) >= (1, 16, 1) {
2770            Err(FlowError::Eos)
2771        } else {
2772            // Broken on 1.16.0
2773            // https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/151
2774            Ok(FlowSuccess::Ok)
2775        };
2776
2777        {
2778            let events = events.clone();
2779            pad.add_probe(crate::PadProbeType::EVENT_DOWNSTREAM, move |_, info| {
2780                if let Some(PadProbeData::Event(event)) = &info.data {
2781                    let mut events = events.lock().unwrap();
2782                    events.push(event.clone());
2783                } else {
2784                    unreachable!();
2785                }
2786                crate::PadProbeReturn::Ok
2787            });
2788        }
2789
2790        {
2791            let events = events.clone();
2792            pad.add_probe(crate::PadProbeType::EVENT_UPSTREAM, move |_, info| {
2793                if let Some(event) = info.take_event() {
2794                    let mut events = events.lock().unwrap();
2795                    events.push(event);
2796                } else {
2797                    unreachable!();
2798                }
2799                probe_return
2800            });
2801        }
2802
2803        {
2804            let buffers = buffers.clone();
2805            pad.add_probe(crate::PadProbeType::BUFFER, move |_, info| {
2806                if let Some(buffer) = info.take_buffer() {
2807                    let mut buffers = buffers.lock().unwrap();
2808                    info.flow_res = if buffers.is_empty() {
2809                        Ok(FlowSuccess::Ok)
2810                    } else {
2811                        flow_override
2812                    };
2813                    buffers.push(buffer);
2814                } else {
2815                    unreachable!();
2816                }
2817                probe_return
2818            });
2819        }
2820
2821        pad.set_active(true).unwrap();
2822
2823        assert!(
2824            pad.send_event(crate::event::Latency::new(crate::ClockTime::from_nseconds(
2825                10
2826            )))
2827        );
2828        assert!(pad.push_event(crate::event::StreamStart::new("test")));
2829        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2830        assert!(pad.push_event(crate::event::Segment::new(segment.as_ref())));
2831
2832        assert_eq!(pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok));
2833        assert_eq!(
2834            pad.push(crate::Buffer::new()),
2835            // On Drop, we will get an Ok, not whatever value we returned
2836            if probe_return == crate::PadProbeReturn::Drop {
2837                Ok(FlowSuccess::Ok)
2838            } else {
2839                flow_override
2840            }
2841        );
2842
2843        let events = events.lock().unwrap();
2844        let buffers = buffers.lock().unwrap();
2845        assert_eq!(events.len(), 3);
2846        assert_eq!(buffers.len(), 2);
2847
2848        assert_eq!(events[0].type_(), crate::EventType::Latency);
2849        assert_eq!(events[1].type_(), crate::EventType::StreamStart);
2850        assert_eq!(events[2].type_(), crate::EventType::Segment);
2851
2852        assert!(
2853            buffers.iter().all(|b| b.is_writable()),
2854            "A buffer ref leaked!"
2855        );
2856
2857        drop(pad); // Need to drop the pad first to unref sticky events
2858        assert!(
2859            events.iter().all(|e| e.is_writable()),
2860            "An event ref leaked!"
2861        );
2862    }
2863
2864    #[test]
2865    fn test_probe() {
2866        crate::init().unwrap();
2867        do_probe_with_return(crate::PadProbeReturn::Handled);
2868    }
2869
2870    #[test]
2871    fn test_probe_drop() {
2872        crate::init().unwrap();
2873        do_probe_with_return(crate::PadProbeReturn::Drop);
2874    }
2875
2876    #[test]
2877    fn test_sticky_events() {
2878        crate::init().unwrap();
2879
2880        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2881            .name("sink")
2882            .build();
2883        pad.set_active(true).unwrap();
2884
2885        // Send some sticky events
2886        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2887
2888        let caps = crate::Caps::builder("some/x-caps").build();
2889        assert!(pad.send_event(crate::event::Caps::new(&caps)));
2890
2891        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2892        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2893
2894        let stream_start = pad.sticky_event::<crate::event::StreamStart>(0).unwrap();
2895        assert_eq!(stream_start.stream_id(), "test");
2896
2897        let caps2 = pad.sticky_event::<crate::event::Caps>(0).unwrap();
2898        assert_eq!(&*caps, caps2.caps());
2899
2900        let segment = pad.sticky_event::<crate::event::Segment>(0).unwrap();
2901        assert_eq!(segment.segment().format(), crate::Format::Time);
2902    }
2903
2904    #[test]
2905    fn test_sticky_events_foreach() {
2906        crate::init().unwrap();
2907
2908        let pad = crate::Pad::builder(crate::PadDirection::Sink)
2909            .name("sink")
2910            .build();
2911        pad.set_active(true).unwrap();
2912
2913        // Send some sticky events
2914        assert!(pad.send_event(crate::event::StreamStart::new("test")));
2915
2916        let caps = crate::Caps::builder("some/x-caps").build();
2917        assert!(pad.send_event(crate::event::Caps::new(&caps)));
2918
2919        let segment = crate::FormattedSegment::<crate::ClockTime>::new();
2920        assert!(pad.send_event(crate::event::Segment::new(segment.as_ref())));
2921
2922        let mut sticky_events = Vec::new();
2923        pad.sticky_events_foreach(|event| {
2924            sticky_events.push(event.clone());
2925            ControlFlow::Continue(EventForeachAction::Keep)
2926        });
2927        assert_eq!(sticky_events.len(), 3);
2928
2929        // Test early exit from foreach loop
2930        let mut sticky_events2 = Vec::new();
2931        pad.sticky_events_foreach(|event| {
2932            sticky_events2.push(event.clone());
2933            if event.type_() == crate::EventType::Caps {
2934                ControlFlow::Break(EventForeachAction::Keep)
2935            } else {
2936                ControlFlow::Continue(EventForeachAction::Keep)
2937            }
2938        });
2939        assert_eq!(sticky_events2.len(), 2);
2940
2941        let mut sticky_events3 = Vec::new();
2942        pad.sticky_events_foreach(|event| {
2943            sticky_events3.push(event.clone());
2944            ControlFlow::Continue(EventForeachAction::Keep)
2945        });
2946        assert_eq!(sticky_events3.len(), 3);
2947
2948        for (e1, e2) in sticky_events.iter().zip(sticky_events3.iter()) {
2949            assert_eq!(e1.as_ref() as *const _, e2.as_ref() as *const _);
2950        }
2951
2952        // Replace segment event
2953        pad.sticky_events_foreach(|event| {
2954            let action = if event.type_() == crate::EventType::Segment {
2955                let byte_segment = crate::FormattedSegment::<crate::format::Bytes>::new();
2956                EventForeachAction::Replace(crate::event::Segment::new(&byte_segment))
2957            } else {
2958                EventForeachAction::Keep
2959            };
2960            ControlFlow::Continue(action)
2961        });
2962
2963        // Check that segment event is different now
2964        let mut sticky_events4 = Vec::new();
2965        pad.sticky_events_foreach(|event| {
2966            sticky_events4.push(event.clone());
2967            ControlFlow::Continue(EventForeachAction::Keep)
2968        });
2969        assert_eq!(sticky_events4.len(), 3);
2970        assert_eq!(
2971            sticky_events[0].as_ref() as *const _,
2972            sticky_events4[0].as_ref() as *const _
2973        );
2974        assert_eq!(
2975            sticky_events[1].as_ref() as *const _,
2976            sticky_events4[1].as_ref() as *const _
2977        );
2978        assert_ne!(
2979            sticky_events[2].as_ref() as *const _,
2980            sticky_events4[2].as_ref() as *const _
2981        );
2982
2983        // Drop caps event
2984        pad.sticky_events_foreach(|event| {
2985            let action = if event.type_() == crate::EventType::Caps {
2986                EventForeachAction::Remove
2987            } else {
2988                EventForeachAction::Keep
2989            };
2990            ControlFlow::Continue(action)
2991        });
2992
2993        // Check that caps event actually got removed
2994        let mut sticky_events5 = Vec::new();
2995        pad.sticky_events_foreach(|event| {
2996            sticky_events5.push(event.clone());
2997            ControlFlow::Continue(EventForeachAction::Keep)
2998        });
2999        assert_eq!(sticky_events5.len(), 2);
3000        assert_eq!(
3001            sticky_events4[0].as_ref() as *const _,
3002            sticky_events5[0].as_ref() as *const _
3003        );
3004        assert_eq!(
3005            sticky_events4[2].as_ref() as *const _,
3006            sticky_events5[1].as_ref() as *const _
3007        );
3008    }
3009
3010    #[test]
3011    #[allow(deprecated)] // maybe_name() is deprecated
3012    fn naming() {
3013        crate::init().unwrap();
3014
3015        let pad = crate::Pad::builder(crate::PadDirection::Sink).build();
3016        assert!(pad.name().starts_with("pad"));
3017
3018        let pad = crate::Pad::builder(crate::PadDirection::Src).build();
3019        assert!(pad.name().starts_with("pad"));
3020
3021        let pad = crate::Pad::builder(crate::PadDirection::Unknown).build();
3022        assert!(pad.name().starts_with("pad"));
3023
3024        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3025            .generated_name()
3026            .build();
3027        assert!(pad.name().starts_with("pad"));
3028
3029        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3030            .maybe_name(None::<&str>)
3031            .build();
3032        assert!(pad.name().starts_with("pad"));
3033
3034        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3035            .name_if_some(None::<&str>)
3036            .build();
3037        assert!(pad.name().starts_with("pad"));
3038
3039        let pad = crate::Pad::builder(crate::PadDirection::Sink)
3040            .name("sink_0")
3041            .build();
3042        assert_eq!(pad.name(), "sink_0");
3043
3044        let pad = crate::Pad::builder(crate::PadDirection::Src)
3045            .name("src_0")
3046            .build();
3047        assert_eq!(pad.name(), "src_0");
3048
3049        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3050            .name("test")
3051            .build();
3052        assert_eq!(pad.name(), "test");
3053
3054        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3055            .maybe_name(Some("test"))
3056            .build();
3057        assert_eq!(pad.name(), "test");
3058
3059        let pad = crate::Pad::builder(crate::PadDirection::Unknown)
3060            .name_if_some(Some("test"))
3061            .build();
3062        assert_eq!(pad.name(), "test");
3063
3064        let caps = crate::Caps::new_any();
3065        let templ = crate::PadTemplate::new(
3066            "sink",
3067            crate::PadDirection::Sink,
3068            crate::PadPresence::Always,
3069            &caps,
3070        )
3071        .unwrap();
3072
3073        let pad = Pad::from_template(&templ);
3074        assert!(pad.name().starts_with("sink"));
3075
3076        let pad = Pad::builder_from_template(&templ)
3077            .name("audio_sink")
3078            .build();
3079        assert!(pad.name().starts_with("audio_sink"));
3080
3081        let pad = Pad::builder_from_template(&templ).generated_name().build();
3082        assert!(pad.name().starts_with("pad"));
3083
3084        let templ = crate::PadTemplate::new(
3085            "audio_%u",
3086            crate::PadDirection::Sink,
3087            crate::PadPresence::Request,
3088            &caps,
3089        )
3090        .unwrap();
3091
3092        let pad = Pad::builder_from_template(&templ).name("audio_0").build();
3093        assert!(pad.name().starts_with("audio_0"));
3094
3095        let pad = Pad::builder_from_template(&templ).generated_name().build();
3096        assert!(pad.name().starts_with("pad"));
3097    }
3098
3099    #[test]
3100    #[should_panic]
3101    fn missing_name() {
3102        crate::init().unwrap();
3103
3104        let caps = crate::Caps::new_any();
3105        let templ = crate::PadTemplate::new(
3106            "audio_%u",
3107            crate::PadDirection::Sink,
3108            crate::PadPresence::Request,
3109            &caps,
3110        )
3111        .unwrap();
3112
3113        // Panic: attempt to build from a wildcard-named template
3114        //        without providing a name.
3115        let _pad = Pad::from_template(&templ);
3116    }
3117}