1use std::any::Any;
10use std::mem;
11use std::ptr;
12
13use libc;
14
15use glib_ffi;
16use gobject_ffi;
17use gst_ffi;
18
19use glib;
20use glib::translate::*;
21use gst;
22use gst::prelude::*;
23
24use gobject_subclass::anyimpl::*;
25use gobject_subclass::object::*;
26
27use object::*;
28
29pub trait ElementImpl<T: ElementBase>: ObjectImpl<T> + AnyImpl + Send + Sync + 'static
30where
31 T::InstanceStructType: PanicPoison,
32{
33 fn change_state(&self, element: &T, transition: gst::StateChange) -> gst::StateChangeReturn {
34 element.parent_change_state(transition)
35 }
36
37 fn request_new_pad(
38 &self,
39 _element: &T,
40 _templ: &gst::PadTemplate,
41 _name: Option<String>,
42 _caps: Option<&gst::CapsRef>,
43 ) -> Option<gst::Pad> {
44 None
45 }
46
47 fn release_pad(&self, _element: &T, _pad: &gst::Pad) {}
48
49 fn send_event(&self, element: &T, event: gst::Event) -> bool {
50 element.parent_send_event(event)
51 }
52
53 fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
54 element.parent_query(query)
55 }
56
57 fn set_context(&self, element: &T, context: &gst::Context) {
58 element.parent_set_context(context)
59 }
60}
61
62pub trait ElementImplExt<T> {
63 fn catch_panic_pad_function<R, F: FnOnce(&Self, &T) -> R, G: FnOnce() -> R>(
64 parent: &Option<gst::Object>,
65 fallback: G,
66 f: F,
67 ) -> R;
68}
69
70impl<S: ElementImpl<T>, T: ObjectType + glib::IsA<gst::Element> + glib::IsA<gst::Object>>
71 ElementImplExt<T> for S
72where
73 T::InstanceStructType: PanicPoison,
74{
75 fn catch_panic_pad_function<R, F: FnOnce(&Self, &T) -> R, G: FnOnce() -> R>(
76 parent: &Option<gst::Object>,
77 fallback: G,
78 f: F,
79 ) -> R {
80 let element = parent.as_ref().unwrap().downcast_ref::<T>().unwrap();
82 let imp = element.get_impl();
83 let imp = Any::downcast_ref::<Box<ElementImpl<T> + 'static>>(imp).unwrap();
84 let imp = imp.downcast_ref::<S>().unwrap();
85 element.catch_panic(fallback, |element| f(imp, element))
86 }
87}
88
89any_impl!(ElementBase, ElementImpl, PanicPoison);
90
91pub unsafe trait ElementBase: IsA<gst::Element> + ObjectType
92where
93 Self::InstanceStructType: PanicPoison,
94{
95 fn parent_change_state(&self, transition: gst::StateChange) -> gst::StateChangeReturn {
96 unsafe {
97 let klass = self.get_class();
98 let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
99 (*parent_klass)
100 .change_state
101 .map(|f| from_glib(f(self.to_glib_none().0, transition.to_glib())))
102 .unwrap_or(gst::StateChangeReturn::Success)
103 }
104 }
105
106 fn parent_send_event(&self, event: gst::Event) -> bool {
107 unsafe {
108 let klass = self.get_class();
109 let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
110 (*parent_klass)
111 .send_event
112 .map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
113 .unwrap_or(false)
114 }
115 }
116
117 fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
118 unsafe {
119 let klass = self.get_class();
120 let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
121 (*parent_klass)
122 .query
123 .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
124 .unwrap_or(false)
125 }
126 }
127
128 fn parent_set_context(&self, context: &gst::Context) {
129 unsafe {
130 let klass = self.get_class();
131 let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
132 (*parent_klass)
133 .set_context
134 .map(|f| f(self.to_glib_none().0, context.to_glib_none().0))
135 .unwrap_or(())
136 }
137 }
138
139 fn catch_panic<T, F: FnOnce(&Self) -> T, G: FnOnce() -> T>(&self, fallback: G, f: F) -> T {
140 let panicked = unsafe { &(*self.get_instance()).panicked() };
141 panic_to_error!(self, panicked, fallback(), { f(self) })
142 }
143}
144
145pub unsafe trait ElementClassExt<T: ElementBase>
146where
147 T::ImplType: ElementImpl<T>,
148 T::InstanceStructType: PanicPoison,
149{
150 fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
151 unsafe {
152 gst_ffi::gst_element_class_add_pad_template(
153 self as *const Self as *mut gst_ffi::GstElementClass,
154 pad_template.to_glib_none().0,
155 );
156 }
157 }
158
159 fn set_metadata(
160 &mut self,
161 long_name: &str,
162 classification: &str,
163 description: &str,
164 author: &str,
165 ) {
166 unsafe {
167 gst_ffi::gst_element_class_set_metadata(
168 self as *const Self as *mut gst_ffi::GstElementClass,
169 long_name.to_glib_none().0,
170 classification.to_glib_none().0,
171 description.to_glib_none().0,
172 author.to_glib_none().0,
173 );
174 }
175 }
176
177 fn override_vfuncs(&mut self, _: &ClassInitToken) {
178 unsafe {
179 let klass = &mut *(self as *const Self as *mut gst_ffi::GstElementClass);
180 klass.change_state = Some(element_change_state::<T>);
181 klass.request_new_pad = Some(element_request_new_pad::<T>);
182 klass.release_pad = Some(element_release_pad::<T>);
183 klass.send_event = Some(element_send_event::<T>);
184 klass.query = Some(element_query::<T>);
185 klass.set_context = Some(element_set_context::<T>);
186 }
187 }
188}
189
190glib_wrapper! {
191 pub struct Element(Object<ElementInstanceStruct<Element>>):
192 [gst::Element => gst_ffi::GstElement,
193 gst::Object => gst_ffi::GstObject];
194
195 match fn {
196 get_type => || get_type::<Element>(),
197 }
198}
199
200unsafe impl<T: IsA<gst::Element> + ObjectType> ElementBase for T where
201 Self::InstanceStructType: PanicPoison
202{
203}
204
205pub type ElementClass = ClassStruct<Element>;
206
207unsafe impl ElementClassExt<Element> for ElementClass {}
209unsafe impl ObjectClassExt<Element> for ElementClass {}
210
211unsafe impl Send for Element {}
212unsafe impl Sync for Element {}
213
214#[macro_export]
215macro_rules! box_element_impl(
216 ($name:ident) => {
217 box_object_impl!($name, PanicPoison);
218
219 impl<T: ElementBase> ElementImpl<T> for Box<$name<T>>
220 where
221 T::InstanceStructType: PanicPoison
222 {
223 fn change_state(
224 &self,
225 element: &T,
226 transition: gst::StateChange,
227 ) -> gst::StateChangeReturn {
228 let imp: &$name<T> = self.as_ref();
229 imp.change_state(element, transition)
230 }
231
232 fn request_new_pad(&self, element: &T, templ: &gst::PadTemplate, name: Option<String>, caps: Option<&gst::CapsRef>) -> Option<gst::Pad> {
233 let imp: &$name<T> = self.as_ref();
234 imp.request_new_pad(element, templ, name, caps)
235 }
236
237 fn release_pad(&self, element: &T, pad: &gst::Pad) {
238 let imp: &$name<T> = self.as_ref();
239 imp.release_pad(element, pad)
240 }
241
242 fn send_event(&self, element: &T, event: gst::Event) -> bool {
243 let imp: &$name<T> = self.as_ref();
244 imp.send_event(element, event)
245 }
246
247 fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
248 let imp: &$name<T> = self.as_ref();
249 ElementImpl::query(imp, element, query)
250 }
251
252 fn set_context(&self, element: &T, context: &gst::Context) {
253 let imp: &$name<T> = self.as_ref();
254 imp.set_context(element, context)
255 }
256 }
257 };
258);
259
260box_element_impl!(ElementImpl);
261
262impl ObjectType for Element {
263 const NAME: &'static str = "RsElement";
264 type ParentType = gst::Element;
265 type ImplType = Box<ElementImpl<Self>>;
266 type InstanceStructType = ElementInstanceStruct<Self>;
267
268 fn class_init(token: &ClassInitToken, klass: &mut ElementClass) {
269 ObjectClassExt::override_vfuncs(klass, token);
270 ElementClassExt::override_vfuncs(klass, token);
271 }
272
273 object_type_fns!();
274}
275
276unsafe extern "C" fn element_change_state<T: ElementBase>(
277 ptr: *mut gst_ffi::GstElement,
278 transition: gst_ffi::GstStateChange,
279) -> gst_ffi::GstStateChangeReturn
280where
281 T::ImplType: ElementImpl<T>,
282 T::InstanceStructType: PanicPoison,
283{
284 floating_reference_guard!(ptr);
285 let element = &*(ptr as *mut T::InstanceStructType);
286 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
287 let imp = element.get_impl();
288
289 let transition = from_glib(transition);
292 let fallback = match transition {
293 gst::StateChange::PlayingToPaused
294 | gst::StateChange::PausedToReady
295 | gst::StateChange::ReadyToNull => gst::StateChangeReturn::Success,
296 _ => gst::StateChangeReturn::Failure,
297 };
298
299 panic_to_error!(&wrap, &element.panicked(), fallback, {
300 imp.change_state(&wrap, transition)
301 })
302 .to_glib()
303}
304
305unsafe extern "C" fn element_request_new_pad<T: ElementBase>(
306 ptr: *mut gst_ffi::GstElement,
307 templ: *mut gst_ffi::GstPadTemplate,
308 name: *const libc::c_char,
309 caps: *const gst_ffi::GstCaps,
310) -> *mut gst_ffi::GstPad
311where
312 T::ImplType: ElementImpl<T>,
313 T::InstanceStructType: PanicPoison,
314{
315 floating_reference_guard!(ptr);
316 let element = &*(ptr as *mut T::InstanceStructType);
317 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
318 let imp = element.get_impl();
319 let caps = if caps.is_null() {
320 None
321 } else {
322 Some(gst::CapsRef::from_ptr(caps))
323 };
324
325 let pad = panic_to_error!(&wrap, &element.panicked(), None, {
328 imp.request_new_pad(&wrap, &from_glib_borrow(templ), from_glib_none(name), caps)
329 });
330
331 if let Some(ref pad) = pad {
333 assert_eq!(
334 pad.get_parent(),
335 Some(gst::Object::from_glib_borrow(
336 ptr as *mut gst_ffi::GstObject
337 ))
338 );
339 }
340
341 pad.to_glib_none().0
342}
343
344unsafe extern "C" fn element_release_pad<T: ElementBase>(
345 ptr: *mut gst_ffi::GstElement,
346 pad: *mut gst_ffi::GstPad,
347) where
348 T::ImplType: ElementImpl<T>,
349 T::InstanceStructType: PanicPoison,
350{
351 floating_reference_guard!(ptr);
352 let element = &*(ptr as *mut T::InstanceStructType);
353 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
354 let imp = element.get_impl();
355
356 panic_to_error!(&wrap, &element.panicked(), (), {
357 imp.release_pad(&wrap, &from_glib_borrow(pad))
358 })
359}
360
361unsafe extern "C" fn element_send_event<T: ElementBase>(
362 ptr: *mut gst_ffi::GstElement,
363 event: *mut gst_ffi::GstEvent,
364) -> glib_ffi::gboolean
365where
366 T::ImplType: ElementImpl<T>,
367 T::InstanceStructType: PanicPoison,
368{
369 floating_reference_guard!(ptr);
370 let element = &*(ptr as *mut T::InstanceStructType);
371 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
372 let imp = element.get_impl();
373
374 panic_to_error!(&wrap, &element.panicked(), false, {
375 imp.send_event(&wrap, from_glib_full(event))
376 })
377 .to_glib()
378}
379
380unsafe extern "C" fn element_query<T: ElementBase>(
381 ptr: *mut gst_ffi::GstElement,
382 query: *mut gst_ffi::GstQuery,
383) -> glib_ffi::gboolean
384where
385 T::ImplType: ElementImpl<T>,
386 T::InstanceStructType: PanicPoison,
387{
388 floating_reference_guard!(ptr);
389 let element = &*(ptr as *mut T::InstanceStructType);
390 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
391 let imp = element.get_impl();
392 let query = gst::QueryRef::from_mut_ptr(query);
393
394 panic_to_error!(&wrap, &element.panicked(), false, {
395 imp.query(&wrap, query)
396 })
397 .to_glib()
398}
399
400unsafe extern "C" fn element_set_context<T: ElementBase>(
401 ptr: *mut gst_ffi::GstElement,
402 context: *mut gst_ffi::GstContext,
403) where
404 T::ImplType: ElementImpl<T>,
405 T::InstanceStructType: PanicPoison,
406{
407 floating_reference_guard!(ptr);
408 let element = &*(ptr as *mut T::InstanceStructType);
409 let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
410 let imp = element.get_impl();
411
412 panic_to_error!(&wrap, &element.panicked(), (), {
413 imp.set_context(&wrap, &from_glib_borrow(context))
414 })
415}