Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2021-03-07 19:22:24 +0300
committerSebastian Dröge <sebastian@centricular.com>2021-03-07 19:27:00 +0300
commitdc0c5f7611d5896f9fcfa9e141fabe02dea16ea6 (patch)
tree74d3f6c20a64a3e5fa9c1f4fcff6efb8a1d694d4 /tutorial
parent5dd0a23986352fa363b002c8495951e6a3593673 (diff)
Update for new #[glib::object_subclass] attribute macro
Diffstat (limited to 'tutorial')
-rw-r--r--tutorial/src/identity/imp.rs7
-rw-r--r--tutorial/src/progressbin/imp.rs7
-rw-r--r--tutorial/src/rgb2gray/imp.rs17
-rw-r--r--tutorial/src/sinesrc/imp.rs30
-rw-r--r--tutorial/tutorial-1.md130
-rw-r--r--tutorial/tutorial-2.md166
6 files changed, 146 insertions, 211 deletions
diff --git a/tutorial/src/identity/imp.rs b/tutorial/src/identity/imp.rs
index 7a256e60c..cddb491a1 100644
--- a/tutorial/src/identity/imp.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::subclass;
use glib::subclass::prelude::*;
use gst::prelude::*;
use gst::subclass::prelude::*;
@@ -114,16 +113,12 @@ impl Identity {
// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
+#[glib::object_subclass]
impl ObjectSubclass for Identity {
const NAME: &'static str = "RsIdentity";
type Type = super::Identity;
type ParentType = gst::Element;
- type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
- type Class = subclass::simple::ClassStruct<Self>;
-
- // This macro provides some boilerplate.
- glib::object_subclass!();
// 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
diff --git a/tutorial/src/progressbin/imp.rs b/tutorial/src/progressbin/imp.rs
index e00d6c0a3..9499147bc 100644
--- a/tutorial/src/progressbin/imp.rs
+++ b/tutorial/src/progressbin/imp.rs
@@ -7,7 +7,6 @@
// except according to those terms.
use glib::prelude::*;
-use glib::subclass;
use glib::subclass::prelude::*;
use gst::gst_info;
use gst::prelude::*;
@@ -44,16 +43,12 @@ pub struct ProgressBin {
// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
+#[glib::object_subclass]
impl ObjectSubclass for ProgressBin {
const NAME: &'static str = "RsProgressBin";
type Type = super::ProgressBin;
type ParentType = gst::Bin;
- type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
- type Class = subclass::simple::ClassStruct<Self>;
-
- // This macro provides some boilerplate.
- glib::object_subclass!();
// 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
diff --git a/tutorial/src/rgb2gray/imp.rs b/tutorial/src/rgb2gray/imp.rs
index 4db88fd8b..db4ac16dd 100644
--- a/tutorial/src/rgb2gray/imp.rs
+++ b/tutorial/src/rgb2gray/imp.rs
@@ -6,7 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use glib::subclass;
use glib::subclass::prelude::*;
use gst::prelude::*;
use gst::subclass::prelude::*;
@@ -55,6 +54,7 @@ struct State {
}
// Struct containing all the element data
+#[derive(Default)]
pub struct Rgb2Gray {
settings: Mutex<Settings>,
state: Mutex<Option<State>>,
@@ -90,25 +90,12 @@ impl Rgb2Gray {
// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
+#[glib::object_subclass]
impl ObjectSubclass for Rgb2Gray {
const NAME: &'static str = "RsRgb2Gray";
type Type = super::Rgb2Gray;
type ParentType = gst_base::BaseTransform;
- type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
- type Class = subclass::simple::ClassStruct<Self>;
-
- // This macro provides some boilerplate
- glib::object_subclass!();
-
- // Called when a new instance is to be created. We need to return an instance
- // of our struct here.
- fn new() -> Self {
- Self {
- settings: Mutex::new(Default::default()),
- state: Mutex::new(None),
- }
- }
}
// Implementation of glib::Object virtual methods
diff --git a/tutorial/src/sinesrc/imp.rs b/tutorial/src/sinesrc/imp.rs
index e18c5a023..90bb1812c 100644
--- a/tutorial/src/sinesrc/imp.rs
+++ b/tutorial/src/sinesrc/imp.rs
@@ -6,7 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use glib::subclass;
use glib::subclass::prelude::*;
use gst::prelude::*;
use gst::subclass::prelude::*;
@@ -89,7 +88,17 @@ struct ClockWait {
flushing: bool,
}
+impl Default for ClockWait {
+ fn default() -> ClockWait {
+ ClockWait {
+ clock_id: None,
+ flushing: true,
+ }
+ }
+}
+
// Struct containing all the element data
+#[derive(Default)]
pub struct SineSrc {
settings: Mutex<Settings>,
state: Mutex<State>,
@@ -144,29 +153,12 @@ impl SineSrc {
// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
+#[glib::object_subclass]
impl ObjectSubclass for SineSrc {
const NAME: &'static str = "RsSineSrc";
type Type = super::SineSrc;
type ParentType = gst_base::PushSrc;
- type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
- type Class = subclass::simple::ClassStruct<Self>;
-
- // This macro provides some boilerplate.
- glib::object_subclass!();
-
- // Called when a new instance is to be created. We need to return an instance
- // of our struct here.
- fn new() -> Self {
- Self {
- settings: Mutex::new(Default::default()),
- state: Mutex::new(Default::default()),
- clock_wait: Mutex::new(ClockWait {
- clock_id: None,
- flushing: true,
- }),
- }
- }
}
// Implementation of glib::Object virtual methods
diff --git a/tutorial/tutorial-1.md b/tutorial/tutorial-1.md
index 2d036d91b..7c5127fba 100644
--- a/tutorial/tutorial-1.md
+++ b/tutorial/tutorial-1.md
@@ -163,27 +163,17 @@ GStreamer is based on the GLib object system ([GObject](https://developer.gnome.
So, as a next step we need to register a new type for our RGB to Grayscale converter GStreamer element with the GObject type system, and then register that type with GStreamer to be able to create new instances of it. We do this with the following code
```rust
-pub struct Rgb2Gray{}
+#[derive(Default)]
+pub struct Rgb2Gray {}
-impl Rgb2Gray{}
+impl Rgb2Gray {}
+#[glib::object_subclass]
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>;
-
- // This macro provides some boilerplate
- glib::object_subclass!();
-
- fn new() -> Self {
- Self {}
- }
-
- fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
-
- }
}
```
@@ -231,19 +221,15 @@ In addition, we also define a `register` function (the one that is already calle
As a next step we implement the `new` funtion and `class_init` functions. In the first version, this struct is empty for now but we will later use it to store all state of our element.
```rust
-pub struct Rgb2Gray {
-}
+#[derive(Default)]
+pub struct Rgb2Gray {}
-impl Rgb2Gray{}
+impl Rgb2Gray {}
+#[glib::object_subclass]
impl ObjectSubclass for Rgb2Gray {
[...]
- fn new() -> Self {
- Self {
- }
- }
-
fn class_init(klass: &mut Self::Class) {
klass.set_metadata(
"RGB-GRAY Converter",
@@ -281,18 +267,17 @@ With all this defined, `gst-inspect-1.0` should be able to show some more inform
```rust
// all imports...
+#[derive(Default)]
pub struct Rgb2Gray {}
impl Rgb2Gray {}
+#[glib::object_subclass]
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>;
-
- glib::object_subclass!();
}
impl ObjectImpl for Rgb2Gray {}
@@ -424,20 +409,16 @@ struct State {
out_info: gst_video::VideoInfo,
}
+#[derive(Default)]
pub struct Rgb2Gray {
state: Mutex<Option<State>>
}
impl Rgb2Gray{}
+#[glib::object_subclass]
impl ObjectSubclass for Rgb2Gray {
[...]
-
- fn new() -> Self {
- Self {
- state: Mutex::new(None),
- }
- }
}
```
@@ -752,29 +733,7 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("invert", |name| {
- glib::ParamSpec::boolean(
- name,
- "Invert",
- "Invert grayscale output",
- DEFAULT_INVERT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("shift", |name| {
- glib::ParamSpec::uint(
- name,
- "Shift",
- "Shift grayscale output (wrapping around)",
- 0,
- 255,
- DEFAULT_SHIFT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
+#[derive(Default)]
pub struct Rgb2Gray {
settings: Mutex<Settings>,
state: Mutex<Option<State>>,
@@ -782,39 +741,46 @@ pub struct Rgb2Gray {
impl Rgb2Gray{...}
-impl ObjectSubclass for Rgb2Gray {
- [...]
+impl ObjectImpl for Rgb2Gray {
+ fn properties() -> &'static [glib::ParamSpec] {
+ // Metadata for the properties
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boolean(
+ "invert",
+ "Invert",
+ "Invert grayscale output",
+ DEFAULT_INVERT,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
+ ),
+ glib::ParamSpec::uint(
+ "shift",
+ "Shift",
+ "Shift grayscale output (wrapping around)",
+ 0,
+ 255,
+ DEFAULT_SHIFT,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
+ ),
+ ]
+ });
- fn new() -> Self {
- Self {
- settings: Mutex::new(Default::default()),
- state: Mutex::new(None),
- }
+ PROPERTIES.as_ref()
}
}
```
This should all be rather straightforward: we define a `Settings` struct that stores the two values, implement the [`Default`](https://doc.rust-lang.org/nightly/std/default/trait.Default.html) trait for it, then define a two-element array with property metadata (names, description, ranges, default value, writability), and then store the default value of our `Settings` struct inside another `Mutex` inside the element struct.
-In the next step we have to make use of these: we need to tell the GObject type system about the properties, and we need to implement functions that are called whenever a property value is set or get.
+In the next step we have to implement functions that are called whenever a property value is set or get.
```rust
-impl ObjectSubclass for Rgb2Gray {
- fn class_init(klass: &mut Self::Class) {
- [...]
- klass.install_properties(&PROPERTIES);
- [...]
- }
-}
-
impl ObjectImpl for Rgb2Gray {
[...]
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("invert", ..) => {
+ fn set_property(&self, obj: &Self::Type, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
+ match pspec.get_name() {
+ "invert" => {
let mut settings = self.settings.lock().unwrap();
let invert = value.get_some().expect("type checked upstream");
gst_info!(
@@ -826,7 +792,7 @@ impl ObjectImpl for Rgb2Gray {
);
settings.invert = invert;
}
- subclass::Property("shift", ..) => {
+ "shift" => {
let mut settings = self.settings.lock().unwrap();
let shift = value.get_some().expect("type checked upstream");
gst_info!(
@@ -842,15 +808,13 @@ impl ObjectImpl for Rgb2Gray {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("invert", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "invert" => {
let settings = self.settings.lock().unwrap();
settings.invert.to_value()
}
- subclass::Property("shift", ..) => {
+ "shift" => {
let settings = self.settings.lock().unwrap();
settings.shift.to_value()
}
@@ -860,7 +824,7 @@ impl ObjectImpl for Rgb2Gray {
}
```
-`Property` values can be changed from any thread at any time, that’s why the `Mutex` is needed here to protect our struct. And we’re using a new mutex to be able to have it locked only for the shorted possible amount of time: we don’t want to keep it locked for the whole time of the `transform` function, otherwise applications trying to set/get values would block for up to the processing time of one frame.
+Property values can be changed from any thread at any time, that’s why the `Mutex` is needed here to protect our struct. And we’re using a new mutex to be able to have it locked only for the shorted possible amount of time: we don’t want to keep it locked for the whole time of the `transform` function, otherwise applications trying to set/get values would block for up to the processing time of one frame.
In the property setter/getter functions we are working with a `glib::Value`. This is a dynamically typed value type that can contain values of any type, together with the type information of the contained value. Here we’re using it to handle an unsigned integer (`u32`) and a boolean for our two properties. To know which property is currently set/get, we get an identifier passed which is the index into our `PROPERTIES` array. We then simply match on the name of that to decide which property was meant
diff --git a/tutorial/tutorial-2.md b/tutorial/tutorial-2.md
index ce70695f4..c735a92b3 100644
--- a/tutorial/tutorial-2.md
+++ b/tutorial/tutorial-2.md
@@ -70,48 +70,6 @@ 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,
- ),
-];
-
// Stream-specific state, i.e. audio format configuration
// and sample offset
struct State {
@@ -133,6 +91,7 @@ impl Default for State {
}
// Struct containing all the element data
+#[derive(Default)]
pub struct SineSrc {
settings: Mutex<Settings>,
state: Mutex<State>,
@@ -146,28 +105,12 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
+#[glib::object_subclass]
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>;
-
- // This macro provides some boilerplate.
- glib::object_subclass!();
-
- // Called when a new instance is to be created. We need to return an instance
- // of our struct here.
- fn new() -> Self {
- Self {
- 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
@@ -223,13 +166,61 @@ impl ObjectSubclass for SineSrc {
)
.unwrap();
klass.add_pad_template(src_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
}
}
impl ObjectImpl for SineSrc {
+ // Metadata for the properties
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ 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 | gst::PARAM_FLAG_MUTABLE_READY,
+ ),
+ glib::ParamSpec::uint(
+ "freq",
+ "Frequency",
+ "Frequency",
+ 1,
+ u32::MAX,
+ DEFAULT_FREQ,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
+ ),
+ glib::ParamSpec::double(
+ "volume",
+ "Volume",
+ "Output volume",
+ 0.0,
+ 10.0,
+ DEFAULT_VOLUME,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
+ ),
+ glib::ParamSpec::boolean(
+ "mute",
+ "Mute",
+ "Mute",
+ DEFAULT_MUTE,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_PLAYING,
+ ),
+ glib::ParamSpec::boolean(
+ "is-live",
+ "Is Live",
+ "(Pseudo) live output",
+ DEFAULT_IS_LIVE,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
// Called right after construction of a new instance
fn constructed(&self, obj: &Self::Type) {
// Call the parent class' ::constructed() implementation first
@@ -243,11 +234,15 @@ impl ObjectImpl for SineSrc {
// Called whenever a value of a property is changed. It can be called
// at any time from any thread.
- fn set_property(&self, obj: &Self::Type, id: u32, value: &glib::Value) {
- let prop = &PROPERTIES[id as usize];
-
- match *prop {
- Property::UInt("samples-per-buffer", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "samples-per-buffer" => {
let mut settings = self.settings.lock().unwrap();
let samples_per_buffer = value.get_some().expect("type checked upstream");
gst_info!(
@@ -260,10 +255,9 @@ impl ObjectImpl for SineSrc {
settings.samples_per_buffer = samples_per_buffer;
drop(settings);
- let _ =
- obj.post_message(&gst::Message::new_latency().src(Some(obj)).build());
+ let _ = obj.post_message(gst::message::Latency::builder().src(obj).build());
}
- Property::UInt("freq", ..) => {
+ "freq" => {
let mut settings = self.settings.lock().unwrap();
let freq = value.get_some().expect("type checked upstream");
gst_info!(
@@ -275,7 +269,7 @@ impl ObjectImpl for SineSrc {
);
settings.freq = freq;
}
- Property::Double("volume", ..) => {
+ "volume" => {
let mut settings = self.settings.lock().unwrap();
let volume = value.get_some().expect("type checked upstream");
gst_info!(
@@ -287,7 +281,7 @@ impl ObjectImpl for SineSrc {
);
settings.volume = volume;
}
- Property::Boolean("mute", ..) => {
+ "mute" => {
let mut settings = self.settings.lock().unwrap();
let mute = value.get_some().expect("type checked upstream");
gst_info!(
@@ -299,7 +293,7 @@ impl ObjectImpl for SineSrc {
);
settings.mute = mute;
}
- Property::Boolean("is-live", ..) => {
+ "is-live" => {
let mut settings = self.settings.lock().unwrap();
let is_live = value.get_some().expect("type checked upstream");
gst_info!(
@@ -317,27 +311,25 @@ 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: &Self::Type, id: u32) -> glib::Value {
- let prop = &PROPERTIES[id as usize];
-
- match *prop {
- Property::UInt("samples-per-buffer", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "samples-per-buffer" => {
let settings = self.settings.lock().unwrap();
settings.samples_per_buffer.to_value()
}
- Property::UInt("freq", ..) => {
+ "freq" => {
let settings = self.settings.lock().unwrap();
settings.freq.to_value()
}
- Property::Double("volume", ..) => {
+ "volume" => {
let settings = self.settings.lock().unwrap();
settings.volume.to_value()
}
- Property::Boolean("mute", ..) => {
+ "mute" => {
let settings = self.settings.lock().unwrap();
settings.mute.to_value()
}
- Property::Boolean("is-live", ..) => {
+ "is-live" => {
let settings = self.settings.lock().unwrap();
settings.is_live.to_value()
}
@@ -827,6 +819,16 @@ struct ClockWait {
flushing: bool,
}
+impl Default for ClockWait {
+ fn default() -> Self {
+ ClockWait {
+ clock_id: None,
+ flushing: true,
+ }
+ }
+}
+
+#[derive(Default)]
struct SineSrc {
settings: Mutex<Settings>,
state: Mutex<State>,