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