1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4use gst::subclass::prelude::*;
5
6use crate::{
7 ffi,
8 prelude::*,
9 video_codec_state::{Readable, VideoCodecState},
10 VideoCodecFrame, VideoEncoder,
11};
12
13pub trait VideoEncoderImpl: VideoEncoderImplExt + ElementImpl {
14 fn open(&self) -> Result<(), gst::ErrorMessage> {
15 self.parent_open()
16 }
17
18 fn close(&self) -> Result<(), gst::ErrorMessage> {
19 self.parent_close()
20 }
21
22 fn start(&self) -> Result<(), gst::ErrorMessage> {
23 self.parent_start()
24 }
25
26 fn stop(&self) -> Result<(), gst::ErrorMessage> {
27 self.parent_stop()
28 }
29
30 fn finish(&self) -> Result<gst::FlowSuccess, gst::FlowError> {
31 self.parent_finish()
32 }
33
34 fn set_format(
35 &self,
36 state: &VideoCodecState<'static, Readable>,
37 ) -> Result<(), gst::LoggableError> {
38 self.parent_set_format(state)
39 }
40
41 fn handle_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> {
42 self.parent_handle_frame(frame)
43 }
44
45 fn flush(&self) -> bool {
46 self.parent_flush()
47 }
48
49 fn negotiate(&self) -> Result<(), gst::LoggableError> {
50 self.parent_negotiate()
51 }
52
53 fn caps(&self, filter: Option<&gst::Caps>) -> gst::Caps {
54 self.parent_caps(filter)
55 }
56
57 fn sink_event(&self, event: gst::Event) -> bool {
58 self.parent_sink_event(event)
59 }
60
61 fn sink_query(&self, query: &mut gst::QueryRef) -> bool {
62 self.parent_sink_query(query)
63 }
64
65 fn src_event(&self, event: gst::Event) -> bool {
66 self.parent_src_event(event)
67 }
68
69 fn src_query(&self, query: &mut gst::QueryRef) -> bool {
70 self.parent_src_query(query)
71 }
72
73 fn propose_allocation(
74 &self,
75 query: &mut gst::query::Allocation,
76 ) -> Result<(), gst::LoggableError> {
77 self.parent_propose_allocation(query)
78 }
79
80 fn decide_allocation(
81 &self,
82 query: &mut gst::query::Allocation,
83 ) -> Result<(), gst::LoggableError> {
84 self.parent_decide_allocation(query)
85 }
86}
87
88mod sealed {
89 pub trait Sealed {}
90 impl<T: super::VideoEncoderImplExt> Sealed for T {}
91}
92
93pub trait VideoEncoderImplExt: sealed::Sealed + ObjectSubclass {
94 fn parent_open(&self) -> Result<(), gst::ErrorMessage> {
95 unsafe {
96 let data = Self::type_data();
97 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
98 (*parent_class)
99 .open
100 .map(|f| {
101 if from_glib(f(self
102 .obj()
103 .unsafe_cast_ref::<VideoEncoder>()
104 .to_glib_none()
105 .0))
106 {
107 Ok(())
108 } else {
109 Err(gst::error_msg!(
110 gst::CoreError::StateChange,
111 ["Parent function `open` failed"]
112 ))
113 }
114 })
115 .unwrap_or(Ok(()))
116 }
117 }
118
119 fn parent_close(&self) -> Result<(), gst::ErrorMessage> {
120 unsafe {
121 let data = Self::type_data();
122 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
123 (*parent_class)
124 .close
125 .map(|f| {
126 if from_glib(f(self
127 .obj()
128 .unsafe_cast_ref::<VideoEncoder>()
129 .to_glib_none()
130 .0))
131 {
132 Ok(())
133 } else {
134 Err(gst::error_msg!(
135 gst::CoreError::StateChange,
136 ["Parent function `close` failed"]
137 ))
138 }
139 })
140 .unwrap_or(Ok(()))
141 }
142 }
143
144 fn parent_start(&self) -> Result<(), gst::ErrorMessage> {
145 unsafe {
146 let data = Self::type_data();
147 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
148 (*parent_class)
149 .start
150 .map(|f| {
151 if from_glib(f(self
152 .obj()
153 .unsafe_cast_ref::<VideoEncoder>()
154 .to_glib_none()
155 .0))
156 {
157 Ok(())
158 } else {
159 Err(gst::error_msg!(
160 gst::CoreError::StateChange,
161 ["Parent function `start` failed"]
162 ))
163 }
164 })
165 .unwrap_or(Ok(()))
166 }
167 }
168
169 fn parent_stop(&self) -> Result<(), gst::ErrorMessage> {
170 unsafe {
171 let data = Self::type_data();
172 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
173 (*parent_class)
174 .stop
175 .map(|f| {
176 if from_glib(f(self
177 .obj()
178 .unsafe_cast_ref::<VideoEncoder>()
179 .to_glib_none()
180 .0))
181 {
182 Ok(())
183 } else {
184 Err(gst::error_msg!(
185 gst::CoreError::StateChange,
186 ["Parent function `stop` failed"]
187 ))
188 }
189 })
190 .unwrap_or(Ok(()))
191 }
192 }
193
194 fn parent_finish(&self) -> Result<gst::FlowSuccess, gst::FlowError> {
195 unsafe {
196 let data = Self::type_data();
197 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
198 (*parent_class)
199 .finish
200 .map(|f| {
201 try_from_glib(f(self
202 .obj()
203 .unsafe_cast_ref::<VideoEncoder>()
204 .to_glib_none()
205 .0))
206 })
207 .unwrap_or(Ok(gst::FlowSuccess::Ok))
208 }
209 }
210
211 fn parent_set_format(
212 &self,
213 state: &VideoCodecState<'static, Readable>,
214 ) -> Result<(), gst::LoggableError> {
215 unsafe {
216 let data = Self::type_data();
217 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
218 (*parent_class)
219 .set_format
220 .map(|f| {
221 gst::result_from_gboolean!(
222 f(
223 self.obj()
224 .unsafe_cast_ref::<VideoEncoder>()
225 .to_glib_none()
226 .0,
227 state.as_mut_ptr()
228 ),
229 gst::CAT_RUST,
230 "parent function `set_format` failed"
231 )
232 })
233 .unwrap_or(Ok(()))
234 }
235 }
236
237 fn parent_handle_frame(
238 &self,
239 frame: VideoCodecFrame,
240 ) -> Result<gst::FlowSuccess, gst::FlowError> {
241 unsafe {
242 let data = Self::type_data();
243 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
244 (*parent_class)
245 .handle_frame
246 .map(|f| {
247 try_from_glib(f(
248 self.obj()
249 .unsafe_cast_ref::<VideoEncoder>()
250 .to_glib_none()
251 .0,
252 frame.to_glib_none().0,
253 ))
254 })
255 .unwrap_or(Err(gst::FlowError::Error))
256 }
257 }
258
259 fn parent_flush(&self) -> bool {
260 unsafe {
261 let data = Self::type_data();
262 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
263 (*parent_class)
264 .flush
265 .map(|f| {
266 from_glib(f(self
267 .obj()
268 .unsafe_cast_ref::<VideoEncoder>()
269 .to_glib_none()
270 .0))
271 })
272 .unwrap_or(false)
273 }
274 }
275
276 fn parent_negotiate(&self) -> Result<(), gst::LoggableError> {
277 unsafe {
278 let data = Self::type_data();
279 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
280 (*parent_class)
281 .negotiate
282 .map(|f| {
283 gst::result_from_gboolean!(
284 f(self
285 .obj()
286 .unsafe_cast_ref::<VideoEncoder>()
287 .to_glib_none()
288 .0),
289 gst::CAT_RUST,
290 "Parent function `negotiate` failed"
291 )
292 })
293 .unwrap_or(Ok(()))
294 }
295 }
296
297 fn parent_caps(&self, filter: Option<&gst::Caps>) -> gst::Caps {
298 unsafe {
299 let data = Self::type_data();
300 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
301 (*parent_class)
302 .getcaps
303 .map(|f| {
304 from_glib_full(f(
305 self.obj()
306 .unsafe_cast_ref::<VideoEncoder>()
307 .to_glib_none()
308 .0,
309 filter.to_glib_none().0,
310 ))
311 })
312 .unwrap_or_else(|| {
313 self.obj()
314 .unsafe_cast_ref::<VideoEncoder>()
315 .proxy_getcaps(None, filter)
316 })
317 }
318 }
319
320 fn parent_sink_event(&self, event: gst::Event) -> bool {
321 unsafe {
322 let data = Self::type_data();
323 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
324 let f = (*parent_class)
325 .sink_event
326 .expect("Missing parent function `sink_event`");
327 from_glib(f(
328 self.obj()
329 .unsafe_cast_ref::<VideoEncoder>()
330 .to_glib_none()
331 .0,
332 event.into_glib_ptr(),
333 ))
334 }
335 }
336
337 fn parent_sink_query(&self, query: &mut gst::QueryRef) -> bool {
338 unsafe {
339 let data = Self::type_data();
340 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
341 let f = (*parent_class)
342 .sink_query
343 .expect("Missing parent function `sink_query`");
344 from_glib(f(
345 self.obj()
346 .unsafe_cast_ref::<VideoEncoder>()
347 .to_glib_none()
348 .0,
349 query.as_mut_ptr(),
350 ))
351 }
352 }
353
354 fn parent_src_event(&self, event: gst::Event) -> bool {
355 unsafe {
356 let data = Self::type_data();
357 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
358 let f = (*parent_class)
359 .src_event
360 .expect("Missing parent function `src_event`");
361 from_glib(f(
362 self.obj()
363 .unsafe_cast_ref::<VideoEncoder>()
364 .to_glib_none()
365 .0,
366 event.into_glib_ptr(),
367 ))
368 }
369 }
370
371 fn parent_src_query(&self, query: &mut gst::QueryRef) -> bool {
372 unsafe {
373 let data = Self::type_data();
374 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
375 let f = (*parent_class)
376 .src_query
377 .expect("Missing parent function `src_query`");
378 from_glib(f(
379 self.obj()
380 .unsafe_cast_ref::<VideoEncoder>()
381 .to_glib_none()
382 .0,
383 query.as_mut_ptr(),
384 ))
385 }
386 }
387
388 fn parent_propose_allocation(
389 &self,
390 query: &mut gst::query::Allocation,
391 ) -> Result<(), gst::LoggableError> {
392 unsafe {
393 let data = Self::type_data();
394 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
395 (*parent_class)
396 .propose_allocation
397 .map(|f| {
398 gst::result_from_gboolean!(
399 f(
400 self.obj()
401 .unsafe_cast_ref::<VideoEncoder>()
402 .to_glib_none()
403 .0,
404 query.as_mut_ptr(),
405 ),
406 gst::CAT_RUST,
407 "Parent function `propose_allocation` failed",
408 )
409 })
410 .unwrap_or(Ok(()))
411 }
412 }
413
414 fn parent_decide_allocation(
415 &self,
416 query: &mut gst::query::Allocation,
417 ) -> Result<(), gst::LoggableError> {
418 unsafe {
419 let data = Self::type_data();
420 let parent_class = data.as_ref().parent_class() as *mut ffi::GstVideoEncoderClass;
421 (*parent_class)
422 .decide_allocation
423 .map(|f| {
424 gst::result_from_gboolean!(
425 f(
426 self.obj()
427 .unsafe_cast_ref::<VideoEncoder>()
428 .to_glib_none()
429 .0,
430 query.as_mut_ptr(),
431 ),
432 gst::CAT_RUST,
433 "Parent function `decide_allocation` failed",
434 )
435 })
436 .unwrap_or(Ok(()))
437 }
438 }
439}
440
441impl<T: VideoEncoderImpl> VideoEncoderImplExt for T {}
442
443unsafe impl<T: VideoEncoderImpl> IsSubclassable<T> for VideoEncoder {
444 fn class_init(klass: &mut glib::Class<Self>) {
445 Self::parent_class_init::<T>(class:klass);
446 let klass: &mut GstVideoEncoderClass = klass.as_mut();
447 klass.open = Some(video_encoder_open::<T>);
448 klass.close = Some(video_encoder_close::<T>);
449 klass.start = Some(video_encoder_start::<T>);
450 klass.stop = Some(video_encoder_stop::<T>);
451 klass.finish = Some(video_encoder_finish::<T>);
452 klass.set_format = Some(video_encoder_set_format::<T>);
453 klass.handle_frame = Some(video_encoder_handle_frame::<T>);
454 klass.flush = Some(video_encoder_flush::<T>);
455 klass.negotiate = Some(video_encoder_negotiate::<T>);
456 klass.getcaps = Some(video_encoder_getcaps::<T>);
457 klass.sink_event = Some(video_encoder_sink_event::<T>);
458 klass.src_event = Some(video_encoder_src_event::<T>);
459 klass.sink_query = Some(video_encoder_sink_query::<T>);
460 klass.src_query = Some(video_encoder_src_query::<T>);
461 klass.propose_allocation = Some(video_encoder_propose_allocation::<T>);
462 klass.decide_allocation = Some(video_encoder_decide_allocation::<T>);
463 }
464}
465
466unsafe extern "C" fn video_encoder_open<T: VideoEncoderImpl>(
467 ptr: *mut ffi::GstVideoEncoder,
468) -> glib::ffi::gboolean {
469 let instance: &::Instance = &*(ptr as *mut T::Instance);
470 let imp: &T = instance.imp();
471
472 gstbool::panic_to_error!(imp, false, {
473 match imp.open() {
474 Ok(()) => true,
475 Err(err) => {
476 imp.post_error_message(err);
477 false
478 }
479 }
480 })
481 .into_glib()
482}
483
484unsafe extern "C" fn video_encoder_close<T: VideoEncoderImpl>(
485 ptr: *mut ffi::GstVideoEncoder,
486) -> glib::ffi::gboolean {
487 let instance: &::Instance = &*(ptr as *mut T::Instance);
488 let imp: &T = instance.imp();
489
490 gstbool::panic_to_error!(imp, false, {
491 match imp.close() {
492 Ok(()) => true,
493 Err(err) => {
494 imp.post_error_message(err);
495 false
496 }
497 }
498 })
499 .into_glib()
500}
501
502unsafe extern "C" fn video_encoder_start<T: VideoEncoderImpl>(
503 ptr: *mut ffi::GstVideoEncoder,
504) -> glib::ffi::gboolean {
505 let instance: &::Instance = &*(ptr as *mut T::Instance);
506 let imp: &T = instance.imp();
507
508 gstbool::panic_to_error!(imp, false, {
509 match imp.start() {
510 Ok(()) => true,
511 Err(err) => {
512 imp.post_error_message(err);
513 false
514 }
515 }
516 })
517 .into_glib()
518}
519
520unsafe extern "C" fn video_encoder_stop<T: VideoEncoderImpl>(
521 ptr: *mut ffi::GstVideoEncoder,
522) -> glib::ffi::gboolean {
523 let instance: &::Instance = &*(ptr as *mut T::Instance);
524 let imp: &T = instance.imp();
525
526 gstbool::panic_to_error!(imp, false, {
527 match imp.stop() {
528 Ok(()) => true,
529 Err(err) => {
530 imp.post_error_message(err);
531 false
532 }
533 }
534 })
535 .into_glib()
536}
537
538unsafe extern "C" fn video_encoder_finish<T: VideoEncoderImpl>(
539 ptr: *mut ffi::GstVideoEncoder,
540) -> gst::ffi::GstFlowReturn {
541 let instance: &::Instance = &*(ptr as *mut T::Instance);
542 let imp: &T = instance.imp();
543
544 gst::panic_to_error!(imp, gst::FlowReturn::Error, { imp.finish().into() }).into_glib()
545}
546
547unsafe extern "C" fn video_encoder_set_format<T: VideoEncoderImpl>(
548 ptr: *mut ffi::GstVideoEncoder,
549 state: *mut ffi::GstVideoCodecState,
550) -> glib::ffi::gboolean {
551 let instance: &::Instance = &*(ptr as *mut T::Instance);
552 let imp: &T = instance.imp();
553 ffi::gst_video_codec_state_ref(state);
554 let wrap_state: VideoCodecState<'_, Readable> = VideoCodecState::<Readable>::new(state);
555
556 gstbool::panic_to_error!(imp, false, {
557 match imp.set_format(&wrap_state) {
558 Ok(()) => true,
559 Err(err) => {
560 err.log_with_imp(imp);
561 false
562 }
563 }
564 })
565 .into_glib()
566}
567
568unsafe extern "C" fn video_encoder_handle_frame<T: VideoEncoderImpl>(
569 ptr: *mut ffi::GstVideoEncoder,
570 frame: *mut ffi::GstVideoCodecFrame,
571) -> gst::ffi::GstFlowReturn {
572 let instance: &::Instance = &*(ptr as *mut T::Instance);
573 let imp: &T = instance.imp();
574 let instance: BorrowedObject<'_, ::Type> = imp.obj();
575 let instance: &VideoEncoder = instance.unsafe_cast_ref::<VideoEncoder>();
576 let wrap_frame: VideoCodecFrame<'_> = VideoCodecFrame::new(frame, element:instance);
577
578 gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, {
579 imp.handle_frame(wrap_frame).into()
580 })
581 .into_glib()
582}
583
584unsafe extern "C" fn video_encoder_flush<T: VideoEncoderImpl>(
585 ptr: *mut ffi::GstVideoEncoder,
586) -> glib::ffi::gboolean {
587 let instance: &::Instance = &*(ptr as *mut T::Instance);
588 let imp: &T = instance.imp();
589
590 gst::panic_to_error!(imp, false, { VideoEncoderImpl::flush(imp) }).into_glib()
591}
592
593unsafe extern "C" fn video_encoder_negotiate<T: VideoEncoderImpl>(
594 ptr: *mut ffi::GstVideoEncoder,
595) -> glib::ffi::gboolean {
596 let instance: &::Instance = &*(ptr as *mut T::Instance);
597 let imp: &T = instance.imp();
598
599 gstbool::panic_to_error!(imp, false, {
600 match imp.negotiate() {
601 Ok(()) => true,
602 Err(err) => {
603 err.log_with_imp(imp);
604 false
605 }
606 }
607 })
608 .into_glib()
609}
610
611unsafe extern "C" fn video_encoder_getcaps<T: VideoEncoderImpl>(
612 ptr: *mut ffi::GstVideoEncoder,
613 filter: *mut gst::ffi::GstCaps,
614) -> *mut gst::ffi::GstCaps {
615 let instance: &::Instance = &*(ptr as *mut T::Instance);
616 let imp: &T = instance.imp();
617
618 gstCaps::panic_to_error!(imp, gst::Caps::new_empty(), {
619 VideoEncoderImpl::caps(
620 imp,
621 Option::<gst::Caps>::from_glib_borrow(filter)
622 .as_ref()
623 .as_ref(),
624 )
625 })
626 .into_glib_ptr()
627}
628
629unsafe extern "C" fn video_encoder_sink_event<T: VideoEncoderImpl>(
630 ptr: *mut ffi::GstVideoEncoder,
631 event: *mut gst::ffi::GstEvent,
632) -> glib::ffi::gboolean {
633 let instance: &::Instance = &*(ptr as *mut T::Instance);
634 let imp: &T = instance.imp();
635
636 gst::panic_to_error!(imp, false, { imp.sink_event(from_glib_full(event)) }).into_glib()
637}
638
639unsafe extern "C" fn video_encoder_sink_query<T: VideoEncoderImpl>(
640 ptr: *mut ffi::GstVideoEncoder,
641 query: *mut gst::ffi::GstQuery,
642) -> glib::ffi::gboolean {
643 let instance: &::Instance = &*(ptr as *mut T::Instance);
644 let imp: &T = instance.imp();
645
646 gstbool::panic_to_error!(imp, false, {
647 imp.sink_query(gst::QueryRef::from_mut_ptr(query))
648 })
649 .into_glib()
650}
651
652unsafe extern "C" fn video_encoder_src_event<T: VideoEncoderImpl>(
653 ptr: *mut ffi::GstVideoEncoder,
654 event: *mut gst::ffi::GstEvent,
655) -> glib::ffi::gboolean {
656 let instance: &::Instance = &*(ptr as *mut T::Instance);
657 let imp: &T = instance.imp();
658
659 gst::panic_to_error!(imp, false, { imp.src_event(from_glib_full(event)) }).into_glib()
660}
661
662unsafe extern "C" fn video_encoder_src_query<T: VideoEncoderImpl>(
663 ptr: *mut ffi::GstVideoEncoder,
664 query: *mut gst::ffi::GstQuery,
665) -> glib::ffi::gboolean {
666 let instance: &::Instance = &*(ptr as *mut T::Instance);
667 let imp: &T = instance.imp();
668
669 gstbool::panic_to_error!(imp, false, {
670 imp.src_query(gst::QueryRef::from_mut_ptr(query))
671 })
672 .into_glib()
673}
674
675unsafe extern "C" fn video_encoder_propose_allocation<T: VideoEncoderImpl>(
676 ptr: *mut ffi::GstVideoEncoder,
677 query: *mut gst::ffi::GstQuery,
678) -> glib::ffi::gboolean {
679 let instance: &::Instance = &*(ptr as *mut T::Instance);
680 let imp: &T = instance.imp();
681 let query: &mut Allocation = match gst::QueryRef::from_mut_ptr(query).view_mut() {
682 gst::QueryViewMut::Allocation(allocation: &mut Allocation) => allocation,
683 _ => unreachable!(),
684 };
685
686 gstbool::panic_to_error!(imp, false, {
687 match imp.propose_allocation(query) {
688 Ok(()) => true,
689 Err(err) => {
690 err.log_with_imp(imp);
691 false
692 }
693 }
694 })
695 .into_glib()
696}
697
698unsafe extern "C" fn video_encoder_decide_allocation<T: VideoEncoderImpl>(
699 ptr: *mut ffi::GstVideoEncoder,
700 query: *mut gst::ffi::GstQuery,
701) -> glib::ffi::gboolean {
702 let instance: &::Instance = &*(ptr as *mut T::Instance);
703 let imp: &T = instance.imp();
704 let query: &mut Allocation = match gst::QueryRef::from_mut_ptr(query).view_mut() {
705 gst::QueryViewMut::Allocation(allocation: &mut Allocation) => allocation,
706 _ => unreachable!(),
707 };
708
709 gstbool::panic_to_error!(imp, false, {
710 match imp.decide_allocation(query) {
711 Ok(()) => true,
712 Err(err) => {
713 err.log_with_imp(imp);
714 false
715 }
716 }
717 })
718 .into_glib()
719}
720