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