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