Port tutorials plugin to new subclassing API

This commit is contained in:
Sebastian Dröge 2018-11-24 10:31:58 +01:00
parent 485839a2a9
commit 4ac6863eed
4 changed files with 295 additions and 290 deletions

View file

@ -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"

View file

@ -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"
);

View file

@ -1,4 +1,4 @@
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
// Copyright (C) 2017,2018 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
@ -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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
// Called when a new instance is to be created
fn new(_transform: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
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<Self>) {
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<BaseTransform> 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::<BaseTransform>().unwrap();
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 {
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<BaseTransform> 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<BaseTransform> 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<glib::Value, ()> {
let prop = &PROPERTIES[id as usize];
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
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<BaseTransform> for Rgb2Gray {
}
// Virtual methods of gst::Element. We override none
impl ElementImpl<BaseTransform> for Rgb2Gray {}
impl ElementImpl for Rgb2Gray {}
// Virtual methods of gst_base::BaseTransform
impl BaseTransformImpl<BaseTransform> 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<BaseTransform> 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<usize> {
fn get_unit_size(&self, _element: &gst_base::BaseTransform, caps: &gst::Caps) -> Option<usize> {
gst_video::VideoInfo::from_caps(caps).map(|info| info.size())
}
@ -335,7 +356,12 @@ impl BaseTransformImpl<BaseTransform> 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<BaseTransform> 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<BaseTransform> 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<BaseTransform> 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<BaseTransform> for Rgb2GrayStatic {
fn get_name(&self) -> &str {
"Rgb2Gray"
}
fn new(&self, element: &BaseTransform) -> Box<BaseTransformImpl<BaseTransform>> {
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())
}

View file

@ -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<BaseSrcImpl<BaseSrc>> {
// 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 <sebastian@centricular.com>",
);
// 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::<i32>::new(1, i32::MAX)),
("channels", &gst::IntRange::<i32>::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<F: Float + FromByteSlice>(
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<Self>;
type Class = subclass::simple::ClassStruct<Self>;
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<Self>) {
klass.set_metadata(
"Sine Wave Source",
"Source/Audio",
"Creates a sine wave",
"Sebastian Dröge <sebastian@centricular.com>",
);
// 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::<i32>::new(1, i32::MAX)),
("channels", &gst::IntRange::<i32>::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<BaseSrc> 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::<gst_base::BaseSrc>().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::<BaseSrc>().unwrap();
fn set_property(&self, obj: &glib::Object, id: usize, value: &glib::Value) {
let prop = &PROPERTIES[id];
let basesrc = obj.downcast_ref::<gst_base::BaseSrc>().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<BaseSrc> 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<BaseSrc> 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<glib::Value, ()> {
let prop = &PROPERTIES[id as usize];
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
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<BaseSrc> for SineSrc {
}
// Virtual methods of gst::Element. We override none
impl ElementImpl<BaseSrc> 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::<gst_base::BaseSrc>().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<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<gst::Buffer, gst::FlowError> {
@ -643,7 +676,7 @@ impl BaseSrcImpl<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<BaseSrc> 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<BaseSrc> for SineSrcStatic {
fn get_name(&self) -> &str {
"SineSrc"
}
fn new(&self, element: &BaseSrc) -> Box<BaseSrcImpl<BaseSrc>> {
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())
}