1use 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 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}