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