Skip to main content

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