// Copyright (C) 2019 Philippe Normand // Copyright (C) 2019 Guillaume Desmottes // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use glib_sys; use gst_sys; use gst_video_sys; use glib::translate::*; use glib::subclass::prelude::*; use gst; use gst::subclass::prelude::*; use gst::MiniObject; use video_codec_state::{Readable, VideoCodecState}; use VideoCodecFrame; use VideoEncoder; use VideoEncoderClass; pub trait VideoEncoderImpl: VideoEncoderImplExt + ElementImpl + Send + Sync + 'static { fn open(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { self.parent_open(element) } fn close(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { self.parent_close(element) } fn start(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { self.parent_start(element) } fn stop(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { self.parent_stop(element) } fn finish(&self, element: &VideoEncoder) -> Result { self.parent_finish(element) } fn set_format( &self, element: &VideoEncoder, state: &VideoCodecState, ) -> Result<(), gst::LoggableError> { self.parent_set_format(element, state) } fn handle_frame( &self, element: &VideoEncoder, frame: VideoCodecFrame, ) -> Result { self.parent_handle_frame(element, frame) } fn flush(&self, element: &VideoEncoder) -> bool { self.parent_flush(element) } fn propose_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { self.parent_propose_allocation(element, query) } fn decide_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { self.parent_decide_allocation(element, query) } } pub trait VideoEncoderImplExt { fn parent_open(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage>; fn parent_close(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage>; fn parent_start(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage>; fn parent_stop(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage>; fn parent_finish(&self, element: &VideoEncoder) -> Result; fn parent_set_format( &self, element: &VideoEncoder, state: &VideoCodecState, ) -> Result<(), gst::LoggableError>; fn parent_handle_frame( &self, element: &VideoEncoder, frame: VideoCodecFrame, ) -> Result; fn parent_flush(&self, element: &VideoEncoder) -> bool; fn parent_propose_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage>; fn parent_decide_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage>; } impl VideoEncoderImplExt for T { fn parent_open(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .open .map(|f| { if from_glib(f(element.to_glib_none().0)) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `open` failed"] )) } }) .unwrap_or(Ok(())) } } fn parent_close(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .close .map(|f| { if from_glib(f(element.to_glib_none().0)) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `close` failed"] )) } }) .unwrap_or(Ok(())) } } fn parent_start(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .start .map(|f| { if from_glib(f(element.to_glib_none().0)) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `start` failed"] )) } }) .unwrap_or(Ok(())) } } fn parent_stop(&self, element: &VideoEncoder) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .stop .map(|f| { if from_glib(f(element.to_glib_none().0)) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `stop` failed"] )) } }) .unwrap_or(Ok(())) } } fn parent_finish(&self, element: &VideoEncoder) -> Result { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .finish .map(|f| gst::FlowReturn::from_glib(f(element.to_glib_none().0))) .unwrap_or(gst::FlowReturn::Ok) .into_result() } } fn parent_set_format( &self, element: &VideoEncoder, state: &VideoCodecState, ) -> Result<(), gst::LoggableError> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .set_format .map(|f| { gst_result_from_gboolean!( f(element.to_glib_none().0, state.as_mut_ptr()), gst::CAT_RUST, "parent function `set_format` failed" ) }) .unwrap_or(Ok(())) } } fn parent_handle_frame( &self, element: &VideoEncoder, frame: VideoCodecFrame, ) -> Result { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .handle_frame .map(|f| { gst::FlowReturn::from_glib(f(element.to_glib_none().0, frame.to_glib_none().0)) }) .unwrap_or(gst::FlowReturn::Error) .into_result() } } fn parent_flush(&self, element: &VideoEncoder) -> bool { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .flush .map(|f| from_glib(f(element.to_glib_none().0))) .unwrap_or(false) } } fn parent_propose_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .propose_allocation .map(|f| { if from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `propose_allocation` failed"] )) } }) .unwrap_or(Ok(())) } } fn parent_decide_allocation( &self, element: &VideoEncoder, query: &mut gst::QueryRef, ) -> Result<(), gst::ErrorMessage> { unsafe { let data = self.get_type_data(); let parent_class = data.as_ref().get_parent_class() as *mut gst_video_sys::GstVideoEncoderClass; (*parent_class) .decide_allocation .map(|f| { if from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) { Ok(()) } else { Err(gst_error_msg!( gst::CoreError::StateChange, ["Parent function `decide_allocation` failed"] )) } }) .unwrap_or(Ok(())) } } } unsafe impl IsSubclassable for VideoEncoderClass where ::Instance: PanicPoison, { fn override_vfuncs(&mut self) { >::override_vfuncs(self); unsafe { let klass = &mut *(self as *mut Self as *mut gst_video_sys::GstVideoEncoderClass); klass.open = Some(video_encoder_open::); klass.close = Some(video_encoder_close::); klass.start = Some(video_encoder_start::); klass.stop = Some(video_encoder_stop::); klass.finish = Some(video_encoder_finish::); klass.set_format = Some(video_encoder_set_format::); klass.handle_frame = Some(video_encoder_handle_frame::); klass.flush = Some(video_encoder_flush::); klass.propose_allocation = Some(video_encoder_propose_allocation::); klass.decide_allocation = Some(video_encoder_decide_allocation::); } } } unsafe extern "C" fn video_encoder_open( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.open(&wrap) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_close( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.close(&wrap) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_start( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.start(&wrap) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_stop( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.stop(&wrap) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_finish( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> gst_sys::GstFlowReturn where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { imp.finish(&wrap).into() }) .to_glib() } unsafe extern "C" fn video_encoder_set_format( ptr: *mut gst_video_sys::GstVideoEncoder, state: *mut gst_video_sys::GstVideoCodecState, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_video_sys::gst_video_codec_state_ref(state); let wrap_state = VideoCodecState::::new(state); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.set_format(&wrap, &wrap_state) { Ok(()) => true, Err(err) => { err.log_with_object(&wrap); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_handle_frame( ptr: *mut gst_video_sys::GstVideoEncoder, frame: *mut gst_video_sys::GstVideoCodecFrame, ) -> gst_sys::GstFlowReturn where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); let wrap_frame = VideoCodecFrame::new(frame, &wrap); gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { imp.handle_frame(&wrap, wrap_frame).into() }) .to_glib() } unsafe extern "C" fn video_encoder_flush( ptr: *mut gst_video_sys::GstVideoEncoder, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); gst_panic_to_error!(&wrap, &instance.panicked(), false, { VideoEncoderImpl::flush(imp, &wrap) }) .to_glib() } unsafe extern "C" fn video_encoder_propose_allocation( ptr: *mut gst_video_sys::GstVideoEncoder, query: *mut gst_sys::GstQuery, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); let query = gst::QueryRef::from_mut_ptr(query); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.propose_allocation(&wrap, query) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() } unsafe extern "C" fn video_encoder_decide_allocation( ptr: *mut gst_video_sys::GstVideoEncoder, query: *mut gst_sys::GstQuery, ) -> glib_sys::gboolean where T: VideoEncoderImpl, T::Instance: PanicPoison, { glib_floating_reference_guard!(ptr); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: VideoEncoder = from_glib_borrow(ptr); let query = gst::QueryRef::from_mut_ptr(query); gst_panic_to_error!(&wrap, &instance.panicked(), false, { match imp.decide_allocation(&wrap, query) { Ok(()) => true, Err(err) => { wrap.post_error_message(&err); false } } }) .to_glib() }