diff --git a/gst-plugin-tutorial/Cargo.toml b/gst-plugin-tutorial/Cargo.toml index 810de30d8..57b4e5b8f 100644 --- a/gst-plugin-tutorial/Cargo.toml +++ b/gst-plugin-tutorial/Cargo.toml @@ -6,11 +6,9 @@ repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs" license = "MIT/Apache-2.0" [dependencies] -gobject-subclass = { git = "https://github.com/gtk-rs/gobject-subclass" } -gst-plugin = { path="../gst-plugin" } -glib = { git = "https://github.com/gtk-rs/glib" } -gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" } -gstreamer-base = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" } +glib = { git = "https://github.com/gtk-rs/glib", features = ["subclassing"] } +gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["subclassing"] } +gstreamer-base = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["subclassing"] } gstreamer-video = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" } gstreamer-audio = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" } byte-slice-cast = "0.2" diff --git a/gst-plugin-tutorial/src/lib.rs b/gst-plugin-tutorial/src/lib.rs index 38bdfb510..6aee8fee2 100644 --- a/gst-plugin-tutorial/src/lib.rs +++ b/gst-plugin-tutorial/src/lib.rs @@ -6,10 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate glib; -extern crate gobject_subclass; #[macro_use] -extern crate gst_plugin; +extern crate glib; #[macro_use] extern crate gstreamer as gst; extern crate gstreamer_audio as gst_audio; @@ -35,14 +33,14 @@ fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { // Plugin name, plugin description, plugin entry point function, version number of this plugin, // license of the plugin, source package name, binary package name, origin where it comes from // and the date/time of release. -plugin_define!( - b"rstutorial\0", - b"Rust Tutorial Plugin\0", +gst_plugin_define!( + "rstutorial", + "Rust Tutorial Plugin", plugin_init, - b"1.0\0", - b"MIT/X11\0", - b"rstutorial\0", - b"rstutorial\0", - b"https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs\0", - b"2017-12-30\0" + "1.0", + "MIT/X11", + "rstutorial", + "rstutorial", + "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs", + "2017-12-30" ); diff --git a/gst-plugin-tutorial/src/rgb2gray.rs b/gst-plugin-tutorial/src/rgb2gray.rs index 32d297ba3..b5c2539ee 100644 --- a/gst-plugin-tutorial/src/rgb2gray.rs +++ b/gst-plugin-tutorial/src/rgb2gray.rs @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Sebastian Dröge +// Copyright (C) 2017,2018 Sebastian Dröge // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -7,14 +7,15 @@ // except according to those terms. use glib; +use glib::subclass; +use glib::subclass::prelude::*; use gst; use gst::prelude::*; +use gst::subclass::prelude::*; +use gst_base; +use gst_base::subclass::prelude::*; use gst_video; -use gobject_subclass::object::*; -use gst_plugin::base_transform::*; -use gst_plugin::element::*; - use std::i32; use std::sync::Mutex; @@ -39,22 +40,27 @@ impl Default for Settings { } // Metadata for the properties -static PROPERTIES: [Property; 2] = [ - Property::Boolean( - "invert", - "Invert", - "Invert grayscale output", - DEFAULT_INVERT, - PropertyMutability::ReadWrite, - ), - Property::UInt( - "shift", - "Shift", - "Shift grayscale output (wrapping around)", - (0, 255), - DEFAULT_SHIFT, - PropertyMutability::ReadWrite, - ), +static PROPERTIES: [subclass::Property; 2] = [ + subclass::Property("invert", || { + glib::ParamSpec::boolean( + "invert", + "Invert", + "Invert grayscale output", + DEFAULT_INVERT, + glib::ParamFlags::READWRITE, + ) + }), + subclass::Property("shift", || { + glib::ParamSpec::uint( + "shift", + "Shift", + "Shift grayscale output (wrapping around)", + 0, + 255, + DEFAULT_SHIFT, + glib::ParamFlags::READWRITE, + ) + }), ]; // Stream-specific state, i.e. video format configuration @@ -71,9 +77,43 @@ struct Rgb2Gray { } impl Rgb2Gray { + // Converts one pixel of BGRx to a grayscale value, shifting and/or + // inverting it as configured + #[inline] + fn bgrx_to_gray(in_p: &[u8], shift: u8, invert: bool) -> u8 { + // See https://en.wikipedia.org/wiki/YUV#SDTV_with_BT.601 + const R_Y: u32 = 19595; // 0.299 * 65536 + const G_Y: u32 = 38470; // 0.587 * 65536 + const B_Y: u32 = 7471; // 0.114 * 65536 + + assert_eq!(in_p.len(), 4); + + let b = u32::from(in_p[0]); + let g = u32::from(in_p[1]); + let r = u32::from(in_p[2]); + + let gray = ((r * R_Y) + (g * G_Y) + (b * B_Y)) / 65536; + let gray = (gray as u8).wrapping_add(shift); + + if invert { + 255 - gray + } else { + gray + } + } +} + +impl ObjectSubclass for Rgb2Gray { + const NAME: &'static str = "RsRgb2Gray"; + type ParentType = gst_base::BaseTransform; + type Instance = gst::subclass::ElementInstanceStruct; + type Class = subclass::simple::ClassStruct; + + glib_object_subclass!(); + // Called when a new instance is to be created - fn new(_transform: &BaseTransform) -> Box> { - Box::new(Self { + fn new() -> Self { + Self { cat: gst::DebugCategory::new( "rsrgb2gray", gst::DebugColorFlags::empty(), @@ -81,7 +121,7 @@ impl Rgb2Gray { ), settings: Mutex::new(Default::default()), state: Mutex::new(None), - }) + } } // Called exactly once when registering the type. Used for @@ -94,7 +134,7 @@ impl Rgb2Gray { // will automatically instantiate pads for them. // // Our element here can convert BGRx to BGRx or GRAY8, both being grayscale. - fn class_init(klass: &mut BaseTransformClass) { + fn class_init(klass: &mut subclass::simple::ClassStruct) { klass.set_metadata( "RGB-GRAY Converter", "Filter/Effect/Converter/Video", @@ -171,45 +211,26 @@ impl Rgb2Gray { // // We could work in-place for BGRx->BGRx but don't do here for simplicity // for now. - klass.configure(BaseTransformMode::NeverInPlace, false, false); - } - - // Converts one pixel of BGRx to a grayscale value, shifting and/or - // inverting it as configured - #[inline] - fn bgrx_to_gray(in_p: &[u8], shift: u8, invert: bool) -> u8 { - // See https://en.wikipedia.org/wiki/YUV#SDTV_with_BT.601 - const R_Y: u32 = 19595; // 0.299 * 65536 - const G_Y: u32 = 38470; // 0.587 * 65536 - const B_Y: u32 = 7471; // 0.114 * 65536 - - assert_eq!(in_p.len(), 4); - - let b = u32::from(in_p[0]); - let g = u32::from(in_p[1]); - let r = u32::from(in_p[2]); - - let gray = ((r * R_Y) + (g * G_Y) + (b * B_Y)) / 65536; - let gray = (gray as u8).wrapping_add(shift); - - if invert { - 255 - gray - } else { - gray - } + klass.configure( + gst_base::subclass::BaseTransformMode::NeverInPlace, + false, + false, + ); } } // Virtual methods of GObject itself -impl ObjectImpl for Rgb2Gray { +impl ObjectImpl for Rgb2Gray { + glib_object_impl!(); + // Called whenever a value of a property is changed. It can be called // at any time from any thread. - fn set_property(&self, obj: &glib::Object, id: u32, value: &glib::Value) { - let prop = &PROPERTIES[id as usize]; - let element = obj.downcast_ref::().unwrap(); + fn set_property(&self, obj: &glib::Object, id: usize, value: &glib::Value) { + let prop = &PROPERTIES[id]; + let element = obj.downcast_ref::().unwrap(); match *prop { - Property::Boolean("invert", ..) => { + subclass::Property("invert", ..) => { let mut settings = self.settings.lock().unwrap(); let invert = value.get().unwrap(); gst_info!( @@ -221,7 +242,7 @@ impl ObjectImpl for Rgb2Gray { ); settings.invert = invert; } - Property::UInt("shift", ..) => { + subclass::Property("shift", ..) => { let mut settings = self.settings.lock().unwrap(); let shift = value.get().unwrap(); gst_info!( @@ -239,15 +260,15 @@ impl ObjectImpl for Rgb2Gray { // Called whenever a value of a property is read. It can be called // at any time from any thread. - fn get_property(&self, _obj: &glib::Object, id: u32) -> Result { - let prop = &PROPERTIES[id as usize]; + fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + let prop = &PROPERTIES[id]; match *prop { - Property::Boolean("invert", ..) => { + subclass::Property("invert", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.invert.to_value()) } - Property::UInt("shift", ..) => { + subclass::Property("shift", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.shift.to_value()) } @@ -257,17 +278,17 @@ impl ObjectImpl for Rgb2Gray { } // Virtual methods of gst::Element. We override none -impl ElementImpl for Rgb2Gray {} +impl ElementImpl for Rgb2Gray {} // Virtual methods of gst_base::BaseTransform -impl BaseTransformImpl for Rgb2Gray { +impl BaseTransformImpl for Rgb2Gray { // Called for converting caps from one pad to another to account for any // changes in the media format this element is performing. // // In our case that means that: fn transform_caps( &self, - element: &BaseTransform, + element: &gst_base::BaseTransform, direction: gst::PadDirection, caps: &gst::Caps, filter: Option<&gst::Caps>, @@ -325,7 +346,7 @@ impl BaseTransformImpl for Rgb2Gray { // Returns the size of one processing unit (i.e. a frame in our case) corresponding // to the given caps. This is used for allocating a big enough output buffer and // sanity checking the input buffer size, among other things. - fn get_unit_size(&self, _element: &BaseTransform, caps: &gst::Caps) -> Option { + fn get_unit_size(&self, _element: &gst_base::BaseTransform, caps: &gst::Caps) -> Option { gst_video::VideoInfo::from_caps(caps).map(|info| info.size()) } @@ -335,7 +356,12 @@ impl BaseTransformImpl for Rgb2Gray { // // We simply remember the resulting VideoInfo from the caps to be able to use this for knowing // the width, stride, etc when transforming buffers - fn set_caps(&self, element: &BaseTransform, incaps: &gst::Caps, outcaps: &gst::Caps) -> bool { + fn set_caps( + &self, + element: &gst_base::BaseTransform, + incaps: &gst::Caps, + outcaps: &gst::Caps, + ) -> bool { let in_info = match gst_video::VideoInfo::from_caps(incaps) { None => return false, Some(info) => info, @@ -360,7 +386,7 @@ impl BaseTransformImpl for Rgb2Gray { // Called when shutting down the element so we can release all stream-related state // There's also start(), which is called whenever starting the element again - fn stop(&self, element: &BaseTransform) -> bool { + fn stop(&self, element: &gst_base::BaseTransform) -> bool { // Drop state let _ = self.state.lock().unwrap().take(); @@ -372,7 +398,7 @@ impl BaseTransformImpl for Rgb2Gray { // Does the actual transformation of the input buffer to the output buffer fn transform( &self, - element: &BaseTransform, + element: &gst_base::BaseTransform, inbuf: &gst::Buffer, outbuf: &mut gst::BufferRef, ) -> gst::FlowReturn { @@ -529,34 +555,9 @@ impl BaseTransformImpl for Rgb2Gray { } } -// This zero-sized struct is containing the static metadata of our element. It is only necessary to -// be able to implement traits on it, but e.g. a plugin that registers multiple elements with the -// same code would use this struct to store information about the concrete element. An example of -// this would be a plugin that wraps around a library that has multiple decoders with the same API, -// but wants (as it should) a separate element registered for each decoder. -struct Rgb2GrayStatic; - -// The basic trait for registering the type: This returns a name for the type and registers the -// instance and class initializations functions with the type system, thus hooking everything -// together. -impl ImplTypeStatic for Rgb2GrayStatic { - fn get_name(&self) -> &str { - "Rgb2Gray" - } - - fn new(&self, element: &BaseTransform) -> Box> { - Rgb2Gray::new(element) - } - - fn class_init(&self, klass: &mut BaseTransformClass) { - Rgb2Gray::class_init(klass); - } -} - // Registers the type for our element, and then registers in GStreamer under // the name "rsrgb2gray" for being able to instantiate it via e.g. // gst::ElementFactory::make(). pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - let type_ = register_type(Rgb2GrayStatic); - gst::Element::register(plugin, "rsrgb2gray", 0, type_) + gst::Element::register(plugin, "rsrgb2gray", 0, Rgb2Gray::get_type()) } diff --git a/gst-plugin-tutorial/src/sinesrc.rs b/gst-plugin-tutorial/src/sinesrc.rs index 030f66307..6e1c8a6d0 100644 --- a/gst-plugin-tutorial/src/sinesrc.rs +++ b/gst-plugin-tutorial/src/sinesrc.rs @@ -7,17 +7,18 @@ // except according to those terms. use glib; +use glib::subclass; +use glib::subclass::prelude::*; use gst; use gst::prelude::*; +use gst::subclass::prelude::*; use gst_audio; +use gst_base; use gst_base::prelude::*; +use gst_base::subclass::prelude::*; use byte_slice_cast::*; -use gobject_subclass::object::*; -use gst_plugin::base_src::*; -use gst_plugin::element::*; - use std::ops::Rem; use std::sync::Mutex; use std::{i32, u32}; @@ -55,45 +56,58 @@ impl Default for Settings { } // Metadata for the properties -static PROPERTIES: [Property; 5] = [ - Property::UInt( - "samples-per-buffer", - "Samples Per Buffer", - "Number of samples per output buffer", - (1, u32::MAX), - DEFAULT_SAMPLES_PER_BUFFER, - PropertyMutability::ReadWrite, - ), - Property::UInt( - "freq", - "Frequency", - "Frequency", - (1, u32::MAX), - DEFAULT_FREQ, - PropertyMutability::ReadWrite, - ), - Property::Double( - "volume", - "Volume", - "Output volume", - (0.0, 10.0), - DEFAULT_VOLUME, - PropertyMutability::ReadWrite, - ), - Property::Boolean( - "mute", - "Mute", - "Mute", - DEFAULT_MUTE, - PropertyMutability::ReadWrite, - ), - Property::Boolean( - "is-live", - "Is Live", - "(Pseudo) live output", - DEFAULT_IS_LIVE, - PropertyMutability::ReadWrite, - ), +static PROPERTIES: [subclass::Property; 5] = [ + subclass::Property("samples-per-buffer", || { + glib::ParamSpec::uint( + "samples-per-buffer", + "Samples Per Buffer", + "Number of samples per output buffer", + 1, + u32::MAX, + DEFAULT_SAMPLES_PER_BUFFER, + glib::ParamFlags::READWRITE, + ) + }), + subclass::Property("freq", || { + glib::ParamSpec::uint( + "freq", + "Frequency", + "Frequency", + 1, + u32::MAX, + DEFAULT_FREQ, + glib::ParamFlags::READWRITE, + ) + }), + subclass::Property("volume", || { + glib::ParamSpec::double( + "volume", + "Volume", + "Output volume", + 0.0, + 10.0, + DEFAULT_VOLUME, + glib::ParamFlags::READWRITE, + ) + }), + subclass::Property("mute", || { + glib::ParamSpec::boolean( + "mute", + "Mute", + "Mute", + DEFAULT_MUTE, + glib::ParamFlags::READWRITE, + ) + }), + subclass::Property("is-live", || { + glib::ParamSpec::boolean( + "is-live", + "Is Live", + "(Pseudo) live output", + DEFAULT_IS_LIVE, + glib::ParamFlags::READWRITE, + ) + }), ]; // Stream-specific state, i.e. audio format configuration @@ -130,77 +144,6 @@ struct SineSrc { } impl SineSrc { - // Called when a new instance is to be created - fn new(element: &BaseSrc) -> Box> { - // Initialize live-ness and notify the base class that - // we'd like to operate in Time format - element.set_live(DEFAULT_IS_LIVE); - element.set_format(gst::Format::Time); - - Box::new(Self { - cat: gst::DebugCategory::new( - "rssinesrc", - gst::DebugColorFlags::empty(), - "Rust Sine Wave Source", - ), - settings: Mutex::new(Default::default()), - state: Mutex::new(Default::default()), - clock_wait: Mutex::new(ClockWait { - clock_id: None, - flushing: true, - }), - }) - } - - // Called exactly once when registering the type. Used for - // setting up metadata for all instances, e.g. the name and - // classification and the pad templates with their caps. - // - // Actual instances can create pads based on those pad templates - // with a subset of the caps given here. In case of basesrc, - // a "src" and "sink" pad template are required here and the base class - // will automatically instantiate pads for them. - // - // Our element here can output f32 and f64 - fn class_init(klass: &mut BaseSrcClass) { - klass.set_metadata( - "Sine Wave Source", - "Source/Audio", - "Creates a sine wave", - "Sebastian Dröge ", - ); - - // On the src pad, we can produce F32/F64 with any sample rate - // and any number of channels - let caps = gst::Caps::new_simple( - "audio/x-raw", - &[ - ( - "format", - &gst::List::new(&[ - &gst_audio::AUDIO_FORMAT_F32.to_string(), - &gst_audio::AUDIO_FORMAT_F64.to_string(), - ]), - ), - ("layout", &"interleaved"), - ("rate", &gst::IntRange::::new(1, i32::MAX)), - ("channels", &gst::IntRange::::new(1, i32::MAX)), - ], - ); - // The src pad template must be named "src" for basesrc - // and specific a pad that is always there - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ); - klass.add_pad_template(src_pad_template); - - // Install all our properties - klass.install_properties(&PROPERTIES); - } - fn process( data: &mut [u8], accumulator_ref: &mut f64, @@ -245,21 +188,109 @@ impl SineSrc { } } +impl ObjectSubclass for SineSrc { + const NAME: &'static str = "RsSineSrc"; + type ParentType = gst_base::BaseSrc; + type Instance = gst::subclass::ElementInstanceStruct; + type Class = subclass::simple::ClassStruct; + + glib_object_subclass!(); + + // Called when a new instance is to be created + fn new() -> Self { + Self { + cat: gst::DebugCategory::new( + "rssinesrc", + gst::DebugColorFlags::empty(), + "Rust Sine Wave Source", + ), + settings: Mutex::new(Default::default()), + state: Mutex::new(Default::default()), + clock_wait: Mutex::new(ClockWait { + clock_id: None, + flushing: true, + }), + } + } + + // Called exactly once when registering the type. Used for + // setting up metadata for all instances, e.g. the name and + // classification and the pad templates with their caps. + // + // Actual instances can create pads based on those pad templates + // with a subset of the caps given here. In case of basesrc, + // a "src" and "sink" pad template are required here and the base class + // will automatically instantiate pads for them. + // + // Our element here can output f32 and f64 + fn class_init(klass: &mut subclass::simple::ClassStruct) { + klass.set_metadata( + "Sine Wave Source", + "Source/Audio", + "Creates a sine wave", + "Sebastian Dröge ", + ); + + // On the src pad, we can produce F32/F64 with any sample rate + // and any number of channels + let caps = gst::Caps::new_simple( + "audio/x-raw", + &[ + ( + "format", + &gst::List::new(&[ + &gst_audio::AUDIO_FORMAT_F32.to_string(), + &gst_audio::AUDIO_FORMAT_F64.to_string(), + ]), + ), + ("layout", &"interleaved"), + ("rate", &gst::IntRange::::new(1, i32::MAX)), + ("channels", &gst::IntRange::::new(1, i32::MAX)), + ], + ); + // The src pad template must be named "src" for basesrc + // and specific a pad that is always there + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ); + klass.add_pad_template(src_pad_template); + + // Install all our properties + klass.install_properties(&PROPERTIES); + } +} + // Virtual methods of GObject itself -impl ObjectImpl for SineSrc { +impl ObjectImpl for SineSrc { + glib_object_impl!(); + + // Called right after construction of each object + fn constructed(&self, obj: &glib::Object) { + self.parent_constructed(obj); + + let basesrc = obj.downcast_ref::().unwrap(); + // Initialize live-ness and notify the base class that + // we'd like to operate in Time format + basesrc.set_live(DEFAULT_IS_LIVE); + basesrc.set_format(gst::Format::Time); + } + // Called whenever a value of a property is changed. It can be called // at any time from any thread. - fn set_property(&self, obj: &glib::Object, id: u32, value: &glib::Value) { - let prop = &PROPERTIES[id as usize]; - let element = obj.downcast_ref::().unwrap(); + fn set_property(&self, obj: &glib::Object, id: usize, value: &glib::Value) { + let prop = &PROPERTIES[id]; + let basesrc = obj.downcast_ref::().unwrap(); match *prop { - Property::UInt("samples-per-buffer", ..) => { + subclass::Property("samples-per-buffer", ..) => { let mut settings = self.settings.lock().unwrap(); let samples_per_buffer = value.get().unwrap(); gst_info!( self.cat, - obj: element, + obj: basesrc, "Changing samples-per-buffer from {} to {}", settings.samples_per_buffer, samples_per_buffer @@ -268,50 +299,50 @@ impl ObjectImpl for SineSrc { drop(settings); let _ = - element.post_message(&gst::Message::new_latency().src(Some(element)).build()); + basesrc.post_message(&gst::Message::new_latency().src(Some(basesrc)).build()); } - Property::UInt("freq", ..) => { + subclass::Property("freq", ..) => { let mut settings = self.settings.lock().unwrap(); let freq = value.get().unwrap(); gst_info!( self.cat, - obj: element, + obj: basesrc, "Changing freq from {} to {}", settings.freq, freq ); settings.freq = freq; } - Property::Double("volume", ..) => { + subclass::Property("volume", ..) => { let mut settings = self.settings.lock().unwrap(); let volume = value.get().unwrap(); gst_info!( self.cat, - obj: element, + obj: basesrc, "Changing volume from {} to {}", settings.volume, volume ); settings.volume = volume; } - Property::Boolean("mute", ..) => { + subclass::Property("mute", ..) => { let mut settings = self.settings.lock().unwrap(); let mute = value.get().unwrap(); gst_info!( self.cat, - obj: element, + obj: basesrc, "Changing mute from {} to {}", settings.mute, mute ); settings.mute = mute; } - Property::Boolean("is-live", ..) => { + subclass::Property("is-live", ..) => { let mut settings = self.settings.lock().unwrap(); let is_live = value.get().unwrap(); gst_info!( self.cat, - obj: element, + obj: basesrc, "Changing is-live from {} to {}", settings.is_live, is_live @@ -324,27 +355,27 @@ impl ObjectImpl for SineSrc { // Called whenever a value of a property is read. It can be called // at any time from any thread. - fn get_property(&self, _obj: &glib::Object, id: u32) -> Result { - let prop = &PROPERTIES[id as usize]; + fn get_property(&self, _obj: &glib::Object, id: usize) -> Result { + let prop = &PROPERTIES[id]; match *prop { - Property::UInt("samples-per-buffer", ..) => { + subclass::Property("samples-per-buffer", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.samples_per_buffer.to_value()) } - Property::UInt("freq", ..) => { + subclass::Property("freq", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.freq.to_value()) } - Property::Double("volume", ..) => { + subclass::Property("volume", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.volume.to_value()) } - Property::Boolean("mute", ..) => { + subclass::Property("mute", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.mute.to_value()) } - Property::Boolean("is-live", ..) => { + subclass::Property("is-live", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.is_live.to_value()) } @@ -354,33 +385,35 @@ impl ObjectImpl for SineSrc { } // Virtual methods of gst::Element. We override none -impl ElementImpl for SineSrc { +impl ElementImpl for SineSrc { fn change_state( &self, - element: &BaseSrc, + element: &gst::Element, transition: gst::StateChange, ) -> gst::StateChangeReturn { + let basesrc = element.downcast_ref::().unwrap(); + // Configure live'ness once here just before starting the source match transition { gst::StateChange::ReadyToPaused => { - element.set_live(self.settings.lock().unwrap().is_live); + basesrc.set_live(self.settings.lock().unwrap().is_live); } _ => (), } - element.parent_change_state(transition) + self.parent_change_state(element, transition) } } // Virtual methods of gst_base::BaseSrc -impl BaseSrcImpl for SineSrc { +impl BaseSrcImpl for SineSrc { // Called whenever the input/output caps are changing, i.e. in the very beginning before data // flow happens and whenever the situation in the pipeline is changing. All buffers after this // call have the caps given here. // // We simply remember the resulting AudioInfo from the caps to be able to use this for knowing // the sample rate, etc. when creating buffers - fn set_caps(&self, element: &BaseSrc, caps: &gst::CapsRef) -> bool { + fn set_caps(&self, element: &gst_base::BaseSrc, caps: &gst::CapsRef) -> bool { use std::f64::consts::PI; let info = match gst_audio::AudioInfo::from_caps(caps) { @@ -431,7 +464,7 @@ impl BaseSrcImpl for SineSrc { } // Called when starting, so we can initialize all stream-related state to its defaults - fn start(&self, element: &BaseSrc) -> bool { + fn start(&self, element: &gst_base::BaseSrc) -> bool { // Reset state *self.state.lock().unwrap() = Default::default(); self.unlock_stop(element); @@ -442,7 +475,7 @@ impl BaseSrcImpl for SineSrc { } // Called when shutting down the element so we can release all stream-related state - fn stop(&self, element: &BaseSrc) -> bool { + fn stop(&self, element: &gst_base::BaseSrc) -> bool { // Reset state *self.state.lock().unwrap() = Default::default(); self.unlock(element); @@ -452,7 +485,7 @@ impl BaseSrcImpl for SineSrc { true } - fn query(&self, element: &BaseSrc, query: &mut gst::QueryRef) -> bool { + fn query(&self, element: &gst_base::BaseSrc, query: &mut gst::QueryRef) -> bool { use gst::QueryView; match query.view_mut() { @@ -483,13 +516,13 @@ impl BaseSrcImpl for SineSrc { } _ => (), } - BaseSrcBase::parent_query(element, query) + BaseSrcImpl::parent_query(self, element, query) } // Creates the audio buffers fn create( &self, - element: &BaseSrc, + element: &gst_base::BaseSrc, _offset: u64, _length: u32, ) -> Result { @@ -643,7 +676,7 @@ impl BaseSrcImpl for SineSrc { Ok(buffer) } - fn fixate(&self, element: &BaseSrc, caps: gst::Caps) -> gst::Caps { + fn fixate(&self, element: &gst_base::BaseSrc, caps: gst::Caps) -> gst::Caps { // Fixate the caps. BaseSrc will do some fixation for us, but // as we allow any rate between 1 and MAX it would fixate to 1. 1Hz // is generally not a useful sample rate. @@ -661,14 +694,14 @@ impl BaseSrcImpl for SineSrc { // Let BaseSrc fixate anything else for us. We could've alternatively have // called Caps::fixate() here - element.parent_fixate(caps) + self.parent_fixate(element, caps) } - fn is_seekable(&self, _element: &BaseSrc) -> bool { + fn is_seekable(&self, _element: &gst_base::BaseSrc) -> bool { true } - fn do_seek(&self, element: &BaseSrc, segment: &mut gst::Segment) -> bool { + fn do_seek(&self, element: &gst_base::BaseSrc, segment: &mut gst::Segment) -> bool { // Handle seeking here. For Time and Default (sample offset) seeks we can // do something and have to update our sample offset and accumulator accordingly. // @@ -774,7 +807,7 @@ impl BaseSrcImpl for SineSrc { } } - fn unlock(&self, element: &BaseSrc) -> bool { + fn unlock(&self, element: &gst_base::BaseSrc) -> bool { // This should unblock the create() function ASAP, so we // just unschedule the clock it here, if any. gst_debug!(self.cat, obj: element, "Unlocking"); @@ -787,7 +820,7 @@ impl BaseSrcImpl for SineSrc { true } - fn unlock_stop(&self, element: &BaseSrc) -> bool { + fn unlock_stop(&self, element: &gst_base::BaseSrc) -> bool { // This signals that unlocking is done, so we can reset // all values again. gst_debug!(self.cat, obj: element, "Unlock stop"); @@ -798,34 +831,9 @@ impl BaseSrcImpl for SineSrc { } } -// This zero-sized struct is containing the static metadata of our element. It is only necessary to -// be able to implement traits on it, but e.g. a plugin that registers multiple elements with the -// same code would use this struct to store information about the concrete element. An example of -// this would be a plugin that wraps around a library that has multiple decoders with the same API, -// but wants (as it should) a separate element registered for each decoder. -struct SineSrcStatic; - -// The basic trait for registering the type: This returns a name for the type and registers the -// instance and class initializations functions with the type system, thus hooking everything -// together. -impl ImplTypeStatic for SineSrcStatic { - fn get_name(&self) -> &str { - "SineSrc" - } - - fn new(&self, element: &BaseSrc) -> Box> { - SineSrc::new(element) - } - - fn class_init(&self, klass: &mut BaseSrcClass) { - SineSrc::class_init(klass); - } -} - // Registers the type for our element, and then registers in GStreamer under // the name "sinesrc" for being able to instantiate it via e.g. // gst::ElementFactory::make(). pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - let type_ = register_type(SineSrcStatic); - gst::Element::register(plugin, "rssinesrc", 0, type_) + gst::Element::register(plugin, "rssinesrc", 0, SineSrc::get_type()) }