mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-02-09 01:22:21 +00:00
tutorial: Add enum property to control output on progress bin
Fixes #84
This commit is contained in:
parent
e73e27cda4
commit
aa40eae581
4 changed files with 190 additions and 2 deletions
|
@ -5,4 +5,4 @@ This tutorial is for the `gst-plugin-tutorial` plugin. This plugin provides 4 fe
|
||||||
1. [Part 1: `rgb2gray` - A Video Filter for converting RGB to grayscale](tutorial-1.md)
|
1. [Part 1: `rgb2gray` - A Video Filter for converting RGB to grayscale](tutorial-1.md)
|
||||||
2. [Part 2: `sinesrc` - A raw audio sine wave source](tutorial-2.md)
|
2. [Part 2: `sinesrc` - A raw audio sine wave source](tutorial-2.md)
|
||||||
3. Part 3: `identity`
|
3. Part 3: `identity`
|
||||||
4. Part 4: `progressBin` - Prints progress information
|
4. Part 4: `progressBin` - Prints progress information. Also showcases how to implement an enum-property on a plugin.
|
||||||
|
|
|
@ -21,6 +21,7 @@ extern crate lazy_static;
|
||||||
|
|
||||||
mod identity;
|
mod identity;
|
||||||
mod progressbin;
|
mod progressbin;
|
||||||
|
mod progressbin_output_enum;
|
||||||
mod rgb2gray;
|
mod rgb2gray;
|
||||||
mod sinesrc;
|
mod sinesrc;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use crate::progressbin_output_enum::ProgressBinOutput;
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
use glib::subclass;
|
use glib::subclass;
|
||||||
|
@ -13,14 +14,41 @@ use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gst::subclass::prelude::*;
|
use gst::subclass::prelude::*;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
const DEFAULT_OUTPUT_TYPE: ProgressBinOutput = ProgressBinOutput::Println;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CAT: gst::DebugCategory = gst::DebugCategory::new(
|
||||||
|
"progressbin",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
Some("Rust Progress Reporter"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Struct containing all the element data
|
// Struct containing all the element data
|
||||||
struct ProgressBin {
|
struct ProgressBin {
|
||||||
progress: gst::Element,
|
progress: gst::Element,
|
||||||
srcpad: gst::GhostPad,
|
srcpad: gst::GhostPad,
|
||||||
sinkpad: gst::GhostPad,
|
sinkpad: gst::GhostPad,
|
||||||
|
// We put the output_type property behind a mutex, as we want
|
||||||
|
// change it in the set_property function, which can be called
|
||||||
|
// from any thread.
|
||||||
|
output_type: Mutex<ProgressBinOutput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metadata for the element's properties
|
||||||
|
static PROPERTIES: [subclass::Property; 1] = [subclass::Property("output", |name| {
|
||||||
|
glib::ParamSpec::enum_(
|
||||||
|
name,
|
||||||
|
"Output",
|
||||||
|
"Defines the output type of the progressbin",
|
||||||
|
ProgressBinOutput::static_type(),
|
||||||
|
DEFAULT_OUTPUT_TYPE as i32,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
})];
|
||||||
|
|
||||||
// This trait registers our type with the GObject object system and
|
// This trait registers our type with the GObject object system and
|
||||||
// provides the entry points for creating a new instance and setting
|
// provides the entry points for creating a new instance and setting
|
||||||
// up the class data
|
// up the class data
|
||||||
|
@ -56,6 +84,7 @@ impl ObjectSubclass for ProgressBin {
|
||||||
progress,
|
progress,
|
||||||
srcpad,
|
srcpad,
|
||||||
sinkpad,
|
sinkpad,
|
||||||
|
output_type: Mutex::new(ProgressBinOutput::Println),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +130,9 @@ impl ObjectSubclass for ProgressBin {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
klass.add_pad_template(sink_pad_template);
|
klass.add_pad_template(sink_pad_template);
|
||||||
|
|
||||||
|
// Install all our properties
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +141,45 @@ impl ObjectImpl for ProgressBin {
|
||||||
// This macro provides some boilerplate
|
// This macro provides some boilerplate
|
||||||
glib_object_impl!();
|
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: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
let element = obj.downcast_ref::<gst_base::BaseTransform>().unwrap();
|
||||||
|
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("output", ..) => {
|
||||||
|
let mut output_type = self.output_type.lock().unwrap();
|
||||||
|
let new_output_type = value
|
||||||
|
.get_some::<ProgressBinOutput>()
|
||||||
|
.expect("type checked upstream");
|
||||||
|
gst_info!(
|
||||||
|
CAT,
|
||||||
|
obj: element,
|
||||||
|
"Changing output from {:?} to {:?}",
|
||||||
|
output_type,
|
||||||
|
new_output_type
|
||||||
|
);
|
||||||
|
*output_type = new_output_type;
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, ()> {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("output", ..) => {
|
||||||
|
let output_type = self.output_type.lock().unwrap();
|
||||||
|
Ok(output_type.to_value())
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Called right after construction of a new instance
|
// Called right after construction of a new instance
|
||||||
fn constructed(&self, obj: &glib::Object) {
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
// Call the parent class' ::constructed() implementation first
|
// Call the parent class' ::constructed() implementation first
|
||||||
|
@ -157,7 +228,13 @@ impl BinImpl for ProgressBin {
|
||||||
{
|
{
|
||||||
let s = msg.get_structure().unwrap();
|
let s = msg.get_structure().unwrap();
|
||||||
if let Ok(percent) = s.get_some::<f64>("percent-double") {
|
if let Ok(percent) = s.get_some::<f64>("percent-double") {
|
||||||
println!("progress: {:5.1}%", percent);
|
let output_type = self.output_type.lock().unwrap();
|
||||||
|
match *output_type {
|
||||||
|
ProgressBinOutput::Println => println!("progress: {:5.1}%", percent),
|
||||||
|
ProgressBinOutput::DebugCategory => {
|
||||||
|
gst_info!(CAT, "progress: {:5.1}%", percent);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => self.parent_handle_message(bin, msg),
|
_ => self.parent_handle_message(bin, msg),
|
||||||
|
|
110
gst-plugin-tutorial/src/progressbin_output_enum.rs
Normal file
110
gst-plugin-tutorial/src/progressbin_output_enum.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
use glib::{gobject_sys, StaticType, Type};
|
||||||
|
|
||||||
|
// 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)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub(crate) enum ProgressBinOutput {
|
||||||
|
Println = 0,
|
||||||
|
DebugCategory = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This trait allows us to translate our custom enum type to a GLib type.
|
||||||
|
impl glib::translate::ToGlib for ProgressBinOutput {
|
||||||
|
// We use i32 as the underlying representation for the enum.
|
||||||
|
type GlibType = i32;
|
||||||
|
|
||||||
|
fn to_glib(&self) -> Self::GlibType {
|
||||||
|
*self as Self::GlibType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This trait allows us to translate from a GLib type back to our custom enum type.
|
||||||
|
impl glib::translate::FromGlib<i32> for ProgressBinOutput {
|
||||||
|
fn from_glib(val: i32) -> Self {
|
||||||
|
match val {
|
||||||
|
0 => ProgressBinOutput::Println,
|
||||||
|
1 => ProgressBinOutput::DebugCategory,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This trait registers our enum with the GLib type system.
|
||||||
|
impl StaticType for ProgressBinOutput {
|
||||||
|
fn static_type() -> Type {
|
||||||
|
progressbin_output_get_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> glib::value::FromValueOptional<'a> for ProgressBinOutput {
|
||||||
|
unsafe fn from_value_optional(value: &glib::Value) -> Option<Self> {
|
||||||
|
Some(glib::value::FromValue::from_value(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> glib::value::FromValue<'a> for ProgressBinOutput {
|
||||||
|
unsafe fn from_value(value: &glib::Value) -> Self {
|
||||||
|
use glib::translate::ToGlibPtr;
|
||||||
|
|
||||||
|
glib::translate::from_glib(gobject_sys::g_value_get_enum(value.to_glib_none().0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl glib::value::SetValue for ProgressBinOutput {
|
||||||
|
unsafe fn set_value(value: &mut glib::Value, this: &Self) {
|
||||||
|
use glib::translate::{ToGlib, ToGlibPtrMut};
|
||||||
|
|
||||||
|
gobject_sys::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On the first call this function will register the enum type with GObject,
|
||||||
|
// on all further calls it will simply return the registered type id.
|
||||||
|
fn progressbin_output_get_type() -> glib::Type {
|
||||||
|
use std::sync::Once;
|
||||||
|
// We only want to register the enum once, and hence we use a Once struct to ensure that.
|
||||||
|
static ONCE: Once = Once::new();
|
||||||
|
static mut TYPE: glib::Type = glib::Type::Invalid;
|
||||||
|
|
||||||
|
// The first time anyone calls this function, we will call ONCE to complete the registration
|
||||||
|
// process, otherwise we'll just skip it
|
||||||
|
ONCE.call_once(|| {
|
||||||
|
use std::ffi;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
// The descriptions in this array will be available to users of the plugin when using gst-inspect-1.0
|
||||||
|
static mut VALUES: [gobject_sys::GEnumValue; 3] = [
|
||||||
|
gobject_sys::GEnumValue {
|
||||||
|
value: ProgressBinOutput::Println as i32,
|
||||||
|
value_name: b"Println: Outputs the progress using a println! macro.\0".as_ptr() as *const _,
|
||||||
|
value_nick: b"println\0".as_ptr() as *const _,
|
||||||
|
},
|
||||||
|
gobject_sys::GEnumValue {
|
||||||
|
value: ProgressBinOutput::DebugCategory as i32,
|
||||||
|
value_name: b"Debug Category: Outputs the progress as info logs under the element's debug category.\0".as_ptr() as *const _,
|
||||||
|
value_nick: b"debug-category\0".as_ptr() as *const _,
|
||||||
|
},
|
||||||
|
// We use a struct with all null values to indicate the end of the array
|
||||||
|
gobject_sys::GEnumValue {
|
||||||
|
value: 0,
|
||||||
|
value_name: ptr::null(),
|
||||||
|
value_nick: ptr::null(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Here we call the bindings to register the enum. We store the result in TYPE, so that we
|
||||||
|
// may re-use it later
|
||||||
|
let name = ffi::CString::new("GstProgressBinOutput").unwrap();
|
||||||
|
unsafe {
|
||||||
|
let type_ = gobject_sys::g_enum_register_static(name.as_ptr(), VALUES.as_ptr());
|
||||||
|
TYPE = glib::translate::from_glib(type_);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that TYPE is not invalid and return it if so
|
||||||
|
unsafe {
|
||||||
|
assert_ne!(TYPE, glib::Type::Invalid);
|
||||||
|
TYPE
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue