1 // Copyright (C) 2017-2019 Sebastian Dröge <sebastian@centricular.com>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use libc;
10 
11 use glib_sys;
12 use gst_sys;
13 
14 use super::prelude::*;
15 use glib;
16 use glib::prelude::*;
17 use glib::subclass::prelude::*;
18 use glib::translate::*;
19 use prelude::*;
20 
21 use Element;
22 use ElementClass;
23 use Event;
24 use PadTemplate;
25 use QueryRef;
26 use StateChange;
27 use StateChangeError;
28 use StateChangeReturn;
29 use StateChangeSuccess;
30 
31 pub trait ElementImpl: ElementImplExt + ObjectImpl + Send + Sync + 'static {
change_state( &self, element: &::Element, transition: StateChange, ) -> Result<StateChangeSuccess, StateChangeError>32     fn change_state(
33         &self,
34         element: &::Element,
35         transition: StateChange,
36     ) -> Result<StateChangeSuccess, StateChangeError> {
37         self.parent_change_state(element, transition)
38     }
39 
request_new_pad( &self, element: &::Element, templ: &::PadTemplate, name: Option<String>, caps: Option<&::Caps>, ) -> Option<::Pad>40     fn request_new_pad(
41         &self,
42         element: &::Element,
43         templ: &::PadTemplate,
44         name: Option<String>,
45         caps: Option<&::Caps>,
46     ) -> Option<::Pad> {
47         self.parent_request_new_pad(element, templ, name, caps)
48     }
49 
release_pad(&self, element: &::Element, pad: &::Pad)50     fn release_pad(&self, element: &::Element, pad: &::Pad) {
51         self.parent_release_pad(element, pad)
52     }
53 
send_event(&self, element: &::Element, event: Event) -> bool54     fn send_event(&self, element: &::Element, event: Event) -> bool {
55         self.parent_send_event(element, event)
56     }
57 
query(&self, element: &::Element, query: &mut QueryRef) -> bool58     fn query(&self, element: &::Element, query: &mut QueryRef) -> bool {
59         self.parent_query(element, query)
60     }
61 
set_context(&self, element: &::Element, context: &::Context)62     fn set_context(&self, element: &::Element, context: &::Context) {
63         self.parent_set_context(element, context)
64     }
65 
set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool66     fn set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool {
67         self.parent_set_clock(element, clock)
68     }
69 
provide_clock(&self, element: &::Element) -> Option<::Clock>70     fn provide_clock(&self, element: &::Element) -> Option<::Clock> {
71         self.parent_provide_clock(element)
72     }
73 }
74 
75 pub trait ElementImplExt {
parent_change_state( &self, element: &::Element, transition: StateChange, ) -> Result<StateChangeSuccess, StateChangeError>76     fn parent_change_state(
77         &self,
78         element: &::Element,
79         transition: StateChange,
80     ) -> Result<StateChangeSuccess, StateChangeError>;
81 
parent_request_new_pad( &self, element: &::Element, templ: &::PadTemplate, name: Option<String>, caps: Option<&::Caps>, ) -> Option<::Pad>82     fn parent_request_new_pad(
83         &self,
84         element: &::Element,
85         templ: &::PadTemplate,
86         name: Option<String>,
87         caps: Option<&::Caps>,
88     ) -> Option<::Pad>;
89 
parent_release_pad(&self, element: &::Element, pad: &::Pad)90     fn parent_release_pad(&self, element: &::Element, pad: &::Pad);
91 
parent_send_event(&self, element: &::Element, event: Event) -> bool92     fn parent_send_event(&self, element: &::Element, event: Event) -> bool;
93 
parent_query(&self, element: &::Element, query: &mut QueryRef) -> bool94     fn parent_query(&self, element: &::Element, query: &mut QueryRef) -> bool;
95 
parent_set_context(&self, element: &::Element, context: &::Context)96     fn parent_set_context(&self, element: &::Element, context: &::Context);
97 
parent_set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool98     fn parent_set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool;
99 
parent_provide_clock(&self, element: &::Element) -> Option<::Clock>100     fn parent_provide_clock(&self, element: &::Element) -> Option<::Clock>;
101 
catch_panic< R, F: FnOnce(&Self) -> R, G: FnOnce() -> R, P: IsA<::Element> + IsA<glib::Object> + glib::value::SetValue, >( &self, element: &P, fallback: G, f: F, ) -> R102     fn catch_panic<
103         R,
104         F: FnOnce(&Self) -> R,
105         G: FnOnce() -> R,
106         P: IsA<::Element> + IsA<glib::Object> + glib::value::SetValue,
107     >(
108         &self,
109         element: &P,
110         fallback: G,
111         f: F,
112     ) -> R;
113 
catch_panic_pad_function<R, F: FnOnce(&Self, &::Element) -> R, G: FnOnce() -> R>( parent: Option<&::Object>, fallback: G, f: F, ) -> R114     fn catch_panic_pad_function<R, F: FnOnce(&Self, &::Element) -> R, G: FnOnce() -> R>(
115         parent: Option<&::Object>,
116         fallback: G,
117         f: F,
118     ) -> R;
119 }
120 
121 impl<T: ElementImpl + ObjectSubclass> ElementImplExt for T
122 where
123     T::Instance: PanicPoison,
124 {
parent_change_state( &self, element: &::Element, transition: StateChange, ) -> Result<StateChangeSuccess, StateChangeError>125     fn parent_change_state(
126         &self,
127         element: &::Element,
128         transition: StateChange,
129     ) -> Result<StateChangeSuccess, StateChangeError> {
130         unsafe {
131             let data = self.get_type_data();
132             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
133 
134             let f = (*parent_class)
135                 .change_state
136                 .expect("Missing parent function `change_state`");
137             StateChangeReturn::from_glib(f(element.to_glib_none().0, transition.to_glib()))
138                 .into_result()
139         }
140     }
141 
parent_request_new_pad( &self, element: &::Element, templ: &::PadTemplate, name: Option<String>, caps: Option<&::Caps>, ) -> Option<::Pad>142     fn parent_request_new_pad(
143         &self,
144         element: &::Element,
145         templ: &::PadTemplate,
146         name: Option<String>,
147         caps: Option<&::Caps>,
148     ) -> Option<::Pad> {
149         unsafe {
150             let data = self.get_type_data();
151             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
152 
153             (*parent_class)
154                 .request_new_pad
155                 .map(|f| {
156                     from_glib_none(f(
157                         element.to_glib_none().0,
158                         templ.to_glib_none().0,
159                         name.to_glib_full(),
160                         caps.to_glib_none().0,
161                     ))
162                 })
163                 .unwrap_or(None)
164         }
165     }
166 
parent_release_pad(&self, element: &::Element, pad: &::Pad)167     fn parent_release_pad(&self, element: &::Element, pad: &::Pad) {
168         unsafe {
169             let data = self.get_type_data();
170             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
171 
172             (*parent_class)
173                 .release_pad
174                 .map(|f| f(element.to_glib_none().0, pad.to_glib_none().0))
175                 .unwrap_or(())
176         }
177     }
178 
parent_send_event(&self, element: &::Element, event: Event) -> bool179     fn parent_send_event(&self, element: &::Element, event: Event) -> bool {
180         unsafe {
181             let data = self.get_type_data();
182             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
183 
184             (*parent_class)
185                 .send_event
186                 .map(|f| from_glib(f(element.to_glib_none().0, event.into_ptr())))
187                 .unwrap_or(false)
188         }
189     }
190 
parent_query(&self, element: &::Element, query: &mut QueryRef) -> bool191     fn parent_query(&self, element: &::Element, query: &mut QueryRef) -> bool {
192         unsafe {
193             let data = self.get_type_data();
194             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
195 
196             (*parent_class)
197                 .query
198                 .map(|f| from_glib(f(element.to_glib_none().0, query.as_mut_ptr())))
199                 .unwrap_or(false)
200         }
201     }
202 
parent_set_context(&self, element: &::Element, context: &::Context)203     fn parent_set_context(&self, element: &::Element, context: &::Context) {
204         unsafe {
205             let data = self.get_type_data();
206             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
207 
208             (*parent_class)
209                 .set_context
210                 .map(|f| f(element.to_glib_none().0, context.to_glib_none().0))
211                 .unwrap_or(())
212         }
213     }
214 
parent_set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool215     fn parent_set_clock(&self, element: &::Element, clock: Option<&::Clock>) -> bool {
216         unsafe {
217             let data = self.get_type_data();
218             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
219 
220             (*parent_class)
221                 .set_clock
222                 .map(|f| from_glib(f(element.to_glib_none().0, clock.to_glib_none().0)))
223                 .unwrap_or(false)
224         }
225     }
226 
parent_provide_clock(&self, element: &::Element) -> Option<::Clock>227     fn parent_provide_clock(&self, element: &::Element) -> Option<::Clock> {
228         unsafe {
229             let data = self.get_type_data();
230             let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstElementClass;
231 
232             (*parent_class)
233                 .provide_clock
234                 .map(|f| from_glib_none(f(element.to_glib_none().0)))
235                 .unwrap_or(None)
236         }
237     }
238 
catch_panic< R, F: FnOnce(&Self) -> R, G: FnOnce() -> R, P: IsA<::Element> + IsA<glib::Object> + glib::value::SetValue, >( &self, element: &P, fallback: G, f: F, ) -> R239     fn catch_panic<
240         R,
241         F: FnOnce(&Self) -> R,
242         G: FnOnce() -> R,
243         P: IsA<::Element> + IsA<glib::Object> + glib::value::SetValue,
244     >(
245         &self,
246         element: &P,
247         fallback: G,
248         f: F,
249     ) -> R {
250         unsafe {
251             assert!(element.get_type().is_a(&T::get_type()));
252             let ptr: *mut gst_sys::GstElement = element.as_ptr() as *mut _;
253             let instance = &*(ptr as *mut T::Instance);
254             let imp = instance.get_impl();
255 
256             gst_panic_to_error!(element, &instance.panicked(), fallback(), { f(&imp) })
257         }
258     }
259 
catch_panic_pad_function<R, F: FnOnce(&Self, &::Element) -> R, G: FnOnce() -> R>( parent: Option<&::Object>, fallback: G, f: F, ) -> R260     fn catch_panic_pad_function<R, F: FnOnce(&Self, &::Element) -> R, G: FnOnce() -> R>(
261         parent: Option<&::Object>,
262         fallback: G,
263         f: F,
264     ) -> R {
265         unsafe {
266             let wrap = parent
267                 .as_ref()
268                 .unwrap()
269                 .downcast_ref::<::Element>()
270                 .unwrap();
271             assert!(wrap.get_type().is_a(&T::get_type()));
272             let ptr: *mut gst_sys::GstElement = wrap.to_glib_none().0;
273             let instance = &*(ptr as *mut T::Instance);
274             let imp = instance.get_impl();
275 
276             gst_panic_to_error!(wrap, &instance.panicked(), fallback(), { f(&imp, &wrap) })
277         }
278     }
279 }
280 
281 pub unsafe trait ElementClassSubclassExt: Sized + 'static {
add_pad_template(&mut self, pad_template: PadTemplate)282     fn add_pad_template(&mut self, pad_template: PadTemplate) {
283         unsafe {
284             gst_sys::gst_element_class_add_pad_template(
285                 self as *mut Self as *mut gst_sys::GstElementClass,
286                 pad_template.to_glib_none().0,
287             );
288         }
289     }
290 
set_metadata( &mut self, long_name: &str, classification: &str, description: &str, author: &str, )291     fn set_metadata(
292         &mut self,
293         long_name: &str,
294         classification: &str,
295         description: &str,
296         author: &str,
297     ) {
298         unsafe {
299             gst_sys::gst_element_class_set_metadata(
300                 self as *mut Self as *mut gst_sys::GstElementClass,
301                 long_name.to_glib_none().0,
302                 classification.to_glib_none().0,
303                 description.to_glib_none().0,
304                 author.to_glib_none().0,
305             );
306         }
307     }
308 
add_metadata(&mut self, key: &str, value: &str)309     fn add_metadata(&mut self, key: &str, value: &str) {
310         unsafe {
311             gst_sys::gst_element_class_add_metadata(
312                 self as *mut Self as *mut gst_sys::GstElementClass,
313                 key.to_glib_none().0,
314                 value.to_glib_none().0,
315             );
316         }
317     }
318 }
319 
320 unsafe impl ElementClassSubclassExt for ElementClass {}
321 
322 unsafe impl<T: ObjectSubclass + ElementImpl> IsSubclassable<T> for ElementClass
323 where
324     <T as ObjectSubclass>::Instance: PanicPoison,
325 {
override_vfuncs(&mut self)326     fn override_vfuncs(&mut self) {
327         <glib::ObjectClass as IsSubclassable<T>>::override_vfuncs(self);
328 
329         unsafe {
330             let klass = &mut *(self as *mut Self as *mut gst_sys::GstElementClass);
331             klass.change_state = Some(element_change_state::<T>);
332             klass.request_new_pad = Some(element_request_new_pad::<T>);
333             klass.release_pad = Some(element_release_pad::<T>);
334             klass.send_event = Some(element_send_event::<T>);
335             klass.query = Some(element_query::<T>);
336             klass.set_context = Some(element_set_context::<T>);
337             klass.set_clock = Some(element_set_clock::<T>);
338             klass.provide_clock = Some(element_provide_clock::<T>);
339         }
340     }
341 }
342 
element_change_state<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, transition: gst_sys::GstStateChange, ) -> gst_sys::GstStateChangeReturn where T: ElementImpl, T::Instance: PanicPoison,343 unsafe extern "C" fn element_change_state<T: ObjectSubclass>(
344     ptr: *mut gst_sys::GstElement,
345     transition: gst_sys::GstStateChange,
346 ) -> gst_sys::GstStateChangeReturn
347 where
348     T: ElementImpl,
349     T::Instance: PanicPoison,
350 {
351     let instance = &*(ptr as *mut T::Instance);
352     let imp = instance.get_impl();
353     let wrap: Element = from_glib_borrow(ptr);
354 
355     // *Never* fail downwards state changes, this causes bugs in GStreamer
356     // and leads to crashes and deadlocks.
357     let transition = from_glib(transition);
358     let fallback = match transition {
359         StateChange::PlayingToPaused | StateChange::PausedToReady | StateChange::ReadyToNull => {
360             StateChangeReturn::Success
361         }
362         _ => StateChangeReturn::Failure,
363     };
364 
365     gst_panic_to_error!(&wrap, &instance.panicked(), fallback, {
366         imp.change_state(&wrap, transition).into()
367     })
368     .to_glib()
369 }
370 
element_request_new_pad<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, templ: *mut gst_sys::GstPadTemplate, name: *const libc::c_char, caps: *const gst_sys::GstCaps, ) -> *mut gst_sys::GstPad where T: ElementImpl, T::Instance: PanicPoison,371 unsafe extern "C" fn element_request_new_pad<T: ObjectSubclass>(
372     ptr: *mut gst_sys::GstElement,
373     templ: *mut gst_sys::GstPadTemplate,
374     name: *const libc::c_char,
375     caps: *const gst_sys::GstCaps,
376 ) -> *mut gst_sys::GstPad
377 where
378     T: ElementImpl,
379     T::Instance: PanicPoison,
380 {
381     let instance = &*(ptr as *mut T::Instance);
382     let imp = instance.get_impl();
383     let wrap: Element = from_glib_borrow(ptr);
384 
385     let caps = Option::<::Caps>::from_glib_borrow(caps);
386 
387     // XXX: This is effectively unsafe but the best we can do
388     // See https://bugzilla.gnome.org/show_bug.cgi?id=791193
389     let pad = gst_panic_to_error!(&wrap, &instance.panicked(), None, {
390         imp.request_new_pad(
391             &wrap,
392             &from_glib_borrow(templ),
393             from_glib_none(name),
394             caps.as_ref(),
395         )
396     });
397 
398     // Ensure that the pad is owned by the element now, if a pad was returned
399     if let Some(ref pad) = pad {
400         assert_eq!(
401             pad.get_parent(),
402             Some(::Object::from_glib_borrow(ptr as *mut gst_sys::GstObject))
403         );
404     }
405 
406     pad.to_glib_none().0
407 }
408 
element_release_pad<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, pad: *mut gst_sys::GstPad, ) where T: ElementImpl, T::Instance: PanicPoison,409 unsafe extern "C" fn element_release_pad<T: ObjectSubclass>(
410     ptr: *mut gst_sys::GstElement,
411     pad: *mut gst_sys::GstPad,
412 ) where
413     T: ElementImpl,
414     T::Instance: PanicPoison,
415 {
416     let instance = &*(ptr as *mut T::Instance);
417     let imp = instance.get_impl();
418     let wrap: Element = from_glib_borrow(ptr);
419 
420     // If we get a floating reference passed simply return here. It can't be stored inside this
421     // element, and if we continued to use it we would take ownership of this floating reference.
422     if gobject_sys::g_object_is_floating(pad as *mut gobject_sys::GObject) != glib_sys::GFALSE {
423         return;
424     }
425 
426     gst_panic_to_error!(&wrap, &instance.panicked(), (), {
427         imp.release_pad(&wrap, &from_glib_none(pad))
428     })
429 }
430 
element_send_event<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, event: *mut gst_sys::GstEvent, ) -> glib_sys::gboolean where T: ElementImpl, T::Instance: PanicPoison,431 unsafe extern "C" fn element_send_event<T: ObjectSubclass>(
432     ptr: *mut gst_sys::GstElement,
433     event: *mut gst_sys::GstEvent,
434 ) -> glib_sys::gboolean
435 where
436     T: ElementImpl,
437     T::Instance: PanicPoison,
438 {
439     let instance = &*(ptr as *mut T::Instance);
440     let imp = instance.get_impl();
441     let wrap: Element = from_glib_borrow(ptr);
442 
443     gst_panic_to_error!(&wrap, &instance.panicked(), false, {
444         imp.send_event(&wrap, from_glib_full(event))
445     })
446     .to_glib()
447 }
448 
element_query<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, query: *mut gst_sys::GstQuery, ) -> glib_sys::gboolean where T: ElementImpl, T::Instance: PanicPoison,449 unsafe extern "C" fn element_query<T: ObjectSubclass>(
450     ptr: *mut gst_sys::GstElement,
451     query: *mut gst_sys::GstQuery,
452 ) -> glib_sys::gboolean
453 where
454     T: ElementImpl,
455     T::Instance: PanicPoison,
456 {
457     let instance = &*(ptr as *mut T::Instance);
458     let imp = instance.get_impl();
459     let wrap: Element = from_glib_borrow(ptr);
460     let query = QueryRef::from_mut_ptr(query);
461 
462     gst_panic_to_error!(&wrap, &instance.panicked(), false, {
463         imp.query(&wrap, query)
464     })
465     .to_glib()
466 }
467 
element_set_context<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, context: *mut gst_sys::GstContext, ) where T: ElementImpl, T::Instance: PanicPoison,468 unsafe extern "C" fn element_set_context<T: ObjectSubclass>(
469     ptr: *mut gst_sys::GstElement,
470     context: *mut gst_sys::GstContext,
471 ) where
472     T: ElementImpl,
473     T::Instance: PanicPoison,
474 {
475     let instance = &*(ptr as *mut T::Instance);
476     let imp = instance.get_impl();
477     let wrap: Element = from_glib_borrow(ptr);
478 
479     gst_panic_to_error!(&wrap, &instance.panicked(), (), {
480         imp.set_context(&wrap, &from_glib_borrow(context))
481     })
482 }
483 
element_set_clock<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, clock: *mut gst_sys::GstClock, ) -> glib_sys::gboolean where T: ElementImpl, T::Instance: PanicPoison,484 unsafe extern "C" fn element_set_clock<T: ObjectSubclass>(
485     ptr: *mut gst_sys::GstElement,
486     clock: *mut gst_sys::GstClock,
487 ) -> glib_sys::gboolean
488 where
489     T: ElementImpl,
490     T::Instance: PanicPoison,
491 {
492     let instance = &*(ptr as *mut T::Instance);
493     let imp = instance.get_impl();
494     let wrap: Element = from_glib_borrow(ptr);
495 
496     let clock = Option::<::Clock>::from_glib_borrow(clock);
497 
498     gst_panic_to_error!(&wrap, &instance.panicked(), false, {
499         imp.set_clock(&wrap, clock.as_ref())
500     })
501     .to_glib()
502 }
503 
element_provide_clock<T: ObjectSubclass>( ptr: *mut gst_sys::GstElement, ) -> *mut gst_sys::GstClock where T: ElementImpl, T::Instance: PanicPoison,504 unsafe extern "C" fn element_provide_clock<T: ObjectSubclass>(
505     ptr: *mut gst_sys::GstElement,
506 ) -> *mut gst_sys::GstClock
507 where
508     T: ElementImpl,
509     T::Instance: PanicPoison,
510 {
511     let instance = &*(ptr as *mut T::Instance);
512     let imp = instance.get_impl();
513     let wrap: Element = from_glib_borrow(ptr);
514 
515     gst_panic_to_error!(&wrap, &instance.panicked(), None, {
516         imp.provide_clock(&wrap)
517     })
518     .to_glib_full()
519 }
520 
521 #[cfg(test)]
522 mod tests {
523     use super::*;
524     use glib;
525     use glib::subclass;
526     use std::sync::atomic;
527 
528     struct TestElement {
529         srcpad: ::Pad,
530         sinkpad: ::Pad,
531         n_buffers: atomic::AtomicU32,
532         reached_playing: atomic::AtomicBool,
533     }
534 
535     impl TestElement {
set_pad_functions(sinkpad: &::Pad, srcpad: &::Pad)536         fn set_pad_functions(sinkpad: &::Pad, srcpad: &::Pad) {
537             sinkpad.set_chain_function(|pad, parent, buffer| {
538                 TestElement::catch_panic_pad_function(
539                     parent,
540                     || Err(::FlowError::Error),
541                     |identity, element| identity.sink_chain(pad, element, buffer),
542                 )
543             });
544             sinkpad.set_event_function(|pad, parent, event| {
545                 TestElement::catch_panic_pad_function(
546                     parent,
547                     || false,
548                     |identity, element| identity.sink_event(pad, element, event),
549                 )
550             });
551             sinkpad.set_query_function(|pad, parent, query| {
552                 TestElement::catch_panic_pad_function(
553                     parent,
554                     || false,
555                     |identity, element| identity.sink_query(pad, element, query),
556                 )
557             });
558 
559             srcpad.set_event_function(|pad, parent, event| {
560                 TestElement::catch_panic_pad_function(
561                     parent,
562                     || false,
563                     |identity, element| identity.src_event(pad, element, event),
564                 )
565             });
566             srcpad.set_query_function(|pad, parent, query| {
567                 TestElement::catch_panic_pad_function(
568                     parent,
569                     || false,
570                     |identity, element| identity.src_query(pad, element, query),
571                 )
572             });
573         }
574 
sink_chain( &self, _pad: &::Pad, _element: &::Element, buffer: ::Buffer, ) -> Result<::FlowSuccess, ::FlowError>575         fn sink_chain(
576             &self,
577             _pad: &::Pad,
578             _element: &::Element,
579             buffer: ::Buffer,
580         ) -> Result<::FlowSuccess, ::FlowError> {
581             self.n_buffers.fetch_add(1, atomic::Ordering::SeqCst);
582             self.srcpad.push(buffer)
583         }
584 
sink_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool585         fn sink_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool {
586             self.srcpad.push_event(event)
587         }
588 
sink_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool589         fn sink_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool {
590             self.srcpad.peer_query(query)
591         }
592 
src_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool593         fn src_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool {
594             self.sinkpad.push_event(event)
595         }
596 
src_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool597         fn src_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool {
598             self.sinkpad.peer_query(query)
599         }
600     }
601 
602     impl ObjectSubclass for TestElement {
603         const NAME: &'static str = "TestElement";
604         type ParentType = ::Element;
605         type Instance = ::subclass::ElementInstanceStruct<Self>;
606         type Class = subclass::simple::ClassStruct<Self>;
607 
608         glib_object_subclass!();
609 
new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self610         fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
611             let templ = klass.get_pad_template("sink").unwrap();
612             let sinkpad = ::Pad::new_from_template(&templ, Some("sink"));
613             let templ = klass.get_pad_template("src").unwrap();
614             let srcpad = ::Pad::new_from_template(&templ, Some("src"));
615 
616             TestElement::set_pad_functions(&sinkpad, &srcpad);
617 
618             Self {
619                 n_buffers: atomic::AtomicU32::new(0),
620                 reached_playing: atomic::AtomicBool::new(false),
621                 srcpad,
622                 sinkpad,
623             }
624         }
625 
class_init(klass: &mut subclass::simple::ClassStruct<Self>)626         fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
627             klass.set_metadata(
628                 "Test Element",
629                 "Generic",
630                 "Does nothing",
631                 "Sebastian Dröge <sebastian@centricular.com>",
632             );
633 
634             let caps = ::Caps::new_any();
635             let src_pad_template =
636                 ::PadTemplate::new("src", ::PadDirection::Src, ::PadPresence::Always, &caps)
637                     .unwrap();
638             klass.add_pad_template(src_pad_template);
639 
640             let sink_pad_template =
641                 ::PadTemplate::new("sink", ::PadDirection::Sink, ::PadPresence::Always, &caps)
642                     .unwrap();
643             klass.add_pad_template(sink_pad_template);
644         }
645     }
646 
647     impl ObjectImpl for TestElement {
648         glib_object_impl!();
649 
constructed(&self, obj: &glib::Object)650         fn constructed(&self, obj: &glib::Object) {
651             self.parent_constructed(obj);
652 
653             let element = obj.downcast_ref::<::Element>().unwrap();
654             element.add_pad(&self.sinkpad).unwrap();
655             element.add_pad(&self.srcpad).unwrap();
656         }
657     }
658 
659     impl ElementImpl for TestElement {
change_state( &self, element: &::Element, transition: ::StateChange, ) -> Result<::StateChangeSuccess, ::StateChangeError>660         fn change_state(
661             &self,
662             element: &::Element,
663             transition: ::StateChange,
664         ) -> Result<::StateChangeSuccess, ::StateChangeError> {
665             let res = self.parent_change_state(element, transition)?;
666 
667             if transition == ::StateChange::PausedToPlaying {
668                 self.reached_playing.store(true, atomic::Ordering::SeqCst);
669             }
670 
671             Ok(res)
672         }
673     }
674 
675     #[test]
test_element_subclass()676     fn test_element_subclass() {
677         ::init().unwrap();
678 
679         let element = glib::Object::new(TestElement::get_type(), &[("name", &"test")])
680             .unwrap()
681             .downcast::<::Element>()
682             .unwrap();
683 
684         assert_eq!(element.get_name(), "test");
685 
686         assert_eq!(
687             element.get_metadata(&::ELEMENT_METADATA_LONGNAME),
688             Some("Test Element")
689         );
690 
691         let pipeline = ::Pipeline::new(None);
692         let src = ::ElementFactory::make("fakesrc", None).unwrap();
693         let sink = ::ElementFactory::make("fakesink", None).unwrap();
694 
695         src.set_property("num-buffers", &100i32).unwrap();
696 
697         pipeline.add_many(&[&src, &element, &sink]).unwrap();
698         ::Element::link_many(&[&src, &element, &sink]).unwrap();
699 
700         pipeline.set_state(::State::Playing).unwrap();
701         let bus = pipeline.get_bus().unwrap();
702 
703         let eos = bus.timed_pop_filtered(::CLOCK_TIME_NONE, &[::MessageType::Eos]);
704         assert!(eos.is_some());
705 
706         pipeline.set_state(::State::Null).unwrap();
707 
708         let imp = TestElement::from_instance(&element);
709         assert_eq!(imp.n_buffers.load(atomic::Ordering::SeqCst), 100);
710         assert_eq!(imp.reached_playing.load(atomic::Ordering::SeqCst), true);
711     }
712 }
713