mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-02-02 06:02:20 +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)
|
||||
2. [Part 2: `sinesrc` - A raw audio sine wave source](tutorial-2.md)
|
||||
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 progressbin;
|
||||
mod progressbin_output_enum;
|
||||
mod rgb2gray;
|
||||
mod sinesrc;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::progressbin_output_enum::ProgressBinOutput;
|
||||
use glib;
|
||||
use glib::prelude::*;
|
||||
use glib::subclass;
|
||||
|
@ -13,14 +14,41 @@ use glib::subclass::prelude::*;
|
|||
use gst;
|
||||
use gst::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 ProgressBin {
|
||||
progress: gst::Element,
|
||||
srcpad: 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
|
||||
// provides the entry points for creating a new instance and setting
|
||||
// up the class data
|
||||
|
@ -56,6 +84,7 @@ impl ObjectSubclass for ProgressBin {
|
|||
progress,
|
||||
srcpad,
|
||||
sinkpad,
|
||||
output_type: Mutex::new(ProgressBinOutput::Println),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +130,9 @@ impl ObjectSubclass for ProgressBin {
|
|||
)
|
||||
.unwrap();
|
||||
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
|
||||
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
|
||||
fn constructed(&self, obj: &glib::Object) {
|
||||
// Call the parent class' ::constructed() implementation first
|
||||
|
@ -157,7 +228,13 @@ impl BinImpl for ProgressBin {
|
|||
{
|
||||
let s = msg.get_structure().unwrap();
|
||||
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),
|
||||
|
|
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