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