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