gstreamer/subclass/
tracer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3#[cfg(not(feature = "v1_26"))]
4use {crate::value::GstValueExt, std::str::FromStr};
5
6use glib::{prelude::*, subclass::prelude::*, translate::*};
7
8use super::prelude::*;
9use crate::{
10    ffi, Bin, Buffer, BufferList, Element, Event, FlowError, FlowSuccess, Message, MiniObject,
11    Object, Pad, PadLinkError, PadLinkSuccess, QueryRef, StateChange, StateChangeError,
12    StateChangeSuccess, Tracer,
13};
14
15#[allow(unused_variables)]
16pub trait TracerImpl: GstObjectImpl + ObjectSubclass<Type: IsA<Tracer>> {
17    // rustdoc-stripper-ignore-next
18    /// Whether to use `gst::Structure` style "params" and automatically pass
19    /// them to the corresponding properties during instantiation.
20    const USE_STRUCTURE_PARAMS: bool = false;
21
22    fn bin_add_post(&self, ts: u64, bin: &Bin, element: &Element, success: bool) {}
23    fn bin_add_pre(&self, ts: u64, bin: &Bin, element: &Element) {}
24    fn bin_remove_post(&self, ts: u64, bin: &Bin, success: bool) {}
25    fn bin_remove_pre(&self, ts: u64, bin: &Bin, element: &Element) {}
26    fn element_new(&self, ts: u64, element: &Element) {}
27    fn element_add_pad(&self, ts: u64, element: &Element, pad: &Pad) {}
28    fn element_remove_pad(&self, ts: u64, element: &Element, pad: &Pad) {}
29    fn element_change_state_post(
30        &self,
31        ts: u64,
32        element: &Element,
33        change: StateChange,
34        result: Result<StateChangeSuccess, StateChangeError>,
35    ) {
36    }
37    fn element_change_state_pre(&self, ts: u64, element: &Element, change: StateChange) {}
38    fn element_post_message_post(&self, ts: u64, element: &Element, success: bool) {}
39    fn element_post_message_pre(&self, ts: u64, element: &Element, message: &Message) {}
40    fn element_query_post(&self, ts: u64, element: &Element, query: &QueryRef, success: bool) {}
41    fn element_query_pre(&self, ts: u64, element: &Element, query: &QueryRef) {}
42    // rustdoc-stripper-ignore-next
43    /// Hook to be called before the GstMiniObject has been fully initialized.
44    fn mini_object_created(&self, ts: u64, object: std::ptr::NonNull<ffi::GstMiniObject>) {}
45    // rustdoc-stripper-ignore-next
46    /// Hook to be called after the GstMiniObject has been finalized.
47    fn mini_object_destroyed(&self, ts: u64, object: std::ptr::NonNull<ffi::GstMiniObject>) {}
48    fn mini_object_reffed(&self, ts: u64, object: &MiniObject, new_refcount: i32) {}
49    fn mini_object_unreffed(&self, ts: u64, object: &MiniObject, new_refcount: i32) {}
50    fn object_created(&self, ts: u64, object: &Object) {}
51    // rustdoc-stripper-ignore-next
52    /// Hook to be called after the GstObject has been finalized.
53    fn object_destroyed(&self, ts: u64, object: std::ptr::NonNull<ffi::GstObject>) {}
54    fn object_reffed(&self, ts: u64, object: &Object, new_refcount: i32) {}
55    fn object_unreffed(&self, ts: u64, object: &Object, new_refcount: i32) {}
56    fn pad_link_post(
57        &self,
58        ts: u64,
59        src: &Pad,
60        sink: &Pad,
61        result: Result<PadLinkSuccess, PadLinkError>,
62    ) {
63    }
64    fn pad_link_pre(&self, ts: u64, src: &Pad, sink: &Pad) {}
65    fn pad_pull_range_post(&self, ts: u64, pad: &Pad, result: Result<&Buffer, FlowError>) {}
66    fn pad_pull_range_pre(&self, ts: u64, pad: &Pad, offset: u64, size: u32) {}
67    fn pad_push_event_post(&self, ts: u64, pad: &Pad, success: bool) {}
68    fn pad_push_event_pre(&self, ts: u64, pad: &Pad, event: &Event) {}
69    #[cfg(feature = "v1_22")]
70    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
71    fn pad_chain_list_post(&self, ts: u64, pad: &Pad, result: Result<FlowSuccess, FlowError>) {}
72    #[cfg(feature = "v1_22")]
73    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
74    fn pad_chain_list_pre(&self, ts: u64, pad: &Pad, buffer_list: &BufferList) {}
75    #[cfg(feature = "v1_22")]
76    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
77    fn pad_chain_post(&self, ts: u64, pad: &Pad, result: Result<FlowSuccess, FlowError>) {}
78    #[cfg(feature = "v1_22")]
79    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
80    fn pad_chain_pre(&self, ts: u64, pad: &Pad, buffer: &Buffer) {}
81    fn pad_push_list_post(&self, ts: u64, pad: &Pad, result: Result<FlowSuccess, FlowError>) {}
82    fn pad_push_list_pre(&self, ts: u64, pad: &Pad, buffer_list: &BufferList) {}
83    fn pad_push_post(&self, ts: u64, pad: &Pad, result: Result<FlowSuccess, FlowError>) {}
84    fn pad_push_pre(&self, ts: u64, pad: &Pad, buffer: &Buffer) {}
85    fn pad_query_post(&self, ts: u64, pad: &Pad, query: &QueryRef, success: bool) {}
86    fn pad_query_pre(&self, ts: u64, pad: &Pad, query: &QueryRef) {}
87    fn pad_unlink_post(&self, ts: u64, src: &Pad, sink: &Pad, success: bool) {}
88    fn pad_unlink_pre(&self, ts: u64, src: &Pad, sink: &Pad) {}
89    #[cfg(feature = "v1_20")]
90    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
91    fn plugin_feature_loaded(&self, ts: u64, feature: &crate::PluginFeature) {}
92    #[cfg(feature = "v1_26")]
93    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
94    fn memory_init(&self, ts: u64, mem: &crate::MemoryRefTrace) {}
95    #[cfg(feature = "v1_26")]
96    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
97    fn memory_free_pre(&self, ts: u64, mem: &crate::MemoryRef) {}
98    #[cfg(feature = "v1_26")]
99    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
100    fn memory_free_post(&self, ts: u64, mem: std::ptr::NonNull<ffi::GstMemory>) {}
101
102    #[cfg(feature = "v1_28")]
103    #[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
104    fn pool_buffer_queued(&self, ts: u64, pool: &crate::BufferPool, buffer: &Buffer) {}
105    #[cfg(feature = "v1_28")]
106    #[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
107    fn pool_buffer_dequeued(&self, ts: u64, pool: &crate::BufferPool, buffer: &Buffer) {}
108}
109
110#[cfg(not(feature = "v1_26"))]
111fn format_available_properties(class: &glib::object::ObjectClass) -> String {
112    class
113        .list_properties()
114        .iter()
115        .filter(|p| {
116            p.flags().contains(glib::ParamFlags::WRITABLE)
117                && p.name() != "parent"
118                && p.name() != "params"
119        })
120        .map(|p| format!("  {}: {}", p.name(), p.blurb().map_or("", |b| b)))
121        .collect::<Vec<_>>()
122        .join("\n")
123}
124
125#[cfg(not(feature = "v1_26"))]
126fn emit_property_warning(obj: &glib::Object, msg: &str) {
127    let props = format_available_properties(obj.class());
128    glib::g_warning!("gsttracer", "{}\nAvailable properties:\n{}", msg, props);
129}
130
131unsafe impl<T: TracerImpl> IsSubclassable<T> for Tracer {
132    fn class_init(class: &mut glib::Class<Self>) {
133        Self::parent_class_init::<T>(class);
134
135        #[cfg(feature = "v1_26")]
136        {
137            let class = class.as_mut();
138            unsafe {
139                ffi::gst_tracer_class_set_use_structure_params(
140                    class,
141                    T::USE_STRUCTURE_PARAMS.into_glib(),
142                );
143            }
144        }
145        #[cfg(not(feature = "v1_26"))]
146        unsafe {
147            if T::USE_STRUCTURE_PARAMS {
148                use std::sync::OnceLock;
149                static TRACER_CONSTRUCTED_FUNC: OnceLock<
150                    unsafe extern "C" fn(*mut glib::gobject_ffi::GObject),
151                > = OnceLock::new();
152
153                let class =
154                    &mut *(class.as_mut() as *mut _ as *mut glib::gobject_ffi::GObjectClass);
155                TRACER_CONSTRUCTED_FUNC.get_or_init(|| class.constructed.unwrap());
156                unsafe extern "C" fn constructed(objptr: *mut glib::gobject_ffi::GObject) {
157                    let obj = glib::Object::from_glib_borrow(objptr);
158                    let params = obj.property::<Option<String>>("params");
159
160                    let Some(params) = params else {
161                        TRACER_CONSTRUCTED_FUNC.get().unwrap()(objptr);
162
163                        return;
164                    };
165
166                    if params.is_empty() {
167                        TRACER_CONSTRUCTED_FUNC.get().unwrap()(objptr);
168
169                        return;
170                    }
171
172                    let s = match crate::Structure::from_str(&format!("tracer-settings,{params}")) {
173                        Ok(s) => s,
174                        Err(err) => {
175                            emit_property_warning(
176                                &obj,
177                                &format!(
178                                    "Can't setup tracer {err:?}: invalid parameters '{params}'"
179                                ),
180                            );
181                            return;
182                        }
183                    };
184
185                    let class = obj.class();
186
187                    for (field, field_value) in s.iter() {
188                        let pspec = match class.find_property(field.as_str()) {
189                            Some(p) => p,
190                            None => {
191                                emit_property_warning(
192                                    &obj,
193                                    &format!(
194                                        "Can't setup tracer: property '{}' not found",
195                                        field.as_str()
196                                    ),
197                                );
198                                return;
199                            }
200                        };
201
202                        let value = if field_value.type_() == pspec.value_type() {
203                            field_value.to_value()
204                        } else if field_value.type_() == glib::types::Type::STRING {
205                            let str_val = field_value.get::<String>().unwrap();
206                            #[cfg(feature = "v1_20")]
207                            {
208                                match glib::Value::deserialize_with_pspec(&str_val, &pspec) {
209                                    Ok(v) => v,
210                                    Err(_) => {
211                                        emit_property_warning(&obj, &format!("Can't instantiate tracer: invalid property '{}' value: '{}'", field.as_str(), str_val));
212                                        return;
213                                    }
214                                }
215                            }
216                            #[cfg(not(feature = "v1_20"))]
217                            {
218                                match glib::Value::deserialize(&str_val, pspec.value_type()) {
219                                    Ok(v) => v,
220                                    Err(_) => {
221                                        emit_property_warning(&obj, &format!("Can't instantiate tracer: invalid property '{}' value: '{}'", field.as_str(), str_val));
222                                        return;
223                                    }
224                                }
225                            }
226                        } else {
227                            emit_property_warning(&obj, &format!(
228                                "Can't setup tracer: property '{}' type mismatch, expected {}, got {}",
229                                field.as_str(),
230                                pspec.value_type().name(),
231                                field_value.type_().name()
232                            ));
233                            return;
234                        };
235
236                        crate::debug!(crate::CAT_RUST, "Setting property {field:?}");
237                        obj.set_property(field.as_str(), &value);
238                    }
239
240                    TRACER_CONSTRUCTED_FUNC.get().unwrap()(objptr);
241                }
242
243                class.constructed = Some(constructed);
244            }
245        }
246    }
247}
248
249pub trait TracerImplExt: TracerImpl {
250    // rustdoc-stripper-ignore-next
251    /// Register a corresponding hook to be called for this tracer when certain events occur.
252    ///
253    /// Upon an event a corresponding method in `TracerImpl` will be called.
254    fn register_hook(&self, hook: TracerHook);
255}
256
257macro_rules! define_tracer_hooks {
258    ($($(#[$attr:meta])* $name: ident($quark: literal) = |$this: ident, $ts: ident, $($cb_arg: ident: $cb_arg_ty: ty),*| $impl: block;)*) => {
259        pub enum TracerHook {
260            $($(#[$attr])* $name),*
261        }
262        impl<T: TracerImpl> TracerImplExt for T {
263            fn register_hook(&self, hook: TracerHook) {
264                use TracerHook::*;
265                let (hook_type, callback) = match hook {
266                    $($(#[$attr])* $name => {
267                        #[allow(non_snake_case)]
268                        unsafe extern "C" fn callback<T: TracerImpl>(
269                            $this: *mut ffi::GstTracer,
270                            $ts: u64,
271                            $($cb_arg: $cb_arg_ty),*
272                        ) {
273                            let $this = Tracer::from_glib_borrow($this);
274                            let $this = T::from_obj($this.unsafe_cast_ref());
275                            $impl
276                        }
277                        (
278                            concat!($quark, "\0"),
279                            callback::<T> as unsafe extern "C" fn(_, _, $($cb_arg_ty),*) as *const ()
280                        )
281                    },)*
282                };
283                unsafe {
284                    let instance = self.obj();
285                    ffi::gst_tracing_register_hook(
286                        instance.to_glib_none().0 as *mut ffi::GstTracer,
287                        hook_type.as_ptr() as *const _,
288                        Some(std::mem::transmute::<*const (), extern "C" fn()>(callback)),
289                    );
290                }
291            }
292        }
293    };
294}
295
296define_tracer_hooks! {
297    BinAddPost("bin-add-post") = |this, ts, b: *mut ffi::GstBin, e: *mut ffi::GstElement, r: glib::ffi::gboolean| {
298        let b = Bin::from_glib_borrow(b);
299        let e = Element::from_glib_borrow(e);
300        this.bin_add_post(ts, &b, &e, bool::from_glib(r))
301    };
302    BinAddPre("bin-add-pre") = |this, ts, b: *mut ffi::GstBin, e: *mut ffi::GstElement| {
303        let b = Bin::from_glib_borrow(b);
304        let e = Element::from_glib_borrow(e);
305        this.bin_add_pre(ts, &b, &e)
306    };
307    BinRemovePost("bin-remove-post") = |this, ts, b: *mut ffi::GstBin, r: glib::ffi::gboolean| {
308        let b = Bin::from_glib_borrow(b);
309        this.bin_remove_post(ts, &b, bool::from_glib(r))
310    };
311    BinRemovePre("bin-remove-pre") = |this, ts, b: *mut ffi::GstBin, e: *mut ffi::GstElement| {
312        let b = Bin::from_glib_borrow(b);
313        let e = Element::from_glib_borrow(e);
314        this.bin_remove_pre(ts, &b, &e)
315    };
316    ElementNew("element-new") = |this, ts, e: *mut ffi::GstElement| {
317        let e = Element::from_glib_borrow(e);
318        this.element_new(ts, &e)
319    };
320    ElementAddPad("element-add-pad") = |this, ts, e: *mut ffi::GstElement, p: *mut ffi::GstPad| {
321        let e = Element::from_glib_borrow(e);
322        let p = Pad::from_glib_borrow(p);
323        this.element_add_pad(ts, &e, &p)
324    };
325    ElementRemovePad("element-remove-pad") = |this, ts, e: *mut ffi::GstElement, p: *mut ffi::GstPad| {
326        let e = Element::from_glib_borrow(e);
327        let p = Pad::from_glib_borrow(p);
328        this.element_remove_pad(ts, &e, &p)
329    };
330    ElementChangeStatePost("element-change-state-post") = |this, ts, e: *mut ffi::GstElement, c: ffi::GstStateChange, r: ffi::GstStateChangeReturn| {
331        let e = Element::from_glib_borrow(e);
332        this.element_change_state_post(ts, &e, StateChange::from_glib(c), try_from_glib(r))
333    };
334    ElementChangeStatePre("element-change-state-pre") = |this, ts, e: *mut ffi::GstElement, c: ffi::GstStateChange| {
335        let e = Element::from_glib_borrow(e);
336        this.element_change_state_pre(ts, &e, StateChange::from_glib(c))
337    };
338    ElementPostMessagePost("element-post-message-post") = |this, ts, e: *mut ffi::GstElement, r: glib::ffi::gboolean| {
339        let e = Element::from_glib_borrow(e);
340        this.element_post_message_post(ts, &e, bool::from_glib(r))
341    };
342    ElementPostMessagePre("element-post-message-pre") = |this, ts, e: *mut ffi::GstElement, m: *mut ffi::GstMessage| {
343        let e = Element::from_glib_borrow(e);
344        let m = Message::from_glib_borrow(m);
345        this.element_post_message_pre(ts, &e, &m)
346    };
347    ElementQueryPost("element-query-post") = |this, ts, e: *mut ffi::GstElement, q: *mut ffi::GstQuery, r: glib::ffi::gboolean| {
348        let e = Element::from_glib_borrow(e);
349        let q = QueryRef::from_ptr(q);
350        this.element_query_post(ts, &e, q, bool::from_glib(r))
351    };
352    ElementQueryPre("element-query-pre") = |this, ts, e: *mut ffi::GstElement, q: *mut ffi::GstQuery| {
353        let e = Element::from_glib_borrow(e);
354        let q = QueryRef::from_ptr(q);
355        this.element_query_pre(ts, &e, q)
356    };
357    // TODO: unclear what to do here as the `GstMiniObject` here is not fully initialized yet…
358    MiniObjectCreated("mini-object-created") = |this, ts, o: *mut ffi::GstMiniObject| {
359        this.mini_object_created(ts, std::ptr::NonNull::new_unchecked(o))
360    };
361    // TODO: unclear what to do here as the `GstMiniObject` here is no longer valid…
362    MiniObjectDestroyed("mini-object-destroyed") = |this, ts, o: *mut ffi::GstMiniObject| {
363        this.mini_object_destroyed(ts, std::ptr::NonNull::new_unchecked(o))
364    };
365    MiniObjectReffed("mini-object-reffed") = |this, ts, o: *mut ffi::GstMiniObject, rc: libc::c_int| {
366        let o = MiniObject::from_glib_borrow(o);
367        this.mini_object_reffed(ts, &o, rc)
368    };
369    MiniObjectUnreffed("mini-object-unreffed") = |this, ts, o: *mut ffi::GstMiniObject, rc: libc::c_int| {
370        let o = MiniObject::from_glib_borrow(o);
371        this.mini_object_unreffed(ts, &o, rc)
372    };
373    ObjectCreated("object-created") = |this, ts, o: *mut ffi::GstObject| {
374        let o = Object::from_glib_borrow(o);
375        this.object_created(ts, &o)
376    };
377    // TODO: unclear what to do here as the `GstObject` here is no longer valid…
378    ObjectDestroyed("object-destroyed") = |this, ts, o: *mut ffi::GstObject| {
379        this.object_destroyed(ts, std::ptr::NonNull::new_unchecked(o))
380    };
381    ObjectReffed("object-reffed") = |this, ts, o: *mut ffi::GstObject, rc: libc::c_int| {
382        let o = Object::from_glib_borrow(o);
383        this.object_reffed(ts, &o, rc)
384    };
385    ObjectUnreffed("object-unreffed") = |this, ts, o: *mut ffi::GstObject, rc: libc::c_int| {
386        let o = Object::from_glib_borrow(o);
387        this.object_unreffed(ts, &o, rc)
388    };
389    PadLinkPost("pad-link-post") = |this, ts, src: *mut ffi::GstPad, sink: *mut ffi::GstPad, r: ffi::GstPadLinkReturn| {
390        let src = Pad::from_glib_borrow(src);
391        let sink = Pad::from_glib_borrow(sink);
392        this.pad_link_post(ts, &src, &sink, try_from_glib(r))
393    };
394    PadLinkPre("pad-link-pre") = |this, ts, src: *mut ffi::GstPad, sink: *mut ffi::GstPad| {
395        let src = Pad::from_glib_borrow(src);
396        let sink = Pad::from_glib_borrow(sink);
397        this.pad_link_pre(ts, &src, &sink)
398    };
399    PadPullRangePost("pad-pull-range-post") = |this, ts, p: *mut ffi::GstPad, b: *mut ffi::GstBuffer, r: ffi::GstFlowReturn| {
400        let p = Pad::from_glib_borrow(p);
401        let res: Result::<FlowSuccess, FlowError> = try_from_glib(r);
402        match res {
403            Ok(_) => {
404                this.pad_pull_range_post(ts, &p, Ok(&from_glib_borrow(b)))
405            }
406            Err(err) => {
407                this.pad_pull_range_post(ts, &p, Err(err))
408            }
409        }
410    };
411    PadPullRangePre("pad-pull-range-pre") = |this, ts, p: *mut ffi::GstPad, o: u64, s: libc::c_uint| {
412        let p = Pad::from_glib_borrow(p);
413        this.pad_pull_range_pre(ts, &p, o, s)
414    };
415    PadPushEventPost("pad-push-event-post") = |this, ts, p: *mut ffi::GstPad, r: glib::ffi::gboolean| {
416        let p = Pad::from_glib_borrow(p);
417        this.pad_push_event_post(ts, &p, bool::from_glib(r))
418    };
419    PadPushEventPre("pad-push-event-pre") = |this, ts, p: *mut ffi::GstPad, e: *mut ffi::GstEvent| {
420        let p = Pad::from_glib_borrow(p);
421        let e = Event::from_glib_borrow(e);
422        this.pad_push_event_pre(ts, &p, &e)
423    };
424    PadPushListPost("pad-push-list-post") = |this, ts, p: *mut ffi::GstPad, r: ffi::GstFlowReturn| {
425        let p = Pad::from_glib_borrow(p);
426        this.pad_push_list_post(ts, &p, try_from_glib(r))
427    };
428    PadPushListPre("pad-push-list-pre") = |this, ts, p: *mut ffi::GstPad, bl: *mut ffi::GstBufferList| {
429        let p = Pad::from_glib_borrow(p);
430        let bl = BufferList::from_glib_borrow(bl);
431        this.pad_push_list_pre(ts, &p, &bl)
432    };
433    PadPushPost("pad-push-post") = |this, ts, p: *mut ffi::GstPad, r: ffi::GstFlowReturn| {
434        let p = Pad::from_glib_borrow(p);
435        this.pad_push_post(ts, &p, try_from_glib(r))
436    };
437    PadPushPre("pad-push-pre") = |this, ts, p: *mut ffi::GstPad, b: *mut ffi::GstBuffer| {
438        let p = Pad::from_glib_borrow(p);
439        let b = Buffer::from_glib_borrow(b);
440        this.pad_push_pre(ts, &p, &b)
441    };
442    #[cfg(feature = "v1_22")]
443    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
444    PadChainListPost("pad-chain-list-post") = |this, ts, p: *mut ffi::GstPad, r: ffi::GstFlowReturn| {
445        let p = Pad::from_glib_borrow(p);
446        this.pad_chain_list_post(ts, &p, try_from_glib(r))
447    };
448    #[cfg(feature = "v1_22")]
449    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
450    PadChainListPre("pad-chain-list-pre") = |this, ts, p: *mut ffi::GstPad, bl: *mut ffi::GstBufferList| {
451        let p = Pad::from_glib_borrow(p);
452        let bl = BufferList::from_glib_borrow(bl);
453        this.pad_chain_list_pre(ts, &p, &bl)
454    };
455    #[cfg(feature = "v1_22")]
456    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
457    PadChainPost("pad-chain-post") = |this, ts, p: *mut ffi::GstPad, r: ffi::GstFlowReturn| {
458        let p = Pad::from_glib_borrow(p);
459        this.pad_chain_post(ts, &p, try_from_glib(r))
460    };
461    #[cfg(feature = "v1_22")]
462    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
463    PadChainPre("pad-chain-pre") = |this, ts, p: *mut ffi::GstPad, b: *mut ffi::GstBuffer| {
464        let p = Pad::from_glib_borrow(p);
465        let b = Buffer::from_glib_borrow(b);
466        this.pad_chain_pre(ts, &p, &b)
467    };
468    PadQueryPost("pad-query-post") = |this, ts, p: *mut ffi::GstPad, q: *mut ffi::GstQuery, r: glib::ffi::gboolean| {
469        let p = Pad::from_glib_borrow(p);
470        let q = QueryRef::from_ptr(q);
471        this.pad_query_post(ts, &p, q, bool::from_glib(r))
472    };
473    PadQueryPre("pad-query-pre") = |this, ts, p: *mut ffi::GstPad, q: *mut ffi::GstQuery| {
474        let p = Pad::from_glib_borrow(p);
475        let q = QueryRef::from_ptr(q);
476        this.pad_query_pre(ts, &p, q)
477    };
478    PadUnlinkPost("pad-unlink-post") = |this, ts, src: *mut ffi::GstPad, sink: *mut ffi::GstPad, r: glib::ffi::gboolean| {
479        let src = Pad::from_glib_borrow(src);
480        let sink = Pad::from_glib_borrow(sink);
481        this.pad_unlink_post(ts, &src, &sink, bool::from_glib(r))
482    };
483    PadUnlinkPre("pad-unlink-pre") = |this, ts, src: *mut ffi::GstPad, sink: *mut ffi::GstPad| {
484        let src = Pad::from_glib_borrow(src);
485        let sink = Pad::from_glib_borrow(sink);
486        this.pad_unlink_pre(ts, &src, &sink)
487    };
488    #[cfg(feature = "v1_20")]
489    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
490    PluginFeatureLoaded("plugin-feature-loaded") = |this, ts, feature: *mut ffi::GstPluginFeature| {
491        let feature = crate::PluginFeature::from_glib_borrow(feature);
492        this.plugin_feature_loaded(ts, &feature)
493    };
494
495    #[cfg(feature = "v1_26")]
496    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
497    MemoryInit("memory-init") = |this, ts, memory: *mut ffi::GstMemory| {
498        let memory = crate::MemoryRefTrace::from_ptr(memory);
499        this.memory_init(ts, memory)
500    };
501    #[cfg(feature = "v1_26")]
502    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
503    MemoryFreePre("memory-free-pre") = |this, ts, memory: *mut ffi::GstMemory| {
504        let memory = crate::MemoryRef::from_ptr(memory);
505        this.memory_free_pre(ts, memory)
506    };
507    #[cfg(feature = "v1_26")]
508    #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))]
509    MemoryFreePost("memory-free-post") = |this, ts, memory: *mut ffi::GstMemory| {
510        this.memory_free_post(ts, std::ptr::NonNull::new_unchecked(memory))
511    };
512    #[cfg(feature = "v1_28")]
513    #[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
514    PoolBufferQueued("pool-buffer-queued") = |this, ts, pool: *mut ffi::GstBufferPool, buffer: *mut ffi::GstBuffer| {
515        let pool = crate::BufferPool::from_glib_borrow(pool);
516        let b = Buffer::from_glib_borrow(buffer);
517
518        this.pool_buffer_queued(ts, &pool, &b)
519    };
520    #[cfg(feature = "v1_28")]
521    #[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
522    PoolBufferDequeued("pool-buffer-dequeued") = |this, ts, pool: *mut ffi::GstBufferPool, buffer: *mut ffi::GstBuffer| {
523        let pool = crate::BufferPool::from_glib_borrow(pool);
524        let b = Buffer::from_glib_borrow(buffer);
525
526        this.pool_buffer_dequeued(ts, &pool, &b)
527    };
528}