1use std::ptr;
4
5use glib::{prelude::*, translate::*};
6use gst::subclass::prelude::*;
7
8use crate::{ffi, BaseSink};
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 let instance = &*(ptr as *mut T::Instance);
401 let imp = instance.imp();
402
403 gst::panic_to_error!(imp, false, {
404 match imp.start() {
405 Ok(()) => true,
406 Err(err) => {
407 imp.post_error_message(err);
408 false
409 }
410 }
411 })
412 .into_glib()
413}
414
415unsafe extern "C" fn base_sink_stop<T: BaseSinkImpl>(
416 ptr: *mut ffi::GstBaseSink,
417) -> glib::ffi::gboolean {
418 let instance = &*(ptr as *mut T::Instance);
419 let imp = instance.imp();
420
421 gst::panic_to_error!(imp, false, {
422 match imp.stop() {
423 Ok(()) => true,
424 Err(err) => {
425 imp.post_error_message(err);
426 false
427 }
428 }
429 })
430 .into_glib()
431}
432
433unsafe extern "C" fn base_sink_render<T: BaseSinkImpl>(
434 ptr: *mut ffi::GstBaseSink,
435 buffer: *mut gst::ffi::GstBuffer,
436) -> gst::ffi::GstFlowReturn {
437 let instance = &*(ptr as *mut T::Instance);
438 let imp = instance.imp();
439 let buffer = from_glib_borrow(buffer);
440
441 gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.render(&buffer).into() }).into_glib()
442}
443
444unsafe extern "C" fn base_sink_prepare<T: BaseSinkImpl>(
445 ptr: *mut ffi::GstBaseSink,
446 buffer: *mut gst::ffi::GstBuffer,
447) -> gst::ffi::GstFlowReturn {
448 let instance = &*(ptr as *mut T::Instance);
449 let imp = instance.imp();
450 let buffer = from_glib_borrow(buffer);
451
452 gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.prepare(&buffer).into() }).into_glib()
453}
454
455unsafe extern "C" fn base_sink_render_list<T: BaseSinkImpl>(
456 ptr: *mut ffi::GstBaseSink,
457 list: *mut gst::ffi::GstBufferList,
458) -> gst::ffi::GstFlowReturn {
459 let instance = &*(ptr as *mut T::Instance);
460 let imp = instance.imp();
461 let list = from_glib_borrow(list);
462
463 gst::panic_to_error!(imp, gst::FlowReturn::Error, {
464 imp.render_list(&list).into()
465 })
466 .into_glib()
467}
468
469unsafe extern "C" fn base_sink_prepare_list<T: BaseSinkImpl>(
470 ptr: *mut ffi::GstBaseSink,
471 list: *mut gst::ffi::GstBufferList,
472) -> gst::ffi::GstFlowReturn {
473 let instance = &*(ptr as *mut T::Instance);
474 let imp = instance.imp();
475 let list = from_glib_borrow(list);
476
477 gst::panic_to_error!(imp, gst::FlowReturn::Error, {
478 imp.prepare_list(&list).into()
479 })
480 .into_glib()
481}
482
483unsafe extern "C" fn base_sink_query<T: BaseSinkImpl>(
484 ptr: *mut ffi::GstBaseSink,
485 query_ptr: *mut gst::ffi::GstQuery,
486) -> glib::ffi::gboolean {
487 let instance = &*(ptr as *mut T::Instance);
488 let imp = instance.imp();
489 let query = gst::QueryRef::from_mut_ptr(query_ptr);
490
491 gst::panic_to_error!(imp, false, { BaseSinkImpl::query(imp, query) }).into_glib()
492}
493
494unsafe extern "C" fn base_sink_event<T: BaseSinkImpl>(
495 ptr: *mut ffi::GstBaseSink,
496 event_ptr: *mut gst::ffi::GstEvent,
497) -> glib::ffi::gboolean {
498 let instance = &*(ptr as *mut T::Instance);
499 let imp = instance.imp();
500
501 gst::panic_to_error!(imp, false, { imp.event(from_glib_full(event_ptr)) }).into_glib()
502}
503
504unsafe extern "C" fn base_sink_get_caps<T: BaseSinkImpl>(
505 ptr: *mut ffi::GstBaseSink,
506 filter: *mut gst::ffi::GstCaps,
507) -> *mut gst::ffi::GstCaps {
508 let instance = &*(ptr as *mut T::Instance);
509 let imp = instance.imp();
510 let filter = Option::<gst::Caps>::from_glib_borrow(filter);
511
512 gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) })
513 .map(|caps| caps.into_glib_ptr())
514 .unwrap_or(ptr::null_mut())
515}
516
517unsafe extern "C" fn base_sink_set_caps<T: BaseSinkImpl>(
518 ptr: *mut ffi::GstBaseSink,
519 caps: *mut gst::ffi::GstCaps,
520) -> glib::ffi::gboolean {
521 let instance = &*(ptr as *mut T::Instance);
522 let imp = instance.imp();
523 let caps = from_glib_borrow(caps);
524
525 gst::panic_to_error!(imp, false, {
526 match imp.set_caps(&caps) {
527 Ok(()) => true,
528 Err(err) => {
529 err.log_with_imp(imp);
530 false
531 }
532 }
533 })
534 .into_glib()
535}
536
537unsafe extern "C" fn base_sink_fixate<T: BaseSinkImpl>(
538 ptr: *mut ffi::GstBaseSink,
539 caps: *mut gst::ffi::GstCaps,
540) -> *mut gst::ffi::GstCaps {
541 let instance = &*(ptr as *mut T::Instance);
542 let imp = instance.imp();
543 let caps = from_glib_full(caps);
544
545 gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr()
546}
547
548unsafe extern "C" fn base_sink_unlock<T: BaseSinkImpl>(
549 ptr: *mut ffi::GstBaseSink,
550) -> glib::ffi::gboolean {
551 let instance = &*(ptr as *mut T::Instance);
552 let imp = instance.imp();
553
554 gst::panic_to_error!(imp, false, {
555 match imp.unlock() {
556 Ok(()) => true,
557 Err(err) => {
558 imp.post_error_message(err);
559 false
560 }
561 }
562 })
563 .into_glib()
564}
565
566unsafe extern "C" fn base_sink_unlock_stop<T: BaseSinkImpl>(
567 ptr: *mut ffi::GstBaseSink,
568) -> glib::ffi::gboolean {
569 let instance = &*(ptr as *mut T::Instance);
570 let imp = instance.imp();
571
572 gst::panic_to_error!(imp, false, {
573 match imp.unlock_stop() {
574 Ok(()) => true,
575 Err(err) => {
576 imp.post_error_message(err);
577 false
578 }
579 }
580 })
581 .into_glib()
582}
583
584unsafe extern "C" fn base_sink_propose_allocation<T: BaseSinkImpl>(
585 ptr: *mut ffi::GstBaseSink,
586 query: *mut gst::ffi::GstQuery,
587) -> glib::ffi::gboolean {
588 let instance = &*(ptr as *mut T::Instance);
589 let imp = instance.imp();
590 let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
591 gst::QueryViewMut::Allocation(allocation) => allocation,
592 _ => unreachable!(),
593 };
594
595 gst::panic_to_error!(imp, false, {
596 match imp.propose_allocation(query) {
597 Ok(()) => true,
598 Err(err) => {
599 err.log_with_imp_and_level(imp, gst::DebugLevel::Info);
600 false
601 }
602 }
603 })
604 .into_glib()
605}