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