1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::ptr; |
4 | |
5 | use glib::{prelude::*, translate::*}; |
6 | use gst::subclass::prelude::*; |
7 | |
8 | use crate::BaseSink; |
9 | |
10 | pub trait BaseSinkImpl: BaseSinkImplExt + ElementImpl { |
11 | fn start(&self) -> Result<(), gst::ErrorMessage> { |
12 | self.parent_start() |
13 | } |
14 | |
15 | fn stop(&self) -> Result<(), gst::ErrorMessage> { |
16 | self.parent_stop() |
17 | } |
18 | |
19 | fn render(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> { |
20 | self.parent_render(buffer) |
21 | } |
22 | |
23 | fn prepare(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> { |
24 | self.parent_prepare(buffer) |
25 | } |
26 | |
27 | fn render_list(&self, list: &gst::BufferList) -> Result<gst::FlowSuccess, gst::FlowError> { |
28 | self.parent_render_list(list) |
29 | } |
30 | |
31 | fn prepare_list(&self, list: &gst::BufferList) -> Result<gst::FlowSuccess, gst::FlowError> { |
32 | self.parent_prepare_list(list) |
33 | } |
34 | |
35 | fn query(&self, query: &mut gst::QueryRef) -> bool { |
36 | BaseSinkImplExt::parent_query(self, query) |
37 | } |
38 | |
39 | fn event(&self, event: gst::Event) -> bool { |
40 | self.parent_event(event) |
41 | } |
42 | |
43 | fn caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
44 | self.parent_caps(filter) |
45 | } |
46 | |
47 | fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
48 | self.parent_set_caps(caps) |
49 | } |
50 | |
51 | fn fixate(&self, caps: gst::Caps) -> gst::Caps { |
52 | self.parent_fixate(caps) |
53 | } |
54 | |
55 | fn unlock(&self) -> Result<(), gst::ErrorMessage> { |
56 | self.parent_unlock() |
57 | } |
58 | |
59 | fn unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
60 | self.parent_unlock_stop() |
61 | } |
62 | |
63 | fn propose_allocation( |
64 | &self, |
65 | query: &mut gst::query::Allocation, |
66 | ) -> Result<(), gst::LoggableError> { |
67 | self.parent_propose_allocation(query) |
68 | } |
69 | } |
70 | |
71 | mod sealed { |
72 | pub trait Sealed {} |
73 | impl<T: super::BaseSinkImplExt> Sealed for T {} |
74 | } |
75 | |
76 | pub trait BaseSinkImplExt: sealed::Sealed + ObjectSubclass { |
77 | fn parent_start(&self) -> Result<(), gst::ErrorMessage> { |
78 | unsafe { |
79 | let data = Self::type_data(); |
80 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
81 | (*parent_class) |
82 | .start |
83 | .map(|f| { |
84 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) { |
85 | Ok(()) |
86 | } else { |
87 | Err(gst::error_msg!( |
88 | gst::CoreError::StateChange, |
89 | ["Parent function `start` failed" ] |
90 | )) |
91 | } |
92 | }) |
93 | .unwrap_or(Ok(())) |
94 | } |
95 | } |
96 | |
97 | fn parent_stop(&self) -> Result<(), gst::ErrorMessage> { |
98 | unsafe { |
99 | let data = Self::type_data(); |
100 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
101 | (*parent_class) |
102 | .stop |
103 | .map(|f| { |
104 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) { |
105 | Ok(()) |
106 | } else { |
107 | Err(gst::error_msg!( |
108 | gst::CoreError::StateChange, |
109 | ["Parent function `stop` failed" ] |
110 | )) |
111 | } |
112 | }) |
113 | .unwrap_or(Ok(())) |
114 | } |
115 | } |
116 | |
117 | fn parent_render(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> { |
118 | unsafe { |
119 | let data = Self::type_data(); |
120 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
121 | (*parent_class) |
122 | .render |
123 | .map(|f| { |
124 | try_from_glib(f( |
125 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
126 | buffer.to_glib_none().0, |
127 | )) |
128 | }) |
129 | .unwrap_or(Ok(gst::FlowSuccess::Ok)) |
130 | } |
131 | } |
132 | |
133 | fn parent_prepare(&self, buffer: &gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> { |
134 | unsafe { |
135 | let data = Self::type_data(); |
136 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
137 | (*parent_class) |
138 | .prepare |
139 | .map(|f| { |
140 | try_from_glib(f( |
141 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
142 | buffer.to_glib_none().0, |
143 | )) |
144 | }) |
145 | .unwrap_or(Ok(gst::FlowSuccess::Ok)) |
146 | } |
147 | } |
148 | |
149 | fn parent_render_list( |
150 | &self, |
151 | list: &gst::BufferList, |
152 | ) -> Result<gst::FlowSuccess, gst::FlowError>; |
153 | |
154 | fn parent_prepare_list( |
155 | &self, |
156 | list: &gst::BufferList, |
157 | ) -> Result<gst::FlowSuccess, gst::FlowError>; |
158 | |
159 | fn parent_query(&self, query: &mut gst::QueryRef) -> bool { |
160 | unsafe { |
161 | let data = Self::type_data(); |
162 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
163 | (*parent_class) |
164 | .query |
165 | .map(|f| { |
166 | from_glib(f( |
167 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
168 | query.as_mut_ptr(), |
169 | )) |
170 | }) |
171 | .unwrap_or(false) |
172 | } |
173 | } |
174 | |
175 | fn parent_event(&self, event: gst::Event) -> bool { |
176 | unsafe { |
177 | let data = Self::type_data(); |
178 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
179 | (*parent_class) |
180 | .event |
181 | .map(|f| { |
182 | from_glib(f( |
183 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
184 | event.into_glib_ptr(), |
185 | )) |
186 | }) |
187 | .unwrap_or(true) |
188 | } |
189 | } |
190 | |
191 | fn parent_caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
192 | unsafe { |
193 | let data = Self::type_data(); |
194 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
195 | |
196 | (*parent_class) |
197 | .get_caps |
198 | .map(|f| { |
199 | from_glib_full(f( |
200 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
201 | filter.to_glib_none().0, |
202 | )) |
203 | }) |
204 | .unwrap_or(None) |
205 | } |
206 | } |
207 | |
208 | fn parent_set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
209 | unsafe { |
210 | let data = Self::type_data(); |
211 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
212 | (*parent_class) |
213 | .set_caps |
214 | .map(|f| { |
215 | gst::result_from_gboolean!( |
216 | f( |
217 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
218 | caps.to_glib_none().0 |
219 | ), |
220 | gst::CAT_RUST, |
221 | "Parent function `set_caps` failed" |
222 | ) |
223 | }) |
224 | .unwrap_or(Ok(())) |
225 | } |
226 | } |
227 | |
228 | fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps { |
229 | unsafe { |
230 | let data = Self::type_data(); |
231 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
232 | |
233 | match (*parent_class).fixate { |
234 | Some(fixate) => from_glib_full(fixate( |
235 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
236 | caps.into_glib_ptr(), |
237 | )), |
238 | None => caps, |
239 | } |
240 | } |
241 | } |
242 | |
243 | fn parent_unlock(&self) -> Result<(), gst::ErrorMessage> { |
244 | unsafe { |
245 | let data = Self::type_data(); |
246 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
247 | (*parent_class) |
248 | .unlock |
249 | .map(|f| { |
250 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) { |
251 | Ok(()) |
252 | } else { |
253 | Err(gst::error_msg!( |
254 | gst::CoreError::Failed, |
255 | ["Parent function `unlock` failed" ] |
256 | )) |
257 | } |
258 | }) |
259 | .unwrap_or(Ok(())) |
260 | } |
261 | } |
262 | |
263 | fn parent_unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
264 | unsafe { |
265 | let data = Self::type_data(); |
266 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
267 | (*parent_class) |
268 | .unlock_stop |
269 | .map(|f| { |
270 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0)) { |
271 | Ok(()) |
272 | } else { |
273 | Err(gst::error_msg!( |
274 | gst::CoreError::Failed, |
275 | ["Parent function `unlock_stop` failed" ] |
276 | )) |
277 | } |
278 | }) |
279 | .unwrap_or(Ok(())) |
280 | } |
281 | } |
282 | |
283 | fn parent_propose_allocation( |
284 | &self, |
285 | query: &mut gst::query::Allocation, |
286 | ) -> Result<(), gst::LoggableError> { |
287 | unsafe { |
288 | let data = Self::type_data(); |
289 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
290 | (*parent_class) |
291 | .propose_allocation |
292 | .map(|f| { |
293 | gst::result_from_gboolean!( |
294 | f( |
295 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
296 | query.as_mut_ptr(), |
297 | ), |
298 | gst::CAT_RUST, |
299 | "Parent function `propose_allocation` failed" , |
300 | ) |
301 | }) |
302 | .unwrap_or(Ok(())) |
303 | } |
304 | } |
305 | } |
306 | |
307 | impl<T: BaseSinkImpl> BaseSinkImplExt for T { |
308 | fn parent_render_list( |
309 | &self, |
310 | list: &gst::BufferList, |
311 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
312 | unsafe { |
313 | let data = Self::type_data(); |
314 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
315 | (*parent_class) |
316 | .render_list |
317 | .map(|f| { |
318 | try_from_glib(f( |
319 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
320 | list.to_glib_none().0, |
321 | )) |
322 | }) |
323 | .unwrap_or_else(|| { |
324 | for buffer in list.iter() { |
325 | self.render(&from_glib_borrow(buffer.as_ptr()))?; |
326 | } |
327 | Ok(gst::FlowSuccess::Ok) |
328 | }) |
329 | } |
330 | } |
331 | |
332 | fn parent_prepare_list( |
333 | &self, |
334 | list: &gst::BufferList, |
335 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
336 | unsafe { |
337 | let data = Self::type_data(); |
338 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSinkClass; |
339 | (*parent_class) |
340 | .prepare_list |
341 | .map(|f| { |
342 | try_from_glib(f( |
343 | self.obj().unsafe_cast_ref::<BaseSink>().to_glib_none().0, |
344 | list.to_glib_none().0, |
345 | )) |
346 | }) |
347 | .unwrap_or_else(|| { |
348 | for buffer in list.iter() { |
349 | self.prepare(&from_glib_borrow(buffer.as_ptr()))?; |
350 | } |
351 | Ok(gst::FlowSuccess::Ok) |
352 | }) |
353 | } |
354 | } |
355 | } |
356 | |
357 | unsafe impl<T: BaseSinkImpl> IsSubclassable<T> for BaseSink { |
358 | fn class_init(klass: &mut glib::Class<Self>) { |
359 | Self::parent_class_init::<T>(class:klass); |
360 | let klass: &mut GstBaseSinkClass = klass.as_mut(); |
361 | klass.start = Some(base_sink_start::<T>); |
362 | klass.stop = Some(base_sink_stop::<T>); |
363 | klass.render = Some(base_sink_render::<T>); |
364 | klass.render_list = Some(base_sink_render_list::<T>); |
365 | klass.prepare = Some(base_sink_prepare::<T>); |
366 | klass.prepare_list = Some(base_sink_prepare_list::<T>); |
367 | klass.query = Some(base_sink_query::<T>); |
368 | klass.event = Some(base_sink_event::<T>); |
369 | klass.get_caps = Some(base_sink_get_caps::<T>); |
370 | klass.set_caps = Some(base_sink_set_caps::<T>); |
371 | klass.fixate = Some(base_sink_fixate::<T>); |
372 | klass.unlock = Some(base_sink_unlock::<T>); |
373 | klass.unlock_stop = Some(base_sink_unlock_stop::<T>); |
374 | klass.propose_allocation = Some(base_sink_propose_allocation::<T>); |
375 | } |
376 | } |
377 | |
378 | unsafe extern "C" fn base_sink_start<T: BaseSinkImpl>( |
379 | ptr: *mut ffi::GstBaseSink, |
380 | ) -> glib::ffi::gboolean { |
381 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
382 | let imp: &T = instance.imp(); |
383 | |
384 | gstbool::panic_to_error!(imp, false, { |
385 | match imp.start() { |
386 | Ok(()) => true, |
387 | Err(err) => { |
388 | imp.post_error_message(err); |
389 | false |
390 | } |
391 | } |
392 | }) |
393 | .into_glib() |
394 | } |
395 | |
396 | unsafe extern "C" fn base_sink_stop<T: BaseSinkImpl>( |
397 | ptr: *mut ffi::GstBaseSink, |
398 | ) -> glib::ffi::gboolean { |
399 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
400 | let imp: &T = instance.imp(); |
401 | |
402 | gstbool::panic_to_error!(imp, false, { |
403 | match imp.stop() { |
404 | Ok(()) => true, |
405 | Err(err) => { |
406 | imp.post_error_message(err); |
407 | false |
408 | } |
409 | } |
410 | }) |
411 | .into_glib() |
412 | } |
413 | |
414 | unsafe extern "C" fn base_sink_render<T: BaseSinkImpl>( |
415 | ptr: *mut ffi::GstBaseSink, |
416 | buffer: *mut gst::ffi::GstBuffer, |
417 | ) -> gst::ffi::GstFlowReturn { |
418 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
419 | let imp: &T = instance.imp(); |
420 | let buffer: Borrowed = from_glib_borrow(ptr:buffer); |
421 | |
422 | gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.render(&buffer).into() }).into_glib() |
423 | } |
424 | |
425 | unsafe extern "C" fn base_sink_prepare<T: BaseSinkImpl>( |
426 | ptr: *mut ffi::GstBaseSink, |
427 | buffer: *mut gst::ffi::GstBuffer, |
428 | ) -> gst::ffi::GstFlowReturn { |
429 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
430 | let imp: &T = instance.imp(); |
431 | let buffer: Borrowed = from_glib_borrow(ptr:buffer); |
432 | |
433 | gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.prepare(&buffer).into() }).into_glib() |
434 | } |
435 | |
436 | unsafe extern "C" fn base_sink_render_list<T: BaseSinkImpl>( |
437 | ptr: *mut ffi::GstBaseSink, |
438 | list: *mut gst::ffi::GstBufferList, |
439 | ) -> gst::ffi::GstFlowReturn { |
440 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
441 | let imp: &T = instance.imp(); |
442 | let list: Borrowed = from_glib_borrow(ptr:list); |
443 | |
444 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
445 | imp.render_list(&list).into() |
446 | }) |
447 | .into_glib() |
448 | } |
449 | |
450 | unsafe extern "C" fn base_sink_prepare_list<T: BaseSinkImpl>( |
451 | ptr: *mut ffi::GstBaseSink, |
452 | list: *mut gst::ffi::GstBufferList, |
453 | ) -> gst::ffi::GstFlowReturn { |
454 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
455 | let imp: &T = instance.imp(); |
456 | let list: Borrowed = from_glib_borrow(ptr:list); |
457 | |
458 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
459 | imp.prepare_list(&list).into() |
460 | }) |
461 | .into_glib() |
462 | } |
463 | |
464 | unsafe extern "C" fn base_sink_query<T: BaseSinkImpl>( |
465 | ptr: *mut ffi::GstBaseSink, |
466 | query_ptr: *mut gst::ffi::GstQuery, |
467 | ) -> glib::ffi::gboolean { |
468 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
469 | let imp: &T = instance.imp(); |
470 | let query: &mut QueryRef = gst::QueryRef::from_mut_ptr(query_ptr); |
471 | |
472 | gst::panic_to_error!(imp, false, { BaseSinkImpl::query(imp, query) }).into_glib() |
473 | } |
474 | |
475 | unsafe extern "C" fn base_sink_event<T: BaseSinkImpl>( |
476 | ptr: *mut ffi::GstBaseSink, |
477 | event_ptr: *mut gst::ffi::GstEvent, |
478 | ) -> glib::ffi::gboolean { |
479 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
480 | let imp: &T = instance.imp(); |
481 | |
482 | gst::panic_to_error!(imp, false, { imp.event(from_glib_full(event_ptr)) }).into_glib() |
483 | } |
484 | |
485 | unsafe extern "C" fn base_sink_get_caps<T: BaseSinkImpl>( |
486 | ptr: *mut ffi::GstBaseSink, |
487 | filter: *mut gst::ffi::GstCaps, |
488 | ) -> *mut gst::ffi::GstCaps { |
489 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
490 | let imp: &T = instance.imp(); |
491 | let filter: Borrowed = Option::<gst::Caps>::from_glib_borrow(_ptr:filter); |
492 | |
493 | gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) }) |
494 | .map(|caps| caps.into_glib_ptr()) |
495 | .unwrap_or(default:ptr::null_mut()) |
496 | } |
497 | |
498 | unsafe extern "C" fn base_sink_set_caps<T: BaseSinkImpl>( |
499 | ptr: *mut ffi::GstBaseSink, |
500 | caps: *mut gst::ffi::GstCaps, |
501 | ) -> glib::ffi::gboolean { |
502 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
503 | let imp: &T = instance.imp(); |
504 | let caps: Borrowed = from_glib_borrow(ptr:caps); |
505 | |
506 | gstbool::panic_to_error!(imp, false, { |
507 | match imp.set_caps(&caps) { |
508 | Ok(()) => true, |
509 | Err(err) => { |
510 | err.log_with_imp(imp); |
511 | false |
512 | } |
513 | } |
514 | }) |
515 | .into_glib() |
516 | } |
517 | |
518 | unsafe extern "C" fn base_sink_fixate<T: BaseSinkImpl>( |
519 | ptr: *mut ffi::GstBaseSink, |
520 | caps: *mut gst::ffi::GstCaps, |
521 | ) -> *mut gst::ffi::GstCaps { |
522 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
523 | let imp: &T = instance.imp(); |
524 | let caps: Caps = from_glib_full(ptr:caps); |
525 | |
526 | gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr() |
527 | } |
528 | |
529 | unsafe extern "C" fn base_sink_unlock<T: BaseSinkImpl>( |
530 | ptr: *mut ffi::GstBaseSink, |
531 | ) -> glib::ffi::gboolean { |
532 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
533 | let imp: &T = instance.imp(); |
534 | |
535 | gstbool::panic_to_error!(imp, false, { |
536 | match imp.unlock() { |
537 | Ok(()) => true, |
538 | Err(err) => { |
539 | imp.post_error_message(err); |
540 | false |
541 | } |
542 | } |
543 | }) |
544 | .into_glib() |
545 | } |
546 | |
547 | unsafe extern "C" fn base_sink_unlock_stop<T: BaseSinkImpl>( |
548 | ptr: *mut ffi::GstBaseSink, |
549 | ) -> glib::ffi::gboolean { |
550 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
551 | let imp: &T = instance.imp(); |
552 | |
553 | gstbool::panic_to_error!(imp, false, { |
554 | match imp.unlock_stop() { |
555 | Ok(()) => true, |
556 | Err(err) => { |
557 | imp.post_error_message(err); |
558 | false |
559 | } |
560 | } |
561 | }) |
562 | .into_glib() |
563 | } |
564 | |
565 | unsafe extern "C" fn base_sink_propose_allocation<T: BaseSinkImpl>( |
566 | ptr: *mut ffi::GstBaseSink, |
567 | query: *mut gst::ffi::GstQuery, |
568 | ) -> glib::ffi::gboolean { |
569 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
570 | let imp: &T = instance.imp(); |
571 | let query: &mut Allocation = match gst::QueryRef::from_mut_ptr(query).view_mut() { |
572 | gst::QueryViewMut::Allocation(allocation: &mut Allocation) => allocation, |
573 | _ => unreachable!(), |
574 | }; |
575 | |
576 | gstbool::panic_to_error!(imp, false, { |
577 | match imp.propose_allocation(query) { |
578 | Ok(()) => true, |
579 | Err(err) => { |
580 | err.log_with_imp(imp); |
581 | false |
582 | } |
583 | } |
584 | }) |
585 | .into_glib() |
586 | } |
587 | |