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