Skip to main content

gstreamer_video/subclass/
video_encoder.rs

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    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}