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