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