From b238d07db0f0bb4e382cb09b43b1c7634f1164d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 13 Sep 2019 22:51:10 +0300 Subject: [PATCH] audio: Add support for subclassing AudioEncoder and AudioDecoder Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/159 Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/158 --- Gir_GstAudio.toml | 61 ++ gstreamer-audio/Cargo.toml | 10 +- gstreamer-audio/src/audio_decoder.rs | 125 +++ gstreamer-audio/src/audio_encoder.rs | 103 ++ gstreamer-audio/src/auto/audio_decoder.rs | 407 ++++++++ gstreamer-audio/src/auto/audio_encoder.rs | 440 ++++++++ gstreamer-audio/src/auto/mod.rs | 10 + gstreamer-audio/src/lib.rs | 12 + gstreamer-audio/src/subclass/audio_decoder.rs | 946 ++++++++++++++++++ gstreamer-audio/src/subclass/audio_encoder.rs | 862 ++++++++++++++++ gstreamer-audio/src/subclass/mod.rs | 16 + 11 files changed, 2988 insertions(+), 4 deletions(-) create mode 100644 gstreamer-audio/src/audio_decoder.rs create mode 100644 gstreamer-audio/src/audio_encoder.rs create mode 100644 gstreamer-audio/src/auto/audio_decoder.rs create mode 100644 gstreamer-audio/src/auto/audio_encoder.rs create mode 100644 gstreamer-audio/src/subclass/audio_decoder.rs create mode 100644 gstreamer-audio/src/subclass/audio_encoder.rs create mode 100644 gstreamer-audio/src/subclass/mod.rs diff --git a/Gir_GstAudio.toml b/Gir_GstAudio.toml index 1a0b8873a..c18f6a029 100644 --- a/Gir_GstAudio.toml +++ b/Gir_GstAudio.toml @@ -29,6 +29,11 @@ generate = [ manual = [ "GObject.Object", "Gst.Object", + "Gst.Element", + "Gst.Allocator", + "Gst.AllocationParams", + "Gst.TagList", + "Gst.TagMergeMode", "GstAudio.AudioInfo", "GstAudio.AudioFormatInfo", ] @@ -38,6 +43,11 @@ name = "Gst.Caps" status = "manual" ref_mode = "ref" +[[object]] +name = "Gst.Buffer" +status = "manual" +ref_mode = "ref" + [[object]] name = "Gst.ClockTime" status = "manual" @@ -125,3 +135,54 @@ status = "generate" name = "process" # bool does not signal error ignore = true + +[[object]] +name = "GstAudio.AudioDecoder" +status = "generate" + [[object.function]] + name = "finish_frame" + ignore = true + + [[object.function]] + name = "finish_subframe" + ignore = true + + [[object.function]] + name = "negotiate" + ignore = true + + [[object.function]] + name = "set_output_caps" + ignore = true + + [[object.function]] + name = "set_output_format" + ignore = true + + [[object.function]] + name = "get_allocator" + ignore = true + +[[object]] +name = "GstAudio.AudioEncoder" +status = "generate" + + [[object.function]] + name = "finish_frame" + ignore = true + + [[object.function]] + name = "negotiate" + ignore = true + + [[object.function]] + name = "set_output_format" + ignore = true + + [[object.function]] + name = "get_allocator" + ignore = true + + [[object.function]] + name = "get_latency" + ignore = true diff --git a/gstreamer-audio/Cargo.toml b/gstreamer-audio/Cargo.toml index 3b72d9a19..49e4dd3b7 100644 --- a/gstreamer-audio/Cargo.toml +++ b/gstreamer-audio/Cargo.toml @@ -17,9 +17,11 @@ bitflags = "1.0" glib-sys = { git = "https://github.com/gtk-rs/sys" } gobject-sys = { git = "https://github.com/gtk-rs/sys" } gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] } +gstreamer-base-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] } gstreamer-audio-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys", features = ["v1_8"] } glib = { git = "https://github.com/gtk-rs/glib" } gstreamer = { path = "../gstreamer" } +gstreamer-base = { path = "../gstreamer-base" } array-init = "0.1" [build-dependencies] @@ -27,10 +29,10 @@ rustdoc-stripper = { version = "0.1", optional = true } [features] default = [] -v1_10 = ["gstreamer/v1_10", "gstreamer-audio-sys/v1_10"] -v1_12 = ["gstreamer/v1_12", "gstreamer-audio-sys/v1_12", "v1_10"] -v1_14 = ["gstreamer/v1_14", "gstreamer-audio-sys/v1_14", "v1_12"] -v1_16 = ["gstreamer/v1_16", "gstreamer-audio-sys/v1_16", "v1_14"] +v1_10 = ["gstreamer/v1_10", "gstreamer-audio-sys/v1_10", "gstreamer-base-sys/v1_10"] +v1_12 = ["gstreamer/v1_12", "gstreamer-audio-sys/v1_12", "gstreamer-base-sys/v1_12", "v1_10"] +v1_14 = ["gstreamer/v1_14", "gstreamer-audio-sys/v1_14", "gstreamer-base-sys/v1_14", "v1_12"] +v1_16 = ["gstreamer/v1_16", "gstreamer-audio-sys/v1_16", "gstreamer-base-sys/v1_16", "v1_14"] embed-lgpl-docs = ["rustdoc-stripper"] purge-lgpl-docs = ["rustdoc-stripper"] dox = ["gstreamer-audio-sys/dox", "glib/dox", "gstreamer/dox"] diff --git a/gstreamer-audio/src/audio_decoder.rs b/gstreamer-audio/src/audio_decoder.rs new file mode 100644 index 000000000..672ad13be --- /dev/null +++ b/gstreamer-audio/src/audio_decoder.rs @@ -0,0 +1,125 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// 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_audio_sys; +use std::mem; +use std::ptr; +use AudioDecoder; +use AudioInfo; + +pub trait AudioDecoderExtManual: 'static { + fn finish_frame( + &self, + buffer: Option, + frames: i32, + ) -> Result; + + #[cfg(any(feature = "v1_16", feature = "dox"))] + fn finish_subframe( + &self, + buffer: Option, + ) -> Result; + + fn negotiate(&self) -> Result<(), gst::FlowError>; + + #[cfg(any(feature = "v1_16", feature = "dox"))] + fn set_output_caps(&self, caps: &gst::Caps) -> Result<(), gst::FlowError>; + + fn set_output_format(&self, info: &AudioInfo) -> Result<(), gst::FlowError>; + + fn get_allocator(&self) -> (gst::Allocator, gst::AllocationParams); +} + +impl> AudioDecoderExtManual for O { + fn finish_frame( + &self, + buffer: Option, + frames: i32, + ) -> Result { + let ret: gst::FlowReturn = unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_finish_frame( + self.as_ref().to_glib_none().0, + buffer.map(|b| b.into_ptr()).unwrap_or(ptr::null_mut()), + frames, + )) + }; + ret.into_result() + } + + #[cfg(any(feature = "v1_16", feature = "dox"))] + fn finish_subframe( + &self, + buffer: Option, + ) -> Result { + let ret: gst::FlowReturn = unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_finish_subframe( + self.as_ref().to_glib_none().0, + buffer.map(|b| b.into_ptr()).unwrap_or(ptr::null_mut()), + )) + }; + ret.into_result() + } + + fn negotiate(&self) -> Result<(), gst::FlowError> { + unsafe { + let ret = from_glib(gst_audio_sys::gst_audio_decoder_negotiate( + self.as_ref().to_glib_none().0, + )); + if ret { + Ok(()) + } else { + Err(gst::FlowError::NotNegotiated) + } + } + } + + #[cfg(any(feature = "v1_16", feature = "dox"))] + fn set_output_caps(&self, caps: &gst::Caps) -> Result<(), gst::FlowError> { + unsafe { + let ret = from_glib(gst_audio_sys::gst_audio_decoder_set_output_caps( + self.as_ref().to_glib_none().0, + caps.to_glib_none().0, + )); + if ret { + Ok(()) + } else { + Err(gst::FlowError::NotNegotiated) + } + } + } + + fn set_output_format(&self, info: &AudioInfo) -> Result<(), gst::FlowError> { + unsafe { + let ret = from_glib(gst_audio_sys::gst_audio_decoder_set_output_format( + self.as_ref().to_glib_none().0, + info.to_glib_none().0, + )); + if ret { + Ok(()) + } else { + Err(gst::FlowError::NotNegotiated) + } + } + } + + fn get_allocator(&self) -> (gst::Allocator, gst::AllocationParams) { + unsafe { + let mut allocator = ptr::null_mut(); + let mut params = mem::zeroed(); + gst_audio_sys::gst_audio_decoder_get_allocator( + self.as_ref().to_glib_none().0, + &mut allocator, + &mut params, + ); + (from_glib_full(allocator), params.into()) + } + } +} diff --git a/gstreamer-audio/src/audio_encoder.rs b/gstreamer-audio/src/audio_encoder.rs new file mode 100644 index 000000000..4fa5144cd --- /dev/null +++ b/gstreamer-audio/src/audio_encoder.rs @@ -0,0 +1,103 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// 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_audio_sys; +use std::mem; +use std::ptr; +use AudioEncoder; + +pub trait AudioEncoderExtManual: 'static { + fn finish_frame( + &self, + buffer: Option, + frames: i32, + ) -> Result; + + fn negotiate(&self) -> Result<(), gst::FlowError>; + + fn set_output_format(&self, caps: &gst::Caps) -> Result<(), gst::FlowError>; + + fn get_allocator(&self) -> (gst::Allocator, gst::AllocationParams); + + fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime); +} + +impl> AudioEncoderExtManual for O { + fn finish_frame( + &self, + buffer: Option, + frames: i32, + ) -> Result { + let ret: gst::FlowReturn = unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_finish_frame( + self.as_ref().to_glib_none().0, + buffer.map(|b| b.into_ptr()).unwrap_or(ptr::null_mut()), + frames, + )) + }; + ret.into_result() + } + + fn negotiate(&self) -> Result<(), gst::FlowError> { + unsafe { + let ret = from_glib(gst_audio_sys::gst_audio_encoder_negotiate( + self.as_ref().to_glib_none().0, + )); + if ret { + Ok(()) + } else { + Err(gst::FlowError::NotNegotiated) + } + } + } + + fn set_output_format(&self, caps: &gst::Caps) -> Result<(), gst::FlowError> { + unsafe { + let ret = from_glib(gst_audio_sys::gst_audio_encoder_set_output_format( + self.as_ref().to_glib_none().0, + caps.to_glib_none().0, + )); + if ret { + Ok(()) + } else { + Err(gst::FlowError::NotNegotiated) + } + } + } + + fn get_allocator(&self) -> (gst::Allocator, gst::AllocationParams) { + unsafe { + let mut allocator = ptr::null_mut(); + let mut params = mem::zeroed(); + gst_audio_sys::gst_audio_encoder_get_allocator( + self.as_ref().to_glib_none().0, + &mut allocator, + &mut params, + ); + (from_glib_full(allocator), params.into()) + } + } + + fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime) { + unsafe { + let mut min = mem::MaybeUninit::uninit(); + let mut max = mem::MaybeUninit::uninit(); + gst_audio_sys::gst_audio_encoder_get_latency( + self.as_ref().to_glib_none().0, + min.as_mut_ptr(), + max.as_mut_ptr(), + ); + let min = min.assume_init(); + let max = max.assume_init(); + (from_glib(min), from_glib(max)) + } + } +} diff --git a/gstreamer-audio/src/auto/audio_decoder.rs b/gstreamer-audio/src/auto/audio_decoder.rs new file mode 100644 index 000000000..b056aea75 --- /dev/null +++ b/gstreamer-audio/src/auto/audio_decoder.rs @@ -0,0 +1,407 @@ +// 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::object::Cast; +use glib::object::IsA; +use glib::signal::connect_raw; +use glib::signal::SignalHandlerId; +use glib::translate::*; +use glib_sys; +use gst; +use gst_audio_sys; +use std::boxed::Box as Box_; +use std::mem; +use std::mem::transmute; +use AudioInfo; + +glib_wrapper! { + pub struct AudioDecoder(Object) @extends gst::Element, gst::Object; + + match fn { + get_type => || gst_audio_sys::gst_audio_decoder_get_type(), + } +} + +unsafe impl Send for AudioDecoder {} +unsafe impl Sync for AudioDecoder {} + +pub const NONE_AUDIO_DECODER: Option<&AudioDecoder> = None; + +pub trait AudioDecoderExt: 'static { + fn allocate_output_buffer(&self, size: usize) -> Option; + + fn get_audio_info(&self) -> Option; + + fn get_delay(&self) -> i32; + + fn get_drainable(&self) -> bool; + + fn get_estimate_rate(&self) -> i32; + + fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime); + + fn get_max_errors(&self) -> i32; + + fn get_min_latency(&self) -> gst::ClockTime; + + fn get_needs_format(&self) -> bool; + + fn get_parse_state(&self) -> (bool, bool); + + fn get_plc(&self) -> bool; + + fn get_plc_aware(&self) -> i32; + + fn get_tolerance(&self) -> gst::ClockTime; + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode); + + fn proxy_getcaps( + &self, + caps: Option<&gst::Caps>, + filter: Option<&gst::Caps>, + ) -> Option; + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn set_allocation_caps(&self, allocation_caps: Option<&gst::Caps>); + + fn set_drainable(&self, enabled: bool); + + fn set_estimate_rate(&self, enabled: bool); + + fn set_latency(&self, min: gst::ClockTime, max: gst::ClockTime); + + fn set_max_errors(&self, num: i32); + + fn set_min_latency(&self, num: gst::ClockTime); + + fn set_needs_format(&self, enabled: bool); + + fn set_plc(&self, enabled: bool); + + fn set_plc_aware(&self, plc: bool); + + fn set_tolerance(&self, tolerance: gst::ClockTime); + + fn set_use_default_pad_acceptcaps(&self, use_: bool); + + fn connect_property_min_latency_notify( + &self, + f: F, + ) -> SignalHandlerId; + + fn connect_property_plc_notify( + &self, + f: F, + ) -> SignalHandlerId; + + fn connect_property_tolerance_notify( + &self, + f: F, + ) -> SignalHandlerId; +} + +impl> AudioDecoderExt for O { + fn allocate_output_buffer(&self, size: usize) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_decoder_allocate_output_buffer( + self.as_ref().to_glib_none().0, + size, + )) + } + } + + fn get_audio_info(&self) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_decoder_get_audio_info( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_delay(&self) -> i32 { + unsafe { gst_audio_sys::gst_audio_decoder_get_delay(self.as_ref().to_glib_none().0) } + } + + fn get_drainable(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_get_drainable( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_estimate_rate(&self) -> i32 { + unsafe { + gst_audio_sys::gst_audio_decoder_get_estimate_rate(self.as_ref().to_glib_none().0) + } + } + + fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime) { + unsafe { + let mut min = mem::MaybeUninit::uninit(); + let mut max = mem::MaybeUninit::uninit(); + gst_audio_sys::gst_audio_decoder_get_latency( + self.as_ref().to_glib_none().0, + min.as_mut_ptr(), + max.as_mut_ptr(), + ); + let min = min.assume_init(); + let max = max.assume_init(); + (from_glib(min), from_glib(max)) + } + } + + fn get_max_errors(&self) -> i32 { + unsafe { gst_audio_sys::gst_audio_decoder_get_max_errors(self.as_ref().to_glib_none().0) } + } + + fn get_min_latency(&self) -> gst::ClockTime { + unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_get_min_latency( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_needs_format(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_get_needs_format( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_parse_state(&self) -> (bool, bool) { + unsafe { + let mut sync = mem::MaybeUninit::uninit(); + let mut eos = mem::MaybeUninit::uninit(); + gst_audio_sys::gst_audio_decoder_get_parse_state( + self.as_ref().to_glib_none().0, + sync.as_mut_ptr(), + eos.as_mut_ptr(), + ); + let sync = sync.assume_init(); + let eos = eos.assume_init(); + (from_glib(sync), from_glib(eos)) + } + } + + fn get_plc(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_get_plc( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_plc_aware(&self) -> i32 { + unsafe { gst_audio_sys::gst_audio_decoder_get_plc_aware(self.as_ref().to_glib_none().0) } + } + + fn get_tolerance(&self) -> gst::ClockTime { + unsafe { + from_glib(gst_audio_sys::gst_audio_decoder_get_tolerance( + self.as_ref().to_glib_none().0, + )) + } + } + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode) { + unsafe { + gst_audio_sys::gst_audio_decoder_merge_tags( + self.as_ref().to_glib_none().0, + tags.to_glib_none().0, + mode.to_glib(), + ); + } + } + + fn proxy_getcaps( + &self, + caps: Option<&gst::Caps>, + filter: Option<&gst::Caps>, + ) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_decoder_proxy_getcaps( + self.as_ref().to_glib_none().0, + caps.to_glib_none().0, + filter.to_glib_none().0, + )) + } + } + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn set_allocation_caps(&self, allocation_caps: Option<&gst::Caps>) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_allocation_caps( + self.as_ref().to_glib_none().0, + allocation_caps.to_glib_none().0, + ); + } + } + + fn set_drainable(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_drainable( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_estimate_rate(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_estimate_rate( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_latency(&self, min: gst::ClockTime, max: gst::ClockTime) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_latency( + self.as_ref().to_glib_none().0, + min.to_glib(), + max.to_glib(), + ); + } + } + + fn set_max_errors(&self, num: i32) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_max_errors(self.as_ref().to_glib_none().0, num); + } + } + + fn set_min_latency(&self, num: gst::ClockTime) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_min_latency( + self.as_ref().to_glib_none().0, + num.to_glib(), + ); + } + } + + fn set_needs_format(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_needs_format( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_plc(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_plc( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_plc_aware(&self, plc: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_plc_aware( + self.as_ref().to_glib_none().0, + plc.to_glib(), + ); + } + } + + fn set_tolerance(&self, tolerance: gst::ClockTime) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_tolerance( + self.as_ref().to_glib_none().0, + tolerance.to_glib(), + ); + } + } + + fn set_use_default_pad_acceptcaps(&self, use_: bool) { + unsafe { + gst_audio_sys::gst_audio_decoder_set_use_default_pad_acceptcaps( + self.as_ref().to_glib_none().0, + use_.to_glib(), + ); + } + } + + fn connect_property_min_latency_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_min_latency_trampoline( + this: *mut gst_audio_sys::GstAudioDecoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioDecoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::min-latency\0".as_ptr() as *const _, + Some(transmute(notify_min_latency_trampoline:: as usize)), + Box_::into_raw(f), + ) + } + } + + fn connect_property_plc_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_plc_trampoline( + this: *mut gst_audio_sys::GstAudioDecoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioDecoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::plc\0".as_ptr() as *const _, + Some(transmute(notify_plc_trampoline:: as usize)), + Box_::into_raw(f), + ) + } + } + + fn connect_property_tolerance_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_tolerance_trampoline( + this: *mut gst_audio_sys::GstAudioDecoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioDecoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::tolerance\0".as_ptr() as *const _, + Some(transmute(notify_tolerance_trampoline:: as usize)), + Box_::into_raw(f), + ) + } + } +} diff --git a/gstreamer-audio/src/auto/audio_encoder.rs b/gstreamer-audio/src/auto/audio_encoder.rs new file mode 100644 index 000000000..082c3d7d9 --- /dev/null +++ b/gstreamer-audio/src/auto/audio_encoder.rs @@ -0,0 +1,440 @@ +// 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::object::Cast; +use glib::object::IsA; +use glib::signal::connect_raw; +use glib::signal::SignalHandlerId; +use glib::translate::*; +use glib_sys; +use gst; +use gst_audio_sys; +use std::boxed::Box as Box_; +use std::mem::transmute; +use AudioInfo; + +glib_wrapper! { + pub struct AudioEncoder(Object) @extends gst::Element, gst::Object; + + match fn { + get_type => || gst_audio_sys::gst_audio_encoder_get_type(), + } +} + +unsafe impl Send for AudioEncoder {} +unsafe impl Sync for AudioEncoder {} + +pub const NONE_AUDIO_ENCODER: Option<&AudioEncoder> = None; + +pub trait AudioEncoderExt: 'static { + fn allocate_output_buffer(&self, size: usize) -> Option; + + fn get_audio_info(&self) -> Option; + + fn get_drainable(&self) -> bool; + + fn get_frame_max(&self) -> i32; + + fn get_frame_samples_max(&self) -> i32; + + fn get_frame_samples_min(&self) -> i32; + + fn get_hard_min(&self) -> bool; + + fn get_hard_resync(&self) -> bool; + + fn get_lookahead(&self) -> i32; + + fn get_mark_granule(&self) -> bool; + + fn get_perfect_timestamp(&self) -> bool; + + fn get_tolerance(&self) -> gst::ClockTime; + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode); + + fn proxy_getcaps( + &self, + caps: Option<&gst::Caps>, + filter: Option<&gst::Caps>, + ) -> Option; + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn set_allocation_caps(&self, allocation_caps: Option<&gst::Caps>); + + fn set_drainable(&self, enabled: bool); + + fn set_frame_max(&self, num: i32); + + fn set_frame_samples_max(&self, num: i32); + + fn set_frame_samples_min(&self, num: i32); + + fn set_hard_min(&self, enabled: bool); + + fn set_hard_resync(&self, enabled: bool); + + fn set_headers(&self, headers: &[&gst::Buffer]); + + fn set_latency(&self, min: gst::ClockTime, max: gst::ClockTime); + + fn set_lookahead(&self, num: i32); + + fn set_mark_granule(&self, enabled: bool); + + fn set_perfect_timestamp(&self, enabled: bool); + + fn set_tolerance(&self, tolerance: gst::ClockTime); + + fn connect_property_hard_resync_notify( + &self, + f: F, + ) -> SignalHandlerId; + + fn connect_property_mark_granule_notify( + &self, + f: F, + ) -> SignalHandlerId; + + fn connect_property_perfect_timestamp_notify( + &self, + f: F, + ) -> SignalHandlerId; + + fn connect_property_tolerance_notify( + &self, + f: F, + ) -> SignalHandlerId; +} + +impl> AudioEncoderExt for O { + fn allocate_output_buffer(&self, size: usize) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_encoder_allocate_output_buffer( + self.as_ref().to_glib_none().0, + size, + )) + } + } + + fn get_audio_info(&self) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_encoder_get_audio_info( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_drainable(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_drainable( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_frame_max(&self) -> i32 { + unsafe { gst_audio_sys::gst_audio_encoder_get_frame_max(self.as_ref().to_glib_none().0) } + } + + fn get_frame_samples_max(&self) -> i32 { + unsafe { + gst_audio_sys::gst_audio_encoder_get_frame_samples_max(self.as_ref().to_glib_none().0) + } + } + + fn get_frame_samples_min(&self) -> i32 { + unsafe { + gst_audio_sys::gst_audio_encoder_get_frame_samples_min(self.as_ref().to_glib_none().0) + } + } + + fn get_hard_min(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_hard_min( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_hard_resync(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_hard_resync( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_lookahead(&self) -> i32 { + unsafe { gst_audio_sys::gst_audio_encoder_get_lookahead(self.as_ref().to_glib_none().0) } + } + + fn get_mark_granule(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_mark_granule( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_perfect_timestamp(&self) -> bool { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_perfect_timestamp( + self.as_ref().to_glib_none().0, + )) + } + } + + fn get_tolerance(&self) -> gst::ClockTime { + unsafe { + from_glib(gst_audio_sys::gst_audio_encoder_get_tolerance( + self.as_ref().to_glib_none().0, + )) + } + } + + fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode) { + unsafe { + gst_audio_sys::gst_audio_encoder_merge_tags( + self.as_ref().to_glib_none().0, + tags.to_glib_none().0, + mode.to_glib(), + ); + } + } + + fn proxy_getcaps( + &self, + caps: Option<&gst::Caps>, + filter: Option<&gst::Caps>, + ) -> Option { + unsafe { + from_glib_full(gst_audio_sys::gst_audio_encoder_proxy_getcaps( + self.as_ref().to_glib_none().0, + caps.to_glib_none().0, + filter.to_glib_none().0, + )) + } + } + + #[cfg(any(feature = "v1_10", feature = "dox"))] + fn set_allocation_caps(&self, allocation_caps: Option<&gst::Caps>) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_allocation_caps( + self.as_ref().to_glib_none().0, + allocation_caps.to_glib_none().0, + ); + } + } + + fn set_drainable(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_drainable( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_frame_max(&self, num: i32) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_frame_max(self.as_ref().to_glib_none().0, num); + } + } + + fn set_frame_samples_max(&self, num: i32) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_frame_samples_max( + self.as_ref().to_glib_none().0, + num, + ); + } + } + + fn set_frame_samples_min(&self, num: i32) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_frame_samples_min( + self.as_ref().to_glib_none().0, + num, + ); + } + } + + fn set_hard_min(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_hard_min( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_hard_resync(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_hard_resync( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_headers(&self, headers: &[&gst::Buffer]) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_headers( + self.as_ref().to_glib_none().0, + headers.to_glib_full(), + ); + } + } + + fn set_latency(&self, min: gst::ClockTime, max: gst::ClockTime) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_latency( + self.as_ref().to_glib_none().0, + min.to_glib(), + max.to_glib(), + ); + } + } + + fn set_lookahead(&self, num: i32) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_lookahead(self.as_ref().to_glib_none().0, num); + } + } + + fn set_mark_granule(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_mark_granule( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_perfect_timestamp(&self, enabled: bool) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_perfect_timestamp( + self.as_ref().to_glib_none().0, + enabled.to_glib(), + ); + } + } + + fn set_tolerance(&self, tolerance: gst::ClockTime) { + unsafe { + gst_audio_sys::gst_audio_encoder_set_tolerance( + self.as_ref().to_glib_none().0, + tolerance.to_glib(), + ); + } + } + + fn connect_property_hard_resync_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_hard_resync_trampoline( + this: *mut gst_audio_sys::GstAudioEncoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioEncoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::hard-resync\0".as_ptr() as *const _, + Some(transmute(notify_hard_resync_trampoline:: as usize)), + Box_::into_raw(f), + ) + } + } + + fn connect_property_mark_granule_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_mark_granule_trampoline( + this: *mut gst_audio_sys::GstAudioEncoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioEncoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::mark-granule\0".as_ptr() as *const _, + Some(transmute( + notify_mark_granule_trampoline:: as usize, + )), + Box_::into_raw(f), + ) + } + } + + fn connect_property_perfect_timestamp_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_perfect_timestamp_trampoline< + P, + F: Fn(&P) + Send + Sync + 'static, + >( + this: *mut gst_audio_sys::GstAudioEncoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioEncoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::perfect-timestamp\0".as_ptr() as *const _, + Some(transmute( + notify_perfect_timestamp_trampoline:: as usize, + )), + Box_::into_raw(f), + ) + } + } + + fn connect_property_tolerance_notify( + &self, + f: F, + ) -> SignalHandlerId { + unsafe extern "C" fn notify_tolerance_trampoline( + this: *mut gst_audio_sys::GstAudioEncoder, + _param_spec: glib_sys::gpointer, + f: glib_sys::gpointer, + ) where + P: IsA, + { + let f: &F = &*(f as *const F); + f(&AudioEncoder::from_glib_borrow(this).unsafe_cast()) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw( + self.as_ptr() as *mut _, + b"notify::tolerance\0".as_ptr() as *const _, + Some(transmute(notify_tolerance_trampoline:: as usize)), + Box_::into_raw(f), + ) + } + } +} diff --git a/gstreamer-audio/src/auto/mod.rs b/gstreamer-audio/src/auto/mod.rs index 362aa1144..294982089 100644 --- a/gstreamer-audio/src/auto/mod.rs +++ b/gstreamer-audio/src/auto/mod.rs @@ -2,6 +2,14 @@ // from gir-files (https://github.com/gtk-rs/gir-files) // DO NOT EDIT +mod audio_decoder; +pub use self::audio_decoder::AudioDecoderExt; +pub use self::audio_decoder::{AudioDecoder, AudioDecoderClass, NONE_AUDIO_DECODER}; + +mod audio_encoder; +pub use self::audio_encoder::AudioEncoderExt; +pub use self::audio_encoder::{AudioEncoder, AudioEncoderClass, NONE_AUDIO_ENCODER}; + mod stream_volume; pub use self::stream_volume::StreamVolumeExt; pub use self::stream_volume::{StreamVolume, NONE_STREAM_VOLUME}; @@ -24,5 +32,7 @@ pub use self::flags::AudioPackFlags; #[doc(hidden)] pub mod traits { + pub use super::AudioDecoderExt; + pub use super::AudioEncoderExt; pub use super::StreamVolumeExt; } diff --git a/gstreamer-audio/src/lib.rs b/gstreamer-audio/src/lib.rs index b16351622..8660b5a34 100644 --- a/gstreamer-audio/src/lib.rs +++ b/gstreamer-audio/src/lib.rs @@ -14,8 +14,11 @@ extern crate bitflags; extern crate glib; extern crate glib_sys; extern crate gobject_sys; +#[macro_use] extern crate gstreamer as gst; extern crate gstreamer_audio_sys as gst_audio_sys; +extern crate gstreamer_base as gst_base; +extern crate gstreamer_base_sys as gst_base_sys; extern crate gstreamer_sys as gst_sys; macro_rules! assert_initialized_main_thread { @@ -49,6 +52,11 @@ pub use audio_channel_position::*; #[cfg(any(feature = "v1_14", feature = "dox"))] mod audio_stream_align; +mod audio_decoder; +pub use audio_decoder::*; +mod audio_encoder; +pub use audio_encoder::*; + use glib::translate::{from_glib_full, ToGlibPtr}; pub fn audio_buffer_clip( buffer: gst::Buffer, @@ -74,5 +82,9 @@ pub mod prelude { pub use glib::prelude::*; pub use gst::prelude::*; + pub use super::audio_decoder::AudioDecoderExtManual; + pub use super::audio_encoder::AudioEncoderExtManual; pub use auto::traits::*; } + +pub mod subclass; diff --git a/gstreamer-audio/src/subclass/audio_decoder.rs b/gstreamer-audio/src/subclass/audio_decoder.rs new file mode 100644 index 000000000..e07e1c994 --- /dev/null +++ b/gstreamer-audio/src/subclass/audio_decoder.rs @@ -0,0 +1,946 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// 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_audio_sys; +use gst_sys; + +use glib::translate::*; + +use glib::subclass::prelude::*; +use gst; +use gst::subclass::prelude::*; +use gst::MiniObject; +use gst_base; + +use std::mem; +use std::ptr; + +use AudioDecoder; +use AudioDecoderClass; + +pub trait AudioDecoderImpl: AudioDecoderImplExt + ElementImpl + Send + Sync + 'static { + fn open(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + self.parent_open(element) + } + + fn close(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + self.parent_close(element) + } + + fn start(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + self.parent_start(element) + } + + fn stop(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + self.parent_stop(element) + } + + fn set_format( + &self, + element: &AudioDecoder, + caps: &gst::Caps, + ) -> Result<(), gst::LoggableError> { + self.parent_set_format(element, caps) + } + + fn parse( + &self, + element: &AudioDecoder, + adapter: &gst_base::Adapter, + ) -> Result<(u32, u32), gst::FlowError> { + self.parent_parse(element, adapter) + } + + fn handle_frame( + &self, + element: &AudioDecoder, + buffer: Option<&gst::Buffer>, + ) -> Result { + self.parent_handle_frame(element, buffer) + } + + fn pre_push( + &self, + element: &AudioDecoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError> { + self.parent_pre_push(element, buffer) + } + + fn flush(&self, element: &AudioDecoder, hard: bool) { + self.parent_flush(element, hard) + } + + fn negotiate(&self, element: &AudioDecoder) -> Result<(), gst::LoggableError> { + self.parent_negotiate(element) + } + + fn get_caps(&self, element: &AudioDecoder, filter: Option<&gst::Caps>) -> Option { + self.parent_get_caps(element, filter) + } + + fn sink_event(&self, element: &AudioDecoder, event: gst::Event) -> bool { + self.parent_sink_event(element, event) + } + + fn sink_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool { + self.parent_sink_query(element, query) + } + + fn src_event(&self, element: &AudioDecoder, event: gst::Event) -> bool { + self.parent_src_event(element, event) + } + + fn src_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool { + self.parent_src_query(element, query) + } + + fn propose_allocation( + &self, + element: &AudioDecoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage> { + self.parent_propose_allocation(element, query) + } + + fn decide_allocation( + &self, + element: &AudioDecoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage> { + self.parent_decide_allocation(element, query) + } +} + +pub trait AudioDecoderImplExt { + fn parent_open(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage>; + + fn parent_close(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage>; + + fn parent_start(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage>; + + fn parent_stop(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage>; + + fn parent_set_format( + &self, + element: &AudioDecoder, + caps: &gst::Caps, + ) -> Result<(), gst::LoggableError>; + + fn parent_parse( + &self, + element: &AudioDecoder, + adapter: &gst_base::Adapter, + ) -> Result<(u32, u32), gst::FlowError>; + + fn parent_handle_frame( + &self, + element: &AudioDecoder, + buffer: Option<&gst::Buffer>, + ) -> Result; + + fn parent_pre_push( + &self, + element: &AudioDecoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError>; + + fn parent_flush(&self, element: &AudioDecoder, hard: bool); + + fn parent_negotiate(&self, element: &AudioDecoder) -> Result<(), gst::LoggableError>; + + fn parent_get_caps( + &self, + element: &AudioDecoder, + filter: Option<&gst::Caps>, + ) -> Option; + + fn parent_sink_event(&self, element: &AudioDecoder, event: gst::Event) -> bool; + + fn parent_sink_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool; + + fn parent_src_event(&self, element: &AudioDecoder, event: gst::Event) -> bool; + + fn parent_src_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool; + + fn parent_propose_allocation( + &self, + element: &AudioDecoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage>; + + fn parent_decide_allocation( + &self, + element: &AudioDecoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage>; +} + +impl AudioDecoderImplExt for T { + fn parent_open(&self, element: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*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: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*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: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*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: &AudioDecoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*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_set_format( + &self, + element: &AudioDecoder, + caps: &gst::Caps, + ) -> Result<(), gst::LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .set_format + .map(|f| { + gst_result_from_gboolean!( + f(element.to_glib_none().0, caps.to_glib_none().0), + gst::CAT_RUST, + "parent function `set_format` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_parse( + &self, + element: &AudioDecoder, + adapter: &gst_base::Adapter, + ) -> Result<(u32, u32), gst::FlowError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .parse + .map(|f| { + let mut offset = mem::MaybeUninit::uninit(); + let mut len = mem::MaybeUninit::uninit(); + match gst::FlowReturn::from_glib(f( + element.to_glib_none().0, + adapter.to_glib_none().0, + offset.as_mut_ptr(), + len.as_mut_ptr(), + )) + .into_result() + { + Ok(_) => { + let offset = offset.assume_init(); + let len = len.assume_init(); + assert!(offset >= 0); + assert!(len >= 0); + Ok((offset as u32, len as u32)) + } + Err(err) => Err(err), + } + }) + .unwrap_or_else(|| Ok((0, adapter.available() as u32))) + } + } + + fn parent_handle_frame( + &self, + element: &AudioDecoder, + buffer: Option<&gst::Buffer>, + ) -> Result { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .handle_frame + .map(|f| { + gst::FlowReturn::from_glib(f( + element.to_glib_none().0, + buffer + .map(|buffer| buffer.as_mut_ptr() as *mut *mut gst_sys::GstBuffer) + .unwrap_or(ptr::null_mut()), + )) + }) + .unwrap_or(gst::FlowReturn::Error) + .into_result() + } + } + + fn parent_pre_push( + &self, + element: &AudioDecoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + if let Some(f) = (*parent_class).pre_push { + let mut buffer = buffer.into_ptr(); + match gst::FlowReturn::from_glib(f(element.to_glib_none().0, &mut buffer)) + .into_result() + { + Ok(_) => Ok(from_glib_full(buffer)), + Err(err) => Err(err), + } + } else { + Ok(Some(buffer)) + } + } + } + + fn parent_flush(&self, element: &AudioDecoder, hard: bool) { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .flush + .map(|f| f(element.to_glib_none().0, hard.to_glib())) + .unwrap_or(()) + } + } + + fn parent_negotiate(&self, element: &AudioDecoder) -> Result<(), gst::LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .negotiate + .map(|f| { + gst_result_from_gboolean!( + f(element.to_glib_none().0), + gst::CAT_RUST, + "Parent function `negotiate` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_get_caps( + &self, + element: &AudioDecoder, + filter: Option<&gst::Caps>, + ) -> Option { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + (*parent_class) + .getcaps + .map(|f| from_glib_full(f(element.to_glib_none().0, filter.to_glib_none().0))) + .unwrap_or(None) + } + } + + fn parent_sink_event(&self, element: &AudioDecoder, event: gst::Event) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + let f = (*parent_class) + .sink_event + .expect("Missing parent function `sink_event`"); + from_glib(f(element.to_glib_none().0, event.into_ptr())) + } + } + + fn parent_sink_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + let f = (*parent_class) + .sink_query + .expect("Missing parent function `sink_query`"); + from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) + } + } + + fn parent_src_event(&self, element: &AudioDecoder, event: gst::Event) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + let f = (*parent_class) + .src_event + .expect("Missing parent function `src_event`"); + from_glib(f(element.to_glib_none().0, event.into_ptr())) + } + } + + fn parent_src_query(&self, element: &AudioDecoder, query: &mut gst::QueryRef) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioDecoderClass; + let f = (*parent_class) + .src_query + .expect("Missing parent function `src_query`"); + from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) + } + } + + fn parent_propose_allocation( + &self, + element: &AudioDecoder, + 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_audio_sys::GstAudioDecoderClass; + (*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: &AudioDecoder, + 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_audio_sys::GstAudioDecoderClass; + (*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 AudioDecoderClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_audio_sys::GstAudioDecoderClass); + klass.open = Some(audio_decoder_open::); + klass.close = Some(audio_decoder_close::); + klass.start = Some(audio_decoder_start::); + klass.stop = Some(audio_decoder_stop::); + klass.set_format = Some(audio_decoder_set_format::); + klass.parse = Some(audio_decoder_parse::); + klass.handle_frame = Some(audio_decoder_handle_frame::); + klass.pre_push = Some(audio_decoder_pre_push::); + klass.flush = Some(audio_decoder_flush::); + klass.negotiate = Some(audio_decoder_negotiate::); + klass.getcaps = Some(audio_decoder_getcaps::); + klass.sink_event = Some(audio_decoder_sink_event::); + klass.src_event = Some(audio_decoder_src_event::); + klass.sink_query = Some(audio_decoder_sink_query::); + klass.src_query = Some(audio_decoder_src_query::); + klass.propose_allocation = Some(audio_decoder_propose_allocation::); + klass.decide_allocation = Some(audio_decoder_decide_allocation::); + } + } +} + +unsafe extern "C" fn audio_decoder_open( + ptr: *mut gst_audio_sys::GstAudioDecoder, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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 audio_decoder_close( + ptr: *mut gst_audio_sys::GstAudioDecoder, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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 audio_decoder_start( + ptr: *mut gst_audio_sys::GstAudioDecoder, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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 audio_decoder_stop( + ptr: *mut gst_audio_sys::GstAudioDecoder, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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 audio_decoder_set_format( + ptr: *mut gst_audio_sys::GstAudioDecoder, + caps: *mut gst_sys::GstCaps, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.set_format(&wrap, &from_glib_borrow(caps)) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_parse( + ptr: *mut gst_audio_sys::GstAudioDecoder, + adapter: *mut gst_base_sys::GstAdapter, + offset: *mut i32, + len: *mut i32, +) -> gst_sys::GstFlowReturn +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { + match imp.parse(&wrap, &from_glib_borrow(adapter)) { + Ok((new_offset, new_len)) => { + assert!(new_offset <= std::i32::MAX as u32); + assert!(new_len <= std::i32::MAX as u32); + *offset = new_offset as i32; + *len = new_len as i32; + Ok(gst::FlowSuccess::Ok) + } + Err(err) => Err(err), + } + .into() + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_handle_frame( + ptr: *mut gst_audio_sys::GstAudioDecoder, + buffer: *mut *mut gst_sys::GstBuffer, +) -> gst_sys::GstFlowReturn +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + // FIXME: Misgenerated in gstreamer-audio-sys + let buffer = buffer as *mut gst_sys::GstBuffer; + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { + imp.handle_frame( + &wrap, + Option::::from_glib_none(buffer).as_ref(), + ) + .into() + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_pre_push( + ptr: *mut gst_audio_sys::GstAudioDecoder, + buffer: *mut *mut gst_sys::GstBuffer, +) -> gst_sys::GstFlowReturn +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { + match imp.pre_push(&wrap, from_glib_full(*buffer)) { + Ok(Some(new_buffer)) => { + *buffer = new_buffer.into_ptr(); + Ok(gst::FlowSuccess::Ok) + } + Ok(None) => { + *buffer = ptr::null_mut(); + Ok(gst::FlowSuccess::Ok) + } + Err(err) => Err(err), + } + .into() + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_flush( + ptr: *mut gst_audio_sys::GstAudioDecoder, + hard: glib_sys::gboolean, +) where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), (), { + AudioDecoderImpl::flush(imp, &wrap, from_glib(hard)) + }) +} + +unsafe extern "C" fn audio_decoder_negotiate( + ptr: *mut gst_audio_sys::GstAudioDecoder, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.negotiate(&wrap) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_getcaps( + ptr: *mut gst_audio_sys::GstAudioDecoder, + filter: *mut gst_sys::GstCaps, +) -> *mut gst_sys::GstCaps +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), None, { + AudioDecoderImpl::get_caps( + imp, + &wrap, + Option::::from_glib_borrow(filter).as_ref(), + ) + }) + .to_glib_full() +} + +unsafe extern "C" fn audio_decoder_sink_event( + ptr: *mut gst_audio_sys::GstAudioDecoder, + event: *mut gst_sys::GstEvent, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.sink_event(&wrap, from_glib_full(event)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_sink_query( + ptr: *mut gst_audio_sys::GstAudioDecoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.sink_query(&wrap, gst::QueryRef::from_mut_ptr(query)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_src_event( + ptr: *mut gst_audio_sys::GstAudioDecoder, + event: *mut gst_sys::GstEvent, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.src_event(&wrap, from_glib_full(event)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_src_query( + ptr: *mut gst_audio_sys::GstAudioDecoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.src_query(&wrap, gst::QueryRef::from_mut_ptr(query)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_decoder_propose_allocation( + ptr: *mut gst_audio_sys::GstAudioDecoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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 audio_decoder_decide_allocation( + ptr: *mut gst_audio_sys::GstAudioDecoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioDecoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioDecoder = 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() +} diff --git a/gstreamer-audio/src/subclass/audio_encoder.rs b/gstreamer-audio/src/subclass/audio_encoder.rs new file mode 100644 index 000000000..a1c47c08f --- /dev/null +++ b/gstreamer-audio/src/subclass/audio_encoder.rs @@ -0,0 +1,862 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// 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_audio_sys; +use gst_sys; + +use glib::translate::*; + +use glib::subclass::prelude::*; +use gst; +use gst::subclass::prelude::*; +use gst::MiniObject; + +use std::ptr; + +use AudioEncoder; +use AudioEncoderClass; +use AudioInfo; + +pub trait AudioEncoderImpl: AudioEncoderImplExt + ElementImpl + Send + Sync + 'static { + fn open(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + self.parent_open(element) + } + + fn close(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + self.parent_close(element) + } + + fn start(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + self.parent_start(element) + } + + fn stop(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + self.parent_stop(element) + } + + fn set_format( + &self, + element: &AudioEncoder, + info: &AudioInfo, + ) -> Result<(), gst::LoggableError> { + self.parent_set_format(element, info) + } + + fn handle_frame( + &self, + element: &AudioEncoder, + buffer: Option<&gst::Buffer>, + ) -> Result { + self.parent_handle_frame(element, buffer) + } + + fn pre_push( + &self, + element: &AudioEncoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError> { + self.parent_pre_push(element, buffer) + } + + fn flush(&self, element: &AudioEncoder) { + self.parent_flush(element) + } + + fn negotiate(&self, element: &AudioEncoder) -> Result<(), gst::LoggableError> { + self.parent_negotiate(element) + } + + fn get_caps(&self, element: &AudioEncoder, filter: Option<&gst::Caps>) -> Option { + self.parent_get_caps(element, filter) + } + + fn sink_event(&self, element: &AudioEncoder, event: gst::Event) -> bool { + self.parent_sink_event(element, event) + } + + fn sink_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool { + self.parent_sink_query(element, query) + } + + fn src_event(&self, element: &AudioEncoder, event: gst::Event) -> bool { + self.parent_src_event(element, event) + } + + fn src_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool { + self.parent_src_query(element, query) + } + + fn propose_allocation( + &self, + element: &AudioEncoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage> { + self.parent_propose_allocation(element, query) + } + + fn decide_allocation( + &self, + element: &AudioEncoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage> { + self.parent_decide_allocation(element, query) + } +} + +pub trait AudioEncoderImplExt { + fn parent_open(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage>; + + fn parent_close(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage>; + + fn parent_start(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage>; + + fn parent_stop(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage>; + + fn parent_set_format( + &self, + element: &AudioEncoder, + info: &AudioInfo, + ) -> Result<(), gst::LoggableError>; + + fn parent_handle_frame( + &self, + element: &AudioEncoder, + buffer: Option<&gst::Buffer>, + ) -> Result; + + fn parent_pre_push( + &self, + element: &AudioEncoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError>; + + fn parent_flush(&self, element: &AudioEncoder); + + fn parent_negotiate(&self, element: &AudioEncoder) -> Result<(), gst::LoggableError>; + + fn parent_get_caps( + &self, + element: &AudioEncoder, + filter: Option<&gst::Caps>, + ) -> Option; + + fn parent_sink_event(&self, element: &AudioEncoder, event: gst::Event) -> bool; + + fn parent_sink_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool; + + fn parent_src_event(&self, element: &AudioEncoder, event: gst::Event) -> bool; + + fn parent_src_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool; + + fn parent_propose_allocation( + &self, + element: &AudioEncoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage>; + + fn parent_decide_allocation( + &self, + element: &AudioEncoder, + query: &mut gst::QueryRef, + ) -> Result<(), gst::ErrorMessage>; +} + +impl AudioEncoderImplExt for T { + fn parent_open(&self, element: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*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: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*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: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*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: &AudioEncoder) -> Result<(), gst::ErrorMessage> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*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_set_format( + &self, + element: &AudioEncoder, + info: &AudioInfo, + ) -> Result<(), gst::LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*parent_class) + .set_format + .map(|f| { + gst_result_from_gboolean!( + f(element.to_glib_none().0, info.to_glib_none().0 as *mut _), + gst::CAT_RUST, + "parent function `set_format` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_handle_frame( + &self, + element: &AudioEncoder, + buffer: Option<&gst::Buffer>, + ) -> Result { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*parent_class) + .handle_frame + .map(|f| { + gst::FlowReturn::from_glib(f( + element.to_glib_none().0, + buffer + .map(|buffer| buffer.as_mut_ptr() as *mut *mut gst_sys::GstBuffer) + .unwrap_or(ptr::null_mut()), + )) + }) + .unwrap_or(gst::FlowReturn::Error) + .into_result() + } + } + + fn parent_pre_push( + &self, + element: &AudioEncoder, + buffer: gst::Buffer, + ) -> Result, gst::FlowError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + if let Some(f) = (*parent_class).pre_push { + let mut buffer = buffer.into_ptr(); + match gst::FlowReturn::from_glib(f(element.to_glib_none().0, &mut buffer)) + .into_result() + { + Ok(_) => Ok(from_glib_full(buffer)), + Err(err) => Err(err), + } + } else { + Ok(Some(buffer)) + } + } + } + + fn parent_flush(&self, element: &AudioEncoder) { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*parent_class) + .flush + .map(|f| f(element.to_glib_none().0)) + .unwrap_or(()) + } + } + + fn parent_negotiate(&self, element: &AudioEncoder) -> Result<(), gst::LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*parent_class) + .negotiate + .map(|f| { + gst_result_from_gboolean!( + f(element.to_glib_none().0), + gst::CAT_RUST, + "Parent function `negotiate` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_get_caps( + &self, + element: &AudioEncoder, + filter: Option<&gst::Caps>, + ) -> Option { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + (*parent_class) + .getcaps + .map(|f| from_glib_full(f(element.to_glib_none().0, filter.to_glib_none().0))) + .unwrap_or(None) + } + } + + fn parent_sink_event(&self, element: &AudioEncoder, event: gst::Event) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + let f = (*parent_class) + .sink_event + .expect("Missing parent function `sink_event`"); + from_glib(f(element.to_glib_none().0, event.into_ptr())) + } + } + + fn parent_sink_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + let f = (*parent_class) + .sink_query + .expect("Missing parent function `sink_query`"); + from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) + } + } + + fn parent_src_event(&self, element: &AudioEncoder, event: gst::Event) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + let f = (*parent_class) + .src_event + .expect("Missing parent function `src_event`"); + from_glib(f(element.to_glib_none().0, event.into_ptr())) + } + } + + fn parent_src_query(&self, element: &AudioEncoder, query: &mut gst::QueryRef) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = + data.as_ref().get_parent_class() as *mut gst_audio_sys::GstAudioEncoderClass; + let f = (*parent_class) + .src_query + .expect("Missing parent function `src_query`"); + from_glib(f(element.to_glib_none().0, query.as_mut_ptr())) + } + } + + fn parent_propose_allocation( + &self, + element: &AudioEncoder, + 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_audio_sys::GstAudioEncoderClass; + (*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: &AudioEncoder, + 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_audio_sys::GstAudioEncoderClass; + (*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 AudioEncoderClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_audio_sys::GstAudioEncoderClass); + klass.open = Some(audio_encoder_open::); + klass.close = Some(audio_encoder_close::); + klass.start = Some(audio_encoder_start::); + klass.stop = Some(audio_encoder_stop::); + klass.set_format = Some(audio_encoder_set_format::); + klass.handle_frame = Some(audio_encoder_handle_frame::); + klass.pre_push = Some(audio_encoder_pre_push::); + klass.flush = Some(audio_encoder_flush::); + klass.negotiate = Some(audio_encoder_negotiate::); + klass.getcaps = Some(audio_encoder_getcaps::); + klass.sink_event = Some(audio_encoder_sink_event::); + klass.src_event = Some(audio_encoder_src_event::); + klass.sink_query = Some(audio_encoder_sink_query::); + klass.src_query = Some(audio_encoder_src_query::); + klass.propose_allocation = Some(audio_encoder_propose_allocation::); + klass.decide_allocation = Some(audio_encoder_decide_allocation::); + } + } +} + +unsafe extern "C" fn audio_encoder_open( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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 audio_encoder_close( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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 audio_encoder_start( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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 audio_encoder_stop( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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 audio_encoder_set_format( + ptr: *mut gst_audio_sys::GstAudioEncoder, + info: *mut gst_audio_sys::GstAudioInfo, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.set_format(&wrap, &from_glib_none(info)) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_handle_frame( + ptr: *mut gst_audio_sys::GstAudioEncoder, + buffer: *mut *mut gst_sys::GstBuffer, +) -> gst_sys::GstFlowReturn +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + // FIXME: Misgenerated in gstreamer-audio-sys + let buffer = buffer as *mut gst_sys::GstBuffer; + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { + imp.handle_frame( + &wrap, + Option::::from_glib_none(buffer).as_ref(), + ) + .into() + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_pre_push( + ptr: *mut gst_audio_sys::GstAudioEncoder, + buffer: *mut *mut gst_sys::GstBuffer, +) -> gst_sys::GstFlowReturn +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), gst::FlowReturn::Error, { + match imp.pre_push(&wrap, from_glib_full(*buffer)) { + Ok(Some(new_buffer)) => { + *buffer = new_buffer.into_ptr(); + Ok(gst::FlowSuccess::Ok) + } + Ok(None) => { + *buffer = ptr::null_mut(); + Ok(gst::FlowSuccess::Ok) + } + Err(err) => Err(err), + } + .into() + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_flush( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), (), { + AudioEncoderImpl::flush(imp, &wrap) + }) +} + +unsafe extern "C" fn audio_encoder_negotiate( + ptr: *mut gst_audio_sys::GstAudioEncoder, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + match imp.negotiate(&wrap) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_getcaps( + ptr: *mut gst_audio_sys::GstAudioEncoder, + filter: *mut gst_sys::GstCaps, +) -> *mut gst_sys::GstCaps +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), None, { + AudioEncoderImpl::get_caps( + imp, + &wrap, + Option::::from_glib_borrow(filter).as_ref(), + ) + }) + .to_glib_full() +} + +unsafe extern "C" fn audio_encoder_sink_event( + ptr: *mut gst_audio_sys::GstAudioEncoder, + event: *mut gst_sys::GstEvent, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.sink_event(&wrap, from_glib_full(event)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_sink_query( + ptr: *mut gst_audio_sys::GstAudioEncoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.sink_query(&wrap, gst::QueryRef::from_mut_ptr(query)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_src_event( + ptr: *mut gst_audio_sys::GstAudioEncoder, + event: *mut gst_sys::GstEvent, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.src_event(&wrap, from_glib_full(event)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_src_query( + ptr: *mut gst_audio_sys::GstAudioEncoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.src_query(&wrap, gst::QueryRef::from_mut_ptr(query)) + }) + .to_glib() +} + +unsafe extern "C" fn audio_encoder_propose_allocation( + ptr: *mut gst_audio_sys::GstAudioEncoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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 audio_encoder_decide_allocation( + ptr: *mut gst_audio_sys::GstAudioEncoder, + query: *mut gst_sys::GstQuery, +) -> glib_sys::gboolean +where + T: AudioEncoderImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: AudioEncoder = 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() +} diff --git a/gstreamer-audio/src/subclass/mod.rs b/gstreamer-audio/src/subclass/mod.rs new file mode 100644 index 000000000..55ac801bf --- /dev/null +++ b/gstreamer-audio/src/subclass/mod.rs @@ -0,0 +1,16 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// 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. +#![allow(clippy::cast_ptr_alignment)] + +pub mod audio_decoder; +pub mod audio_encoder; + +pub mod prelude { + pub use super::audio_decoder::{AudioDecoderImpl, AudioDecoderImplExt}; + pub use super::audio_encoder::{AudioEncoderImpl, AudioEncoderImplExt}; +}