diff --git a/Gir_GstBase.toml b/Gir_GstBase.toml index a3ca5e5fc..c3d59aba8 100644 --- a/Gir_GstBase.toml +++ b/Gir_GstBase.toml @@ -18,6 +18,7 @@ external_libraries = [ generate = [ "GstBase.PushSrc", + "GstBase.BaseParseFrameFlags", ] manual = [ @@ -32,6 +33,8 @@ manual = [ "Gst.Format", "Gst.Pad", "Gst.TypeFindProbability", + "Gst.TagMergeMode", + "GstBase.BaseParseFrame", ] [[object]] @@ -196,3 +199,33 @@ ref_mode = "ref" name = "Gst.ClockTime" status = "manual" conversion_type = "scalar" + +[[object]] +name = "Gst.TagList" +status = "manual" +ref_mode = "ref" + +[[object]] +name = "GstBase.BaseParse" +subclassing = true +status = "generate" + [[object.function]] + name = "finish_frame" + ignore = true + + [[object.function]] + name = "set_duration" + ignore = true + + [[object.function]] + name = "convert_default" + ignore = true + + [[object.function]] + name = "set_frame_rate" + ignore = true + + # Didn't bind gst_base_parse_frame_{new,init} so not needed + [[object.function]] + name = "push_frame" + ignore = true diff --git a/gstreamer-base/src/auto/base_parse.rs b/gstreamer-base/src/auto/base_parse.rs new file mode 100644 index 000000000..1b463e2f7 --- /dev/null +++ b/gstreamer-base/src/auto/base_parse.rs @@ -0,0 +1,166 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// DO NOT EDIT + +use glib::StaticType; +use glib::Value; +use glib::object::Cast; +use glib::object::IsA; +use glib::signal::SignalHandlerId; +use glib::signal::connect_raw; +use glib::translate::*; +use glib_sys; +use gobject_sys; +use gst; +use gst_base_sys; +use std::boxed::Box as Box_; +use std::mem::transmute; + +glib_wrapper! { + pub struct BaseParse(Object) @extends gst::Element, gst::Object; + + match fn { + get_type => || gst_base_sys::gst_base_parse_get_type(), + } +} + +unsafe impl Send for BaseParse {} +unsafe impl Sync for BaseParse {} + +pub const NONE_BASE_PARSE: Option<&BaseParse> = None; + +pub trait BaseParseExt: 'static { + fn add_index_entry(&self, offset: u64, ts: gst::ClockTime, key: bool, force: bool) -> bool; + + #[cfg(any(feature = "v1_12", feature = "dox"))] + fn drain(&self); + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode); + + fn set_average_bitrate(&self, bitrate: u32); + + fn set_has_timing_info(&self, has_timing: bool); + + fn set_infer_ts(&self, infer_ts: bool); + + fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime); + + fn set_min_frame_size(&self, min_size: u32); + + fn set_passthrough(&self, passthrough: bool); + + fn set_pts_interpolation(&self, pts_interpolate: bool); + + fn set_syncable(&self, syncable: bool); + + fn set_ts_at_offset(&self, offset: usize); + + fn get_property_disable_passthrough(&self) -> bool; + + fn set_property_disable_passthrough(&self, disable_passthrough: bool); + + fn connect_property_disable_passthrough_notify(&self, f: F) -> SignalHandlerId; +} + +impl> BaseParseExt for O { + fn add_index_entry(&self, offset: u64, ts: gst::ClockTime, key: bool, force: bool) -> bool { + unsafe { + from_glib(gst_base_sys::gst_base_parse_add_index_entry(self.as_ref().to_glib_none().0, offset, ts.to_glib(), key.to_glib(), force.to_glib())) + } + } + + #[cfg(any(feature = "v1_12", feature = "dox"))] + fn drain(&self) { + unsafe { + gst_base_sys::gst_base_parse_drain(self.as_ref().to_glib_none().0); + } + } + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode) { + unsafe { + gst_base_sys::gst_base_parse_merge_tags(self.as_ref().to_glib_none().0, tags.to_glib_none().0, mode.to_glib()); + } + } + + fn set_average_bitrate(&self, bitrate: u32) { + unsafe { + gst_base_sys::gst_base_parse_set_average_bitrate(self.as_ref().to_glib_none().0, bitrate); + } + } + + fn set_has_timing_info(&self, has_timing: bool) { + unsafe { + gst_base_sys::gst_base_parse_set_has_timing_info(self.as_ref().to_glib_none().0, has_timing.to_glib()); + } + } + + fn set_infer_ts(&self, infer_ts: bool) { + unsafe { + gst_base_sys::gst_base_parse_set_infer_ts(self.as_ref().to_glib_none().0, infer_ts.to_glib()); + } + } + + fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime) { + unsafe { + gst_base_sys::gst_base_parse_set_latency(self.as_ref().to_glib_none().0, min_latency.to_glib(), max_latency.to_glib()); + } + } + + fn set_min_frame_size(&self, min_size: u32) { + unsafe { + gst_base_sys::gst_base_parse_set_min_frame_size(self.as_ref().to_glib_none().0, min_size); + } + } + + fn set_passthrough(&self, passthrough: bool) { + unsafe { + gst_base_sys::gst_base_parse_set_passthrough(self.as_ref().to_glib_none().0, passthrough.to_glib()); + } + } + + fn set_pts_interpolation(&self, pts_interpolate: bool) { + unsafe { + gst_base_sys::gst_base_parse_set_pts_interpolation(self.as_ref().to_glib_none().0, pts_interpolate.to_glib()); + } + } + + fn set_syncable(&self, syncable: bool) { + unsafe { + gst_base_sys::gst_base_parse_set_syncable(self.as_ref().to_glib_none().0, syncable.to_glib()); + } + } + + fn set_ts_at_offset(&self, offset: usize) { + unsafe { + gst_base_sys::gst_base_parse_set_ts_at_offset(self.as_ref().to_glib_none().0, offset); + } + } + + fn get_property_disable_passthrough(&self) -> bool { + unsafe { + let mut value = Value::from_type(::static_type()); + gobject_sys::g_object_get_property(self.to_glib_none().0 as *mut gobject_sys::GObject, b"disable-passthrough\0".as_ptr() as *const _, value.to_glib_none_mut().0); + value.get().unwrap() + } + } + + fn set_property_disable_passthrough(&self, disable_passthrough: bool) { + unsafe { + gobject_sys::g_object_set_property(self.to_glib_none().0 as *mut gobject_sys::GObject, b"disable-passthrough\0".as_ptr() as *const _, Value::from(&disable_passthrough).to_glib_none().0); + } + } + + fn connect_property_disable_passthrough_notify(&self, f: F) -> SignalHandlerId { + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::disable-passthrough\0".as_ptr() as *const _, + Some(transmute(notify_disable_passthrough_trampoline:: as usize)), Box_::into_raw(f)) + } + } +} + +unsafe extern "C" fn notify_disable_passthrough_trampoline(this: *mut gst_base_sys::GstBaseParse, _param_spec: glib_sys::gpointer, f: glib_sys::gpointer) +where P: IsA { + let f: &F = &*(f as *const F); + f(&BaseParse::from_glib_borrow(this).unsafe_cast()) +} diff --git a/gstreamer-base/src/auto/flags.rs b/gstreamer-base/src/auto/flags.rs index db4949d05..5f09306cc 100644 --- a/gstreamer-base/src/auto/flags.rs +++ b/gstreamer-base/src/auto/flags.rs @@ -2,6 +2,34 @@ // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT -use gst_base_sys; use glib::translate::*; +use gst_base_sys; + +bitflags! { + pub struct BaseParseFrameFlags: u32 { + const NONE = 0; + const NEW_FRAME = 1; + const NO_FRAME = 2; + const CLIP = 4; + const DROP = 8; + const QUEUE = 16; + } +} + +#[doc(hidden)] +impl ToGlib for BaseParseFrameFlags { + type GlibType = gst_base_sys::GstBaseParseFrameFlags; + + fn to_glib(&self) -> gst_base_sys::GstBaseParseFrameFlags { + self.bits() + } +} + +#[doc(hidden)] +impl FromGlib for BaseParseFrameFlags { + fn from_glib(value: gst_base_sys::GstBaseParseFrameFlags) -> BaseParseFrameFlags { + skip_assert_initialized!(); + BaseParseFrameFlags::from_bits_truncate(value) + } +} diff --git a/gstreamer-base/src/auto/mod.rs b/gstreamer-base/src/auto/mod.rs index 715c87970..c60a15d8e 100644 --- a/gstreamer-base/src/auto/mod.rs +++ b/gstreamer-base/src/auto/mod.rs @@ -19,6 +19,10 @@ pub use self::aggregator_pad::{AggregatorPad, AggregatorPadClass, NONE_AGGREGATO #[cfg(any(feature = "v1_14", feature = "dox"))] pub use self::aggregator_pad::AggregatorPadExt; +mod base_parse; +pub use self::base_parse::{BaseParse, BaseParseClass, NONE_BASE_PARSE}; +pub use self::base_parse::BaseParseExt; + mod base_sink; pub use self::base_sink::{BaseSink, BaseSinkClass, NONE_BASE_SINK}; pub use self::base_sink::BaseSinkExt; @@ -34,6 +38,9 @@ pub use self::base_transform::BaseTransformExt; mod push_src; pub use self::push_src::{PushSrc, PushSrcClass, NONE_PUSH_SRC}; +mod flags; +pub use self::flags::BaseParseFrameFlags; + pub mod functions; #[doc(hidden)] @@ -42,6 +49,7 @@ pub mod traits { pub use super::AggregatorExt; #[cfg(any(feature = "v1_14", feature = "dox"))] pub use super::AggregatorPadExt; + pub use super::BaseParseExt; pub use super::BaseSinkExt; pub use super::BaseSrcExt; pub use super::BaseTransformExt; diff --git a/gstreamer-base/src/auto/versions.txt b/gstreamer-base/src/auto/versions.txt index a9e0ccc5d..d07525712 100644 --- a/gstreamer-base/src/auto/versions.txt +++ b/gstreamer-base/src/auto/versions.txt @@ -1,2 +1,2 @@ -Generated by gir (https://github.com/gtk-rs/gir @ 58cffd4) +Generated by gir (https://github.com/gtk-rs/gir @ f511aae) from gir-files (https://github.com/gtk-rs/gir-files @ ???) diff --git a/gstreamer-base/src/base_parse.rs b/gstreamer-base/src/base_parse.rs new file mode 100644 index 000000000..99c48a076 --- /dev/null +++ b/gstreamer-base/src/base_parse.rs @@ -0,0 +1,142 @@ +// 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::object::IsA; +use glib::translate::*; +use gst; +use gst::FormattedValue; +use gst_base_sys; +use std::convert::TryFrom; +use std::mem; +use BaseParse; +use BaseParseFrame; + +pub trait BaseParseExtManual: 'static { + fn get_sink_pad(&self) -> gst::Pad; + fn get_src_pad(&self) -> gst::Pad; + + fn set_duration>(&self, duration: V, interval: u32); + fn set_frame_rate(&self, fps: gst::Fraction, lead_in: u32, lead_out: u32); + + fn convert_default, U: gst::SpecificFormattedValue>( + &self, + src_val: V, + ) -> Option; + fn convert_default_generic>( + &self, + src_val: V, + dest_format: gst::Format, + ) -> Option; + + fn finish_frame( + &self, + frame: BaseParseFrame, + size: u32, + ) -> Result; +} + +impl> BaseParseExtManual for O { + fn get_sink_pad(&self) -> gst::Pad { + unsafe { + let elt: &gst_base_sys::GstBaseParse = &*(self.as_ptr() as *const _); + from_glib_none(elt.sinkpad) + } + } + + fn get_src_pad(&self) -> gst::Pad { + unsafe { + let elt: &gst_base_sys::GstBaseParse = &*(self.as_ptr() as *const _); + from_glib_none(elt.srcpad) + } + } + + fn set_duration>(&self, duration: V, interval: u32) { + let duration = duration.into(); + unsafe { + gst_base_sys::gst_base_parse_set_duration( + self.as_ref().to_glib_none().0, + duration.get_format().to_glib(), + duration.get_value(), + interval as i32, + ); + } + } + + fn set_frame_rate(&self, fps: gst::Fraction, lead_in: u32, lead_out: u32) { + let (fps_num, fps_den) = fps.into(); + unsafe { + gst_base_sys::gst_base_parse_set_frame_rate( + self.as_ref().to_glib_none().0, + fps_num as u32, + fps_den as u32, + lead_in, + lead_out, + ); + } + } + + fn convert_default, U: gst::SpecificFormattedValue>( + &self, + src_val: V, + ) -> Option { + let src_val = src_val.into(); + unsafe { + let mut dest_val = mem::uninitialized(); + let ret = from_glib(gst_base_sys::gst_base_parse_convert_default( + self.as_ref().to_glib_none().0, + src_val.get_format().to_glib(), + src_val.to_raw_value(), + U::get_default_format().to_glib(), + &mut dest_val, + )); + if ret { + Some(U::from_raw(U::get_default_format(), dest_val)) + } else { + None + } + } + } + + fn convert_default_generic>( + &self, + src_val: V, + dest_format: gst::Format, + ) -> Option { + let src_val = src_val.into(); + unsafe { + let mut dest_val = mem::uninitialized(); + let ret = from_glib(gst_base_sys::gst_base_parse_convert_default( + self.as_ref().to_glib_none().0, + src_val.get_format().to_glib(), + src_val.to_raw_value(), + dest_format.to_glib(), + &mut dest_val, + )); + if ret { + Some(gst::GenericFormattedValue::new(dest_format, dest_val)) + } else { + None + } + } + } + + fn finish_frame( + &self, + frame: BaseParseFrame, + size: u32, + ) -> Result { + unsafe { + gst::FlowReturn::from_glib(gst_base_sys::gst_base_parse_finish_frame( + self.as_ref().to_glib_none().0, + frame.to_glib_none().0, + i32::try_from(size).expect("size higher than i32::MAX"), + )) + .into_result() + } + } +} diff --git a/gstreamer-base/src/base_parse_frame.rs b/gstreamer-base/src/base_parse_frame.rs new file mode 100644 index 000000000..7cb3ae668 --- /dev/null +++ b/gstreamer-base/src/base_parse_frame.rs @@ -0,0 +1,175 @@ +// 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::translate::*; +use gst; +use gst::MiniObject; +use gst_base_sys; +use std::convert::TryFrom; +use std::fmt; +use std::marker::PhantomData; +use std::ptr; + +use BaseParse; +use BaseParseFrameFlags; + +pub struct BaseParseFrame<'a>( + ptr::NonNull, + PhantomData<&'a BaseParse>, +); + +#[derive(Debug)] +pub enum Overhead { + None, + Frame, + Bytes(u32), +} + +#[doc(hidden)] +impl ToGlib for Overhead { + type GlibType = i32; + + fn to_glib(&self) -> i32 { + match *self { + Overhead::None => 0, + Overhead::Frame => -1, + Overhead::Bytes(b) => i32::try_from(b).expect("overhead is higher than i32::MAX"), + } + } +} + +impl FromGlib for Overhead { + #[inline] + fn from_glib(val: i32) -> Overhead { + match val { + 0 => Overhead::None, + 1 => Overhead::Frame, + b if b > 0 => Overhead::Bytes(val as u32), + _ => panic!("overheader is lower than -1"), + } + } +} + +#[doc(hidden)] +impl<'a> ::glib::translate::ToGlibPtr<'a, *mut gst_base_sys::GstBaseParseFrame> + for BaseParseFrame<'a> +{ + type Storage = &'a Self; + + fn to_glib_none( + &'a self, + ) -> ::glib::translate::Stash<*mut gst_base_sys::GstBaseParseFrame, Self> { + Stash(self.0.as_ptr(), self) + } + + fn to_glib_full(&self) -> *mut gst_base_sys::GstBaseParseFrame { + unimplemented!() + } +} + +impl<'a> fmt::Debug for BaseParseFrame<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let mut b = f.debug_struct("BaseParseFrame"); + + b.field("buffer", &self.get_buffer()) + .field("output_buffer", &self.get_output_buffer()) + .field("flags", &self.get_flags()) + .field("offset", &self.get_offset()) + .field("overhead", &self.get_overhead()); + + b.finish() + } +} + +impl<'a> BaseParseFrame<'a> { + #[cfg(feature = "subclassing")] + pub(crate) unsafe fn new( + frame: *mut gst_base_sys::GstBaseParseFrame, + _parse: &'a BaseParse, + ) -> BaseParseFrame<'a> { + assert!(!frame.is_null()); + BaseParseFrame(ptr::NonNull::new_unchecked(frame), PhantomData) + } + + pub fn get_buffer(&self) -> Option<&mut gst::BufferRef> { + unsafe { + let ptr = (*self.to_glib_none().0).buffer; + if ptr.is_null() { + None + } else { + let writable: bool = from_glib(gst_sys::gst_mini_object_is_writable( + ptr as *const gst_sys::GstMiniObject, + )); + assert!(writable); + + Some(gst::BufferRef::from_mut_ptr(ptr)) + } + } + } + + pub fn get_output_buffer(&self) -> Option<&mut gst::BufferRef> { + unsafe { + let ptr = (*self.to_glib_none().0).out_buffer; + if ptr.is_null() { + None + } else { + let writable: bool = from_glib(gst_sys::gst_mini_object_is_writable( + ptr as *const gst_sys::GstMiniObject, + )); + assert!(writable); + + Some(gst::BufferRef::from_mut_ptr(ptr)) + } + } + } + + pub fn set_output_buffer(&self, output_buffer: gst::Buffer) { + unsafe { + let prev = (*self.to_glib_none().0).out_buffer; + + if !prev.is_null() { + gst_sys::gst_mini_object_unref(prev as *mut gst_sys::GstMiniObject); + } + + let ptr = output_buffer.into_ptr(); + let writable: bool = from_glib(gst_sys::gst_mini_object_is_writable( + ptr as *const gst_sys::GstMiniObject, + )); + assert!(writable); + + (*self.to_glib_none().0).out_buffer = ptr; + } + } + + pub fn get_flags(&self) -> BaseParseFrameFlags { + let flags = unsafe { (*self.to_glib_none().0).flags }; + BaseParseFrameFlags::from_bits_truncate(flags) + } + + pub fn set_flags(&self, flags: BaseParseFrameFlags) { + unsafe { (*self.to_glib_none().0).flags |= flags.bits() } + } + + pub fn unset_flags(&self, flags: BaseParseFrameFlags) { + unsafe { (*self.to_glib_none().0).flags &= !flags.bits() } + } + + pub fn get_offset(&self) -> u64 { + unsafe { (*self.to_glib_none().0).offset } + } + + pub fn get_overhead(&self) -> Overhead { + unsafe { from_glib((*self.to_glib_none().0).overhead) } + } + + pub fn set_overhead(&self, overhead: Overhead) { + unsafe { + (*self.to_glib_none().0).overhead = overhead.to_glib(); + } + } +} diff --git a/gstreamer-base/src/lib.rs b/gstreamer-base/src/lib.rs index 08d2258c6..9b336359e 100644 --- a/gstreamer-base/src/lib.rs +++ b/gstreamer-base/src/lib.rs @@ -14,6 +14,8 @@ extern crate gstreamer_base_sys as gst_base_sys; extern crate gstreamer_sys as gst_sys; extern crate libc; +#[macro_use] +extern crate bitflags; #[macro_use] extern crate glib; @@ -26,6 +28,10 @@ macro_rules! assert_initialized_main_thread { }; } +macro_rules! skip_assert_initialized { + () => {}; +} + pub use glib::{Cast, Continue, Error, IsA, StaticType, ToValue, Type, TypedValue, Value}; #[allow(clippy::unreadable_literal)] @@ -48,10 +54,14 @@ pub use flow_combiner::*; mod aggregator; #[cfg(any(feature = "v1_14", feature = "dox"))] mod aggregator_pad; +mod base_parse; mod base_sink; mod base_src; mod base_transform; +pub mod base_parse_frame; +pub use base_parse_frame::BaseParseFrame; + // Re-export all the traits in a prelude module, so that applications // can always "use gst::prelude::*" without getting conflicts pub mod prelude { @@ -63,6 +73,8 @@ pub mod prelude { #[cfg(any(feature = "v1_14", feature = "dox"))] pub use aggregator_pad::AggregatorPadExtManual; pub use auto::traits::*; + pub use base_parse::BaseParseExtManual; + pub use base_parse_frame::BaseParseFrame; pub use base_sink::BaseSinkExtManual; pub use base_src::BaseSrcExtManual; pub use base_transform::BaseTransformExtManual; diff --git a/gstreamer-base/src/subclass/base_parse.rs b/gstreamer-base/src/subclass/base_parse.rs new file mode 100644 index 000000000..32869932c --- /dev/null +++ b/gstreamer-base/src/subclass/base_parse.rs @@ -0,0 +1,311 @@ +// 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_base_sys; +use gst_sys; +use std::convert::TryFrom; +use std::mem; + +use glib::translate::*; +use prelude::*; + +use glib::subclass::prelude::*; +use gst; +use gst::subclass::prelude::*; + +use BaseParse; +use BaseParseClass; + +pub trait BaseParseImpl: BaseParseImplExt + ElementImpl + Send + Sync + 'static { + fn start(&self, element: &BaseParse) -> Result<(), gst::ErrorMessage> { + self.parent_start(element) + } + + fn set_sink_caps( + &self, + element: &BaseParse, + caps: &gst::Caps, + ) -> Result<(), gst::ErrorMessage> { + self.parent_set_sink_caps(element, caps) + } + + fn handle_frame<'a>( + &'a self, + element: &BaseParse, + frame: BaseParseFrame, + ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> { + self.parent_handle_frame(element, frame) + } + + fn convert>( + &self, + element: &BaseParse, + src_val: V, + dest_format: gst::Format, + ) -> Option; +} + +pub trait BaseParseImplExt { + fn parent_start(&self, element: &BaseParse) -> Result<(), gst::ErrorMessage>; + + fn parent_set_sink_caps( + &self, + element: &BaseParse, + caps: &gst::Caps, + ) -> Result<(), gst::ErrorMessage>; + + fn parent_handle_frame<'a>( + &'a self, + element: &BaseParse, + frame: BaseParseFrame, + ) -> Result<(gst::FlowSuccess, u32), gst::FlowError>; + + fn parent_convert>( + &self, + element: &BaseParse, + src_val: V, + dest_format: gst::Format, + ) -> Option; +} + +impl BaseParseImplExt for T { + fn parent_start(&self, element: &BaseParse) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseParseClass; + (*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_set_sink_caps( + &self, + element: &BaseParse, + caps: &gst::Caps, + ) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseParseClass; + (*parent_class) + .set_sink_caps + .map(|f| { + if from_glib(f(element.to_glib_none().0, caps.to_glib_none().0)) { + Ok(()) + } else { + Err(gst_error_msg!( + gst::CoreError::StateChange, + ["Parent function `set_sink_caps` failed"] + )) + } + }) + .unwrap_or(Ok(())) + } + } + + fn parent_handle_frame<'a>( + &'a self, + element: &'a BaseParse, + frame: BaseParseFrame, + ) -> Result<(gst::FlowSuccess, u32), gst::FlowError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseParseClass; + let mut skipsize = 0; + let res = (*parent_class).handle_frame.map(|f| { + let res = gst::FlowReturn::from_glib(f( + element.to_glib_none().0, + frame.to_glib_none().0, + &mut skipsize, + )); + (res, skipsize as u32) + }); + + match res { + Some((res, skipsize)) => { + let res = res.into_result(); + Ok((res.unwrap(), skipsize)) + } + None => Err(gst::FlowError::Error), + } + } + } + + fn parent_convert>( + &self, + element: &BaseParse, + src_val: V, + dest_format: gst::Format, + ) -> Option { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_base_sys::GstBaseParseClass; + let src_val = src_val.into(); + let res = (*parent_class).convert.map(|f| { + let mut dest_val = mem::uninitialized(); + + let res = from_glib(f( + element.to_glib_none().0, + src_val.get_format().to_glib(), + src_val.to_raw_value(), + dest_format.to_glib(), + &mut dest_val, + )); + (res, dest_val) + }); + + match res { + Some((true, dest_val)) => { + Some(gst::GenericFormattedValue::new(dest_format, dest_val)) + } + _ => None, + } + } + } +} + +unsafe impl IsSubclassable for BaseParseClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_base_sys::GstBaseParseClass); + klass.start = Some(base_parse_start::); + klass.set_sink_caps = Some(base_parse_set_sink_caps::); + klass.handle_frame = Some(base_parse_handle_frame::); + klass.convert = Some(base_parse_convert::); + } + } +} + +unsafe extern "C" fn base_parse_start( + ptr: *mut gst_base_sys::GstBaseParse, +) -> glib_sys::gboolean +where + T: BaseParseImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: BaseParse = 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 base_parse_set_sink_caps( + ptr: *mut gst_base_sys::GstBaseParse, + caps: *mut gst_sys::GstCaps, +) -> glib_sys::gboolean +where + T: BaseParseImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: BaseParse = from_glib_borrow(ptr); + let caps: gst::Caps = from_glib_none(caps); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.set_sink_caps(&wrap, &caps) { + Ok(()) => true, + Err(err) => { + wrap.post_error_message(&err); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn base_parse_handle_frame( + ptr: *mut gst_base_sys::GstBaseParse, + frame: *mut gst_base_sys::GstBaseParseFrame, + skipsize: *mut i32, +) -> gst_sys::GstFlowReturn +where + T: BaseParseImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: BaseParse = from_glib_borrow(ptr); + let wrap_frame = BaseParseFrame::new(frame, &wrap); + + let res = gst_panic_to_error!(&wrap, &instance.panicked(), Err(gst::FlowError::Error), { + imp.handle_frame(&wrap, wrap_frame) + }); + + match res { + Ok((flow, skip)) => { + *skipsize = i32::try_from(skip).expect("skip is higher than i32::MAX"); + gst::FlowReturn::from_ok(flow) + } + Err(flow) => gst::FlowReturn::from_error(flow), + } + .to_glib() +} + +unsafe extern "C" fn base_parse_convert( + ptr: *mut gst_base_sys::GstBaseParse, + source_format: gst_sys::GstFormat, + source_value: i64, + dest_format: gst_sys::GstFormat, + dest_value: *mut i64, +) -> glib_sys::gboolean +where + T: BaseParseImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: BaseParse = from_glib_borrow(ptr); + let source = gst::GenericFormattedValue::new(from_glib(source_format), source_value); + + let res = gst_panic_to_error!(&wrap, &instance.panicked(), None, { + imp.convert(&wrap, source, from_glib(dest_format)) + }); + + match res { + Some(dest) => { + *dest_value = dest.to_raw_value(); + true + } + _ => false, + } + .to_glib() +} diff --git a/gstreamer-base/src/subclass/mod.rs b/gstreamer-base/src/subclass/mod.rs index efe1f4360..7654ba07b 100644 --- a/gstreamer-base/src/subclass/mod.rs +++ b/gstreamer-base/src/subclass/mod.rs @@ -8,6 +8,7 @@ // except according to those terms. #![allow(clippy::cast_ptr_alignment)] +pub mod base_parse; pub mod base_sink; pub mod base_src; pub mod base_transform; @@ -24,6 +25,7 @@ pub mod prelude { pub use super::aggregator::{AggregatorImpl, AggregatorImplExt}; #[cfg(any(feature = "v1_14", feature = "dox"))] pub use super::aggregator_pad::{AggregatorPadImpl, AggregatorPadImplExt}; + pub use super::base_parse::{BaseParseImpl, BaseParseImplExt}; pub use super::base_sink::{BaseSinkImpl, BaseSinkImplExt}; pub use super::base_src::{BaseSrcImpl, BaseSrcImplExt}; pub use super::base_transform::{