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