1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, translate::*};
6use gst::subclass::prelude::*;
7
8use crate::BaseSink;
9
10pub 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
71mod sealed {
72 pub trait Sealed {}
73 impl<T: super::BaseSinkImplExt> Sealed for T {}
74}
75
76pub 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
307impl<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
357unsafe 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
378unsafe 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
396unsafe 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
414unsafe 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
425unsafe 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
436unsafe 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
450unsafe 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
464unsafe 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
475unsafe 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
485unsafe 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
498unsafe 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
518unsafe 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
529unsafe 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
547unsafe 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
565unsafe 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