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    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>(klass);
446        let klass = 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 = &*(ptr as *mut T::Instance);
470    let imp = instance.imp();
471
472    gst::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 = &*(ptr as *mut T::Instance);
488    let imp = instance.imp();
489
490    gst::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 = &*(ptr as *mut T::Instance);
506    let imp = instance.imp();
507
508    gst::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 = &*(ptr as *mut T::Instance);
524    let imp = instance.imp();
525
526    gst::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 = &*(ptr as *mut T::Instance);
542    let imp = 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 = &*(ptr as *mut T::Instance);
552    let imp = instance.imp();
553    ffi::gst_video_codec_state_ref(state);
554    let wrap_state = VideoCodecState::<Readable>::new(state);
555
556    gst::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 = &*(ptr as *mut T::Instance);
573    let imp = instance.imp();
574    let instance = imp.obj();
575    let instance = instance.unsafe_cast_ref::<VideoEncoder>();
576    let wrap_frame = VideoCodecFrame::new(frame, instance);
577
578    gst::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 = &*(ptr as *mut T::Instance);
588    let imp = 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 = &*(ptr as *mut T::Instance);
597    let imp = instance.imp();
598
599    gst::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 = &*(ptr as *mut T::Instance);
616    let imp = instance.imp();
617
618    gst::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 = &*(ptr as *mut T::Instance);
634    let imp = 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 = &*(ptr as *mut T::Instance);
644    let imp = instance.imp();
645
646    gst::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 = &*(ptr as *mut T::Instance);
657    let imp = 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 = &*(ptr as *mut T::Instance);
667    let imp = instance.imp();
668
669    gst::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 = &*(ptr as *mut T::Instance);
680    let imp = instance.imp();
681    let query = match gst::QueryRef::from_mut_ptr(query).view_mut() {
682        gst::QueryViewMut::Allocation(allocation) => allocation,
683        _ => unreachable!(),
684    };
685
686    gst::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 = &*(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.decide_allocation(query) {
711            Ok(()) => true,
712            Err(err) => {
713                err.log_with_imp(imp);
714                false
715            }
716        }
717    })
718    .into_glib()
719}