diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2020-11-15 11:08:32 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2020-11-15 19:25:42 +0300 |
commit | 4829e31191213eda72e2eecdcbf16f7168ba81a6 (patch) | |
tree | 70c06ff9b38bb851b8a5d7149cf1749d9f88b079 /tutorial/src | |
parent | dbf108d9a4ca8760913aaf74ca0a6891dae5bb1a (diff) |
tutorial: Update for subclassing API changes
Diffstat (limited to 'tutorial/src')
-rw-r--r-- | tutorial/src/identity/imp.rs (renamed from tutorial/src/identity.rs) | 49 | ||||
-rw-r--r-- | tutorial/src/identity/mod.rs | 33 | ||||
-rw-r--r-- | tutorial/src/progressbin/imp.rs (renamed from tutorial/src/progressbin.rs) | 58 | ||||
-rw-r--r-- | tutorial/src/progressbin/mod.rs | 52 | ||||
-rw-r--r-- | tutorial/src/rgb2gray/imp.rs (renamed from tutorial/src/rgb2gray.rs) | 54 | ||||
-rw-r--r-- | tutorial/src/rgb2gray/mod.rs | 33 | ||||
-rw-r--r-- | tutorial/src/sinesrc/imp.rs (renamed from tutorial/src/sinesrc.rs) | 89 | ||||
-rw-r--r-- | tutorial/src/sinesrc/mod.rs | 33 |
8 files changed, 243 insertions, 158 deletions
diff --git a/tutorial/src/identity.rs b/tutorial/src/identity/imp.rs index e77b44fdd..a02a18388 100644 --- a/tutorial/src/identity.rs +++ b/tutorial/src/identity/imp.rs @@ -6,7 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use glib::prelude::*; use glib::subclass; use glib::subclass::prelude::*; use gst::prelude::*; @@ -14,11 +13,7 @@ use gst::subclass::prelude::*; use once_cell::sync::Lazy; -// Struct containing all the element data -struct Identity { - srcpad: gst::Pad, - sinkpad: gst::Pad, -} +// This module contains the private implementation details of our element static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { gst::DebugCategory::new( @@ -28,6 +23,12 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { ) }); +// Struct containing all the element data +pub struct Identity { + srcpad: gst::Pad, + sinkpad: gst::Pad, +} + impl Identity { // Called whenever a new buffer is passed to our sink pad. Here buffers should be processed and // whenever some output buffer is available have to push it out of the source pad. @@ -38,7 +39,7 @@ impl Identity { fn sink_chain( &self, pad: &gst::Pad, - _element: &gst::Element, + _element: &super::Identity, buffer: gst::Buffer, ) -> Result<gst::FlowSuccess, gst::FlowError> { gst_log!(CAT, obj: pad, "Handling buffer {:?}", buffer); @@ -52,7 +53,7 @@ impl Identity { // // See the documentation of gst::Event and gst::EventRef to see what can be done with // events, and especially the gst::EventView type for inspecting events. - fn sink_event(&self, pad: &gst::Pad, _element: &gst::Element, event: gst::Event) -> bool { + fn sink_event(&self, pad: &gst::Pad, _element: &super::Identity, event: gst::Event) -> bool { gst_log!(CAT, obj: pad, "Handling event {:?}", event); self.srcpad.push_event(event) } @@ -69,7 +70,7 @@ impl Identity { fn sink_query( &self, pad: &gst::Pad, - _element: &gst::Element, + _element: &super::Identity, query: &mut gst::QueryRef, ) -> bool { gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -84,7 +85,7 @@ impl Identity { // // See the documentation of gst::Event and gst::EventRef to see what can be done with // events, and especially the gst::EventView type for inspecting events. - fn src_event(&self, pad: &gst::Pad, _element: &gst::Element, event: gst::Event) -> bool { + fn src_event(&self, pad: &gst::Pad, _element: &super::Identity, event: gst::Event) -> bool { gst_log!(CAT, obj: pad, "Handling event {:?}", event); self.sinkpad.push_event(event) } @@ -101,7 +102,7 @@ impl Identity { fn src_query( &self, pad: &gst::Pad, - _element: &gst::Element, + _element: &super::Identity, query: &mut gst::QueryRef, ) -> bool { gst_log!(CAT, obj: pad, "Handling query {:?}", query); @@ -114,6 +115,7 @@ impl Identity { // up the class data impl ObjectSubclass for Identity { const NAME: &'static str = "RsIdentity"; + type Type = super::Identity; type ParentType = gst::Element; type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; @@ -123,7 +125,7 @@ impl ObjectSubclass for Identity { // Called when a new instance is to be created. We need to return an instance // of our struct here and also get the class struct passed in case it's needed - fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self { + fn with_class(klass: &Self::Class) -> Self { // Create our two pads from the templates that were registered with // the class and set all the functions on them. // @@ -189,7 +191,7 @@ impl ObjectSubclass for Identity { // // Actual instances can create pads based on those pad templates // with a subset of the caps given here. - fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) { + fn class_init(klass: &mut Self::Class) { // Set the element specific metadata. This information is what // is visible from gst-inspect-1.0 and can also be programatically // retrieved from the gst::Registry after initial registration @@ -231,15 +233,14 @@ impl ObjectSubclass for Identity { // Implementation of glib::Object virtual methods impl ObjectImpl for Identity { // Called right after construction of a new instance - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { // Call the parent class' ::constructed() implementation first self.parent_constructed(obj); // Here we actually add the pads we created in Identity::new() to the // element so that GStreamer is aware of their existence. - let element = obj.downcast_ref::<gst::Element>().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } @@ -250,7 +251,7 @@ impl ElementImpl for Identity { // the element again. fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result<gst::StateChangeSuccess, gst::StateChangeError> { gst_trace!(CAT, obj: element, "Changing state {:?}", transition); @@ -259,15 +260,3 @@ impl ElementImpl for Identity { self.parent_change_state(element, transition) } } - -// Registers the type for our element, and then registers in GStreamer under -// the name "rsidentity" for being able to instantiate it via e.g. -// gst::ElementFactory::make(). -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rsidentity", - gst::Rank::None, - Identity::get_type(), - ) -} diff --git a/tutorial/src/identity/mod.rs b/tutorial/src/identity/mod.rs new file mode 100644 index 000000000..027d52a52 --- /dev/null +++ b/tutorial/src/identity/mod.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +// The public Rust wrapper type for our element +glib_wrapper! { + pub struct Identity(ObjectSubclass<imp::Identity>) @extends gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Identity {} +unsafe impl Sync for Identity {} + +// Registers the type for our element, and then registers in GStreamer under +// the name "rsidentity" for being able to instantiate it via e.g. +// gst::ElementFactory::make(). +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rsidentity", + gst::Rank::None, + Identity::static_type(), + ) +} diff --git a/tutorial/src/progressbin.rs b/tutorial/src/progressbin/imp.rs index 35a9e650d..3198d2711 100644 --- a/tutorial/src/progressbin.rs +++ b/tutorial/src/progressbin/imp.rs @@ -15,24 +15,9 @@ use std::sync::Mutex; use once_cell::sync::Lazy; -// This enum may be used to control what type of output the progressbin should produce. -// It also serves the secondary purpose of illustrating how to add enum-type properties -// to a plugin written in rust. -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] -#[repr(u32)] -#[genum(type_name = "GstProgressBinOutput")] -pub(crate) enum ProgressBinOutput { - #[genum( - name = "Println: Outputs the progress using a println! macro.", - nick = "println" - )] - Println = 0, - #[genum( - name = "Debug Category: Outputs the progress as info logs under the element's debug category.", - nick = "debug-category" - )] - DebugCategory = 1, -} +use super::ProgressBinOutput; + +// This module contains the private implementation details of our element const DEFAULT_OUTPUT_TYPE: ProgressBinOutput = ProgressBinOutput::Println; @@ -45,7 +30,7 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { }); // Struct containing all the element data -struct ProgressBin { +pub struct ProgressBin { progress: gst::Element, srcpad: gst::GhostPad, sinkpad: gst::GhostPad, @@ -72,6 +57,7 @@ static PROPERTIES: [subclass::Property; 1] = [subclass::Property("output", |name // up the class data impl ObjectSubclass for ProgressBin { const NAME: &'static str = "RsProgressBin"; + type Type = super::ProgressBin; type ParentType = gst::Bin; type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; @@ -81,7 +67,7 @@ impl ObjectSubclass for ProgressBin { // Called when a new instance is to be created. We need to return an instance // of our struct here and also get the class struct passed in case it's needed - fn with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self { + fn with_class(klass: &Self::Class) -> Self { // Create our two ghostpads from the templates that were registered with // the class. We don't provide a target for them yet because we can only // do so after the progressreport element was added to the bin. @@ -112,7 +98,7 @@ impl ObjectSubclass for ProgressBin { // // Actual instances can create pads based on those pad templates // with a subset of the caps given here. - fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) { + fn class_init(klass: &mut Self::Class) { // Set the element specific metadata. This information is what // is visible from gst-inspect-1.0 and can also be programatically // retrieved from the gst::Registry after initial registration @@ -158,9 +144,8 @@ impl ObjectSubclass for ProgressBin { impl ObjectImpl for ProgressBin { // 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: usize, value: &glib::Value) { + fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; - let element = obj.downcast_ref::<gst::Bin>().unwrap(); match *prop { subclass::Property("output", ..) => { @@ -170,7 +155,7 @@ impl ObjectImpl for ProgressBin { .expect("type checked upstream"); gst_info!( CAT, - obj: element, + obj: obj, "Changing output from {:?} to {:?}", output_type, new_output_type @@ -183,7 +168,7 @@ impl ObjectImpl for ProgressBin { // 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: usize) -> Result<glib::Value, ()> { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> { let prop = &PROPERTIES[id]; match *prop { @@ -196,16 +181,15 @@ impl ObjectImpl for ProgressBin { } // Called right after construction of a new instance - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { // Call the parent class' ::constructed() implementation first self.parent_constructed(obj); // Here we actually add the pads we created in ProgressBin::new() to the // element so that GStreamer is aware of their existence. - let bin = obj.downcast_ref::<gst::Bin>().unwrap(); // Add the progressreport element to the bin. - bin.add(&self.progress).unwrap(); + obj.add(&self.progress).unwrap(); // Then set the ghost pad targets to the corresponding pads of the progressreport element. self.sinkpad @@ -216,8 +200,8 @@ impl ObjectImpl for ProgressBin { .unwrap(); // And finally add the two ghostpads to the bin. - bin.add_pad(&self.sinkpad).unwrap(); - bin.add_pad(&self.srcpad).unwrap(); + obj.add_pad(&self.sinkpad).unwrap(); + obj.add_pad(&self.srcpad).unwrap(); } } @@ -226,7 +210,7 @@ impl ElementImpl for ProgressBin {} // Implementation of gst::Bin virtual methods impl BinImpl for ProgressBin { - fn handle_message(&self, bin: &gst::Bin, msg: gst::Message) { + fn handle_message(&self, bin: &Self::Type, msg: gst::Message) { use gst::MessageView; match msg.view() { @@ -256,15 +240,3 @@ impl BinImpl for ProgressBin { } } } - -// Registers the type for our element, and then registers in GStreamer under -// the name "rsprogressbin" for being able to instantiate it via e.g. -// gst::ElementFactory::make(). -pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { - gst::Element::register( - Some(plugin), - "rsprogressbin", - gst::Rank::None, - ProgressBin::get_type(), - ) -} diff --git a/tutorial/src/progressbin/mod.rs b/tutorial/src/progressbin/mod.rs new file mode 100644 index 000000000..4c1a41309 --- /dev/null +++ b/tutorial/src/progressbin/mod.rs @@ -0,0 +1,52 @@ +// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +// This enum may be used to control what type of output the progressbin should produce. +// It also serves the secondary purpose of illustrating how to add enum-type properties +// to a plugin written in rust. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, GEnum)] +#[repr(u32)] +#[genum(type_name = "GstProgressBinOutput")] +pub enum ProgressBinOutput { + #[genum( + name = "Println: Outputs the progress using a println! macro.", + nick = "println" + )] + Println = 0, + #[genum( + name = "Debug Category: Outputs the progress as info logs under the element's debug category.", + nick = "debug-category" + )] + DebugCategory = 1, +} + +// The public Rust wrapper type for our element +glib_wrapper! { + pub struct ProgressBin(ObjectSubclass<imp::ProgressBin>) @extends gst::Bin, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for ProgressBin {} +unsafe impl Sync for ProgressBin {} + +// Registers the type for our element, and then registers in GStreamer under +// the name "rsprogressbin" for being able to instantiate it via e.g. +// gst::ElementFactory::make(). +pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + gst::Element::register( + Some(plugin), + "rsprogressbin", + gst::Rank::None, + ProgressBin::static_type(), + ) +} diff --git a/tutorial/src/rgb2gray.rs b/tutorial/src/rgb2gray/imp.rs index af47ad352..4dbacbdd4 100644 --- a/tutorial/src/rgb2gray.rs +++ b/tutorial/src/rgb2gray/imp.rs @@ -17,6 +17,16 @@ use std::sync::Mutex; use once_cell::sync::Lazy; +// This module contains the private implementation details of our element +// +static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { + gst::DebugCategory::new( + "rsrgb2gray", + gst::DebugColorFlags::empty(), + Some("Rust RGB-GRAY converter"), + ) +}); + // Default values of properties const DEFAULT_INVERT: bool = false; const DEFAULT_SHIFT: u32 = 0; @@ -68,19 +78,11 @@ struct State { } // Struct containing all the element data -struct Rgb2Gray { +pub struct Rgb2Gray { settings: Mutex<Settings>, state: Mutex<Option<State>>, } -static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { - gst::DebugCategory::new( - "rsrgb2gray", - gst::DebugColorFlags::empty(), - Some("Rust RGB-GRAY converter"), - ) -}); - impl Rgb2Gray { // Converts one pixel of BGRx to a grayscale value, shifting and/or // inverting it as configured @@ -113,6 +115,7 @@ impl Rgb2Gray { // up the class data impl ObjectSubclass for Rgb2Gray { const NAME: &'static str = "RsRgb2Gray"; + type Type = super::Rgb2Gray; type ParentType = gst_base::BaseTransform; type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; @@ -139,7 +142,7 @@ impl ObjectSubclass for 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 subclass::simple::ClassStruct<Self>) { + fn class_init(klass: &mut Self::Class) { // Set the element specific metadata. This information is what // is visible from gst-inspect-1.0 and can also be programatically // retrieved from the gst::Registry after initial registration @@ -239,9 +242,8 @@ impl ObjectSubclass for Rgb2Gray { impl ObjectImpl for Rgb2Gray { // 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: usize, value: &glib::Value) { + fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; - let element = obj.downcast_ref::<gst_base::BaseTransform>().unwrap(); match *prop { subclass::Property("invert", ..) => { @@ -249,7 +251,7 @@ impl ObjectImpl for Rgb2Gray { let invert = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: element, + obj: obj, "Changing invert from {} to {}", settings.invert, invert @@ -261,7 +263,7 @@ impl ObjectImpl for Rgb2Gray { let shift = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: element, + obj: obj, "Changing shift from {} to {}", settings.shift, shift @@ -274,7 +276,7 @@ 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: usize) -> Result<glib::Value, ()> { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> { let prop = &PROPERTIES[id]; match *prop { @@ -302,7 +304,7 @@ impl BaseTransformImpl for Rgb2Gray { // In our case that means that: fn transform_caps( &self, - element: &gst_base::BaseTransform, + element: &Self::Type, direction: gst::PadDirection, caps: &gst::Caps, filter: Option<&gst::Caps>, @@ -360,7 +362,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: &gst_base::BaseTransform, caps: &gst::Caps) -> Option<usize> { + fn get_unit_size(&self, _element: &Self::Type, caps: &gst::Caps) -> Option<usize> { gst_video::VideoInfo::from_caps(caps) .map(|info| info.size()) .ok() @@ -374,7 +376,7 @@ impl BaseTransformImpl for Rgb2Gray { // the width, stride, etc when transforming buffers fn set_caps( &self, - element: &gst_base::BaseTransform, + element: &Self::Type, incaps: &gst::Caps, outcaps: &gst::Caps, ) -> Result<(), gst::LoggableError> { @@ -402,7 +404,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: &gst_base::BaseTransform) -> Result<(), gst::ErrorMessage> { + fn stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { // Drop state let _ = self.state.lock().unwrap().take(); @@ -414,7 +416,7 @@ impl BaseTransformImpl for Rgb2Gray { // Does the actual transformation of the input buffer to the output buffer fn transform( &self, - element: &gst_base::BaseTransform, + element: &Self::Type, inbuf: &gst::Buffer, outbuf: &mut gst::BufferRef, ) -> Result<gst::FlowSuccess, gst::FlowError> { @@ -562,15 +564,3 @@ impl BaseTransformImpl for Rgb2Gray { Ok(gst::FlowSuccess::Ok) } } - -// 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> { - gst::Element::register( - Some(plugin), - "rsrgb2gray", - gst::Rank::None, - Rgb2Gray::get_type(), - ) -} diff --git a/tutorial/src/rgb2gray/mod.rs b/tutorial/src/rgb2gray/mod.rs new file mode 100644 index 000000000..b85d708e4 --- /dev/null +++ b/tutorial/src/rgb2gray/mod.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +// The public Rust wrapper type for our element +glib_wrapper! { + pub struct Rgb2Gray(ObjectSubclass<imp::Rgb2Gray>) @extends gst_base::BaseTransform, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for Rgb2Gray {} +unsafe impl Sync for Rgb2Gray {} + +// 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> { + gst::Element::register( + Some(plugin), + "rsrgb2gray", + gst::Rank::None, + Rgb2Gray::static_type(), + ) +} diff --git a/tutorial/src/sinesrc.rs b/tutorial/src/sinesrc/imp.rs index ff2e5aff5..6f4b933fd 100644 --- a/tutorial/src/sinesrc.rs +++ b/tutorial/src/sinesrc/imp.rs @@ -24,6 +24,16 @@ use num_traits::float::Float; use once_cell::sync::Lazy; +// This module contains the private implementation details of our element + +static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { + gst::DebugCategory::new( + "rssinesrc", + gst::DebugColorFlags::empty(), + Some("Rust Sine Wave Source"), + ) +}); + // Default values of properties const DEFAULT_SAMPLES_PER_BUFFER: u32 = 1024; const DEFAULT_FREQ: u32 = 440; @@ -134,20 +144,12 @@ struct ClockWait { } // Struct containing all the element data -struct SineSrc { +pub struct SineSrc { settings: Mutex<Settings>, state: Mutex<State>, clock_wait: Mutex<ClockWait>, } -static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| { - gst::DebugCategory::new( - "rssinesrc", - gst::DebugColorFlags::empty(), - Some("Rust Sine Wave Source"), - ) -}); - impl SineSrc { fn process<F: Float + FromByteSlice>( data: &mut [u8], @@ -198,6 +200,7 @@ impl SineSrc { // up the class data impl ObjectSubclass for SineSrc { const NAME: &'static str = "RsSineSrc"; + type Type = super::SineSrc; type ParentType = gst_base::PushSrc; type Instance = gst::subclass::ElementInstanceStruct<Self>; type Class = subclass::simple::ClassStruct<Self>; @@ -228,7 +231,7 @@ impl ObjectSubclass for SineSrc { // will automatically instantiate pads for them. // // Our element here can output f32 and f64 - fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) { + fn class_init(klass: &mut Self::Class) { // Set the element specific metadata. This information is what // is visible from gst-inspect-1.0 and can also be programatically // retrieved from the gst::Registry after initial registration @@ -281,22 +284,20 @@ impl ObjectSubclass for SineSrc { // Implementation of glib::Object virtual methods impl ObjectImpl for SineSrc { // Called right after construction of a new instance - fn constructed(&self, obj: &glib::Object) { + fn constructed(&self, obj: &Self::Type) { // Call the parent class' ::constructed() implementation first self.parent_constructed(obj); // Initialize live-ness and notify the base class that // we'd like to operate in Time format - let basesrc = obj.downcast_ref::<gst_base::BaseSrc>().unwrap(); - basesrc.set_live(DEFAULT_IS_LIVE); - basesrc.set_format(gst::Format::Time); + obj.set_live(DEFAULT_IS_LIVE); + obj.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: usize, value: &glib::Value) { + fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) { let prop = &PROPERTIES[id]; - let basesrc = obj.downcast_ref::<gst_base::BaseSrc>().unwrap(); match *prop { subclass::Property("samples-per-buffer", ..) => { @@ -304,7 +305,7 @@ impl ObjectImpl for SineSrc { let samples_per_buffer = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: basesrc, + obj: obj, "Changing samples-per-buffer from {} to {}", settings.samples_per_buffer, samples_per_buffer @@ -312,14 +313,14 @@ impl ObjectImpl for SineSrc { settings.samples_per_buffer = samples_per_buffer; drop(settings); - let _ = basesrc.post_message(gst::message::Latency::builder().src(basesrc).build()); + let _ = obj.post_message(gst::message::Latency::builder().src(obj).build()); } subclass::Property("freq", ..) => { let mut settings = self.settings.lock().unwrap(); let freq = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: basesrc, + obj: obj, "Changing freq from {} to {}", settings.freq, freq @@ -331,7 +332,7 @@ impl ObjectImpl for SineSrc { let volume = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: basesrc, + obj: obj, "Changing volume from {} to {}", settings.volume, volume @@ -343,7 +344,7 @@ impl ObjectImpl for SineSrc { let mute = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: basesrc, + obj: obj, "Changing mute from {} to {}", settings.mute, mute @@ -355,7 +356,7 @@ impl ObjectImpl for SineSrc { let is_live = value.get_some().expect("type checked upstream"); gst_info!( CAT, - obj: basesrc, + obj: obj, "Changing is-live from {} to {}", settings.is_live, is_live @@ -368,7 +369,7 @@ 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: usize) -> Result<glib::Value, ()> { + fn get_property(&self, _obj: &Self::Type, id: usize) -> Result<glib::Value, ()> { let prop = &PROPERTIES[id]; match *prop { @@ -404,14 +405,12 @@ impl ElementImpl for SineSrc { // the element again. fn change_state( &self, - element: &gst::Element, + element: &Self::Type, transition: gst::StateChange, ) -> Result<gst::StateChangeSuccess, gst::StateChangeError> { - let basesrc = element.downcast_ref::<gst_base::BaseSrc>().unwrap(); - // Configure live'ness once here just before starting the source if let gst::StateChange::ReadyToPaused = transition { - basesrc.set_live(self.settings.lock().unwrap().is_live); + element.set_live(self.settings.lock().unwrap().is_live); } // Call the parent class' implementation of ::change_state() @@ -427,11 +426,7 @@ impl BaseSrcImpl for SineSrc { // // 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: &gst_base::BaseSrc, - caps: &gst::Caps, - ) -> Result<(), gst::LoggableError> { + fn set_caps(&self, element: &Self::Type, caps: &gst::Caps) -> Result<(), gst::LoggableError> { use std::f64::consts::PI; let info = gst_audio::AudioInfo::from_caps(caps).map_err(|_| { @@ -481,7 +476,7 @@ impl BaseSrcImpl for SineSrc { } // Called when starting, so we can initialize all stream-related state to its defaults - fn start(&self, element: &gst_base::BaseSrc) -> Result<(), gst::ErrorMessage> { + fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { // Reset state *self.state.lock().unwrap() = Default::default(); self.unlock_stop(element)?; @@ -492,7 +487,7 @@ impl BaseSrcImpl for SineSrc { } // Called when shutting down the element so we can release all stream-related state - fn stop(&self, element: &gst_base::BaseSrc) -> Result<(), gst::ErrorMessage> { + fn stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { // Reset state *self.state.lock().unwrap() = Default::default(); self.unlock(element)?; @@ -502,7 +497,7 @@ impl BaseSrcImpl for SineSrc { Ok(()) } - fn query(&self, element: &gst_base::BaseSrc, query: &mut gst::QueryRef) -> bool { + fn query(&self, element: &Self::Type, query: &mut gst::QueryRef) -> bool { use gst::QueryView; match query.view_mut() { @@ -528,7 +523,7 @@ impl BaseSrcImpl for SineSrc { } } - fn fixate(&self, element: &gst_base::BaseSrc, mut caps: gst::Caps) -> gst::Caps { + fn fixate(&self, element: &Self::Type, mut 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. @@ -549,11 +544,11 @@ impl BaseSrcImpl for SineSrc { self.parent_fixate(element, caps) } - fn is_seekable(&self, _element: &gst_base::BaseSrc) -> bool { + fn is_seekable(&self, _element: &Self::Type) -> bool { true } - fn do_seek(&self, element: &gst_base::BaseSrc, segment: &mut gst::Segment) -> bool { + fn do_seek(&self, element: &Self::Type, 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. // @@ -659,7 +654,7 @@ impl BaseSrcImpl for SineSrc { } } - fn unlock(&self, element: &gst_base::BaseSrc) -> Result<(), gst::ErrorMessage> { + fn unlock(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { // This should unblock the create() function ASAP, so we // just unschedule the clock it here, if any. gst_debug!(CAT, obj: element, "Unlocking"); @@ -672,7 +667,7 @@ impl BaseSrcImpl for SineSrc { Ok(()) } - fn unlock_stop(&self, element: &gst_base::BaseSrc) -> Result<(), gst::ErrorMessage> { + fn unlock_stop(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> { // This signals that unlocking is done, so we can reset // all values again. gst_debug!(CAT, obj: element, "Unlock stop"); @@ -685,7 +680,7 @@ impl BaseSrcImpl for SineSrc { impl PushSrcImpl for SineSrc { // Creates the audio buffers - fn create(&self, element: &gst_base::PushSrc) -> Result<gst::Buffer, gst::FlowError> { + fn create(&self, element: &Self::Type) -> Result<gst::Buffer, gst::FlowError> { // Keep a local copy of the values of all our properties at this very moment. This // ensures that the mutex is never locked for long and the application wouldn't // have to block until this function returns when getting/setting property values @@ -830,15 +825,3 @@ impl PushSrcImpl for SineSrc { Ok(buffer) } } - -// 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> { - gst::Element::register( - Some(plugin), - "rssinesrc", - gst::Rank::None, - SineSrc::get_type(), - ) -} diff --git a/tutorial/src/sinesrc/mod.rs b/tutorial/src/sinesrc/mod.rs new file mode 100644 index 000000000..7baf92280 --- /dev/null +++ b/tutorial/src/sinesrc/mod.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com> +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib::prelude::*; + +mod imp; + +// The public Rust wrapper type for our element +glib_wrapper! { + pub struct SineSrc(ObjectSubclass<imp::SineSrc>) @extends gst_base::BaseSrc, gst::Element, gst::Object; +} + +// GStreamer elements need to be thread-safe. For the private implementation this is automatically +// enforced but for the public wrapper type we need to specify this manually. +unsafe impl Send for SineSrc {} +unsafe impl Sync for SineSrc {} + +// 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> { + gst::Element::register( + Some(plugin), + "rssinesrc", + gst::Rank::None, + SineSrc::static_type(), + ) +} |