gstreamer/
element.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{ffi::CStr, future::Future, mem, num::NonZeroU64, ops::ControlFlow, pin::Pin};
4
5use glib::translate::*;
6use itertools::Itertools;
7
8use crate::{
9    ffi,
10    format::{
11        CompatibleFormattedValue, FormattedValue, SpecificFormattedValueFullRange,
12        SpecificFormattedValueIntrinsic,
13    },
14    prelude::*,
15    ClockTime, Element, ElementFlags, Event, Format, GenericFormattedValue, Pad, PadTemplate,
16    Plugin, QueryRef, Rank, State,
17};
18
19impl Element {
20    #[doc(alias = "gst_element_link_many")]
21    pub fn link_many<E: AsRef<Element> + Clone>(
22        elements: impl IntoIterator<Item = E>,
23    ) -> Result<(), glib::BoolError> {
24        skip_assert_initialized!();
25        for (src, dest) in elements.into_iter().tuple_windows() {
26            unsafe {
27                glib::result_from_gboolean!(
28                    ffi::gst_element_link(
29                        src.as_ref().to_glib_none().0,
30                        dest.as_ref().to_glib_none().0,
31                    ),
32                    "Failed to link elements '{}' and '{}'",
33                    src.as_ref().name(),
34                    dest.as_ref().name(),
35                )?;
36            }
37        }
38
39        Ok(())
40    }
41
42    #[doc(alias = "gst_element_unlink_many")]
43    pub fn unlink_many<E: AsRef<Element> + Clone>(elements: impl IntoIterator<Item = E>) {
44        skip_assert_initialized!();
45        for (src, dest) in elements.into_iter().tuple_windows() {
46            unsafe {
47                ffi::gst_element_unlink(
48                    src.as_ref().to_glib_none().0,
49                    dest.as_ref().to_glib_none().0,
50                );
51            }
52        }
53    }
54
55    #[doc(alias = "gst_element_register")]
56    pub fn register(
57        plugin: Option<&Plugin>,
58        name: &str,
59        rank: Rank,
60        type_: glib::types::Type,
61    ) -> Result<(), glib::error::BoolError> {
62        skip_assert_initialized!();
63        unsafe {
64            glib::result_from_gboolean!(
65                ffi::gst_element_register(
66                    plugin.to_glib_none().0,
67                    name.to_glib_none().0,
68                    rank.into_glib() as u32,
69                    type_.into_glib()
70                ),
71                "Failed to register element factory"
72            )
73        }
74    }
75}
76
77#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
78pub enum ElementMessageType {
79    Error,
80    Warning,
81    Info,
82}
83
84#[derive(Debug, PartialEq, Eq)]
85pub struct NotifyWatchId(NonZeroU64);
86
87impl IntoGlib for NotifyWatchId {
88    type GlibType = libc::c_ulong;
89
90    #[inline]
91    fn into_glib(self) -> libc::c_ulong {
92        self.0.get() as libc::c_ulong
93    }
94}
95
96impl FromGlib<libc::c_ulong> for NotifyWatchId {
97    #[inline]
98    unsafe fn from_glib(val: libc::c_ulong) -> NotifyWatchId {
99        skip_assert_initialized!();
100        debug_assert_ne!(val, 0);
101        NotifyWatchId(NonZeroU64::new_unchecked(val as _))
102    }
103}
104
105pub trait ElementExtManual: IsA<Element> + 'static {
106    #[doc(alias = "get_element_class")]
107    #[inline]
108    fn element_class(&self) -> &glib::Class<Element> {
109        unsafe { self.unsafe_cast_ref::<Element>().class() }
110    }
111
112    #[doc(alias = "get_current_state")]
113    fn current_state(&self) -> State {
114        self.state(Some(ClockTime::ZERO)).1
115    }
116
117    #[doc(alias = "get_pending_state")]
118    fn pending_state(&self) -> State {
119        self.state(Some(ClockTime::ZERO)).2
120    }
121
122    #[doc(alias = "gst_element_query")]
123    fn query(&self, query: &mut QueryRef) -> bool {
124        unsafe {
125            from_glib(ffi::gst_element_query(
126                self.as_ref().to_glib_none().0,
127                query.as_mut_ptr(),
128            ))
129        }
130    }
131
132    #[doc(alias = "gst_element_send_event")]
133    fn send_event(&self, event: impl Into<Event>) -> bool {
134        unsafe {
135            from_glib(ffi::gst_element_send_event(
136                self.as_ref().to_glib_none().0,
137                event.into().into_glib_ptr(),
138            ))
139        }
140    }
141
142    #[doc(alias = "get_metadata")]
143    #[doc(alias = "gst_element_class_get_metadata")]
144    fn metadata<'a>(&self, key: &str) -> Option<&'a str> {
145        self.element_class().metadata(key)
146    }
147
148    #[doc(alias = "get_pad_template")]
149    #[doc(alias = "gst_element_class_get_pad_template")]
150    fn pad_template(&self, name: &str) -> Option<PadTemplate> {
151        self.element_class().pad_template(name)
152    }
153
154    #[doc(alias = "get_pad_template_list")]
155    #[doc(alias = "gst_element_class_get_pad_template_list")]
156    fn pad_template_list(&self) -> glib::List<PadTemplate> {
157        self.element_class().pad_template_list()
158    }
159
160    #[allow(clippy::too_many_arguments)]
161    #[doc(alias = "gst_element_message_full")]
162    fn message_full<T: crate::MessageErrorDomain>(
163        &self,
164        type_: ElementMessageType,
165        code: T,
166        message: Option<&str>,
167        debug: Option<&str>,
168        file: &str,
169        function: &str,
170        line: u32,
171    ) {
172        unsafe {
173            let type_ = match type_ {
174                ElementMessageType::Error => ffi::GST_MESSAGE_ERROR,
175                ElementMessageType::Warning => ffi::GST_MESSAGE_WARNING,
176                ElementMessageType::Info => ffi::GST_MESSAGE_INFO,
177            };
178
179            ffi::gst_element_message_full(
180                self.as_ref().to_glib_none().0,
181                type_,
182                T::domain().into_glib(),
183                code.code(),
184                message.to_glib_full(),
185                debug.to_glib_full(),
186                file.to_glib_none().0,
187                function.to_glib_none().0,
188                line as i32,
189            );
190        }
191    }
192
193    fn set_element_flags(&self, flags: ElementFlags) {
194        unsafe {
195            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
196            let _guard = self.as_ref().object_lock();
197            (*ptr).flags |= flags.into_glib();
198        }
199    }
200
201    fn unset_element_flags(&self, flags: ElementFlags) {
202        unsafe {
203            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
204            let _guard = self.as_ref().object_lock();
205            (*ptr).flags &= !flags.into_glib();
206        }
207    }
208
209    #[doc(alias = "get_element_flags")]
210    fn element_flags(&self) -> ElementFlags {
211        unsafe {
212            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
213            let _guard = self.as_ref().object_lock();
214            from_glib((*ptr).flags)
215        }
216    }
217
218    #[allow(clippy::too_many_arguments)]
219    #[doc(alias = "gst_element_message_full_with_details")]
220    fn message_full_with_details<T: crate::MessageErrorDomain>(
221        &self,
222        type_: ElementMessageType,
223        code: T,
224        message: Option<&str>,
225        debug: Option<&str>,
226        file: &str,
227        function: &str,
228        line: u32,
229        structure: crate::Structure,
230    ) {
231        unsafe {
232            let type_ = match type_ {
233                ElementMessageType::Error => ffi::GST_MESSAGE_ERROR,
234                ElementMessageType::Warning => ffi::GST_MESSAGE_WARNING,
235                ElementMessageType::Info => ffi::GST_MESSAGE_INFO,
236            };
237
238            ffi::gst_element_message_full_with_details(
239                self.as_ref().to_glib_none().0,
240                type_,
241                T::domain().into_glib(),
242                code.code(),
243                message.to_glib_full(),
244                debug.to_glib_full(),
245                file.to_glib_none().0,
246                function.to_glib_none().0,
247                line as i32,
248                structure.into_glib_ptr(),
249            );
250        }
251    }
252
253    fn post_error_message(&self, msg: crate::ErrorMessage) {
254        let crate::ErrorMessage {
255            error_domain,
256            error_code,
257            ref message,
258            ref debug,
259            filename,
260            function,
261            line,
262        } = msg;
263
264        unsafe {
265            ffi::gst_element_message_full(
266                self.as_ref().to_glib_none().0,
267                ffi::GST_MESSAGE_ERROR,
268                error_domain.into_glib(),
269                error_code,
270                message.to_glib_full(),
271                debug.to_glib_full(),
272                filename.to_glib_none().0,
273                function.to_glib_none().0,
274                line as i32,
275            );
276        }
277    }
278
279    #[doc(alias = "gst_element_iterate_pads")]
280    fn iterate_pads(&self) -> crate::Iterator<Pad> {
281        unsafe {
282            from_glib_full(ffi::gst_element_iterate_pads(
283                self.as_ref().to_glib_none().0,
284            ))
285        }
286    }
287
288    #[doc(alias = "gst_element_iterate_sink_pads")]
289    fn iterate_sink_pads(&self) -> crate::Iterator<Pad> {
290        unsafe {
291            from_glib_full(ffi::gst_element_iterate_sink_pads(
292                self.as_ref().to_glib_none().0,
293            ))
294        }
295    }
296
297    #[doc(alias = "gst_element_iterate_src_pads")]
298    fn iterate_src_pads(&self) -> crate::Iterator<Pad> {
299        unsafe {
300            from_glib_full(ffi::gst_element_iterate_src_pads(
301                self.as_ref().to_glib_none().0,
302            ))
303        }
304    }
305
306    #[doc(alias = "get_pads")]
307    #[doc(alias = "gst_element_foreach_pad")]
308    fn pads(&self) -> Vec<Pad> {
309        unsafe {
310            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
311            let _guard = self.as_ref().object_lock();
312            FromGlibPtrContainer::from_glib_none(elt.pads)
313        }
314    }
315
316    #[doc(alias = "get_sink_pads")]
317    #[doc(alias = "gst_element_foreach_sink_pad")]
318    fn sink_pads(&self) -> Vec<Pad> {
319        unsafe {
320            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
321            let _guard = self.as_ref().object_lock();
322            FromGlibPtrContainer::from_glib_none(elt.sinkpads)
323        }
324    }
325
326    #[doc(alias = "get_src_pads")]
327    #[doc(alias = "gst_element_foreach_src_pad")]
328    fn src_pads(&self) -> Vec<Pad> {
329        unsafe {
330            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
331            let _guard = self.as_ref().object_lock();
332            FromGlibPtrContainer::from_glib_none(elt.srcpads)
333        }
334    }
335
336    #[doc(alias = "gst_element_foreach_pad")]
337    fn foreach_pad<F: FnMut(&Element, &Pad) -> ControlFlow<()>>(&self, func: F) {
338        unsafe extern "C" fn trampoline<F: FnMut(&Element, &Pad) -> ControlFlow<()>>(
339            element: *mut ffi::GstElement,
340            pad: *mut ffi::GstPad,
341            user_data: glib::ffi::gpointer,
342        ) -> glib::ffi::gboolean {
343            let element = from_glib_borrow(element);
344            let pad = from_glib_borrow(pad);
345            let callback = user_data as *mut F;
346            (*callback)(&element, &pad).is_continue().into_glib()
347        }
348
349        unsafe {
350            let mut func = func;
351            let func_ptr: &mut F = &mut func;
352
353            let _ = ffi::gst_element_foreach_pad(
354                self.as_ptr() as *mut _,
355                Some(trampoline::<F>),
356                func_ptr as *mut _ as *mut _,
357            );
358        }
359    }
360
361    #[doc(alias = "gst_element_foreach_sink_pad")]
362    fn foreach_sink_pad<F: FnMut(&Element, &Pad) -> ControlFlow<()>>(&self, func: F) {
363        unsafe extern "C" fn trampoline<P: FnMut(&Element, &Pad) -> ControlFlow<()>>(
364            element: *mut ffi::GstElement,
365            pad: *mut ffi::GstPad,
366            user_data: glib::ffi::gpointer,
367        ) -> glib::ffi::gboolean {
368            let element = from_glib_borrow(element);
369            let pad = from_glib_borrow(pad);
370            let callback = user_data as *mut P;
371            (*callback)(&element, &pad).is_continue().into_glib()
372        }
373
374        unsafe {
375            let mut func = func;
376            let func_ptr: &mut F = &mut func;
377
378            let _ = ffi::gst_element_foreach_sink_pad(
379                self.as_ptr() as *mut _,
380                Some(trampoline::<F>),
381                func_ptr as *mut _ as *mut _,
382            );
383        }
384    }
385
386    #[doc(alias = "gst_element_foreach_src_pad")]
387    fn foreach_src_pad<F: FnMut(&Element, &Pad) -> ControlFlow<()>>(&self, func: F) {
388        unsafe extern "C" fn trampoline<P: FnMut(&Element, &Pad) -> ControlFlow<()>>(
389            element: *mut ffi::GstElement,
390            pad: *mut ffi::GstPad,
391            user_data: glib::ffi::gpointer,
392        ) -> glib::ffi::gboolean {
393            let element = from_glib_borrow(element);
394            let pad = from_glib_borrow(pad);
395            let callback = user_data as *mut P;
396            (*callback)(&element, &pad).is_continue().into_glib()
397        }
398
399        unsafe {
400            let mut func = func;
401            let func_ptr: &mut F = &mut func;
402
403            let _ = ffi::gst_element_foreach_src_pad(
404                self.as_ptr() as *mut _,
405                Some(trampoline::<F>),
406                func_ptr as *mut _ as *mut _,
407            );
408        }
409    }
410
411    fn num_pads(&self) -> u16 {
412        unsafe {
413            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
414            let _guard = self.as_ref().object_lock();
415            elt.numpads
416        }
417    }
418
419    fn num_sink_pads(&self) -> u16 {
420        unsafe {
421            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
422            let _guard = self.as_ref().object_lock();
423            elt.numsinkpads
424        }
425    }
426
427    fn num_src_pads(&self) -> u16 {
428        unsafe {
429            let elt: &ffi::GstElement = &*(self.as_ptr() as *const _);
430            let _guard = self.as_ref().object_lock();
431            elt.numsrcpads
432        }
433    }
434
435    #[doc(alias = "gst_element_add_property_deep_notify_watch")]
436    fn add_property_deep_notify_watch(
437        &self,
438        property_name: Option<&str>,
439        include_value: bool,
440    ) -> NotifyWatchId {
441        let property_name = property_name.to_glib_none();
442        unsafe {
443            from_glib(ffi::gst_element_add_property_deep_notify_watch(
444                self.as_ref().to_glib_none().0,
445                property_name.0,
446                include_value.into_glib(),
447            ))
448        }
449    }
450
451    #[doc(alias = "gst_element_add_property_notify_watch")]
452    fn add_property_notify_watch(
453        &self,
454        property_name: Option<&str>,
455        include_value: bool,
456    ) -> NotifyWatchId {
457        let property_name = property_name.to_glib_none();
458        unsafe {
459            from_glib(ffi::gst_element_add_property_notify_watch(
460                self.as_ref().to_glib_none().0,
461                property_name.0,
462                include_value.into_glib(),
463            ))
464        }
465    }
466
467    #[doc(alias = "gst_element_remove_property_notify_watch")]
468    fn remove_property_notify_watch(&self, watch_id: NotifyWatchId) {
469        unsafe {
470            ffi::gst_element_remove_property_notify_watch(
471                self.as_ref().to_glib_none().0,
472                watch_id.into_glib(),
473            );
474        }
475    }
476
477    #[doc(alias = "gst_element_query_convert")]
478    fn query_convert<U: SpecificFormattedValueFullRange>(
479        &self,
480        src_val: impl FormattedValue,
481    ) -> Option<U> {
482        unsafe {
483            let mut dest_val = mem::MaybeUninit::uninit();
484            let ret = from_glib(ffi::gst_element_query_convert(
485                self.as_ref().to_glib_none().0,
486                src_val.format().into_glib(),
487                src_val.into_raw_value(),
488                U::default_format().into_glib(),
489                dest_val.as_mut_ptr(),
490            ));
491            if ret {
492                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
493            } else {
494                None
495            }
496        }
497    }
498
499    #[doc(alias = "gst_element_query_convert")]
500    fn query_convert_generic(
501        &self,
502        src_val: impl FormattedValue,
503        dest_format: Format,
504    ) -> Option<GenericFormattedValue> {
505        unsafe {
506            let mut dest_val = mem::MaybeUninit::uninit();
507            let ret = from_glib(ffi::gst_element_query_convert(
508                self.as_ref().to_glib_none().0,
509                src_val.format().into_glib(),
510                src_val.into_raw_value(),
511                dest_format.into_glib(),
512                dest_val.as_mut_ptr(),
513            ));
514            if ret {
515                Some(GenericFormattedValue::new(
516                    dest_format,
517                    dest_val.assume_init(),
518                ))
519            } else {
520                None
521            }
522        }
523    }
524
525    #[doc(alias = "gst_element_query_duration")]
526    fn query_duration<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
527        unsafe {
528            let mut duration = mem::MaybeUninit::uninit();
529            let ret = from_glib(ffi::gst_element_query_duration(
530                self.as_ref().to_glib_none().0,
531                T::default_format().into_glib(),
532                duration.as_mut_ptr(),
533            ));
534            if ret {
535                try_from_glib(duration.assume_init()).ok()
536            } else {
537                None
538            }
539        }
540    }
541
542    #[doc(alias = "gst_element_query_duration")]
543    fn query_duration_generic(&self, format: Format) -> Option<GenericFormattedValue> {
544        unsafe {
545            let mut duration = mem::MaybeUninit::uninit();
546            let ret = from_glib(ffi::gst_element_query_duration(
547                self.as_ref().to_glib_none().0,
548                format.into_glib(),
549                duration.as_mut_ptr(),
550            ));
551            if ret {
552                Some(GenericFormattedValue::new(format, duration.assume_init()))
553            } else {
554                None
555            }
556        }
557    }
558
559    #[doc(alias = "gst_element_query_position")]
560    fn query_position<T: SpecificFormattedValueIntrinsic>(&self) -> Option<T> {
561        unsafe {
562            let mut cur = mem::MaybeUninit::uninit();
563            let ret = from_glib(ffi::gst_element_query_position(
564                self.as_ref().to_glib_none().0,
565                T::default_format().into_glib(),
566                cur.as_mut_ptr(),
567            ));
568            if ret {
569                try_from_glib(cur.assume_init()).ok()
570            } else {
571                None
572            }
573        }
574    }
575
576    #[doc(alias = "gst_element_query_position")]
577    fn query_position_generic(&self, format: Format) -> Option<GenericFormattedValue> {
578        unsafe {
579            let mut cur = mem::MaybeUninit::uninit();
580            let ret = from_glib(ffi::gst_element_query_position(
581                self.as_ref().to_glib_none().0,
582                format.into_glib(),
583                cur.as_mut_ptr(),
584            ));
585            if ret {
586                Some(GenericFormattedValue::new(format, cur.assume_init()))
587            } else {
588                None
589            }
590        }
591    }
592
593    #[doc(alias = "gst_element_seek")]
594    fn seek<V: FormattedValue>(
595        &self,
596        rate: f64,
597        flags: crate::SeekFlags,
598        start_type: crate::SeekType,
599        start: V,
600        stop_type: crate::SeekType,
601        stop: impl CompatibleFormattedValue<V>,
602    ) -> Result<(), glib::error::BoolError> {
603        let stop = stop.try_into_checked(start).unwrap();
604
605        unsafe {
606            glib::result_from_gboolean!(
607                ffi::gst_element_seek(
608                    self.as_ref().to_glib_none().0,
609                    rate,
610                    start.format().into_glib(),
611                    flags.into_glib(),
612                    start_type.into_glib(),
613                    start.into_raw_value(),
614                    stop_type.into_glib(),
615                    stop.into_raw_value(),
616                ),
617                "Failed to seek",
618            )
619        }
620    }
621
622    #[doc(alias = "gst_element_seek_simple")]
623    fn seek_simple(
624        &self,
625        seek_flags: crate::SeekFlags,
626        seek_pos: impl FormattedValue,
627    ) -> Result<(), glib::error::BoolError> {
628        unsafe {
629            glib::result_from_gboolean!(
630                ffi::gst_element_seek_simple(
631                    self.as_ref().to_glib_none().0,
632                    seek_pos.format().into_glib(),
633                    seek_flags.into_glib(),
634                    seek_pos.into_raw_value(),
635                ),
636                "Failed to seek",
637            )
638        }
639    }
640
641    #[doc(alias = "gst_element_call_async")]
642    fn call_async<F>(&self, func: F)
643    where
644        F: FnOnce(&Self) + Send + 'static,
645    {
646        let user_data: Box<Option<F>> = Box::new(Some(func));
647
648        unsafe extern "C" fn trampoline<O: IsA<Element>, F: FnOnce(&O) + Send + 'static>(
649            element: *mut ffi::GstElement,
650            user_data: glib::ffi::gpointer,
651        ) {
652            let user_data: &mut Option<F> = &mut *(user_data as *mut _);
653            let callback = user_data.take().unwrap();
654
655            callback(Element::from_glib_borrow(element).unsafe_cast_ref());
656        }
657
658        unsafe extern "C" fn free_user_data<O: IsA<Element>, F: FnOnce(&O) + Send + 'static>(
659            user_data: glib::ffi::gpointer,
660        ) {
661            let _: Box<Option<F>> = Box::from_raw(user_data as *mut _);
662        }
663
664        unsafe {
665            ffi::gst_element_call_async(
666                self.as_ref().to_glib_none().0,
667                Some(trampoline::<Self, F>),
668                Box::into_raw(user_data) as *mut _,
669                Some(free_user_data::<Self, F>),
670            );
671        }
672    }
673
674    fn call_async_future<F, T>(&self, func: F) -> Pin<Box<dyn Future<Output = T> + Send + 'static>>
675    where
676        F: FnOnce(&Self) -> T + Send + 'static,
677        T: Send + 'static,
678    {
679        use futures_channel::oneshot;
680
681        let (sender, receiver) = oneshot::channel();
682
683        self.call_async(move |element| {
684            let _ = sender.send(func(element));
685        });
686
687        Box::pin(async move { receiver.await.expect("sender dropped") })
688    }
689
690    #[doc(alias = "get_current_running_time")]
691    #[doc(alias = "gst_element_get_current_running_time")]
692    fn current_running_time(&self) -> Option<crate::ClockTime> {
693        let base_time = self.base_time();
694        let clock_time = self.current_clock_time();
695
696        clock_time
697            .zip(base_time)
698            .and_then(|(ct, bt)| ct.checked_sub(bt))
699    }
700
701    #[doc(alias = "get_current_clock_time")]
702    #[doc(alias = "gst_element_get_current_clock_time")]
703    fn current_clock_time(&self) -> Option<crate::ClockTime> {
704        self.clock().as_ref().map(crate::Clock::time)
705    }
706
707    #[doc(alias = "gst_element_get_request_pad")]
708    #[doc(alias = "get_request_pad")]
709    #[doc(alias = "gst_element_request_pad_simple")]
710    fn request_pad_simple(&self, name: &str) -> Option<Pad> {
711        unsafe {
712            #[cfg(feature = "v1_20")]
713            {
714                from_glib_full(ffi::gst_element_request_pad_simple(
715                    self.as_ref().to_glib_none().0,
716                    name.to_glib_none().0,
717                ))
718            }
719            #[cfg(not(feature = "v1_20"))]
720            {
721                from_glib_full(ffi::gst_element_get_request_pad(
722                    self.as_ref().to_glib_none().0,
723                    name.to_glib_none().0,
724                ))
725            }
726        }
727    }
728
729    #[doc(alias = "gst_element_link")]
730    fn link(&self, dest: &impl IsA<Element>) -> Result<(), glib::error::BoolError> {
731        unsafe {
732            glib::result_from_gboolean!(
733                ffi::gst_element_link(
734                    self.as_ref().to_glib_none().0,
735                    dest.as_ref().to_glib_none().0
736                ),
737                "Failed to link elements '{}' and '{}'",
738                self.as_ref().name(),
739                dest.as_ref().name(),
740            )
741        }
742    }
743
744    #[doc(alias = "gst_element_link_filtered")]
745    fn link_filtered(
746        &self,
747        dest: &impl IsA<Element>,
748        filter: &crate::Caps,
749    ) -> Result<(), glib::error::BoolError> {
750        unsafe {
751            glib::result_from_gboolean!(
752                ffi::gst_element_link_filtered(
753                    self.as_ref().to_glib_none().0,
754                    dest.as_ref().to_glib_none().0,
755                    filter.to_glib_none().0
756                ),
757                "Failed to link elements '{}' and '{}' with filter '{:?}'",
758                self.as_ref().name(),
759                dest.as_ref().name(),
760                filter,
761            )
762        }
763    }
764
765    #[doc(alias = "gst_element_link_pads")]
766    fn link_pads(
767        &self,
768        srcpadname: Option<&str>,
769        dest: &impl IsA<Element>,
770        destpadname: Option<&str>,
771    ) -> Result<(), glib::error::BoolError> {
772        unsafe {
773            glib::result_from_gboolean!(
774                ffi::gst_element_link_pads(
775                    self.as_ref().to_glib_none().0,
776                    srcpadname.to_glib_none().0,
777                    dest.as_ref().to_glib_none().0,
778                    destpadname.to_glib_none().0
779                ),
780                "Failed to link pads '{}' and '{}'",
781                if let Some(srcpadname) = srcpadname {
782                    format!("{}:{}", self.as_ref().name(), srcpadname)
783                } else {
784                    format!("{}:*", self.as_ref().name())
785                },
786                if let Some(destpadname) = destpadname {
787                    format!("{}:{}", dest.as_ref().name(), destpadname)
788                } else {
789                    format!("{}:*", dest.as_ref().name())
790                },
791            )
792        }
793    }
794
795    #[doc(alias = "gst_element_link_pads_filtered")]
796    fn link_pads_filtered(
797        &self,
798        srcpadname: Option<&str>,
799        dest: &impl IsA<Element>,
800        destpadname: Option<&str>,
801        filter: &crate::Caps,
802    ) -> Result<(), glib::error::BoolError> {
803        unsafe {
804            glib::result_from_gboolean!(
805                ffi::gst_element_link_pads_filtered(
806                    self.as_ref().to_glib_none().0,
807                    srcpadname.to_glib_none().0,
808                    dest.as_ref().to_glib_none().0,
809                    destpadname.to_glib_none().0,
810                    filter.to_glib_none().0
811                ),
812                "Failed to link pads '{}' and '{}' with filter '{:?}'",
813                if let Some(srcpadname) = srcpadname {
814                    format!("{}:{}", self.as_ref().name(), srcpadname)
815                } else {
816                    format!("{}:*", self.as_ref().name())
817                },
818                if let Some(destpadname) = destpadname {
819                    format!("{}:{}", dest.as_ref().name(), destpadname)
820                } else {
821                    format!("{}:*", dest.as_ref().name())
822                },
823                filter,
824            )
825        }
826    }
827
828    #[doc(alias = "gst_element_link_pads_full")]
829    fn link_pads_full(
830        &self,
831        srcpadname: Option<&str>,
832        dest: &impl IsA<Element>,
833        destpadname: Option<&str>,
834        flags: crate::PadLinkCheck,
835    ) -> Result<(), glib::error::BoolError> {
836        unsafe {
837            glib::result_from_gboolean!(
838                ffi::gst_element_link_pads_full(
839                    self.as_ref().to_glib_none().0,
840                    srcpadname.to_glib_none().0,
841                    dest.as_ref().to_glib_none().0,
842                    destpadname.to_glib_none().0,
843                    flags.into_glib()
844                ),
845                "Failed to link pads '{}' and '{}' with flags '{:?}'",
846                if let Some(srcpadname) = srcpadname {
847                    format!("{}:{}", self.as_ref().name(), srcpadname)
848                } else {
849                    format!("{}:*", self.as_ref().name())
850                },
851                if let Some(destpadname) = destpadname {
852                    format!("{}:{}", dest.as_ref().name(), destpadname)
853                } else {
854                    format!("{}:*", dest.as_ref().name())
855                },
856                flags,
857            )
858        }
859    }
860}
861
862impl<O: IsA<Element>> ElementExtManual for O {}
863
864pub unsafe trait ElementClassExt {
865    #[doc(alias = "get_metadata")]
866    #[doc(alias = "gst_element_class_get_metadata")]
867    fn metadata<'a>(&self, key: &str) -> Option<&'a str> {
868        unsafe {
869            let klass = self as *const _ as *const ffi::GstElementClass;
870
871            let ptr = ffi::gst_element_class_get_metadata(klass as *mut _, key.to_glib_none().0);
872
873            if ptr.is_null() {
874                None
875            } else {
876                Some(CStr::from_ptr(ptr).to_str().unwrap())
877            }
878        }
879    }
880
881    #[doc(alias = "get_pad_template")]
882    #[doc(alias = "gst_element_class_get_pad_template")]
883    fn pad_template(&self, name: &str) -> Option<PadTemplate> {
884        unsafe {
885            let klass = self as *const _ as *const ffi::GstElementClass;
886
887            from_glib_none(ffi::gst_element_class_get_pad_template(
888                klass as *mut _,
889                name.to_glib_none().0,
890            ))
891        }
892    }
893
894    #[doc(alias = "get_pad_template_list")]
895    #[doc(alias = "gst_element_class_get_pad_template_list")]
896    fn pad_template_list(&self) -> glib::List<PadTemplate> {
897        unsafe {
898            let klass = self as *const _ as *const ffi::GstElementClass;
899
900            glib::List::from_glib_none(ffi::gst_element_class_get_pad_template_list(
901                klass as *mut _,
902            ))
903        }
904    }
905}
906
907unsafe impl<T: IsA<Element> + glib::object::IsClass> ElementClassExt for glib::object::Class<T> {}
908
909#[doc(alias = "GST_ELEMENT_METADATA_AUTHOR")]
910pub static ELEMENT_METADATA_AUTHOR: &glib::GStr =
911    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_AUTHOR) };
912#[doc(alias = "GST_ELEMENT_METADATA_DESCRIPTION")]
913pub static ELEMENT_METADATA_DESCRIPTION: &glib::GStr =
914    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_DESCRIPTION) };
915#[doc(alias = "GST_ELEMENT_METADATA_DOC_URI")]
916pub static ELEMENT_METADATA_DOC_URI: &glib::GStr =
917    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_DOC_URI) };
918#[doc(alias = "GST_ELEMENT_METADATA_ICON_NAME")]
919pub static ELEMENT_METADATA_ICON_NAME: &glib::GStr =
920    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_ICON_NAME) };
921#[doc(alias = "GST_ELEMENT_METADATA_KLASS")]
922pub static ELEMENT_METADATA_KLASS: &glib::GStr =
923    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_KLASS) };
924#[doc(alias = "GST_ELEMENT_METADATA_LONGNAME")]
925pub static ELEMENT_METADATA_LONGNAME: &glib::GStr =
926    unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_LONGNAME) };
927
928#[doc(alias = "GST_ELEMENT_ERROR")]
929#[doc(alias = "GST_ELEMENT_ERROR_WITH_DETAILS")]
930#[macro_export]
931macro_rules! element_error(
932    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
933        use $crate::prelude::ElementExtManual;
934        $obj.message_full(
935            $crate::ElementMessageType::Error,
936            $err,
937            Some(&format!($($msg)*)),
938            Some(&format!($($debug)*)),
939            file!(),
940            $crate::glib::function_name!(),
941            line!(),
942        );
943    }};
944    ($obj:expr, $err:expr, ($($msg:tt)*)) => { {
945        use $crate::prelude::ElementExtManual;
946        $obj.message_full(
947            $crate::ElementMessageType::Error,
948            $err,
949            Some(&format!($($msg)*)),
950            None,
951            file!(),
952            $crate::glib::function_name!(),
953            line!(),
954        );
955    }};
956    ($obj:expr, $err:expr, [$($debug:tt)*]) => { {
957        use $crate::prelude::ElementExtManual;
958        $obj.message_full(
959            $crate::ElementMessageType::Error,
960            $err,
961            None,
962            Some(&format!($($debug)*)),
963            file!(),
964            $crate::glib::function_name!(),
965            line!(),
966        );
967    }};
968
969    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
970        use $crate::prelude::ElementExtManual;
971        $obj.message_full_with_details(
972            $crate::ElementMessageType::Error,
973            $err,
974            Some(&format!($($msg)*)),
975            Some(&format!($($debug)*)),
976            file!(),
977            $crate::glib::function_name!(),
978            line!(),
979            $details,
980        );
981    }};
982    ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
983        use $crate::prelude::ElementExtManual;
984        $obj.message_full_with_details(
985            $crate::ElementMessageType::Error,
986            $err,
987            Some(&format!($($msg)*)),
988            None,
989            file!(),
990            $crate::glib::function_name!(),
991            line!(),
992            $details,
993        );
994    }};
995    ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
996        use $crate::prelude::ElementExtManual;
997        $obj.message_full_with_details(
998            $crate::ElementMessageType::Error,
999            $err,
1000            None,
1001            Some(&format!($($debug)*)),
1002            file!(),
1003            $crate::glib::function_name!(),
1004            line!(),
1005            $details,
1006        );
1007    }};
1008);
1009
1010#[doc(alias = "GST_ELEMENT_WARNING")]
1011#[doc(alias = "GST_ELEMENT_WARNING_WITH_DETAILS")]
1012#[macro_export]
1013macro_rules! element_warning(
1014    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
1015        use $crate::prelude::ElementExtManual;
1016        $obj.message_full(
1017            $crate::ElementMessageType::Warning,
1018            $err,
1019            Some(&format!($($msg)*)),
1020            Some(&format!($($debug)*)),
1021            file!(),
1022            $crate::glib::function_name!(),
1023            line!(),
1024        );
1025    }};
1026    ($obj:expr, $err:expr, ($($msg:tt)*)) => { {
1027        use $crate::prelude::ElementExtManual;
1028        $obj.message_full(
1029            $crate::ElementMessageType::Warning,
1030            $err,
1031            Some(&format!($($msg)*)),
1032            None,
1033            file!(),
1034            $crate::glib::function_name!(),
1035            line!(),
1036        );
1037    }};
1038    ($obj:expr, $err:expr, [$($debug:tt)*]) => { {
1039        use $crate::prelude::ElementExtManual;
1040        $obj.message_full(
1041            $crate::ElementMessageType::Warning,
1042            $err,
1043            None,
1044            Some(&format!($($debug)*)),
1045            file!(),
1046            $crate::glib::function_name!(),
1047            line!(),
1048        );
1049    }};
1050
1051    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
1052        use $crate::prelude::ElementExtManual;
1053        $obj.message_full_with_details(
1054            $crate::ElementMessageType::Warning,
1055            $err,
1056            Some(&format!($($msg)*)),
1057            Some(&format!($($debug)*)),
1058            file!(),
1059            $crate::glib::function_name!(),
1060            line!(),
1061            $details,
1062        );
1063    }};
1064    ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
1065        use $crate::prelude::ElementExtManual;
1066        $obj.message_full_with_details(
1067            $crate::ElementMessageType::Warning,
1068            $err,
1069            Some(&format!($($msg)*)),
1070            None,
1071            file!(),
1072            $crate::glib::function_name!(),
1073            line!(),
1074            $details,
1075        );
1076    }};
1077    ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
1078        use $crate::prelude::ElementExtManual;
1079        $obj.message_full_with_details(
1080            $crate::ElementMessageType::Warning,
1081            $err,
1082            None,
1083            Some(&format!($($debug)*)),
1084            file!(),
1085            $crate::glib::function_name!(),
1086            line!(),
1087            $details,
1088        );
1089    }};
1090);
1091
1092#[doc(alias = "GST_ELEMENT_INFO")]
1093#[doc(alias = "GST_ELEMENT_INFO_WITH_DETAILS")]
1094#[macro_export]
1095macro_rules! element_info(
1096    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
1097        use $crate::prelude::ElementExtManual;
1098        $obj.message_full(
1099            $crate::ElementMessageType::Info,
1100            $err,
1101            Some(&format!($($msg)*)),
1102            Some(&format!($($debug)*)),
1103            file!(),
1104            $crate::glib::function_name!(),
1105            line!(),
1106        );
1107    }};
1108    ($obj:expr, $err:expr, ($($msg:tt)*)) => { {
1109        use $crate::prelude::ElementExtManual;
1110        $obj.message_full(
1111            $crate::ElementMessageType::Info,
1112            $err,
1113            Some(&format!($($msg)*)),
1114            None,
1115            file!(),
1116            $crate::glib::function_name!(),
1117            line!(),
1118        );
1119    }};
1120    ($obj:expr, $err:expr, [$($debug:tt)*]) => { {
1121        use $crate::prelude::ElementExtManual;
1122        $obj.message_full(
1123            $crate::ElementMessageType::Info,
1124            $err,
1125            None,
1126            Some(&format!($($debug)*)),
1127            file!(),
1128            $crate::glib::function_name!(),
1129            line!(),
1130        );
1131    }};
1132
1133    ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
1134        use $crate::prelude::ElementExtManual;
1135        $obj.message_full_with_details(
1136            $crate::ElementMessageType::Info,
1137            $err,
1138            Some(&format!($($msg)*)),
1139            Some(&format!($($debug)*)),
1140            file!(),
1141            $crate::glib::function_name!(),
1142            line!(),
1143            $details,
1144        );
1145    }};
1146    ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
1147        use $crate::prelude::ElementExtManual;
1148        $obj.message_full_with_details(
1149            $crate::ElementMessageType::Info,
1150            $err,
1151            Some(&format!($($msg)*)),
1152            None,
1153            file!(),
1154            $crate::glib::function_name!(),
1155            line!(),
1156            $details,
1157        );
1158    }};
1159    ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
1160        use $crate::prelude::ElementExtManual;
1161        $obj.message_full_with_details(
1162            $crate::ElementMessageType::Info,
1163            $err,
1164            None,
1165            Some(&format!($($debug)*)),
1166            file!(),
1167            $crate::glib::function_name!(),
1168            line!(),
1169            $details,
1170        );
1171    }};
1172);
1173
1174#[doc(alias = "GST_ELEMENT_ERROR")]
1175#[doc(alias = "GST_ELEMENT_ERROR_WITH_DETAILS")]
1176#[macro_export]
1177macro_rules! element_imp_error(
1178    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
1179        let obj = $imp.obj();
1180        $crate::element_error!(obj, $err, ($($msg)*), [$($debug)*]);
1181    }};
1182    ($imp:expr, $err:expr, ($($msg:tt)*)) => { {
1183        let obj = $imp.obj();
1184        $crate::element_error!(obj, $err, ($($msg)*));
1185    }};
1186    ($imp:expr, $err:expr, [$($debug:tt)*]) => { {
1187        let obj = $imp.obj();
1188        $crate::element_error!(obj, $err, [$($debug)*]);
1189    }};
1190
1191    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
1192        let obj = $imp.obj();
1193        $crate::element_error!(obj, $err, ($($msg)*), [$($debug)*], details: $details);
1194    }};
1195    ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
1196        let obj = $imp.obj();
1197        $crate::element_error!(obj, $err, ($($msg)*), details: $details);
1198    }};
1199    ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
1200        let obj = $imp.obj();
1201        $crate::element_error!(obj, $err, [$($debug)*], details: $details);
1202    }};
1203);
1204
1205#[doc(alias = "GST_ELEMENT_WARNING")]
1206#[doc(alias = "GST_ELEMENT_WARNING_WITH_DETAILS")]
1207#[macro_export]
1208macro_rules! element_imp_warning(
1209    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
1210        let obj = $imp.obj();
1211        $crate::element_warning!(obj, $err, ($($msg)*), [$($debug)*]);
1212    }};
1213    ($imp:expr, $err:expr, ($($msg:tt)*)) => { {
1214        let obj = $imp.obj();
1215        $crate::element_warning!(obj, $err, ($($msg)*));
1216    }};
1217    ($imp:expr, $err:expr, [$($debug:tt)*]) => { {
1218        let obj = $imp.obj();
1219        $crate::element_warning!(obj, $err, [$($debug)*]);
1220    }};
1221
1222    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
1223        let obj = $imp.obj();
1224        $crate::element_warning!(obj, $err, ($($msg)*), [$($debug)*], details: $details);
1225    }};
1226    ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
1227        let obj = $imp.obj();
1228        $crate::element_warning!(obj, $err, ($($msg)*), details: $details);
1229    }};
1230    ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
1231        let obj = $imp.obj();
1232        $crate::element_warning!(obj, $err, [$($debug)*], details: $details);
1233    }};
1234);
1235
1236#[doc(alias = "GST_ELEMENT_INFO")]
1237#[doc(alias = "GST_ELEMENT_INFO_WITH_DETAILS")]
1238#[macro_export]
1239macro_rules! element_imp_info(
1240    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
1241        let obj = $imp.obj();
1242        $crate::element_info!(obj, $err, ($($msg)*), [$($debug)*]);
1243    }};
1244    ($imp:expr, $err:expr, ($($msg:tt)*)) => { {
1245        let obj = $imp.obj();
1246        $crate::element_info!(obj, $err, ($($msg)*));
1247    }};
1248    ($imp:expr, $err:expr, [$($debug:tt)*]) => { {
1249        let obj = $imp.obj();
1250        $crate::element_info!(obj, $err, [$($debug)*]);
1251    }};
1252
1253    ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { {
1254        let obj = $imp.obj();
1255        $crate::element_info!(obj, $err, ($($msg)*), [$($debug)*], details: $details);
1256    }};
1257    ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { {
1258        let obj = $imp.obj();
1259        $crate::element_info!(obj, $err, ($($msg)*), details: $details);
1260    }};
1261    ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { {
1262        let obj = $imp.obj();
1263        $crate::element_info!(obj, $err, [$($debug)*], details: $details);
1264    }};
1265);
1266
1267#[cfg(test)]
1268mod tests {
1269    use std::sync::mpsc::channel;
1270
1271    use glib::GString;
1272
1273    use super::*;
1274
1275    #[test]
1276    fn test_get_pads() {
1277        crate::init().unwrap();
1278
1279        let identity = crate::ElementFactory::make("identity").build().unwrap();
1280
1281        let mut pad_names = identity
1282            .pads()
1283            .iter()
1284            .map(|p| p.name())
1285            .collect::<Vec<GString>>();
1286        pad_names.sort();
1287        assert_eq!(pad_names, vec![String::from("sink"), String::from("src")]);
1288
1289        let mut pad_names = identity
1290            .sink_pads()
1291            .iter()
1292            .map(|p| p.name())
1293            .collect::<Vec<GString>>();
1294        pad_names.sort();
1295        assert_eq!(pad_names, vec![String::from("sink")]);
1296
1297        let mut pad_names = identity
1298            .src_pads()
1299            .iter()
1300            .map(|p| p.name())
1301            .collect::<Vec<GString>>();
1302        pad_names.sort();
1303        assert_eq!(pad_names, vec![String::from("src")]);
1304    }
1305
1306    #[test]
1307    fn test_foreach_pad() {
1308        crate::init().unwrap();
1309
1310        let identity = crate::ElementFactory::make("identity").build().unwrap();
1311
1312        let mut pad_names = Vec::new();
1313        identity.foreach_pad(|_element, pad| {
1314            pad_names.push(pad.name());
1315
1316            ControlFlow::Continue(())
1317        });
1318        pad_names.sort();
1319        assert_eq!(pad_names, vec![String::from("sink"), String::from("src")]);
1320
1321        pad_names.clear();
1322        identity.foreach_sink_pad(|_element, pad| {
1323            pad_names.push(pad.name());
1324
1325            ControlFlow::Continue(())
1326        });
1327        assert_eq!(pad_names, vec![String::from("sink")]);
1328
1329        pad_names.clear();
1330        identity.foreach_src_pad(|_element, pad| {
1331            pad_names.push(pad.name());
1332
1333            ControlFlow::Continue(())
1334        });
1335        assert_eq!(pad_names, vec![String::from("src")]);
1336    }
1337
1338    #[test]
1339    fn test_call_async() {
1340        crate::init().unwrap();
1341
1342        let identity = crate::ElementFactory::make("identity").build().unwrap();
1343        let (sender, receiver) = channel();
1344
1345        identity.call_async(move |_| {
1346            sender.send(()).unwrap();
1347        });
1348
1349        assert_eq!(receiver.recv(), Ok(()));
1350    }
1351
1352    #[test]
1353    fn test_element_error() {
1354        crate::init().unwrap();
1355
1356        let identity = crate::ElementFactory::make("identity").build().unwrap();
1357
1358        crate::element_error!(identity, crate::CoreError::Failed, ("msg"), ["debug"]);
1359        crate::element_error!(identity, crate::CoreError::Failed, ["debug"]);
1360        crate::element_error!(identity, crate::CoreError::Failed, ("msg"));
1361
1362        // We define a new variable for each call so there would be a compiler warning if the
1363        // string formatting did not actually use it.
1364        let x = 123i32;
1365        crate::element_error!(identity, crate::CoreError::Failed, ("msg {x}"), ["debug"]);
1366        let x = 123i32;
1367        crate::element_error!(identity, crate::CoreError::Failed, ["debug {x}"]);
1368        let x = 123i32;
1369        crate::element_error!(identity, crate::CoreError::Failed, ("msg {}", x));
1370    }
1371}