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