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:
-rw-r--r--audio/audiofx/src/audioecho/imp.rs229
-rw-r--r--audio/audiofx/src/audioloudnorm/imp.rs209
-rw-r--r--audio/audiofx/src/audiornnoise/imp.rs97
-rw-r--r--audio/claxon/Cargo.toml1
-rw-r--r--audio/claxon/src/claxondec/imp.rs141
-rw-r--r--audio/csound/src/filter/imp.rs213
-rw-r--r--audio/lewton/src/lewtondec/imp.rs85
-rw-r--r--generic/file/src/filesink/imp.rs116
-rw-r--r--generic/file/src/filesrc/imp.rs116
-rw-r--r--generic/sodium/src/decrypter/imp.rs136
-rw-r--r--generic/sodium/src/encrypter/imp.rs160
-rw-r--r--generic/threadshare/src/appsrc/imp.rs265
-rw-r--r--generic/threadshare/src/inputselector/imp.rs162
-rw-r--r--generic/threadshare/src/jitterbuffer/imp.rs295
-rw-r--r--generic/threadshare/src/proxy/imp.rs316
-rw-r--r--generic/threadshare/src/queue/imp.rs215
-rw-r--r--generic/threadshare/src/tcpclientsrc/imp.rs212
-rw-r--r--generic/threadshare/src/udpsink/imp.rs599
-rw-r--r--generic/threadshare/src/udpsrc/imp.rs316
-rw-r--r--generic/threadshare/tests/pad.rs178
-rw-r--r--net/reqwest/src/reqwesthttpsrc/imp.rs322
-rw-r--r--net/rusoto/src/aws_transcriber/imp.rs178
-rw-r--r--net/rusoto/src/s3sink/imp.rs164
-rw-r--r--net/rusoto/src/s3src/imp.rs114
-rw-r--r--text/json/src/jsongstenc/imp.rs71
-rw-r--r--text/json/src/jsongstparse/imp.rs69
-rw-r--r--text/wrap/src/gsttextwrap/imp.rs197
-rw-r--r--tutorial/src/identity/imp.rs94
-rw-r--r--tutorial/src/progressbin/imp.rs149
-rw-r--r--tutorial/src/rgb2gray/imp.rs284
-rw-r--r--tutorial/src/sinesrc/imp.rs260
-rw-r--r--utils/fallbackswitch/src/fallbacksrc/custom_source/imp.rs82
-rw-r--r--utils/fallbackswitch/src/fallbacksrc/imp.rs403
-rw-r--r--utils/fallbackswitch/src/fallbacksrc/video_fallback/imp.rs101
-rw-r--r--utils/fallbackswitch/src/fallbackswitch/imp.rs228
-rw-r--r--utils/togglerecord/src/togglerecord/imp.rs174
-rw-r--r--video/cdg/src/cdgdec/imp.rs87
-rw-r--r--video/cdg/src/cdgparse/imp.rs87
-rw-r--r--video/closedcaption/src/ccdetect/imp.rs186
-rw-r--r--video/closedcaption/src/cea608overlay/imp.rs75
-rw-r--r--video/closedcaption/src/cea608tott/imp.rs111
-rw-r--r--video/closedcaption/src/mcc_enc/imp.rs189
-rw-r--r--video/closedcaption/src/mcc_parse/imp.rs111
-rw-r--r--video/closedcaption/src/scc_enc/imp.rs79
-rw-r--r--video/closedcaption/src/scc_parse/imp.rs84
-rw-r--r--video/closedcaption/src/tttocea608/imp.rs161
-rw-r--r--video/closedcaption/src/tttojson/imp.rs125
-rw-r--r--video/dav1d/src/dav1ddec/imp.rs97
-rw-r--r--video/flavors/src/flvdemux/imp.rs204
-rw-r--r--video/gif/src/gifenc/imp.rs169
-rw-r--r--video/hsv/src/hsvdetector/imp.rs325
-rw-r--r--video/hsv/src/hsvfilter/imp.rs266
-rw-r--r--video/rav1e/src/rav1enc/imp.rs391
-rw-r--r--video/rspng/src/pngenc/imp.rs186
54 files changed, 5185 insertions, 4699 deletions
diff --git a/audio/audiofx/src/audioecho/imp.rs b/audio/audiofx/src/audioecho/imp.rs
index 88204141e..19fa2deca 100644
--- a/audio/audiofx/src/audioecho/imp.rs
+++ b/audio/audiofx/src/audioecho/imp.rs
@@ -65,51 +65,6 @@ pub struct AudioEcho {
state: Mutex<Option<State>>,
}
-static PROPERTIES: [subclass::Property; 4] = [
- subclass::Property("max-delay", |name| {
- glib::ParamSpec::uint64(name,
- "Maximum Delay",
- "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
- 0, u64::MAX,
- DEFAULT_MAX_DELAY,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("delay", |name| {
- glib::ParamSpec::uint64(
- name,
- "Delay",
- "Delay of the echo in nanoseconds",
- 0,
- u64::MAX,
- DEFAULT_DELAY,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("intensity", |name| {
- glib::ParamSpec::double(
- name,
- "Intensity",
- "Intensity of the echo",
- 0.0,
- 1.0,
- DEFAULT_INTENSITY,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("feedback", |name| {
- glib::ParamSpec::double(
- name,
- "Feedback",
- "Amount of feedback",
- 0.0,
- 1.0,
- DEFAULT_FEEDBACK,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
impl AudioEcho {
fn process<F: Float + ToPrimitive + FromPrimitive>(
data: &mut [F],
@@ -134,6 +89,7 @@ impl ObjectSubclass for AudioEcho {
const NAME: &'static str = "RsAudioEcho";
type Type = super::AudioEcho;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -145,78 +101,75 @@ impl ObjectSubclass for AudioEcho {
state: Mutex::new(None),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Audio echo",
- "Filter/Effect/Audio",
- "Adds an echo or reverb effect to an audio stream",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_audio::AUDIO_FORMAT_F32.to_str(),
- &gst_audio::AUDIO_FORMAT_F64.to_str(),
- ]),
- ),
- ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::AlwaysInPlace,
- false,
- false,
- );
- }
}
impl ObjectImpl for AudioEcho {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::uint64("max-delay",
+ "Maximum Delay",
+ "Maximum delay of the echo in nanoseconds (can't be changed in PLAYING or PAUSED state)",
+ 0, u64::MAX,
+ DEFAULT_MAX_DELAY,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "delay",
+ "Delay",
+ "Delay of the echo in nanoseconds",
+ 0,
+ u64::MAX,
+ DEFAULT_DELAY,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "intensity",
+ "Intensity",
+ "Intensity of the echo",
+ 0.0,
+ 1.0,
+ DEFAULT_INTENSITY,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "feedback",
+ "Feedback",
+ "Amount of feedback",
+ 0.0,
+ 1.0,
+ DEFAULT_FEEDBACK,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- match *prop {
- subclass::Property("max-delay", ..) => {
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "max-delay" => {
let mut settings = self.settings.lock().unwrap();
if self.state.lock().unwrap().is_none() {
settings.max_delay = value.get_some().expect("type checked upstream");
}
}
- subclass::Property("delay", ..) => {
+ "delay" => {
let mut settings = self.settings.lock().unwrap();
settings.delay = value.get_some().expect("type checked upstream");
}
- subclass::Property("intensity", ..) => {
+ "intensity" => {
let mut settings = self.settings.lock().unwrap();
settings.intensity = value.get_some().expect("type checked upstream");
}
- subclass::Property("feedback", ..) => {
+ "feedback" => {
let mut settings = self.settings.lock().unwrap();
settings.feedback = value.get_some().expect("type checked upstream");
}
@@ -224,23 +177,21 @@ impl ObjectImpl for AudioEcho {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("max-delay", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "max-delay" => {
let settings = self.settings.lock().unwrap();
settings.max_delay.to_value()
}
- subclass::Property("delay", ..) => {
+ "delay" => {
let settings = self.settings.lock().unwrap();
settings.delay.to_value()
}
- subclass::Property("intensity", ..) => {
+ "intensity" => {
let settings = self.settings.lock().unwrap();
settings.intensity.to_value()
}
- subclass::Property("feedback", ..) => {
+ "feedback" => {
let settings = self.settings.lock().unwrap();
settings.feedback.to_value()
}
@@ -249,9 +200,65 @@ impl ObjectImpl for AudioEcho {
}
}
-impl ElementImpl for AudioEcho {}
+impl ElementImpl for AudioEcho {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Audio echo",
+ "Filter/Effect/Audio",
+ "Adds an echo or reverb effect to an audio stream",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_audio::AUDIO_FORMAT_F32.to_str(),
+ &gst_audio::AUDIO_FORMAT_F64.to_str(),
+ ]),
+ ),
+ ("rate", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("channels", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for AudioEcho {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::AlwaysInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
fn transform_ip(
&self,
_element: &Self::Type,
diff --git a/audio/audiofx/src/audioloudnorm/imp.rs b/audio/audiofx/src/audioloudnorm/imp.rs
index 76e227e44..102894e55 100644
--- a/audio/audiofx/src/audioloudnorm/imp.rs
+++ b/audio/audiofx/src/audioloudnorm/imp.rs
@@ -210,53 +210,6 @@ pub struct AudioLoudNorm {
state: Mutex<Option<State>>,
}
-static PROPERTIES: [subclass::Property; 4] = [
- subclass::Property("loudness-target", |name| {
- glib::ParamSpec::double(
- name,
- "Loudness Target",
- "Loudness target in LUFS",
- -70.0,
- -5.0,
- DEFAULT_LOUDNESS_TARGET,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("loudness-range-target", |name| {
- glib::ParamSpec::double(
- name,
- "Loudness Range Target",
- "Loudness range target in LU",
- 1.0,
- 20.0,
- DEFAULT_LOUDNESS_RANGE_TARGET,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-true-peak", |name| {
- glib::ParamSpec::double(
- name,
- "Maximum True Peak",
- "Maximum True Peak in dbTP",
- -9.0,
- 0.0,
- DEFAULT_MAX_TRUE_PEAK,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("offset", |name| {
- glib::ParamSpec::double(
- name,
- "Offset Gain",
- "Offset Gain in LU",
- -99.0,
- 99.0,
- DEFAULT_OFFSET,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
// Gain analysis parameters
const GAIN_LOOKAHEAD: usize = 3 * 192_000; // 3s
const FRAME_SIZE: usize = 19_200; // 100ms
@@ -1752,6 +1705,7 @@ impl ObjectSubclass for AudioLoudNorm {
const NAME: &'static str = "RsAudioLoudNorm";
type Type = super::AudioLoudNorm;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1796,47 +1750,54 @@ impl ObjectSubclass for AudioLoudNorm {
state: Mutex::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Audio loudness normalizer",
- "Filter/Effect/Audio",
- "Normalizes perceived loudness of an audio stream",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- ("format", &gst_audio::AUDIO_FORMAT_F64.to_str()),
- ("rate", &192_000i32),
- ("channels", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
+impl ObjectImpl for AudioLoudNorm {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::double(
+ "loudness-target",
+ "Loudness Target",
+ "Loudness target in LUFS",
+ -70.0,
+ -5.0,
+ DEFAULT_LOUDNESS_TARGET,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "loudness-range-target",
+ "Loudness Range Target",
+ "Loudness range target in LU",
+ 1.0,
+ 20.0,
+ DEFAULT_LOUDNESS_RANGE_TARGET,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "max-true-peak",
+ "Maximum True Peak",
+ "Maximum True Peak in dbTP",
+ -9.0,
+ 0.0,
+ DEFAULT_MAX_TRUE_PEAK,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "offset",
+ "Offset Gain",
+ "Offset Gain in LU",
+ -99.0,
+ 99.0,
+ DEFAULT_OFFSET,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- klass.install_properties(&PROPERTIES);
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for AudioLoudNorm {
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -1844,23 +1805,27 @@ impl ObjectImpl for AudioLoudNorm {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("loudness-target", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "loudness-target" => {
let mut settings = self.settings.lock().unwrap();
settings.loudness_target = value.get_some().expect("type checked upstream");
}
- subclass::Property("loudness-range-target", ..) => {
+ "loudness-range-target" => {
let mut settings = self.settings.lock().unwrap();
settings.loudness_range_target = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-true-peak", ..) => {
+ "max-true-peak" => {
let mut settings = self.settings.lock().unwrap();
settings.max_true_peak = value.get_some().expect("type checked upstream");
}
- subclass::Property("offset", ..) => {
+ "offset" => {
let mut settings = self.settings.lock().unwrap();
settings.offset = value.get_some().expect("type checked upstream");
}
@@ -1868,23 +1833,21 @@ impl ObjectImpl for AudioLoudNorm {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("loudness-target", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "loudness-target" => {
let settings = self.settings.lock().unwrap();
settings.loudness_target.to_value()
}
- subclass::Property("loudness-range-target", ..) => {
+ "loudness-range-target" => {
let settings = self.settings.lock().unwrap();
settings.loudness_range_target.to_value()
}
- subclass::Property("max-true-peak", ..) => {
+ "max-true-peak" => {
let settings = self.settings.lock().unwrap();
settings.max_true_peak.to_value()
}
- subclass::Property("offset", ..) => {
+ "offset" => {
let settings = self.settings.lock().unwrap();
settings.offset.to_value()
}
@@ -1894,6 +1857,52 @@ impl ObjectImpl for AudioLoudNorm {
}
impl ElementImpl for AudioLoudNorm {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Audio loudness normalizer",
+ "Filter/Effect/Audio",
+ "Normalizes perceived loudness of an audio stream",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ ("format", &gst_audio::AUDIO_FORMAT_F64.to_str()),
+ ("rate", &192_000i32),
+ ("channels", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/audio/audiofx/src/audiornnoise/imp.rs b/audio/audiofx/src/audiornnoise/imp.rs
index 71a75f695..02a23a755 100644
--- a/audio/audiofx/src/audiornnoise/imp.rs
+++ b/audio/audiofx/src/audiornnoise/imp.rs
@@ -193,6 +193,7 @@ impl ObjectSubclass for AudioRNNoise {
const NAME: &'static str = "AudioRNNoise";
type Type = super::AudioRNNoise;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -203,54 +204,64 @@ impl ObjectSubclass for AudioRNNoise {
state: Mutex::new(None),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Audio denoise",
- "Filter/Effect/Audio",
- "Removes noise from an audio stream",
- "Philippe Normand <philn@igalia.com>",
- );
-
- let caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- ("format", &gst_audio::AUDIO_FORMAT_F32.to_str()),
- ("rate", &48000),
- ("channels", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::NeverInPlace,
- false,
- false,
- );
- }
}
impl ObjectImpl for AudioRNNoise {}
-impl ElementImpl for AudioRNNoise {}
+
+impl ElementImpl for AudioRNNoise {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Audio denoise",
+ "Filter/Effect/Audio",
+ "Removes noise from an audio stream",
+ "Philippe Normand <philn@igalia.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ ("format", &gst_audio::AUDIO_FORMAT_F32.to_str()),
+ ("rate", &48000),
+ ("channels", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for AudioRNNoise {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::NeverInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
fn set_caps(
&self,
element: &Self::Type,
diff --git a/audio/claxon/Cargo.toml b/audio/claxon/Cargo.toml
index 531f49623..322471fa5 100644
--- a/audio/claxon/Cargo.toml
+++ b/audio/claxon/Cargo.toml
@@ -14,6 +14,7 @@ gst-audio = { package = "gstreamer-audio", git = "https://gitlab.freedesktop.org
claxon = { version = "0.4" }
byte-slice-cast = "1.0"
atomic_refcell = "0.1"
+once_cell = "1"
[dev-dependencies]
gst-check = { package = "gstreamer-check", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
diff --git a/audio/claxon/src/claxondec/imp.rs b/audio/claxon/src/claxondec/imp.rs
index ce8d2761b..bbec688d9 100644
--- a/audio/claxon/src/claxondec/imp.rs
+++ b/audio/claxon/src/claxondec/imp.rs
@@ -19,13 +19,22 @@ use atomic_refcell::AtomicRefCell;
use byte_slice_cast::*;
+use once_cell::sync::Lazy;
+
+static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
+ gst::DebugCategory::new(
+ "claxondec",
+ gst::DebugColorFlags::empty(),
+ Some("Claxon FLAC decoder"),
+ )
+});
+
struct State {
streaminfo: Option<claxon::metadata::StreamInfo>,
audio_info: Option<gst_audio::AudioInfo>,
}
pub struct ClaxonDec {
- cat: gst::DebugCategory,
state: AtomicRefCell<Option<State>>,
}
@@ -33,6 +42,7 @@ impl ObjectSubclass for ClaxonDec {
const NAME: &'static str = "ClaxonDec";
type Type = super::ClaxonDec;
type ParentType = gst_audio::AudioDecoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -40,64 +50,69 @@ impl ObjectSubclass for ClaxonDec {
fn new() -> Self {
Self {
- cat: gst::DebugCategory::new(
- "claxondec",
- gst::DebugColorFlags::empty(),
- Some("Claxon FLAC decoder"),
- ),
state: AtomicRefCell::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Claxon FLAC decoder",
- "Decoder/Audio",
- "Claxon FLAC decoder",
- "Ruben Gonzalez <rgonzalez@fluendo.com>",
- );
+impl ObjectImpl for ClaxonDec {}
- let sink_caps = gst::Caps::new_simple("audio/x-flac", &[("framed", &true)]);
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_audio::AudioFormat::S8.to_str(),
- &gst_audio::AUDIO_FORMAT_S16.to_str(),
- &gst_audio::AUDIO_FORMAT_S2432.to_str(),
- &gst_audio::AUDIO_FORMAT_S32.to_str(),
- ]),
- ),
- ("rate", &gst::IntRange::<i32>::new(1, 655_350)),
- ("channels", &gst::IntRange::<i32>::new(1, 8)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
+impl ElementImpl for ClaxonDec {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Claxon FLAC decoder",
+ "Decoder/Audio",
+ "Claxon FLAC decoder",
+ "Ruben Gonzalez <rgonzalez@fluendo.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
}
-}
-impl ObjectImpl for ClaxonDec {}
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple("audio/x-flac", &[("framed", &true)]);
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_audio::AudioFormat::S8.to_str(),
+ &gst_audio::AUDIO_FORMAT_S16.to_str(),
+ &gst_audio::AUDIO_FORMAT_S2432.to_str(),
+ &gst_audio::AUDIO_FORMAT_S32.to_str(),
+ ]),
+ ),
+ ("rate", &gst::IntRange::<i32>::new(1, 655_350)),
+ ("channels", &gst::IntRange::<i32>::new(1, 8)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
-impl ElementImpl for ClaxonDec {}
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl AudioDecoderImpl for ClaxonDec {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {
@@ -116,7 +131,7 @@ impl AudioDecoderImpl for ClaxonDec {
}
fn set_format(&self, element: &Self::Type, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
- gst_debug!(self.cat, obj: element, "Setting format {:?}", caps);
+ gst_debug!(CAT, obj: element, "Setting format {:?}", caps);
let mut streaminfo: Option<claxon::metadata::StreamInfo> = None;
let mut audio_info: Option<gst_audio::AudioInfo> = None;
@@ -127,18 +142,18 @@ impl AudioDecoderImpl for ClaxonDec {
if streamheaders.len() < 2 {
gst_debug!(
- self.cat,
+ CAT,
obj: element,
"Not enough streamheaders, trying in-band"
);
} else {
let ident_buf = streamheaders[0].get::<gst::Buffer>();
if let Ok(Some(ident_buf)) = ident_buf {
- gst_debug!(self.cat, obj: element, "Got streamheader buffers");
+ gst_debug!(CAT, obj: element, "Got streamheader buffers");
let inmap = ident_buf.map_readable().unwrap();
if inmap[0..7] != [0x7f, b'F', b'L', b'A', b'C', 0x01, 0x00] {
- gst_debug!(self.cat, obj: element, "Unknown streamheader format");
+ gst_debug!(CAT, obj: element, "Unknown streamheader format");
} else if let Ok(tstreaminfo) = get_claxon_streaminfo(&inmap[13..]) {
if let Ok(taudio_info) = get_gstaudioinfo(tstreaminfo) {
// To speed up negotiation
@@ -146,7 +161,7 @@ impl AudioDecoderImpl for ClaxonDec {
|| element.negotiate().is_err()
{
gst_debug!(
- self.cat,
+ CAT,
obj: element,
"Error to negotiate output from based on in-caps streaminfo"
);
@@ -175,7 +190,7 @@ impl AudioDecoderImpl for ClaxonDec {
element: &Self::Type,
inbuf: Option<&gst::Buffer>,
) -> Result<gst::FlowSuccess, gst::FlowError> {
- gst_debug!(self.cat, obj: element, "Handling buffer {:?}", inbuf);
+ gst_debug!(CAT, obj: element, "Handling buffer {:?}", inbuf);
let inbuf = match inbuf {
None => return Ok(gst::FlowSuccess::Ok),
@@ -183,7 +198,7 @@ impl AudioDecoderImpl for ClaxonDec {
};
let inmap = inbuf.map_readable().map_err(|_| {
- gst_error!(self.cat, obj: element, "Failed to buffer readable");
+ gst_error!(CAT, obj: element, "Failed to buffer readable");
gst::FlowError::Error
})?;
@@ -191,17 +206,17 @@ impl AudioDecoderImpl for ClaxonDec {
let state = state_guard.as_mut().ok_or(gst::FlowError::NotNegotiated)?;
if inmap.as_slice() == b"fLaC" {
- gst_debug!(self.cat, obj: element, "fLaC buffer received");
+ gst_debug!(CAT, obj: element, "fLaC buffer received");
} else if inmap[0] & 0x7F == 0x00 {
- gst_debug!(self.cat, obj: element, "Streaminfo header buffer received");
+ gst_debug!(CAT, obj: element, "Streaminfo header buffer received");
return self.handle_streaminfo_header(element, state, inmap.as_ref());
} else if inmap[0] == 0b1111_1111 && inmap[1] & 0b1111_1100 == 0b1111_1000 {
- gst_debug!(self.cat, obj: element, "Data buffer received");
+ gst_debug!(CAT, obj: element, "Data buffer received");
return self.handle_data(element, state, inmap.as_ref());
} else {
// info about other headers in flacparse and https://xiph.org/flac/format.html
gst_debug!(
- self.cat,
+ CAT,
obj: element,
"Other header buffer received {:?}",
inmap[0] & 0x7F
@@ -230,7 +245,7 @@ impl ClaxonDec {
})?;
gst_debug!(
- self.cat,
+ CAT,
obj: element,
"Successfully parsed headers: {:?}",
audio_info
diff --git a/audio/csound/src/filter/imp.rs b/audio/csound/src/filter/imp.rs
index 6fdda3aff..9967587e4 100644
--- a/audio/csound/src/filter/imp.rs
+++ b/audio/csound/src/filter/imp.rs
@@ -80,49 +80,6 @@ pub struct CsoundFilter {
compiled: AtomicBool,
}
-static PROPERTIES: [subclass::Property; 4] = [
- subclass::Property("loop", |name| {
- glib::ParamSpec::boolean(
- name,
- "Loop",
- "loop over the score (can be changed in PLAYING or PAUSED state)",
- DEFAULT_LOOP,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("location", |name| {
- glib::ParamSpec::string(
- name,
- "Location",
- "Location of the csd file to be used by csound.
- Use either location or CSD-text but not both at the same time, if so and error would be triggered",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("csd-text", |name| {
- glib::ParamSpec::string(
- name,
- "CSD-text",
- "The content of a csd file passed as a String.
- Use either location or csd-text but not both at the same time, if so and error would be triggered",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("score_offset", |name| {
- glib::ParamSpec::double(
- name,
- "Score Offset",
- "Score offset in seconds to start the performance",
- 0.0,
- f64::MAX,
- SCORE_OFFSET_DEFAULT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
impl State {
// Considering an input of size: input_size and the user's ksmps,
// calculates the equivalent output_size
@@ -361,6 +318,7 @@ impl ObjectSubclass for CsoundFilter {
const NAME: &'static str = "CsoundFilter";
type Type = super::CsoundFilter;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -383,61 +341,63 @@ impl ObjectSubclass for CsoundFilter {
compiled: AtomicBool::new(false),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Audio filter",
- "Filter/Effect/Audio",
- "Implement an audio filter/effects using Csound",
- "Natanael Mojica <neithanmo@gmail.com>",
- );
+impl ObjectImpl for CsoundFilter {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boolean(
+ "loop",
+ "Loop",
+ "loop over the score (can be changed in PLAYING or PAUSED state)",
+ DEFAULT_LOOP,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "location",
+ "Location",
+ "Location of the csd file to be used by csound.
+ Use either location or CSD-text but not both at the same time, if so and error would be triggered",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "csd-text",
+ "CSD-text",
+ "The content of a csd file passed as a String.
+ Use either location or csd-text but not both at the same time, if so and error would be triggered",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "score-offset",
+ "Score Offset",
+ "Score offset in seconds to start the performance",
+ 0.0,
+ f64::MAX,
+ SCORE_OFFSET_DEFAULT,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- let caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- ("format", &gst_audio::AUDIO_FORMAT_F64.to_str()),
- ("rate", &gst::IntRange::<i32>::new(1, i32::MAX)),
- ("channels", &gst::IntRange::<i32>::new(1, i32::MAX)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::NeverInPlace,
- false,
- false,
- );
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for CsoundFilter {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("loop", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "loop" => {
let mut settings = self.settings.lock().unwrap();
settings.loop_ = value.get_some().expect("type checked upstream");
}
- subclass::Property("location", ..) => {
+ "location" => {
let mut settings = self.settings.lock().unwrap();
if self.state.lock().unwrap().is_none() {
settings.location = match value.get::<String>() {
@@ -446,7 +406,7 @@ impl ObjectImpl for CsoundFilter {
};
}
}
- subclass::Property("csd-text", ..) => {
+ "csd-text" => {
let mut settings = self.settings.lock().unwrap();
if self.state.lock().unwrap().is_none() {
settings.csd_text = match value.get::<String>() {
@@ -455,7 +415,7 @@ impl ObjectImpl for CsoundFilter {
};
}
}
- subclass::Property("score_offset", ..) => {
+ "score_offset" => {
let mut settings = self.settings.lock().unwrap();
settings.offset = value.get_some().expect("type checked upstream");
}
@@ -463,23 +423,21 @@ impl ObjectImpl for CsoundFilter {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("loop", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "loop" => {
let settings = self.settings.lock().unwrap();
settings.loop_.to_value()
}
- subclass::Property("location", ..) => {
+ "location" => {
let settings = self.settings.lock().unwrap();
settings.location.to_value()
}
- subclass::Property("csd-text", ..) => {
+ "csd-text" => {
let settings = self.settings.lock().unwrap();
settings.csd_text.to_value()
}
- subclass::Property("score_offset", ..) => {
+ "score_offset" => {
let settings = self.settings.lock().unwrap();
settings.offset.to_value()
}
@@ -488,9 +446,60 @@ impl ObjectImpl for CsoundFilter {
}
}
-impl ElementImpl for CsoundFilter {}
+impl ElementImpl for CsoundFilter {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Audio filter",
+ "Filter/Effect/Audio",
+ "Implement an audio filter/effects using Csound",
+ "Natanael Mojica <neithanmo@gmail.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ ("format", &gst_audio::AUDIO_FORMAT_F64.to_str()),
+ ("rate", &gst::IntRange::<i32>::new(1, i32::MAX)),
+ ("channels", &gst::IntRange::<i32>::new(1, i32::MAX)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for CsoundFilter {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::NeverInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
fn start(&self, _element: &Self::Type) -> std::result::Result<(), gst::ErrorMessage> {
self.compile_score()?;
diff --git a/audio/lewton/src/lewtondec/imp.rs b/audio/lewton/src/lewtondec/imp.rs
index 3573a55e7..c08167752 100644
--- a/audio/lewton/src/lewtondec/imp.rs
+++ b/audio/lewton/src/lewtondec/imp.rs
@@ -47,6 +47,7 @@ impl ObjectSubclass for LewtonDec {
const NAME: &'static str = "LewtonDec";
type Type = super::LewtonDec;
type ParentType = gst_audio::AudioDecoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -57,48 +58,58 @@ impl ObjectSubclass for LewtonDec {
state: AtomicRefCell::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "lewton Vorbis decoder",
- "Decoder/Audio",
- "lewton Vorbis decoder",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
+impl ObjectImpl for LewtonDec {}
- let sink_caps = gst::Caps::new_simple("audio/x-vorbis", &[]);
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple(
- "audio/x-raw",
- &[
- ("format", &gst_audio::AUDIO_FORMAT_F32.to_str()),
- ("rate", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- ("channels", &gst::IntRange::<i32>::new(1, 255)),
- ("layout", &"interleaved"),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
+impl ElementImpl for LewtonDec {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "lewton Vorbis decoder",
+ "Decoder/Audio",
+ "lewton Vorbis decoder",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
}
-}
-impl ObjectImpl for LewtonDec {}
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple("audio/x-vorbis", &[]);
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple(
+ "audio/x-raw",
+ &[
+ ("format", &gst_audio::AUDIO_FORMAT_F32.to_str()),
+ ("rate", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ ("channels", &gst::IntRange::<i32>::new(1, 255)),
+ ("layout", &"interleaved"),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
-impl ElementImpl for LewtonDec {}
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl AudioDecoderImpl for LewtonDec {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/generic/file/src/filesink/imp.rs b/generic/file/src/filesink/imp.rs
index 2c301db8c..13d9015ac 100644
--- a/generic/file/src/filesink/imp.rs
+++ b/generic/file/src/filesink/imp.rs
@@ -38,16 +38,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("location", |name| {
- glib::ParamSpec::string(
- name,
- "File Location",
- "Location of the file to write",
- None,
- glib::ParamFlags::READWRITE,
- )
-})];
-
enum State {
Stopped,
Started { file: File, position: u64 },
@@ -120,6 +110,7 @@ impl ObjectSubclass for FileSink {
const NAME: &'static str = "RsFileSink";
type Type = super::FileSink;
type ParentType = gst_base::BaseSink;
+ type Interfaces = (gst::URIHandler,);
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -131,38 +122,32 @@ impl ObjectSubclass for FileSink {
state: Mutex::new(Default::default()),
}
}
-
- fn type_init(type_: &mut subclass::InitializingType<Self>) {
- type_.add_interface::<gst::URIHandler>();
- }
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "File Sink",
- "Sink/File",
- "Write stream to a file",
- "François Laignel <fengalin@free.fr>, Luis de Bethencourt <luisbg@osg.samsung.com>",
- );
-
- let caps = gst::Caps::new_any();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for FileSink {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::string(
+ "location",
+ "File Location",
+ "Location of the file to write",
+ None,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "location" => {
let res = match value.get::<String>() {
Ok(Some(location)) => FileLocation::try_from_path_str(location)
.and_then(|file_location| self.set_location(obj, Some(file_location))),
@@ -178,10 +163,9 @@ impl ObjectImpl for FileSink {
};
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "location" => {
let settings = self.settings.lock().unwrap();
let location = settings
.location
@@ -195,7 +179,37 @@ impl ObjectImpl for FileSink {
}
}
-impl ElementImpl for FileSink {}
+impl ElementImpl for FileSink {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "File Sink",
+ "Sink/File",
+ "Write stream to a file",
+ "François Laignel <fengalin@free.fr>, Luis de Bethencourt <luisbg@osg.samsung.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseSinkImpl for FileSink {
fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
@@ -286,6 +300,12 @@ impl BaseSinkImpl for FileSink {
}
impl URIHandlerImpl for FileSink {
+ const URI_TYPE: gst::URIType = gst::URIType::Sink;
+
+ fn get_protocols() -> &'static [&'static str] {
+ &["file"]
+ }
+
fn get_uri(&self, _element: &Self::Type) -> Option<String> {
let settings = self.settings.lock().unwrap();
@@ -308,12 +328,4 @@ impl URIHandlerImpl for FileSink {
Ok(())
}
}
-
- fn get_uri_type() -> gst::URIType {
- gst::URIType::Sink
- }
-
- fn get_protocols() -> Vec<String> {
- vec!["file".to_string()]
- }
}
diff --git a/generic/file/src/filesrc/imp.rs b/generic/file/src/filesrc/imp.rs
index baae92fac..1d037c371 100644
--- a/generic/file/src/filesrc/imp.rs
+++ b/generic/file/src/filesrc/imp.rs
@@ -38,16 +38,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("location", |name| {
- glib::ParamSpec::string(
- name,
- "File Location",
- "Location of the file to read from",
- None,
- glib::ParamFlags::READWRITE,
- )
-})];
-
enum State {
Stopped,
Started { file: File, position: u64 },
@@ -134,6 +124,7 @@ impl ObjectSubclass for FileSrc {
const NAME: &'static str = "RsFileSrc";
type Type = super::FileSrc;
type ParentType = gst_base::BaseSrc;
+ type Interfaces = (gst::URIHandler,);
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -145,38 +136,32 @@ impl ObjectSubclass for FileSrc {
state: Mutex::new(Default::default()),
}
}
-
- fn type_init(type_: &mut subclass::InitializingType<Self>) {
- type_.add_interface::<gst::URIHandler>();
- }
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "File Source",
- "Source/File",
- "Read stream from a file",
- "François Laignel <fengalin@free.fr>, Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for FileSrc {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::string(
+ "location",
+ "File Location",
+ "Location of the file to read from",
+ None,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "location" => {
let res = match value.get::<String>() {
Ok(Some(location)) => FileLocation::try_from_path_str(location)
.and_then(|file_location| self.set_location(obj, Some(file_location))),
@@ -192,10 +177,9 @@ impl ObjectImpl for FileSrc {
};
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "location" => {
let settings = self.settings.lock().unwrap();
let location = settings
.location
@@ -215,7 +199,37 @@ impl ObjectImpl for FileSrc {
}
}
-impl ElementImpl for FileSrc {}
+impl ElementImpl for FileSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "File Source",
+ "Source/File",
+ "Read stream from a file",
+ "François Laignel <fengalin@free.fr>, Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseSrcImpl for FileSrc {
fn is_seekable(&self, _src: &Self::Type) -> bool {
@@ -339,6 +353,12 @@ impl BaseSrcImpl for FileSrc {
}
impl URIHandlerImpl for FileSrc {
+ const URI_TYPE: gst::URIType = gst::URIType::Src;
+
+ fn get_protocols() -> &'static [&'static str] {
+ &["file"]
+ }
+
fn get_uri(&self, _element: &Self::Type) -> Option<String> {
let settings = self.settings.lock().unwrap();
@@ -361,12 +381,4 @@ impl URIHandlerImpl for FileSrc {
Ok(())
}
}
-
- fn get_uri_type() -> gst::URIType {
- gst::URIType::Src
- }
-
- fn get_protocols() -> Vec<String> {
- vec!["file".to_string()]
- }
}
diff --git a/generic/sodium/src/decrypter/imp.rs b/generic/sodium/src/decrypter/imp.rs
index d1b73aab4..9aa80b863 100644
--- a/generic/sodium/src/decrypter/imp.rs
+++ b/generic/sodium/src/decrypter/imp.rs
@@ -41,27 +41,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("receiver-key", |name| {
- glib::ParamSpec::boxed(
- name,
- "Receiver Key",
- "The private key of the Reeiver",
- glib::Bytes::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("sender-key", |name| {
- glib::ParamSpec::boxed(
- name,
- "Sender Key",
- "The public key of the Sender",
- glib::Bytes::static_type(),
- glib::ParamFlags::WRITABLE,
- )
- }),
-];
-
#[derive(Debug, Clone, Default)]
struct Props {
receiver_key: Option<glib::Bytes>,
@@ -570,6 +549,7 @@ impl ObjectSubclass for Decrypter {
const NAME: &'static str = "RsSodiumDecryptor";
type Type = super::Decrypter;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -621,38 +601,32 @@ impl ObjectSubclass for Decrypter {
state,
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Decrypter",
- "Generic",
- "libsodium-based file decrypter",
- "Jordan Petridis <jordan@centricular.com>",
- );
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_caps = gst::Caps::builder("application/x-sodium-encrypted").build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for Decrypter {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boxed(
+ "receiver-key",
+ "Receiver Key",
+ "The private key of the Reeiver",
+ glib::Bytes::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "sender-key",
+ "Sender Key",
+ "The public key of the Sender",
+ glib::Bytes::static_type(),
+ glib::ParamFlags::WRITABLE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -660,16 +634,20 @@ impl ObjectImpl for Decrypter {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("sender-key", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "sender-key" => {
let mut props = self.props.lock().unwrap();
props.sender_key = value.get().expect("type checked upstream");
}
- subclass::Property("receiver-key", ..) => {
+ "receiver-key" => {
let mut props = self.props.lock().unwrap();
props.receiver_key = value.get().expect("type checked upstream");
}
@@ -678,11 +656,9 @@ impl ObjectImpl for Decrypter {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("receiver-key", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "receiver-key" => {
let props = self.props.lock().unwrap();
props.receiver_key.to_value()
}
@@ -693,6 +669,44 @@ impl ObjectImpl for Decrypter {
}
impl ElementImpl for Decrypter {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Decrypter",
+ "Generic",
+ "libsodium-based file decrypter",
+ "Jordan Petridis <jordan@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ let sink_caps = gst::Caps::builder("application/x-sodium-encrypted").build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/sodium/src/encrypter/imp.rs b/generic/sodium/src/encrypter/imp.rs
index 28d921e33..3827669e5 100644
--- a/generic/sodium/src/encrypter/imp.rs
+++ b/generic/sodium/src/encrypter/imp.rs
@@ -44,38 +44,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 3] = [
- subclass::Property("receiver-key", |name| {
- glib::ParamSpec::boxed(
- name,
- "Receiver Key",
- "The public key of the Receiver",
- glib::Bytes::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("sender-key", |name| {
- glib::ParamSpec::boxed(
- name,
- "Sender Key",
- "The private key of the Sender",
- glib::Bytes::static_type(),
- glib::ParamFlags::WRITABLE,
- )
- }),
- subclass::Property("block-size", |name| {
- glib::ParamSpec::uint(
- name,
- "Block Size",
- "The block-size of the chunks",
- 1024,
- std::u32::MAX,
- 32768,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug, Clone)]
struct Props {
receiver_key: Option<glib::Bytes>,
@@ -392,6 +360,7 @@ impl ObjectSubclass for Encrypter {
const NAME: &'static str = "RsSodiumEncrypter";
type Type = super::Encrypter;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -444,38 +413,41 @@ impl ObjectSubclass for Encrypter {
state,
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Encrypter",
- "Generic",
- "libsodium-based file encrypter",
- "Jordan Petridis <jordan@centricular.com>",
- );
-
- let src_caps = gst::Caps::builder("application/x-sodium-encrypted").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for Encrypter {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boxed(
+ "receiver-key",
+ "Receiver Key",
+ "The public key of the Receiver",
+ glib::Bytes::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "sender-key",
+ "Sender Key",
+ "The private key of the Sender",
+ glib::Bytes::static_type(),
+ glib::ParamFlags::WRITABLE,
+ ),
+ glib::ParamSpec::uint(
+ "block-size",
+ "Block Size",
+ "The block-size of the chunks",
+ 1024,
+ std::u32::MAX,
+ 32768,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -483,21 +455,25 @@ impl ObjectImpl for Encrypter {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("sender-key", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "sender-key" => {
let mut props = self.props.lock().unwrap();
props.sender_key = value.get().expect("type checked upstream");
}
- subclass::Property("receiver-key", ..) => {
+ "receiver-key" => {
let mut props = self.props.lock().unwrap();
props.receiver_key = value.get().expect("type checked upstream");
}
- subclass::Property("block-size", ..) => {
+ "block-size" => {
let mut props = self.props.lock().unwrap();
props.block_size = value.get_some().expect("type checked upstream");
}
@@ -506,16 +482,14 @@ impl ObjectImpl for Encrypter {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("receiver-key", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "receiver-key" => {
let props = self.props.lock().unwrap();
props.receiver_key.to_value()
}
- subclass::Property("block-size", ..) => {
+ "block-size" => {
let props = self.props.lock().unwrap();
props.block_size.to_value()
}
@@ -526,6 +500,44 @@ impl ObjectImpl for Encrypter {
}
impl ElementImpl for Encrypter {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Encrypter",
+ "Generic",
+ "libsodium-based file encrypter",
+ "Jordan Petridis <jordan@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let src_caps = gst::Caps::builder("application/x-sodium-encrypted").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/appsrc/imp.rs b/generic/threadshare/src/appsrc/imp.rs
index 908b99a53..e34ef3150 100644
--- a/generic/threadshare/src/appsrc/imp.rs
+++ b/generic/threadshare/src/appsrc/imp.rs
@@ -66,58 +66,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 5] = [
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-buffers", |name| {
- glib::ParamSpec::uint(
- name,
- "Max Buffers",
- "Maximum number of buffers to queue up",
- 1,
- u32::MAX,
- DEFAULT_MAX_BUFFERS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("caps", |name| {
- glib::ParamSpec::boxed(
- name,
- "Caps",
- "Caps to use",
- gst::Caps::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("do-timestamp", |name| {
- glib::ParamSpec::boolean(
- name,
- "Do Timestamp",
- "Timestamp buffers with the current running time on arrival",
- DEFAULT_DO_TIMESTAMP,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"ts-appsrc",
@@ -560,68 +508,12 @@ impl ObjectSubclass for AppSrc {
const NAME: &'static str = "RsTsAppSrc";
type Type = super::AppSrc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing app source",
- "Source/Generic",
- "Thread-sharing app source",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
-
- klass.add_signal_with_class_handler(
- "push-buffer",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[gst::Buffer::static_type()],
- bool::static_type(),
- |_, args| {
- let element = args[0]
- .get::<super::AppSrc>()
- .expect("signal arg")
- .expect("missing signal arg");
- let buffer = args[1]
- .get::<gst::Buffer>()
- .expect("signal arg")
- .expect("missing signal arg");
- let appsrc = Self::from_instance(&element);
-
- Some(appsrc.push_buffer(&element, buffer).to_value())
- },
- );
-
- klass.add_signal_with_class_handler(
- "end-of-stream",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[],
- bool::static_type(),
- |_, args| {
- let element = args[0]
- .get::<super::AppSrc>()
- .expect("signal arg")
- .expect("missing signal arg");
- let appsrc = Self::from_instance(&element);
- Some(appsrc.end_of_stream(&element).to_value())
- },
- );
- }
-
fn with_class(klass: &Self::Class) -> Self {
let src_pad_handler = AppSrcPadHandler::default();
@@ -639,43 +531,134 @@ impl ObjectSubclass for AppSrc {
}
impl ObjectImpl for AppSrc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-buffers",
+ "Max Buffers",
+ "Maximum number of buffers to queue up",
+ 1,
+ u32::MAX,
+ DEFAULT_MAX_BUFFERS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "caps",
+ "Caps",
+ "Caps to use",
+ gst::Caps::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "do-timestamp",
+ "Do Timestamp",
+ "Timestamp buffers with the current running time on arrival",
+ DEFAULT_DO_TIMESTAMP,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+ fn signals() -> &'static [glib::subclass::Signal] {
+ static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
+ vec![
+ glib::subclass::Signal::builder(
+ "push-buffer",
+ &[gst::Buffer::static_type()],
+ bool::static_type(),
+ )
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::AppSrc>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let buffer = args[1]
+ .get::<gst::Buffer>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let appsrc = AppSrc::from_instance(&element);
+
+ Some(appsrc.push_buffer(&element, buffer).to_value())
+ })
+ .build(),
+ glib::subclass::Signal::builder("end-of-stream", &[], bool::static_type())
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::AppSrc>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let appsrc = AppSrc::from_instance(&element);
+
+ Some(appsrc.end_of_stream(&element).to_value())
+ })
+ .build(),
+ ]
+ });
+
+ SIGNALS.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("context", ..) => {
+ match pspec.get_name() {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
- subclass::Property("caps", ..) => {
+ "caps" => {
settings.caps = value.get().expect("type checked upstream");
}
- subclass::Property("max-buffers", ..) => {
+ "max-buffers" => {
settings.max_buffers = value.get_some().expect("type checked upstream");
}
- subclass::Property("do-timestamp", ..) => {
+ "do-timestamp" => {
settings.do_timestamp = value.get_some().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
- subclass::Property("caps", ..) => settings.caps.to_value(),
- subclass::Property("max-buffers", ..) => settings.max_buffers.to_value(),
- subclass::Property("do-timestamp", ..) => settings.do_timestamp.to_value(),
+ match pspec.get_name() {
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
+ "caps" => settings.caps.to_value(),
+ "max-buffers" => settings.max_buffers.to_value(),
+ "do-timestamp" => settings.do_timestamp.to_value(),
_ => unimplemented!(),
}
}
@@ -690,6 +673,36 @@ impl ObjectImpl for AppSrc {
}
impl ElementImpl for AppSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing app source",
+ "Source/Generic",
+ "Thread-sharing app source",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/inputselector/imp.rs b/generic/threadshare/src/inputselector/imp.rs
index 3b03add30..36c736495 100644
--- a/generic/threadshare/src/inputselector/imp.rs
+++ b/generic/threadshare/src/inputselector/imp.rs
@@ -55,38 +55,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 3] = [
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("active-pad", |name| {
- glib::ParamSpec::object(
- name,
- "Active Pad",
- "Currently active pad",
- gst::Pad::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug)]
struct InputSelectorPadSinkHandlerInner {
segment: Option<gst::Segment>,
@@ -429,42 +397,12 @@ impl ObjectSubclass for InputSelector {
const NAME: &'static str = "RsTsInputSelector";
type Type = super::InputSelector;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing input selector",
- "Generic",
- "Simple input selector element",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink_%u",
- gst::PadDirection::Sink,
- gst::PadPresence::Request,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
Self {
src_pad: PadSrc::new(
@@ -479,22 +417,58 @@ impl ObjectSubclass for InputSelector {
}
impl ObjectImpl for InputSelector {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::object(
+ "active-pad",
+ "Active Pad",
+ "Currently active pad",
+ gst::Pad::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("context", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "context" => {
let mut settings = self.settings.lock().unwrap();
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
let mut settings = self.settings.lock().unwrap();
settings.context_wait = value.get_some().expect("type checked upstream");
}
- subclass::Property("active-pad", ..) => {
+ "active-pad" => {
let pad = value.get::<gst::Pad>().expect("type checked upstream");
let mut state = self.state.lock().unwrap();
let pads = self.pads.lock().unwrap();
@@ -526,19 +500,17 @@ impl ObjectImpl for InputSelector {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("context", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "context" => {
let settings = self.settings.lock().unwrap();
settings.context.to_value()
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
let settings = self.settings.lock().unwrap();
settings.context_wait.to_value()
}
- subclass::Property("active-pad", ..) => {
+ "active-pad" => {
let state = self.state.lock().unwrap();
let active_pad = state.active_sinkpad.clone();
active_pad.to_value()
@@ -556,6 +528,44 @@ impl ObjectImpl for InputSelector {
}
impl ElementImpl for InputSelector {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing input selector",
+ "Generic",
+ "Simple input selector element",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink_%u",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Request,
+ &caps,
+ )
+ .unwrap();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/jitterbuffer/imp.rs b/generic/threadshare/src/jitterbuffer/imp.rs
index 430f8fd35..19e376900 100644
--- a/generic/threadshare/src/jitterbuffer/imp.rs
+++ b/generic/threadshare/src/jitterbuffer/imp.rs
@@ -72,80 +72,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 7] = [
- subclass::Property("latency", |name| {
- glib::ParamSpec::uint(
- name,
- "Buffer latency in ms",
- "Amount of ms to buffer",
- 0,
- std::u32::MAX,
- DEFAULT_LATENCY_MS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("do-lost", |name| {
- glib::ParamSpec::boolean(
- name,
- "Do Lost",
- "Send an event downstream when a packet is lost",
- DEFAULT_DO_LOST,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-dropout-time", |name| {
- glib::ParamSpec::uint(
- name,
- "Max dropout time",
- "The maximum time (milliseconds) of missing packets tolerated.",
- 0,
- std::u32::MAX,
- DEFAULT_MAX_DROPOUT_TIME,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-misorder-time", |name| {
- glib::ParamSpec::uint(
- name,
- "Max misorder time",
- "The maximum time (milliseconds) of misordered packets tolerated.",
- 0,
- std::u32::MAX,
- DEFAULT_MAX_MISORDER_TIME,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("stats", |name| {
- glib::ParamSpec::boxed(
- name,
- "Statistics",
- "Various statistics",
- gst::Structure::static_type(),
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Eq)]
struct GapPacket {
buffer: gst::Buffer,
@@ -1413,63 +1339,12 @@ impl ObjectSubclass for JitterBuffer {
const NAME: &'static str = "RsTsJitterBuffer";
type Type = super::JitterBuffer;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing jitterbuffer",
- "Generic",
- "Simple jitterbuffer",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- klass.add_signal(
- "request-pt-map",
- glib::SignalFlags::RUN_LAST,
- &[u32::static_type()],
- gst::Caps::static_type(),
- );
-
- klass.add_signal_with_class_handler(
- "clear-pt-map",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[],
- glib::types::Type::Unit,
- |_, args| {
- let element = args[0]
- .get::<super::JitterBuffer>()
- .expect("signal arg")
- .expect("missing signal arg");
- let jb = Self::from_instance(&element);
- jb.clear_pt_map(&element);
- None
- },
- );
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- klass.install_properties(&PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
let sink_pad_handler = SinkHandler::default();
let src_pad_handler = SrcHandler::default();
@@ -1493,11 +1368,102 @@ impl ObjectSubclass for JitterBuffer {
}
impl ObjectImpl for JitterBuffer {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "latency",
+ "Buffer latency in ms",
+ "Amount of ms to buffer",
+ 0,
+ std::u32::MAX,
+ DEFAULT_LATENCY_MS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "do-lost",
+ "Do Lost",
+ "Send an event downstream when a packet is lost",
+ DEFAULT_DO_LOST,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-dropout-time",
+ "Max dropout time",
+ "The maximum time (milliseconds) of missing packets tolerated.",
+ 0,
+ std::u32::MAX,
+ DEFAULT_MAX_DROPOUT_TIME,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-misorder-time",
+ "Max misorder time",
+ "The maximum time (milliseconds) of misordered packets tolerated.",
+ 0,
+ std::u32::MAX,
+ DEFAULT_MAX_MISORDER_TIME,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "stats",
+ "Statistics",
+ "Various statistics",
+ gst::Structure::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn signals() -> &'static [glib::subclass::Signal] {
+ static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
+ vec![
+ glib::subclass::Signal::builder("clear-pt-map", &[], glib::types::Type::Unit)
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::JitterBuffer>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let jb = JitterBuffer::from_instance(&element);
+ jb.clear_pt_map(&element);
+ None
+ })
+ .build(),
+ ]
+ });
+
+ SIGNALS.as_ref()
+ }
- match *prop {
- subclass::Property("latency", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "latency" => {
let latency_ms = {
let mut settings = self.settings.lock().unwrap();
settings.latency_ms = value.get_some().expect("type checked upstream");
@@ -1509,26 +1475,26 @@ impl ObjectImpl for JitterBuffer {
let _ = obj.post_message(gst::message::Latency::builder().src(obj).build());
}
- subclass::Property("do-lost", ..) => {
+ "do-lost" => {
let mut settings = self.settings.lock().unwrap();
settings.do_lost = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-dropout-time", ..) => {
+ "max-dropout-time" => {
let mut settings = self.settings.lock().unwrap();
settings.max_dropout_time = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-misorder-time", ..) => {
+ "max-misorder-time" => {
let mut settings = self.settings.lock().unwrap();
settings.max_misorder_time = value.get_some().expect("type checked upstream");
}
- subclass::Property("context", ..) => {
+ "context" => {
let mut settings = self.settings.lock().unwrap();
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
let mut settings = self.settings.lock().unwrap();
settings.context_wait = value.get_some().expect("type checked upstream");
}
@@ -1536,27 +1502,25 @@ impl ObjectImpl for JitterBuffer {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("latency", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "latency" => {
let settings = self.settings.lock().unwrap();
settings.latency_ms.to_value()
}
- subclass::Property("do-lost", ..) => {
+ "do-lost" => {
let settings = self.settings.lock().unwrap();
settings.do_lost.to_value()
}
- subclass::Property("max-dropout-time", ..) => {
+ "max-dropout-time" => {
let settings = self.settings.lock().unwrap();
settings.max_dropout_time.to_value()
}
- subclass::Property("max-misorder-time", ..) => {
+ "max-misorder-time" => {
let settings = self.settings.lock().unwrap();
settings.max_misorder_time.to_value()
}
- subclass::Property("stats", ..) => {
+ "stats" => {
let state = self.state.lock().unwrap();
let s = gst::Structure::new(
"application/x-rtp-jitterbuffer-stats",
@@ -1568,11 +1532,11 @@ impl ObjectImpl for JitterBuffer {
);
s.to_value()
}
- subclass::Property("context", ..) => {
+ "context" => {
let settings = self.settings.lock().unwrap();
settings.context.to_value()
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
let settings = self.settings.lock().unwrap();
settings.context_wait.to_value()
}
@@ -1590,6 +1554,45 @@ impl ObjectImpl for JitterBuffer {
}
impl ElementImpl for JitterBuffer {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing jitterbuffer",
+ "Generic",
+ "Simple jitterbuffer",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/proxy/imp.rs b/generic/threadshare/src/proxy/imp.rs
index 52d408242..bc13654d4 100644
--- a/generic/threadshare/src/proxy/imp.rs
+++ b/generic/threadshare/src/proxy/imp.rs
@@ -93,81 +93,6 @@ impl Default for SettingsSrc {
}
}
-static PROPERTIES_SRC: [subclass::Property; 6] = [
- subclass::Property("max-size-buffers", |name| {
- glib::ParamSpec::uint(
- name,
- "Max Size Buffers",
- "Maximum number of buffers to queue (0=unlimited)",
- 0,
- u32::MAX,
- DEFAULT_MAX_SIZE_BUFFERS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-size-bytes", |name| {
- glib::ParamSpec::uint(
- name,
- "Max Size Bytes",
- "Maximum number of bytes to queue (0=unlimited)",
- 0,
- u32::MAX,
- DEFAULT_MAX_SIZE_BYTES,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-size-time", |name| {
- glib::ParamSpec::uint64(
- name,
- "Max Size Time",
- "Maximum number of nanoseconds to queue (0=unlimited)",
- 0,
- u64::MAX - 1,
- DEFAULT_MAX_SIZE_TIME,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("proxy-context", |name| {
- glib::ParamSpec::string(
- name,
- "Proxy Context",
- "Context name of the proxy to share with",
- Some(DEFAULT_PROXY_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
-static PROPERTIES_SINK: [subclass::Property; 1] = [subclass::Property("proxy-context", |name| {
- glib::ParamSpec::string(
- name,
- "Proxy Context",
- "Context name of the proxy to share with",
- Some(DEFAULT_PROXY_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
-})];
-
// TODO: Refactor into a Sender and Receiver instead of the have_ booleans
#[derive(Debug, Default)]
@@ -650,34 +575,13 @@ impl ProxySink {
impl ObjectSubclass for ProxySink {
const NAME: &'static str = "RsTsProxySink";
type Type = super::ProxySink;
+ type Interfaces = ();
type ParentType = gst::Element;
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing proxy sink",
- "Sink/Generic",
- "Thread-sharing proxy sink",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES_SINK);
- }
-
fn with_class(klass: &Self::Class) -> Self {
Self {
sink_pad: PadSink::new(
@@ -691,12 +595,30 @@ impl ObjectSubclass for ProxySink {
}
impl ObjectImpl for ProxySink {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES_SINK[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::string(
+ "proxy-context",
+ "Proxy Context",
+ "Context name of the proxy to share with",
+ Some(DEFAULT_PROXY_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("proxy-context", ..) => {
+ match pspec.get_name() {
+ "proxy-context" => {
settings.proxy_context = value
.get()
.expect("type checked upstream")
@@ -706,12 +628,10 @@ impl ObjectImpl for ProxySink {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES_SINK[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("proxy-context", ..) => settings.proxy_context.to_value(),
+ match pspec.get_name() {
+ "proxy-context" => settings.proxy_context.to_value(),
_ => unimplemented!(),
}
}
@@ -726,6 +646,37 @@ impl ObjectImpl for ProxySink {
}
impl ElementImpl for ProxySink {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing proxy sink",
+ "Sink/Generic",
+ "Thread-sharing proxy sink",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
@@ -1166,33 +1117,12 @@ impl ObjectSubclass for ProxySrc {
const NAME: &'static str = "RsTsProxySrc";
type Type = super::ProxySrc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing proxy source",
- "Source/Generic",
- "Thread-sharing proxy source",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES_SRC);
- }
-
fn new() -> Self {
unreachable!()
}
@@ -1212,30 +1142,93 @@ impl ObjectSubclass for ProxySrc {
}
impl ObjectImpl for ProxySrc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES_SRC[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "proxy-context",
+ "Proxy Context",
+ "Context name of the proxy to share with",
+ Some(DEFAULT_PROXY_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-size-buffers",
+ "Max Size Buffers",
+ "Maximum number of buffers to queue (0=unlimited)",
+ 0,
+ u32::MAX,
+ DEFAULT_MAX_SIZE_BUFFERS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-size-bytes",
+ "Max Size Bytes",
+ "Maximum number of bytes to queue (0=unlimited)",
+ 0,
+ u32::MAX,
+ DEFAULT_MAX_SIZE_BYTES,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "max-size-time",
+ "Max Size Time",
+ "Maximum number of nanoseconds to queue (0=unlimited)",
+ 0,
+ u64::MAX - 1,
+ DEFAULT_MAX_SIZE_TIME,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("max-size-buffers", ..) => {
+ match pspec.get_name() {
+ "max-size-buffers" => {
settings.max_size_buffers = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-size-bytes", ..) => {
+ "max-size-bytes" => {
settings.max_size_bytes = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-size-time", ..) => {
+ "max-size-time" => {
settings.max_size_time = value.get_some().expect("type checked upstream");
}
- subclass::Property("context", ..) => {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
- subclass::Property("proxy-context", ..) => {
+ "proxy-context" => {
settings.proxy_context = value
.get()
.expect("type checked upstream")
@@ -1245,17 +1238,15 @@ impl ObjectImpl for ProxySrc {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES_SRC[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("max-size-buffers", ..) => settings.max_size_buffers.to_value(),
- subclass::Property("max-size-bytes", ..) => settings.max_size_bytes.to_value(),
- subclass::Property("max-size-time", ..) => settings.max_size_time.to_value(),
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
- subclass::Property("proxy-context", ..) => settings.proxy_context.to_value(),
+ match pspec.get_name() {
+ "max-size-buffers" => settings.max_size_buffers.to_value(),
+ "max-size-bytes" => settings.max_size_bytes.to_value(),
+ "max-size-time" => settings.max_size_time.to_value(),
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
+ "proxy-context" => settings.proxy_context.to_value(),
_ => unimplemented!(),
}
}
@@ -1270,6 +1261,37 @@ impl ObjectImpl for ProxySrc {
}
impl ElementImpl for ProxySrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing proxy source",
+ "Source/Generic",
+ "Thread-sharing proxy source",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/queue/imp.rs b/generic/threadshare/src/queue/imp.rs
index 8f0d98c05..dd257cadc 100644
--- a/generic/threadshare/src/queue/imp.rs
+++ b/generic/threadshare/src/queue/imp.rs
@@ -65,62 +65,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 5] = [
- subclass::Property("max-size-buffers", |name| {
- glib::ParamSpec::uint(
- name,
- "Max Size Buffers",
- "Maximum number of buffers to queue (0=unlimited)",
- 0,
- u32::MAX,
- DEFAULT_MAX_SIZE_BUFFERS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-size-bytes", |name| {
- glib::ParamSpec::uint(
- name,
- "Max Size Bytes",
- "Maximum number of bytes to queue (0=unlimited)",
- 0,
- u32::MAX,
- DEFAULT_MAX_SIZE_BYTES,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-size-time", |name| {
- glib::ParamSpec::uint64(
- name,
- "Max Size Time",
- "Maximum number of nanoseconds to queue (0=unlimited)",
- 0,
- u64::MAX - 1,
- DEFAULT_MAX_SIZE_TIME,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug)]
struct PendingQueue {
more_queue_space_sender: Option<oneshot::Sender<()>>,
@@ -752,42 +696,12 @@ impl ObjectSubclass for Queue {
const NAME: &'static str = "RsTsQueue";
type Type = super::Queue;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing queue",
- "Generic",
- "Simple data queue",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
Self {
sink_pad: PadSink::new(
@@ -808,43 +722,97 @@ impl ObjectSubclass for Queue {
}
impl ObjectImpl for Queue {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-size-buffers",
+ "Max Size Buffers",
+ "Maximum number of buffers to queue (0=unlimited)",
+ 0,
+ u32::MAX,
+ DEFAULT_MAX_SIZE_BUFFERS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "max-size-bytes",
+ "Max Size Bytes",
+ "Maximum number of bytes to queue (0=unlimited)",
+ 0,
+ u32::MAX,
+ DEFAULT_MAX_SIZE_BYTES,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "max-size-time",
+ "Max Size Time",
+ "Maximum number of nanoseconds to queue (0=unlimited)",
+ 0,
+ u64::MAX - 1,
+ DEFAULT_MAX_SIZE_TIME,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("max-size-buffers", ..) => {
+ match pspec.get_name() {
+ "max-size-buffers" => {
settings.max_size_buffers = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-size-bytes", ..) => {
+ "max-size-bytes" => {
settings.max_size_bytes = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-size-time", ..) => {
+ "max-size-time" => {
settings.max_size_time = value.get_some().expect("type checked upstream");
}
- subclass::Property("context", ..) => {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("max-size-buffers", ..) => settings.max_size_buffers.to_value(),
- subclass::Property("max-size-bytes", ..) => settings.max_size_bytes.to_value(),
- subclass::Property("max-size-time", ..) => settings.max_size_time.to_value(),
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
+ match pspec.get_name() {
+ "max-size-buffers" => settings.max_size_buffers.to_value(),
+ "max-size-bytes" => settings.max_size_bytes.to_value(),
+ "max-size-time" => settings.max_size_time.to_value(),
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
_ => unimplemented!(),
}
}
@@ -858,6 +826,45 @@ impl ObjectImpl for Queue {
}
impl ElementImpl for Queue {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing queue",
+ "Generic",
+ "Simple data queue",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/tcpclientsrc/imp.rs b/generic/threadshare/src/tcpclientsrc/imp.rs
index afd23423b..4b584b07e 100644
--- a/generic/threadshare/src/tcpclientsrc/imp.rs
+++ b/generic/threadshare/src/tcpclientsrc/imp.rs
@@ -75,69 +75,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 6] = [
- subclass::Property("host", |name| {
- glib::ParamSpec::string(
- name,
- "Host",
- "The host IP address to receive packets from",
- DEFAULT_HOST,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("port", |name| {
- glib::ParamSpec::int(
- name,
- "Port",
- "Port to receive packets from",
- 0,
- u16::MAX as i32,
- DEFAULT_PORT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("caps", |name| {
- glib::ParamSpec::boxed(
- name,
- "Caps",
- "Caps to use",
- gst::Caps::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("blocksize", |name| {
- glib::ParamSpec::uint(
- name,
- "Blocksize",
- "Size in bytes to read per buffer (-1 = default)",
- 0,
- u32::MAX,
- DEFAULT_BLOCKSIZE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
struct TcpClientReader(tokio::net::TcpStream);
impl TcpClientReader {
@@ -612,32 +549,12 @@ impl ObjectSubclass for TcpClientSrc {
const NAME: &'static str = "RsTsTcpClientSrc";
type Type = super::TcpClientSrc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing TCP client source",
- "Source/Network",
- "Receives data over the network via TCP",
- "Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
let src_pad_handler = TcpClientSrcPadHandler::default();
@@ -654,47 +571,106 @@ impl ObjectSubclass for TcpClientSrc {
}
impl ObjectImpl for TcpClientSrc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "host",
+ "Host",
+ "The host IP address to receive packets from",
+ DEFAULT_HOST,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "port",
+ "Port",
+ "Port to receive packets from",
+ 0,
+ u16::MAX as i32,
+ DEFAULT_PORT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "caps",
+ "Caps",
+ "Caps to use",
+ gst::Caps::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "blocksize",
+ "Blocksize",
+ "Size in bytes to read per buffer (-1 = default)",
+ 0,
+ u32::MAX,
+ DEFAULT_BLOCKSIZE,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("host", ..) => {
+ match pspec.get_name() {
+ "host" => {
settings.host = value.get().expect("type checked upstream");
}
- subclass::Property("port", ..) => {
+ "port" => {
settings.port = value.get_some().expect("type checked upstream");
}
- subclass::Property("caps", ..) => {
+ "caps" => {
settings.caps = value.get().expect("type checked upstream");
}
- subclass::Property("blocksize", ..) => {
+ "blocksize" => {
settings.blocksize = value.get_some().expect("type checked upstream");
}
- subclass::Property("context", ..) => {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("host", ..) => settings.host.to_value(),
- subclass::Property("port", ..) => settings.port.to_value(),
- subclass::Property("caps", ..) => settings.caps.to_value(),
- subclass::Property("blocksize", ..) => settings.blocksize.to_value(),
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
+ match pspec.get_name() {
+ "host" => settings.host.to_value(),
+ "port" => settings.port.to_value(),
+ "caps" => settings.caps.to_value(),
+ "blocksize" => settings.blocksize.to_value(),
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
_ => unimplemented!(),
}
}
@@ -709,6 +685,36 @@ impl ObjectImpl for TcpClientSrc {
}
impl ElementImpl for TcpClientSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing TCP client source",
+ "Source/Network",
+ "Receives data over the network via TCP",
+ "Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/udpsink/imp.rs b/generic/threadshare/src/udpsink/imp.rs
index bd991bbc1..8b44588c1 100644
--- a/generic/threadshare/src/udpsink/imp.rs
+++ b/generic/threadshare/src/udpsink/imp.rs
@@ -118,174 +118,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 17] = [
- subclass::Property("sync", |name| {
- glib::ParamSpec::boolean(
- name,
- "Sync",
- "Sync on the clock",
- DEFAULT_SYNC,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("bind-address", |name| {
- glib::ParamSpec::string(
- name,
- "Bind Address",
- "Address to bind the socket to",
- Some(DEFAULT_BIND_ADDRESS),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("bind-port", |name| {
- glib::ParamSpec::int(
- name,
- "Bind Port",
- "Port to bind the socket to",
- 0,
- u16::MAX as i32,
- DEFAULT_BIND_PORT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("bind-address-v6", |name| {
- glib::ParamSpec::string(
- name,
- "Bind Address V6",
- "Address to bind the V6 socket to",
- Some(DEFAULT_BIND_ADDRESS_V6),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("bind-port-v6", |name| {
- glib::ParamSpec::int(
- name,
- "Bind Port",
- "Port to bind the V6 socket to",
- 0,
- u16::MAX as i32,
- DEFAULT_BIND_PORT_V6,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("socket", |name| {
- glib::ParamSpec::object(
- name,
- "Socket",
- "Socket to use for UDP transmission. (None == allocate)",
- gio::Socket::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("used-socket", |name| {
- glib::ParamSpec::object(
- name,
- "Used Socket",
- "Socket currently in use for UDP transmission. (None = no socket)",
- gio::Socket::static_type(),
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("socket-v6", |name| {
- glib::ParamSpec::object(
- name,
- "Socket V6",
- "IPV6 Socket to use for UDP transmission. (None == allocate)",
- gio::Socket::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("used-socket-v6", |name| {
- glib::ParamSpec::object(
- name,
- "Used Socket V6",
- "V6 Socket currently in use for UDP transmission. (None = no socket)",
- gio::Socket::static_type(),
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("auto-multicast", |name| {
- glib::ParamSpec::boolean(
- name,
- "Auto multicast",
- "Automatically join/leave the multicast groups, FALSE means user has to do it himself",
- DEFAULT_AUTO_MULTICAST,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("loop", |name| {
- glib::ParamSpec::boolean(
- name,
- "Loop",
- "Set the multicast loop parameter.",
- DEFAULT_LOOP,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("ttl", |name| {
- glib::ParamSpec::uint(
- name,
- "Time To Live",
- "Used for setting the unicast TTL parameter",
- 0,
- u8::MAX as u32,
- DEFAULT_TTL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("ttl-mc", |name| {
- glib::ParamSpec::uint(
- name,
- "Time To Live Multicast",
- "Used for setting the multicast TTL parameter",
- 0,
- u8::MAX as u32,
- DEFAULT_TTL_MC,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("qos-dscp", |name| {
- glib::ParamSpec::int(
- name,
- "QoS DSCP",
- "Quality of Service, differentiated services code point (-1 default)",
- -1,
- 63,
- DEFAULT_QOS_DSCP,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("clients", |name| {
- glib::ParamSpec::string(
- name,
- "Clients",
- "A comma separated list of host:port pairs with destinations",
- Some(DEFAULT_CLIENTS),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug)]
enum TaskItem {
Buffer(gst::Buffer),
@@ -1127,107 +959,12 @@ impl ObjectSubclass for UdpSink {
const NAME: &'static str = "RsTsUdpSink";
type Type = super::UdpSink;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing UDP sink",
- "Sink/Network",
- "Thread-sharing UDP sink",
- "Mathieu <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- klass.add_signal_with_class_handler(
- "add",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[String::static_type(), i32::static_type()],
- glib::types::Type::Unit,
- |_, args| {
- let element = args[0]
- .get::<super::UdpSink>()
- .expect("signal arg")
- .expect("missing signal arg");
- let host = args[1]
- .get::<String>()
- .expect("signal arg")
- .expect("missing signal arg");
- let port = args[2]
- .get::<i32>()
- .expect("signal arg")
- .expect("missing signal arg");
-
- if let Ok(addr) = try_into_socket_addr(&element, &host, port) {
- let udpsink = Self::from_instance(&element);
- udpsink.add_client(addr);
- }
-
- None
- },
- );
-
- klass.add_signal_with_class_handler(
- "remove",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[String::static_type(), i32::static_type()],
- glib::types::Type::Unit,
- |_, args| {
- let element = args[0]
- .get::<super::UdpSink>()
- .expect("signal arg")
- .expect("missing signal arg");
- let host = args[1]
- .get::<String>()
- .expect("signal arg")
- .expect("missing signal arg");
- let port = args[2]
- .get::<i32>()
- .expect("signal arg")
- .expect("missing signal arg");
-
- let udpsink = Self::from_instance(&element);
-
- if let Ok(addr) = try_into_socket_addr(&element, &host, port) {
- udpsink.remove_client(addr);
- }
-
- None
- },
- );
-
- klass.add_signal_with_class_handler(
- "clear",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[],
- glib::types::Type::Unit,
- |_, args| {
- let element = args[0]
- .get::<super::UdpSink>()
- .expect("signal arg")
- .expect("missing signal arg");
-
- let udpsink = Self::from_instance(&element);
- udpsink.clear_clients(std::iter::empty());
-
- None
- },
- );
-
- klass.install_properties(&PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
let settings = Arc::new(StdMutex::new(Settings::default()));
let sink_pad_handler = UdpSinkPadHandler::new(Arc::clone(&settings));
@@ -1245,66 +982,289 @@ impl ObjectSubclass for UdpSink {
}
impl ObjectImpl for UdpSink {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "sync",
+ "Sync",
+ "Sync on the clock",
+ DEFAULT_SYNC,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "bind-address",
+ "Bind Address",
+ "Address to bind the socket to",
+ Some(DEFAULT_BIND_ADDRESS),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "bind-port",
+ "Bind Port",
+ "Port to bind the socket to",
+ 0,
+ u16::MAX as i32,
+ DEFAULT_BIND_PORT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "bind-address-v6",
+ "Bind Address V6",
+ "Address to bind the V6 socket to",
+ Some(DEFAULT_BIND_ADDRESS_V6),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "bind-port-v6",
+ "Bind Port",
+ "Port to bind the V6 socket to",
+ 0,
+ u16::MAX as i32,
+ DEFAULT_BIND_PORT_V6,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::object(
+ "socket",
+ "Socket",
+ "Socket to use for UDP transmission. (None == allocate)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::object(
+ "used-socket",
+ "Used Socket",
+ "Socket currently in use for UDP transmission. (None = no socket)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::object(
+ "socket-v6",
+ "Socket V6",
+ "IPV6 Socket to use for UDP transmission. (None == allocate)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::object(
+ "used-socket-v6",
+ "Used Socket V6",
+ "V6 Socket currently in use for UDP transmission. (None = no socket)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::boolean(
+ "auto-multicast",
+ "Auto multicast",
+ "Automatically join/leave the multicast groups, FALSE means user has to do it himself",
+ DEFAULT_AUTO_MULTICAST,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "loop",
+ "Loop",
+ "Set the multicast loop parameter.",
+ DEFAULT_LOOP,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "ttl",
+ "Time To Live",
+ "Used for setting the unicast TTL parameter",
+ 0,
+ u8::MAX as u32,
+ DEFAULT_TTL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "ttl-mc",
+ "Time To Live Multicast",
+ "Used for setting the multicast TTL parameter",
+ 0,
+ u8::MAX as u32,
+ DEFAULT_TTL_MC,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "qos-dscp",
+ "QoS DSCP",
+ "Quality of Service, differentiated services code point (-1 default)",
+ -1,
+ 63,
+ DEFAULT_QOS_DSCP,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "clients",
+ "Clients",
+ "A comma separated list of host:port pairs with destinations",
+ Some(DEFAULT_CLIENTS),
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn signals() -> &'static [glib::subclass::Signal] {
+ static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
+ vec![
+ glib::subclass::Signal::builder(
+ "add",
+ &[String::static_type(), i32::static_type()],
+ glib::types::Type::Unit,
+ )
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::UdpSink>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let host = args[1]
+ .get::<String>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let port = args[2]
+ .get::<i32>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+
+ if let Ok(addr) = try_into_socket_addr(&element, &host, port) {
+ let udpsink = UdpSink::from_instance(&element);
+ udpsink.add_client(addr);
+ }
+
+ None
+ })
+ .build(),
+ glib::subclass::Signal::builder(
+ "remove",
+ &[String::static_type(), i32::static_type()],
+ glib::types::Type::Unit,
+ )
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::UdpSink>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let host = args[1]
+ .get::<String>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+ let port = args[2]
+ .get::<i32>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+
+ if let Ok(addr) = try_into_socket_addr(&element, &host, port) {
+ let udpsink = UdpSink::from_instance(&element);
+ udpsink.remove_client(addr);
+ }
+
+ None
+ })
+ .build(),
+ glib::subclass::Signal::builder("clear", &[], glib::types::Type::Unit)
+ .action()
+ .class_handler(|_, args| {
+ let element = args[0]
+ .get::<super::UdpSink>()
+ .expect("signal arg")
+ .expect("missing signal arg");
+
+ let udpsink = UdpSink::from_instance(&element);
+ udpsink.clear_clients(std::iter::empty());
+
+ None
+ })
+ .build(),
+ ]
+ });
+ SIGNALS.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("sync", ..) => {
+ match pspec.get_name() {
+ "sync" => {
settings.sync = value.get_some().expect("type checked upstream");
}
- subclass::Property("bind-address", ..) => {
+ "bind-address" => {
settings.bind_address = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("bind-port", ..) => {
+ "bind-port" => {
settings.bind_port = value.get_some().expect("type checked upstream");
}
- subclass::Property("bind-address-v6", ..) => {
+ "bind-address-v6" => {
settings.bind_address_v6 = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("bind-port-v6", ..) => {
+ "bind-port-v6" => {
settings.bind_port_v6 = value.get_some().expect("type checked upstream");
}
- subclass::Property("socket", ..) => {
+ "socket" => {
settings.socket = value
.get::<gio::Socket>()
.expect("type checked upstream")
.map(|socket| GioSocketWrapper::new(&socket));
}
- subclass::Property("used-socket", ..) => {
+ "used-socket" => {
unreachable!();
}
- subclass::Property("socket-v6", ..) => {
+ "socket-v6" => {
settings.socket_v6 = value
.get::<gio::Socket>()
.expect("type checked upstream")
.map(|socket| GioSocketWrapper::new(&socket));
}
- subclass::Property("used-socket-v6", ..) => {
+ "used-socket-v6" => {
unreachable!();
}
- subclass::Property("auto-multicast", ..) => {
+ "auto-multicast" => {
settings.auto_multicast = value.get_some().expect("type checked upstream");
}
- subclass::Property("loop", ..) => {
+ "loop" => {
settings.multicast_loop = value.get_some().expect("type checked upstream");
}
- subclass::Property("ttl", ..) => {
+ "ttl" => {
settings.ttl = value.get_some().expect("type checked upstream");
}
- subclass::Property("ttl-mc", ..) => {
+ "ttl-mc" => {
settings.ttl_mc = value.get_some().expect("type checked upstream");
}
- subclass::Property("qos-dscp", ..) => {
+ "qos-dscp" => {
settings.qos_dscp = value.get_some().expect("type checked upstream");
}
- subclass::Property("clients", ..) => {
+ "clients" => {
let clients: String = value
.get()
.expect("type checked upstream")
@@ -1329,55 +1289,53 @@ impl ObjectImpl for UdpSink {
self.clear_clients(clients_iter);
}
- subclass::Property("context", ..) => {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("sync", ..) => settings.sync.to_value(),
- subclass::Property("bind-address", ..) => settings.bind_address.to_value(),
- subclass::Property("bind-port", ..) => settings.bind_port.to_value(),
- subclass::Property("bind-address-v6", ..) => settings.bind_address_v6.to_value(),
- subclass::Property("bind-port-v6", ..) => settings.bind_port_v6.to_value(),
- subclass::Property("socket", ..) => settings
+ match pspec.get_name() {
+ "sync" => settings.sync.to_value(),
+ "bind-address" => settings.bind_address.to_value(),
+ "bind-port" => settings.bind_port.to_value(),
+ "bind-address-v6" => settings.bind_address_v6.to_value(),
+ "bind-port-v6" => settings.bind_port_v6.to_value(),
+ "socket" => settings
.socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("used-socket", ..) => settings
+ "used-socket" => settings
.used_socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("socket-v6", ..) => settings
+ "socket-v6" => settings
.socket_v6
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("used-socket-v6", ..) => settings
+ "used-socket-v6" => settings
.used_socket_v6
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("auto-multicast", ..) => settings.sync.to_value(),
- subclass::Property("loop", ..) => settings.multicast_loop.to_value(),
- subclass::Property("ttl", ..) => settings.ttl.to_value(),
- subclass::Property("ttl-mc", ..) => settings.ttl_mc.to_value(),
- subclass::Property("qos-dscp", ..) => settings.qos_dscp.to_value(),
- subclass::Property("clients", ..) => {
+ "auto-multicast" => settings.sync.to_value(),
+ "loop" => settings.multicast_loop.to_value(),
+ "ttl" => settings.ttl.to_value(),
+ "ttl-mc" => settings.ttl_mc.to_value(),
+ "qos-dscp" => settings.qos_dscp.to_value(),
+ "clients" => {
drop(settings);
let clients: Vec<String> = self
@@ -1389,8 +1347,8 @@ impl ObjectImpl for UdpSink {
clients.join(",").to_value()
}
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
_ => unimplemented!(),
}
}
@@ -1405,6 +1363,37 @@ impl ObjectImpl for UdpSink {
}
impl ElementImpl for UdpSink {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing UDP sink",
+ "Sink/Network",
+ "Thread-sharing UDP sink",
+ "Mathieu <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/src/udpsrc/imp.rs b/generic/threadshare/src/udpsrc/imp.rs
index 1d42561c9..b8d92e143 100644
--- a/generic/threadshare/src/udpsrc/imp.rs
+++ b/generic/threadshare/src/udpsrc/imp.rs
@@ -84,105 +84,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 10] = [
- subclass::Property("address", |name| {
- glib::ParamSpec::string(
- name,
- "Address",
- "Address/multicast group to listen on",
- DEFAULT_ADDRESS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("port", |name| {
- glib::ParamSpec::int(
- name,
- "Port",
- "Port to listen on",
- 0,
- u16::MAX as i32,
- DEFAULT_PORT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("reuse", |name| {
- glib::ParamSpec::boolean(
- name,
- "Reuse",
- "Allow reuse of the port",
- DEFAULT_REUSE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("caps", |name| {
- glib::ParamSpec::boxed(
- name,
- "Caps",
- "Caps to use",
- gst::Caps::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("mtu", |name| {
- glib::ParamSpec::uint(
- name,
- "MTU",
- "Maximum expected packet size. This directly defines the allocation size of the receive buffer pool",
- 0,
- i32::MAX as u32,
- DEFAULT_MTU,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("socket", |name| {
- glib::ParamSpec::object(
- name,
- "Socket",
- "Socket to use for UDP reception. (None == allocate)",
- gio::Socket::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("used-socket", |name| {
- glib::ParamSpec::object(
- name,
- "Used Socket",
- "Socket currently in use for UDP reception. (None = no socket)",
- gio::Socket::static_type(),
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("context-wait", |name| {
- glib::ParamSpec::uint(
- name,
- "Context Wait",
- "Throttle poll loop to run at most once every this many ms",
- 0,
- 1000,
- DEFAULT_CONTEXT_WAIT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("retrieve-sender-address", |name| {
- glib::ParamSpec::boolean(
- name,
- "Retrieve sender address",
- "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios",
- DEFAULT_RETRIEVE_SENDER_ADDRESS,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug)]
struct UdpReader(tokio::net::UdpSocket);
@@ -789,48 +690,12 @@ impl ObjectSubclass for UdpSrc {
const NAME: &'static str = "RsTsUdpSrc";
type Type = super::UdpSrc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing UDP source",
- "Source/Network",
- "Receives data over the network via UDP",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- #[cfg(not(windows))]
- {
- klass.install_properties(&PROPERTIES);
- }
- #[cfg(windows)]
- {
- let properties = PROPERTIES
- .iter()
- .filter(|p| match *p {
- subclass::Property("socket", ..) | subclass::Property("used-socket", ..) => {
- false
- }
- _ => true,
- })
- .collect::<Vec<_>>();
- klass.install_properties(properties.as_slice());
- }
- }
-
fn with_class(klass: &Self::Class) -> Self {
let src_pad_handler = UdpSrcPadHandler::default();
@@ -847,76 +712,167 @@ impl ObjectSubclass for UdpSrc {
}
impl ObjectImpl for UdpSrc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ let mut properties = vec![
+ glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "context-wait",
+ "Context Wait",
+ "Throttle poll loop to run at most once every this many ms",
+ 0,
+ 1000,
+ DEFAULT_CONTEXT_WAIT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "address",
+ "Address",
+ "Address/multicast group to listen on",
+ DEFAULT_ADDRESS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "port",
+ "Port",
+ "Port to listen on",
+ 0,
+ u16::MAX as i32,
+ DEFAULT_PORT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "reuse",
+ "Reuse",
+ "Allow reuse of the port",
+ DEFAULT_REUSE,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "caps",
+ "Caps",
+ "Caps to use",
+ gst::Caps::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "mtu",
+ "MTU",
+ "Maximum expected packet size. This directly defines the allocation size of the receive buffer pool",
+ 0,
+ i32::MAX as u32,
+ DEFAULT_MTU,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "retrieve-sender-address",
+ "Retrieve sender address",
+ "Whether to retrieve the sender address and add it to buffers as meta. Disabling this might result in minor performance improvements in certain scenarios",
+ DEFAULT_RETRIEVE_SENDER_ADDRESS,
+ glib::ParamFlags::READWRITE,
+ ),
+ ];
+
+ #[cfg(not(windows))]
+ {
+ properties.push(glib::ParamSpec::object(
+ "socket",
+ "Socket",
+ "Socket to use for UDP reception. (None == allocate)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READWRITE,
+ ));
+ properties.push(glib::ParamSpec::object(
+ "used-socket",
+ "Used Socket",
+ "Socket currently in use for UDP reception. (None = no socket)",
+ gio::Socket::static_type(),
+ glib::ParamFlags::READABLE,
+ ));
+ }
+ properties
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("address", ..) => {
+ match pspec.get_name() {
+ "address" => {
settings.address = value.get().expect("type checked upstream");
}
- subclass::Property("port", ..) => {
+ "port" => {
settings.port = value.get_some().expect("type checked upstream");
}
- subclass::Property("reuse", ..) => {
+ "reuse" => {
settings.reuse = value.get_some().expect("type checked upstream");
}
- subclass::Property("caps", ..) => {
+ "caps" => {
settings.caps = value.get().expect("type checked upstream");
}
- subclass::Property("mtu", ..) => {
+ "mtu" => {
settings.mtu = value.get_some().expect("type checked upstream");
}
- subclass::Property("socket", ..) => {
+ "socket" => {
settings.socket = value
.get::<gio::Socket>()
.expect("type checked upstream")
.map(|socket| GioSocketWrapper::new(&socket));
}
- subclass::Property("used-socket", ..) => {
+ "used-socket" => {
unreachable!();
}
- subclass::Property("context", ..) => {
+ "context" => {
settings.context = value
.get()
.expect("type checked upstream")
.unwrap_or_else(|| "".into());
}
- subclass::Property("context-wait", ..) => {
+ "context-wait" => {
settings.context_wait = value.get_some().expect("type checked upstream");
}
- subclass::Property("retrieve-sender-address", ..) => {
+ "retrieve-sender-address" => {
settings.retrieve_sender_address = value.get_some().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("address", ..) => settings.address.to_value(),
- subclass::Property("port", ..) => settings.port.to_value(),
- subclass::Property("reuse", ..) => settings.reuse.to_value(),
- subclass::Property("caps", ..) => settings.caps.to_value(),
- subclass::Property("mtu", ..) => settings.mtu.to_value(),
- subclass::Property("socket", ..) => settings
+ match pspec.get_name() {
+ "address" => settings.address.to_value(),
+ "port" => settings.port.to_value(),
+ "reuse" => settings.reuse.to_value(),
+ "caps" => settings.caps.to_value(),
+ "mtu" => settings.mtu.to_value(),
+ "socket" => settings
.socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("used-socket", ..) => settings
+ "used-socket" => settings
.used_socket
.as_ref()
.map(GioSocketWrapper::as_socket)
.to_value(),
- subclass::Property("context", ..) => settings.context.to_value(),
- subclass::Property("context-wait", ..) => settings.context_wait.to_value(),
- subclass::Property("retrieve-sender-address", ..) => {
- settings.retrieve_sender_address.to_value()
- }
+ "context" => settings.context.to_value(),
+ "context-wait" => settings.context_wait.to_value(),
+ "retrieve-sender-address" => settings.retrieve_sender_address.to_value(),
_ => unimplemented!(),
}
}
@@ -931,6 +887,36 @@ impl ObjectImpl for UdpSrc {
}
impl ElementImpl for UdpSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing UDP source",
+ "Source/Network",
+ "Receives data over the network via UDP",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/generic/threadshare/tests/pad.rs b/generic/threadshare/tests/pad.rs
index ee8bc2457..e7d8bb960 100644
--- a/generic/threadshare/tests/pad.rs
+++ b/generic/threadshare/tests/pad.rs
@@ -69,17 +69,6 @@ struct ItemSender {
mod imp_src {
use super::*;
- static SRC_PROPERTIES: [glib::subclass::Property; 1] =
- [glib::subclass::Property("context", |name| {
- glib::ParamSpec::string(
- name,
- "Context",
- "Context name to share threads with",
- Some(DEFAULT_CONTEXT),
- glib::ParamFlags::READWRITE,
- )
- })];
-
#[derive(Clone, Debug, Default)]
struct Settings {
context: String,
@@ -316,32 +305,12 @@ mod imp_src {
const NAME: &'static str = "TsElementSrcTest";
type Type = super::ElementSrcTest;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = glib::subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing Test Src Element",
- "Generic",
- "Src Element for Pad Src Test",
- "François Laignel <fengalin@free.fr>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&SRC_PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
ElementSrcTest {
src_pad: PadSrc::new(
@@ -356,11 +325,29 @@ mod imp_src {
}
impl ObjectImpl for ElementSrcTest {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &SRC_PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::string(
+ "context",
+ "Context",
+ "Context name to share threads with",
+ Some(DEFAULT_CONTEXT),
+ glib::ParamFlags::WRITABLE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- glib::subclass::Property("context", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "context" => {
let context = value
.get()
.expect("type checked upstream")
@@ -380,6 +367,36 @@ mod imp_src {
}
impl ElementImpl for ElementSrcTest {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing Test Src Element",
+ "Generic",
+ "Src Element for Pad Src Test",
+ "François Laignel <fengalin@free.fr>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
@@ -452,17 +469,6 @@ unsafe impl Sync for ElementSrcTest {}
mod imp_sink {
use super::*;
- static SINK_PROPERTIES: [glib::subclass::Property; 1] =
- [glib::subclass::Property("sender", |name| {
- glib::ParamSpec::boxed(
- name,
- "Sender",
- "Channel sender to forward the incoming items to",
- ItemSender::get_type(),
- glib::ParamFlags::WRITABLE,
- )
- })];
-
#[derive(Clone, Debug, Default)]
struct PadSinkTestHandler;
@@ -634,32 +640,12 @@ mod imp_sink {
const NAME: &'static str = "TsElementSinkTest";
type Type = super::ElementSinkTest;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = glib::subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Thread-sharing Test Sink Element",
- "Generic",
- "Sink Element for Pad Test",
- "François Laignel <fengalin@free.fr>",
- );
-
- let caps = gst::Caps::new_any();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&SINK_PROPERTIES);
- }
-
fn with_class(klass: &Self::Class) -> Self {
ElementSinkTest {
sink_pad: PadSink::new(
@@ -673,11 +659,29 @@ mod imp_sink {
}
impl ObjectImpl for ElementSinkTest {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &SINK_PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::boxed(
+ "sender",
+ "Sender",
+ "Channel sender to forward the incoming items to",
+ ItemSender::get_type(),
+ glib::ParamFlags::WRITABLE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- glib::subclass::Property("sender", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "sender" => {
let ItemSender { sender } = value
.get::<&ItemSender>()
.expect("type checked upstream")
@@ -697,6 +701,36 @@ mod imp_sink {
}
impl ElementImpl for ElementSinkTest {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Thread-sharing Test Sink Element",
+ "Generic",
+ "Sink Element for Pad Test",
+ "François Laignel <fengalin@free.fr>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/net/reqwest/src/reqwesthttpsrc/imp.rs b/net/reqwest/src/reqwesthttpsrc/imp.rs
index 8c0f223d0..429d86c33 100644
--- a/net/reqwest/src/reqwesthttpsrc/imp.rs
+++ b/net/reqwest/src/reqwesthttpsrc/imp.rs
@@ -69,110 +69,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 11] = [
- subclass::Property("location", |name| {
- glib::ParamSpec::string(
- name,
- "Location",
- "URL to read from",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("user-agent", |name| {
- glib::ParamSpec::string(
- name,
- "User-Agent",
- "Value of the User-Agent HTTP request header field",
- DEFAULT_USER_AGENT.into(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("is-live", |name| {
- glib::ParamSpec::boolean(
- name,
- "Is Live",
- "Act like a live source",
- DEFAULT_IS_LIVE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("user-id", |name| {
- glib::ParamSpec::string(
- name,
- "User-id",
- "HTTP location URI user id for authentication",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("user-pw", |name| {
- glib::ParamSpec::string(
- name,
- "User-pw",
- "HTTP location URI user password for authentication",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("timeout", |name| {
- glib::ParamSpec::uint(
- name,
- "Timeout",
- "Value in seconds to timeout a blocking I/O (0 = No timeout).",
- 0,
- 3600,
- DEFAULT_TIMEOUT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("compress", |name| {
- glib::ParamSpec::boolean(
- name,
- "Compress",
- "Allow compressed content encodings",
- DEFAULT_COMPRESS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("extra-headers", |name| {
- glib::ParamSpec::boxed(
- name,
- "Extra Headers",
- "Extra headers to append to the HTTP request",
- gst::Structure::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("cookies", |name| {
- glib::ParamSpec::boxed(
- name,
- "Cookies",
- "HTTP request cookies",
- Vec::<String>::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("iradio-mode", |name| {
- glib::ParamSpec::boolean(
- name,
- "I-Radio Mode",
- "Enable internet radio mode (ask server to send shoutcast/icecast metadata interleaved with the actual stream data",
- DEFAULT_IRADIO_MODE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("keep-alive", |name| {
- glib::ParamSpec::boolean(
- name,
- "Keep Alive",
- "Use HTTP persistent connections",
- DEFAULT_KEEP_ALIVE,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
const REQWEST_CLIENT_CONTEXT: &str = "gst.reqwest.client";
#[derive(Clone, Debug, glib::GBoxed)]
@@ -681,10 +577,103 @@ impl ReqwestHttpSrc {
}
impl ObjectImpl for ReqwestHttpSrc {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "location",
+ "Location",
+ "URL to read from",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "user-agent",
+ "User-Agent",
+ "Value of the User-Agent HTTP request header field",
+ DEFAULT_USER_AGENT.into(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "is-live",
+ "Is Live",
+ "Act like a live source",
+ DEFAULT_IS_LIVE,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "user-id",
+ "User-id",
+ "HTTP location URI user id for authentication",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "user-pw",
+ "User-pw",
+ "HTTP location URI user password for authentication",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "timeout",
+ "Timeout",
+ "Value in seconds to timeout a blocking I/O (0 = No timeout).",
+ 0,
+ 3600,
+ DEFAULT_TIMEOUT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "compress",
+ "Compress",
+ "Allow compressed content encodings",
+ DEFAULT_COMPRESS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "extra-headers",
+ "Extra Headers",
+ "Extra headers to append to the HTTP request",
+ gst::Structure::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "cookies",
+ "Cookies",
+ "HTTP request cookies",
+ Vec::<String>::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "iradio-mode",
+ "I-Radio Mode",
+ "Enable internet radio mode (ask server to send shoutcast/icecast metadata interleaved with the actual stream data",
+ DEFAULT_IRADIO_MODE,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "keep-alive",
+ "Keep Alive",
+ "Use HTTP persistent connections",
+ DEFAULT_KEEP_ALIVE,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "location" => {
let location = value.get::<&str>().expect("type checked upstream");
if let Err(err) = self.set_location(obj, location) {
gst_error!(
@@ -695,7 +684,7 @@ impl ObjectImpl for ReqwestHttpSrc {
);
}
}
- subclass::Property("user-agent", ..) => {
+ "user-agent" => {
let mut settings = self.settings.lock().unwrap();
let user_agent = value
.get()
@@ -703,46 +692,46 @@ impl ObjectImpl for ReqwestHttpSrc {
.unwrap_or_else(|| DEFAULT_USER_AGENT.into());
settings.user_agent = user_agent;
}
- subclass::Property("is-live", ..) => {
+ "is-live" => {
let is_live = value.get_some().expect("type checked upstream");
obj.set_live(is_live);
}
- subclass::Property("user-id", ..) => {
+ "user-id" => {
let mut settings = self.settings.lock().unwrap();
let user_id = value.get().expect("type checked upstream");
settings.user_id = user_id;
}
- subclass::Property("user-pw", ..) => {
+ "user-pw" => {
let mut settings = self.settings.lock().unwrap();
let user_pw = value.get().expect("type checked upstream");
settings.user_pw = user_pw;
}
- subclass::Property("timeout", ..) => {
+ "timeout" => {
let mut settings = self.settings.lock().unwrap();
let timeout = value.get_some().expect("type checked upstream");
settings.timeout = timeout;
}
- subclass::Property("compress", ..) => {
+ "compress" => {
let mut settings = self.settings.lock().unwrap();
let compress = value.get_some().expect("type checked upstream");
settings.compress = compress;
}
- subclass::Property("extra-headers", ..) => {
+ "extra-headers" => {
let mut settings = self.settings.lock().unwrap();
let extra_headers = value.get().expect("type checked upstream");
settings.extra_headers = extra_headers;
}
- subclass::Property("cookies", ..) => {
+ "cookies" => {
let mut settings = self.settings.lock().unwrap();
let cookies = value.get().expect("type checked upstream");
settings.cookies = cookies.unwrap_or_else(Vec::new);
}
- subclass::Property("iradio-mode", ..) => {
+ "iradio-mode" => {
let mut settings = self.settings.lock().unwrap();
let iradio_mode = value.get_some().expect("type checked upstream");
settings.iradio_mode = iradio_mode;
}
- subclass::Property("keep-alive", ..) => {
+ "keep-alive" => {
let mut settings = self.settings.lock().unwrap();
let keep_alive = value.get_some().expect("type checked upstream");
settings.keep_alive = keep_alive;
@@ -751,49 +740,48 @@ impl ObjectImpl for ReqwestHttpSrc {
};
}
- fn get_property(&self, obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("location", ..) => {
+ fn get_property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "location" => {
let settings = self.settings.lock().unwrap();
let location = settings.location.as_ref().map(Url::to_string);
location.to_value()
}
- subclass::Property("user-agent", ..) => {
+ "user-agent" => {
let settings = self.settings.lock().unwrap();
settings.user_agent.to_value()
}
- subclass::Property("is-live", ..) => obj.is_live().to_value(),
- subclass::Property("user-id", ..) => {
+ "is-live" => obj.is_live().to_value(),
+ "user-id" => {
let settings = self.settings.lock().unwrap();
settings.user_id.to_value()
}
- subclass::Property("user-pw", ..) => {
+ "user-pw" => {
let settings = self.settings.lock().unwrap();
settings.user_pw.to_value()
}
- subclass::Property("timeout", ..) => {
+ "timeout" => {
let settings = self.settings.lock().unwrap();
settings.timeout.to_value()
}
- subclass::Property("compress", ..) => {
+ "compress" => {
let settings = self.settings.lock().unwrap();
settings.compress.to_value()
}
- subclass::Property("extra-headers", ..) => {
+ "extra-headers" => {
let settings = self.settings.lock().unwrap();
settings.extra_headers.to_value()
}
- subclass::Property("cookies", ..) => {
+ "cookies" => {
let settings = self.settings.lock().unwrap();
settings.cookies.to_value()
}
- subclass::Property("iradio-mode", ..) => {
+ "iradio-mode" => {
let settings = self.settings.lock().unwrap();
settings.iradio_mode.to_value()
}
- subclass::Property("keep-alive", ..) => {
+ "keep-alive" => {
let settings = self.settings.lock().unwrap();
settings.keep_alive.to_value()
}
@@ -809,6 +797,36 @@ impl ObjectImpl for ReqwestHttpSrc {
}
impl ElementImpl for ReqwestHttpSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "HTTP Source",
+ "Source/Network/HTTP",
+ "Read stream from an HTTP/HTTPS location",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn set_context(&self, element: &Self::Type, context: &gst::Context) {
if context.get_context_type() == REQWEST_CLIENT_CONTEXT {
let mut external_client = self.external_client.lock().unwrap();
@@ -1077,6 +1095,12 @@ impl PushSrcImpl for ReqwestHttpSrc {
}
impl URIHandlerImpl for ReqwestHttpSrc {
+ const URI_TYPE: gst::URIType = gst::URIType::Src;
+
+ fn get_protocols() -> &'static [&'static str] {
+ &["http", "https"]
+ }
+
fn get_uri(&self, _element: &Self::Type) -> Option<String> {
let settings = self.settings.lock().unwrap();
@@ -1086,20 +1110,13 @@ impl URIHandlerImpl for ReqwestHttpSrc {
fn set_uri(&self, element: &Self::Type, uri: &str) -> Result<(), glib::Error> {
self.set_location(&element, Some(uri))
}
-
- fn get_uri_type() -> gst::URIType {
- gst::URIType::Src
- }
-
- fn get_protocols() -> Vec<String> {
- vec!["http".to_string(), "https".to_string()]
- }
}
impl ObjectSubclass for ReqwestHttpSrc {
const NAME: &'static str = "ReqwestHttpSrc";
type Type = super::ReqwestHttpSrc;
type ParentType = gst_base::PushSrc;
+ type Interfaces = (gst::URIHandler,);
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1114,29 +1131,4 @@ impl ObjectSubclass for ReqwestHttpSrc {
canceller: Mutex::new(None),
}
}
-
- fn type_init(type_: &mut subclass::InitializingType<Self>) {
- type_.add_interface::<gst::URIHandler>();
- }
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "HTTP Source",
- "Source/Network/HTTP",
- "Read stream from an HTTP/HTTPS location",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
diff --git a/net/rusoto/src/aws_transcriber/imp.rs b/net/rusoto/src/aws_transcriber/imp.rs
index e62120fed..3e5a9ae80 100644
--- a/net/rusoto/src/aws_transcriber/imp.rs
+++ b/net/rusoto/src/aws_transcriber/imp.rs
@@ -116,40 +116,6 @@ const DEFAULT_LATENCY_MS: u32 = 8000;
const DEFAULT_USE_PARTIAL_RESULTS: bool = true;
const GRANULARITY_MS: u32 = 100;
-static PROPERTIES: [subclass::Property; 3] = [
- subclass::Property("language-code", |name| {
- glib::ParamSpec::string(
- name,
- "Language Code",
- "The Language of the Stream, see \
- <https://docs.aws.amazon.com/transcribe/latest/dg/how-streaming-transcription.html> \
- for an up to date list of allowed languages",
- Some("en-US"),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("use-partial-results", |name| {
- glib::ParamSpec::boolean(
- name,
- "Latency",
- "Whether partial results from AWS should be used",
- DEFAULT_USE_PARTIAL_RESULTS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("latency", |name| {
- glib::ParamSpec::uint(
- name,
- "Latency",
- "Amount of milliseconds to allow AWS transcribe",
- 2 * GRANULARITY_MS,
- std::u32::MAX,
- DEFAULT_LATENCY_MS,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug, Clone)]
struct Settings {
latency_ms: u32,
@@ -1010,6 +976,7 @@ impl ObjectSubclass for Transcriber {
const NAME: &'static str = "RsAwsTranscriber";
type Type = super::Transcriber;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1063,45 +1030,43 @@ impl ObjectSubclass for Transcriber {
ws_sink: AtomicRefCell::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Transcriber",
- "Audio/Text/Filter",
- "Speech to Text filter, using AWS transcribe",
- "Jordan Petridis <jordan@centricular.com>, Mathieu Duponchelle <mathieu@centricular.com>",
- );
+impl ObjectImpl for Transcriber {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "language-code",
+ "Language Code",
+ "The Language of the Stream, see \
+ <https://docs.aws.amazon.com/transcribe/latest/dg/how-streaming-transcription.html> \
+ for an up to date list of allowed languages",
+ Some("en-US"),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "use-partial-results",
+ "Latency",
+ "Whether partial results from AWS should be used",
+ DEFAULT_USE_PARTIAL_RESULTS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "latency",
+ "Latency",
+ "Amount of milliseconds to allow AWS transcribe",
+ 2 * GRANULARITY_MS,
+ std::u32::MAX,
+ DEFAULT_LATENCY_MS,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- let src_caps = gst::Caps::builder("text/x-raw")
- .field("format", &"utf8")
- .build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_caps = gst::Caps::builder("audio/x-raw")
- .field("format", &"S16LE")
- .field("rate", &gst::IntRange::<i32>::new(8000, 48000))
- .field("channels", &1)
- .build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- klass.install_properties(&PROPERTIES);
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for Transcriber {
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -1110,19 +1075,23 @@ impl ObjectImpl for Transcriber {
obj.set_element_flags(gst::ElementFlags::PROVIDE_CLOCK | gst::ElementFlags::REQUIRE_CLOCK);
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("language_code", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "language_code" => {
let mut settings = self.settings.lock().unwrap();
settings.language_code = value.get().expect("type checked upstream");
}
- subclass::Property("latency", ..) => {
+ "latency" => {
let mut settings = self.settings.lock().unwrap();
settings.latency_ms = value.get_some().expect("type checked upstream");
}
- subclass::Property("use-partial-results", ..) => {
+ "use-partial-results" => {
let mut settings = self.settings.lock().unwrap();
settings.use_partial_results = value.get_some().expect("type checked upstream");
}
@@ -1130,19 +1099,17 @@ impl ObjectImpl for Transcriber {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("language-code", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "language-code" => {
let settings = self.settings.lock().unwrap();
settings.language_code.to_value()
}
- subclass::Property("latency", ..) => {
+ "latency" => {
let settings = self.settings.lock().unwrap();
settings.latency_ms.to_value()
}
- subclass::Property("use-partial-results", ..) => {
+ "use-partial-results" => {
let settings = self.settings.lock().unwrap();
settings.use_partial_results.to_value()
}
@@ -1152,6 +1119,51 @@ impl ObjectImpl for Transcriber {
}
impl ElementImpl for Transcriber {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Transcriber",
+ "Audio/Text/Filter",
+ "Speech to Text filter, using AWS transcribe",
+ "Jordan Petridis <jordan@centricular.com>, Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let src_caps = gst::Caps::builder("text/x-raw")
+ .field("format", &"utf8")
+ .build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ let sink_caps = gst::Caps::builder("audio/x-raw")
+ .field("format", &"S16LE")
+ .field("rate", &gst::IntRange::<i32>::new(8000, 48000))
+ .field("channels", &1)
+ .build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/net/rusoto/src/s3sink/imp.rs b/net/rusoto/src/s3sink/imp.rs
index 93dfee28b..0896419e4 100644
--- a/net/rusoto/src/s3sink/imp.rs
+++ b/net/rusoto/src/s3sink/imp.rs
@@ -116,47 +116,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 4] = [
- subclass::Property("bucket", |name| {
- glib::ParamSpec::string(
- name,
- "S3 Bucket",
- "The bucket of the file to write",
- None,
- glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
- )
- }),
- subclass::Property("key", |name| {
- glib::ParamSpec::string(
- name,
- "S3 Key",
- "The key of the file to write",
- None,
- glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
- )
- }),
- subclass::Property("region", |name| {
- glib::ParamSpec::string(
- name,
- "AWS Region",
- "An AWS region (e.g. eu-west-2).",
- None,
- glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
- )
- }),
- subclass::Property("part-size", |name| {
- glib::ParamSpec::uint64(
- name,
- "Part size",
- "A size (in bytes) of an individual part used for multipart upload.",
- 5 * 1024 * 1024, // 5 MB
- 5 * 1024 * 1024 * 1024, // 5 GB
- DEFAULT_BUFFER_SIZE,
- glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
- )
- }),
-];
-
impl S3Sink {
fn flush_current_buffer(
&self,
@@ -386,6 +345,7 @@ impl ObjectSubclass for S3Sink {
const NAME: &'static str = "RusotoS3Sink";
type Type = super::S3Sink;
type ParentType = gst_base::BaseSink;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -398,42 +358,65 @@ impl ObjectSubclass for S3Sink {
canceller: Mutex::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Amazon S3 sink",
- "Source/Network",
- "Writes an object to Amazon S3",
- "Marcin Kolny <mkolny@amazon.com>",
- );
+impl ObjectImpl for S3Sink {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "bucket",
+ "S3 Bucket",
+ "The bucket of the file to write",
+ None,
+ glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
+ ),
+ glib::ParamSpec::string(
+ "key",
+ "S3 Key",
+ "The key of the file to write",
+ None,
+ glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
+ ),
+ glib::ParamSpec::string(
+ "region",
+ "AWS Region",
+ "An AWS region (e.g. eu-west-2).",
+ None,
+ glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
+ ),
+ glib::ParamSpec::uint64(
+ "part-size",
+ "Part size",
+ "A size (in bytes) of an individual part used for multipart upload.",
+ 5 * 1024 * 1024, // 5 MB
+ 5 * 1024 * 1024 * 1024, // 5 GB
+ DEFAULT_BUFFER_SIZE,
+ glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
+ ),
+ ]
+ });
- let caps = gst::Caps::new_any();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for S3Sink {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id as usize];
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
let mut settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("bucket", ..) => {
+ match pspec.get_name() {
+ "bucket" => {
settings.bucket = value.get::<String>().expect("type checked upstream");
}
- subclass::Property("key", ..) => {
+ "key" => {
settings.key = value.get::<String>().expect("type checked upstream");
}
- subclass::Property("region", ..) => {
+ "region" => {
settings.region = Region::from_str(
&value
.get::<String>()
@@ -442,28 +425,57 @@ impl ObjectImpl for S3Sink {
)
.unwrap();
}
- subclass::Property("part-size", ..) => {
+ "part-size" => {
settings.buffer_size = value.get_some::<u64>().expect("type checked upstream");
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id as usize];
+ fn get_property(&self, _: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
let settings = self.settings.lock().unwrap();
- match *prop {
- subclass::Property("key", ..) => settings.key.to_value(),
- subclass::Property("bucket", ..) => settings.bucket.to_value(),
- subclass::Property("region", ..) => settings.region.name().to_value(),
- subclass::Property("part-size", ..) => settings.buffer_size.to_value(),
+ match pspec.get_name() {
+ "key" => settings.key.to_value(),
+ "bucket" => settings.bucket.to_value(),
+ "region" => settings.region.name().to_value(),
+ "part-size" => settings.buffer_size.to_value(),
_ => unimplemented!(),
}
}
}
-impl ElementImpl for S3Sink {}
+impl ElementImpl for S3Sink {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Amazon S3 sink",
+ "Source/Network",
+ "Writes an object to Amazon S3",
+ "Marcin Kolny <mkolny@amazon.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseSinkImpl for S3Sink {
fn start(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/net/rusoto/src/s3src/imp.rs b/net/rusoto/src/s3src/imp.rs
index 01248af08..6bf1615a6 100644
--- a/net/rusoto/src/s3src/imp.rs
+++ b/net/rusoto/src/s3src/imp.rs
@@ -51,16 +51,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("uri", |name| {
- glib::ParamSpec::string(
- name,
- "URI",
- "The S3 object URI",
- None,
- glib::ParamFlags::READWRITE, /* + GST_PARAM_MUTABLE_READY) */
- )
-})];
-
impl S3Src {
fn cancel(&self) {
let mut canceller = self.canceller.lock().unwrap();
@@ -210,6 +200,7 @@ impl ObjectSubclass for S3Src {
const NAME: &'static str = "RusotoS3Src";
type Type = super::S3Src;
type ParentType = gst_base::BaseSrc;
+ type Interfaces = (gst::URIHandler,);
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -222,50 +213,41 @@ impl ObjectSubclass for S3Src {
canceller: Mutex::new(None),
}
}
-
- fn type_init(typ: &mut subclass::InitializingType<Self>) {
- typ.add_interface::<gst::URIHandler>();
- }
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Amazon S3 source",
- "Source/Network",
- "Reads an object from Amazon S3",
- "Arun Raghavan <arun@arunraghavan.net>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for S3Src {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id as usize];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::string(
+ "uri",
+ "URI",
+ "The S3 object URI",
+ None,
+ glib::ParamFlags::READWRITE | gst::PARAM_FLAG_MUTABLE_READY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("uri", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "uri" => {
let _ = self.set_uri(obj, value.get().expect("type checked upstream"));
}
_ => unimplemented!(),
}
}
- fn get_property(&self, _: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id as usize];
-
- match *prop {
- subclass::Property("uri", ..) => {
+ fn get_property(&self, _: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "uri" => {
let url = match *self.url.lock().unwrap() {
Some(ref url) => url.to_string(),
None => "".to_string(),
@@ -287,10 +269,44 @@ impl ObjectImpl for S3Src {
}
impl ElementImpl for S3Src {
- // No overrides
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Amazon S3 source",
+ "Source/Network",
+ "Reads an object from Amazon S3",
+ "Arun Raghavan <arun@arunraghavan.net>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
}
impl URIHandlerImpl for S3Src {
+ const URI_TYPE: gst::URIType = gst::URIType::Src;
+
+ fn get_protocols() -> &'static [&'static str] {
+ &["s3"]
+ }
+
fn get_uri(&self, _: &Self::Type) -> Option<String> {
self.url.lock().unwrap().as_ref().map(|s| s.to_string())
}
@@ -298,14 +314,6 @@ impl URIHandlerImpl for S3Src {
fn set_uri(&self, element: &Self::Type, uri: &str) -> Result<(), glib::Error> {
self.set_uri(element, Some(uri))
}
-
- fn get_uri_type() -> gst::URIType {
- gst::URIType::Src
- }
-
- fn get_protocols() -> Vec<String> {
- vec!["s3".to_string()]
- }
}
impl BaseSrcImpl for S3Src {
diff --git a/text/json/src/jsongstenc/imp.rs b/text/json/src/jsongstenc/imp.rs
index 07e555e14..5844eb930 100644
--- a/text/json/src/jsongstenc/imp.rs
+++ b/text/json/src/jsongstenc/imp.rs
@@ -205,6 +205,7 @@ impl ObjectSubclass for JsonGstEnc {
const NAME: &'static str = "RsJsonGstEnc";
type Type = super::JsonGstEnc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -238,36 +239,6 @@ impl ObjectSubclass for JsonGstEnc {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "GStreamer buffers to JSON",
- "Encoder/JSON",
- "Wraps buffers containing any valid top-level JSON structures \
- into higher level JSON objects, and outputs those as ndjson",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::builder("application/x-json").build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let caps = gst::Caps::builder("application/x-json").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- }
}
impl ObjectImpl for JsonGstEnc {
@@ -280,6 +251,46 @@ impl ObjectImpl for JsonGstEnc {
}
impl ElementImpl for JsonGstEnc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "GStreamer buffers to JSON",
+ "Encoder/JSON",
+ "Wraps buffers containing any valid top-level JSON structures \
+ into higher level JSON objects, and outputs those as ndjson",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::builder("application/x-json").build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-json").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/text/json/src/jsongstparse/imp.rs b/text/json/src/jsongstparse/imp.rs
index bb4d7fb99..8b51edc32 100644
--- a/text/json/src/jsongstparse/imp.rs
+++ b/text/json/src/jsongstparse/imp.rs
@@ -867,6 +867,7 @@ impl ObjectSubclass for JsonGstParse {
const NAME: &'static str = "RsJsonGstParse";
type Type = super::JsonGstParse;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -934,35 +935,6 @@ impl ObjectSubclass for JsonGstParse {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "JSON GStreamer parser",
- "Parser/JSON",
- "Parses ndjson as output by jsongstenc",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::builder("application/x-json").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let caps = gst::Caps::new_any();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for JsonGstParse {
@@ -975,6 +947,45 @@ impl ObjectImpl for JsonGstParse {
}
impl ElementImpl for JsonGstParse {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "JSON GStreamer parser",
+ "Parser/JSON",
+ "Parses ndjson as output by jsongstenc",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::builder("application/x-json").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::new_any();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/text/wrap/src/gsttextwrap/imp.rs b/text/wrap/src/gsttextwrap/imp.rs
index e0401212e..86b623577 100644
--- a/text/wrap/src/gsttextwrap/imp.rs
+++ b/text/wrap/src/gsttextwrap/imp.rs
@@ -45,52 +45,6 @@ const DEFAULT_COLUMNS: u32 = 32; /* CEA 608 max columns */
const DEFAULT_LINES: u32 = 0;
const DEFAULT_ACCUMULATE: i64 = -1;
-static PROPERTIES: [subclass::Property; 4] = [
- subclass::Property("dictionary", |name| {
- glib::ParamSpec::string(
- name,
- "Dictionary",
- "Path to a dictionary to load at runtime to perform hyphenation, see \
- <https://docs.rs/crate/hyphenation/0.7.1> for more information",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("columns", |name| {
- glib::ParamSpec::uint(
- name,
- "Columns",
- "Maximum number of columns for any given line",
- 1,
- std::u32::MAX,
- DEFAULT_COLUMNS,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("lines", |name| {
- glib::ParamSpec::uint(
- name,
- "Lines",
- "Split input buffer into output buffers with max lines (0=do not split)",
- 0,
- std::u32::MAX,
- DEFAULT_LINES,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("accumulate-time", |name| {
- glib::ParamSpec::int64(
- name,
- "accumulate-time",
- "Cut-off time for input text accumulation (-1=do not accumulate)",
- -1,
- std::i64::MAX,
- DEFAULT_ACCUMULATE,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug, Clone)]
struct Settings {
dictionary: Option<String>,
@@ -409,6 +363,7 @@ impl ObjectSubclass for TextWrap {
const NAME: &'static str = "RsTextWrap";
type Type = super::TextWrap;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -449,41 +404,53 @@ impl ObjectSubclass for TextWrap {
state,
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Text Wrapper",
- "Text/Filter",
- "Breaks text into fixed-size lines, with optional hyphenationz",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::builder("text/x-raw")
- .field("format", &"utf8")
- .build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for TextWrap {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "dictionary",
+ "Dictionary",
+ "Path to a dictionary to load at runtime to perform hyphenation, see \
+ <https://docs.rs/crate/hyphenation/0.7.1> for more information",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "columns",
+ "Columns",
+ "Maximum number of columns for any given line",
+ 1,
+ std::u32::MAX,
+ DEFAULT_COLUMNS,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "lines",
+ "Lines",
+ "Split input buffer into output buffers with max lines (0=do not split)",
+ 0,
+ std::u32::MAX,
+ DEFAULT_LINES,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int64(
+ "accumulate-time",
+ "accumulate-time",
+ "Cut-off time for input text accumulation (-1=do not accumulate)",
+ -1,
+ std::i64::MAX,
+ DEFAULT_ACCUMULATE,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -491,27 +458,31 @@ impl ObjectImpl for TextWrap {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("dictionary", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "dictionary" => {
let mut settings = self.settings.lock().unwrap();
let mut state = self.state.lock().unwrap();
settings.dictionary = value.get().expect("type checked upstream");
state.options = None;
}
- subclass::Property("columns", ..) => {
+ "columns" => {
let mut settings = self.settings.lock().unwrap();
let mut state = self.state.lock().unwrap();
settings.columns = value.get_some().expect("type checked upstream");
state.options = None;
}
- subclass::Property("lines", ..) => {
+ "lines" => {
let mut settings = self.settings.lock().unwrap();
settings.lines = value.get_some().expect("type checked upstream");
}
- subclass::Property("accumulate-time", ..) => {
+ "accumulate-time" => {
let mut settings = self.settings.lock().unwrap();
settings.accumulate_time = match value.get_some().expect("type checked upstream") {
-1i64 => gst::CLOCK_TIME_NONE,
@@ -522,23 +493,21 @@ impl ObjectImpl for TextWrap {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("dictionary", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "dictionary" => {
let settings = self.settings.lock().unwrap();
settings.dictionary.to_value()
}
- subclass::Property("columns", ..) => {
+ "columns" => {
let settings = self.settings.lock().unwrap();
settings.columns.to_value()
}
- subclass::Property("lines", ..) => {
+ "lines" => {
let settings = self.settings.lock().unwrap();
settings.lines.to_value()
}
- subclass::Property("accumulate-time", ..) => {
+ "accumulate-time" => {
let settings = self.settings.lock().unwrap();
match settings.accumulate_time.0 {
Some(time) => (time as i64).to_value(),
@@ -551,6 +520,46 @@ impl ObjectImpl for TextWrap {
}
impl ElementImpl for TextWrap {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Text Wrapper",
+ "Text/Filter",
+ "Breaks text into fixed-size lines, with optional hyphenation",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::builder("text/x-raw")
+ .field("format", &"utf8")
+ .build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/tutorial/src/identity/imp.rs b/tutorial/src/identity/imp.rs
index d94ec448d..7a256e60c 100644
--- a/tutorial/src/identity/imp.rs
+++ b/tutorial/src/identity/imp.rs
@@ -118,6 +118,7 @@ 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>;
@@ -185,50 +186,6 @@ impl ObjectSubclass for Identity {
// into the debug logs
Self { srcpad, sinkpad }
}
-
- // 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.
- 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
- // without having to load the plugin in memory.
- klass.set_metadata(
- "Identity",
- "Generic",
- "Does nothing with the data",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- // Create and add pad templates for our sink and source pad. These
- // are later used for actually creating the pads and beforehand
- // already provide information to GStreamer about all possible
- // pads that could exist for this type.
-
- // Our element can accept any possible caps on both pads
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
// Implementation of glib::Object virtual methods
@@ -247,6 +204,55 @@ impl ObjectImpl for Identity {
// Implementation of gst::Element virtual methods
impl ElementImpl for Identity {
+ // 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
+ // without having to load the plugin in memory.
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Identity",
+ "Generic",
+ "Does nothing with the data",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ // Create and add pad templates for our sink and source pad. These
+ // are later used for actually creating the pads and beforehand
+ // already provide information to GStreamer about all possible
+ // pads that could exist for this type.
+ //
+ // Actual instances can create pads based on those pad templates
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ // Our element can accept any possible caps on both pads
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
// Called whenever the state of the element should be changed. This allows for
// starting up the element, allocating/deallocating resources or shutting down
// the element again.
diff --git a/tutorial/src/progressbin/imp.rs b/tutorial/src/progressbin/imp.rs
index 9a1e5c7cf..7410bc2b3 100644
--- a/tutorial/src/progressbin/imp.rs
+++ b/tutorial/src/progressbin/imp.rs
@@ -41,18 +41,6 @@ pub struct ProgressBin {
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
@@ -60,6 +48,7 @@ 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>;
@@ -92,64 +81,37 @@ impl ObjectSubclass for ProgressBin {
output_type: Mutex::new(ProgressBinOutput::Println),
}
}
-
- // 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.
- 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
- // without having to load the plugin in memory.
- klass.set_metadata(
- "ProgressBin",
- "Generic",
- "Prints progress information to stdout",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- // Create and add pad templates for our sink and source pad. These
- // are later used for actually creating the pads and beforehand
- // already provide information to GStreamer about all possible
- // pads that could exist for this type.
-
- // Our element can accept any possible caps on both pads
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
- }
}
// Implementation of glib::Object virtual methods
impl ObjectImpl for ProgressBin {
+ // Metadata for the element's properties
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::enum_(
+ "output",
+ "Output",
+ "Defines the output type of the progressbin",
+ ProgressBinOutput::static_type(),
+ DEFAULT_OUTPUT_TYPE as i32,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
// 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: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("output", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "output" => {
let mut output_type = self.output_type.lock().unwrap();
let new_output_type = value
.get_some::<ProgressBinOutput>()
@@ -169,11 +131,9 @@ 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: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("output", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "output" => {
let output_type = self.output_type.lock().unwrap();
output_type.to_value()
}
@@ -207,7 +167,56 @@ impl ObjectImpl for ProgressBin {
}
// Implementation of gst::Element virtual methods
-impl ElementImpl for ProgressBin {}
+impl ElementImpl for ProgressBin {
+ // 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
+ // without having to load the plugin in memory.
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "ProgressBin",
+ "Generic",
+ "Prints progress information to stdout",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+ // Create and add pad templates for our sink and source pad. These
+ // are later used for actually creating the pads and beforehand
+ // already provide information to GStreamer about all possible
+ // pads that could exist for this type.
+ //
+ // Actual instances can create pads based on those pad templates
+ // with a subset of the caps given here.
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ // Our element can accept any possible caps on both pads
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
// Implementation of gst::Bin virtual methods
impl BinImpl for ProgressBin {
diff --git a/tutorial/src/rgb2gray/imp.rs b/tutorial/src/rgb2gray/imp.rs
index f330e467b..019e48d33 100644
--- a/tutorial/src/rgb2gray/imp.rs
+++ b/tutorial/src/rgb2gray/imp.rs
@@ -48,30 +48,6 @@ impl Default for Settings {
}
}
-// Metadata for the properties
-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,
- )
- }),
-];
-
// Stream-specific state, i.e. video format configuration
struct State {
in_info: gst_video::VideoInfo,
@@ -118,6 +94,7 @@ 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>;
@@ -132,122 +109,47 @@ impl ObjectSubclass for Rgb2Gray {
state: Mutex::new(None),
}
}
+}
- // 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 basetransform,
- // a "src" and "sink" pad template are required here and the base class
- // will automatically instantiate pads for them.
- //
- // Our element here can convert BGRx to BGRx or GRAY8, both being grayscale.
- 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
- // without having to load the plugin in memory.
- klass.set_metadata(
- "RGB-GRAY Converter",
- "Filter/Effect/Converter/Video",
- "Converts RGB to GRAY or grayscale RGB",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- // Create and add pad templates for our sink and source pad. These
- // are later used for actually creating the pads and beforehand
- // already provide information to GStreamer about all possible
- // pads that could exist for this type.
-
- // On the src pad, we can produce BGRx and GRAY8 of any
- // width/height and with any framerate
- let caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_video::VideoFormat::Bgrx.to_str(),
- &gst_video::VideoFormat::Gray8.to_str(),
- ]),
- ),
- ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
+// Implementation of glib::Object virtual methods
+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,
),
- ],
- );
- // The src pad template must be named "src" for basetransform
- // and specific a pad that is always there
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- // On the sink pad, we can accept BGRx of any
- // width/height and with any framerate
- let caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- ("format", &gst_video::VideoFormat::Bgrx.to_str()),
- ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
+ glib::ParamSpec::uint(
+ "shift",
+ "Shift",
+ "Shift grayscale output (wrapping around)",
+ 0,
+ 255,
+ DEFAULT_SHIFT,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
- // The sink pad template must be named "sink" for basetransform
- // and specific a pad that is always there
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
-
- // Configure basetransform so that we are never running in-place,
- // don't passthrough on same caps and also never call transform_ip
- // in passthrough mode (which does not matter for us here).
- //
- // We could work in-place for BGRx->BGRx but don't do here for simplicity
- // for now.
- klass.configure(
- gst_base::subclass::BaseTransformMode::NeverInPlace,
- false,
- false,
- );
+ ]
+ });
+
+ PROPERTIES.as_ref()
}
-}
-// Implementation of glib::Object virtual methods
-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: &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!(
@@ -259,7 +161,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!(
@@ -277,15 +179,13 @@ 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: &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()
}
@@ -295,10 +195,112 @@ impl ObjectImpl for Rgb2Gray {
}
// Implementation of gst::Element virtual methods
-impl ElementImpl for Rgb2Gray {}
+impl ElementImpl for Rgb2Gray {
+ // 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
+ // without having to load the plugin in memory.
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "RGB-GRAY Converter",
+ "Filter/Effect/Converter/Video",
+ "Converts RGB to GRAY or grayscale RGB",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ // Create and add pad templates for our sink and source pad. These
+ // are later used for actually creating the pads and beforehand
+ // already provide information to GStreamer about all possible
+ // pads that could exist for this type.
+ //
+ // Our element here can convert BGRx to BGRx or GRAY8, both being grayscale.
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ // On the src pad, we can produce BGRx and GRAY8 of any
+ // width/height and with any framerate
+ let caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_video::VideoFormat::Bgrx.to_str(),
+ &gst_video::VideoFormat::Gray8.to_str(),
+ ]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+ // The src pad template must be named "src" for basetransform
+ // and specific a pad that is always there
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ // On the sink pad, we can accept BGRx of any
+ // width/height and with any framerate
+ let caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ ("format", &gst_video::VideoFormat::Bgrx.to_str()),
+ ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+ // The sink pad template must be named "sink" for basetransform
+ // and specific a pad that is always there
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
// Implementation of gst_base::BaseTransform virtual methods
impl BaseTransformImpl for Rgb2Gray {
+ // Configure basetransform so that we are never running in-place,
+ // don't passthrough on same caps and also never call transform_ip
+ // in passthrough mode (which does not matter for us here).
+ //
+ // We could work in-place for BGRx->BGRx but don't do here for simplicity
+ // for now.
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::NeverInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
// Called for converting caps from one pad to another to account for any
// changes in the media format this element is performing.
//
diff --git a/tutorial/src/sinesrc/imp.rs b/tutorial/src/sinesrc/imp.rs
index 951dc4b4e..558aaf58a 100644
--- a/tutorial/src/sinesrc/imp.rs
+++ b/tutorial/src/sinesrc/imp.rs
@@ -64,61 +64,6 @@ impl Default for Settings {
}
}
-// Metadata for the properties
-static PROPERTIES: [subclass::Property; 5] = [
- subclass::Property("samples-per-buffer", |name| {
- glib::ParamSpec::uint(
- name,
- "Samples Per Buffer",
- "Number of samples per output buffer",
- 1,
- u32::MAX,
- DEFAULT_SAMPLES_PER_BUFFER,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("freq", |name| {
- glib::ParamSpec::uint(
- name,
- "Frequency",
- "Frequency",
- 1,
- u32::MAX,
- DEFAULT_FREQ,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("volume", |name| {
- glib::ParamSpec::double(
- name,
- "Volume",
- "Output volume",
- 0.0,
- 10.0,
- DEFAULT_VOLUME,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("mute", |name| {
- glib::ParamSpec::boolean(
- name,
- "Mute",
- "Mute",
- DEFAULT_MUTE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("is-live", |name| {
- glib::ParamSpec::boolean(
- name,
- "Is Live",
- "(Pseudo) live output",
- DEFAULT_IS_LIVE,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
// Stream-specific state, i.e. audio format configuration
// and sample offset
struct State {
@@ -203,6 +148,7 @@ 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>;
@@ -221,69 +167,61 @@ impl ObjectSubclass for SineSrc {
}),
}
}
-
- // 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 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
- // without having to load the plugin in memory.
- klass.set_metadata(
- "Sine Wave Source",
- "Source/Audio",
- "Creates a sine wave",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- // Create and add pad templates for our sink and source pad. These
- // are later used for actually creating the pads and beforehand
- // already provide information to GStreamer about all possible
- // pads that could exist for this type.
-
- // 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_str(),
- &gst_audio::AUDIO_FORMAT_F64.to_str(),
- ]),
- ),
- ("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,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
- }
}
// Implementation of glib::Object virtual methods
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,
+ ),
+ glib::ParamSpec::uint(
+ "freq",
+ "Frequency",
+ "Frequency",
+ 1,
+ u32::MAX,
+ DEFAULT_FREQ,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::double(
+ "volume",
+ "Volume",
+ "Output volume",
+ 0.0,
+ 10.0,
+ DEFAULT_VOLUME,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "mute",
+ "Mute",
+ "Mute",
+ DEFAULT_MUTE,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "is-live",
+ "Is Live",
+ "(Pseudo) live output",
+ DEFAULT_IS_LIVE,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
// Called right after construction of a new instance
fn constructed(&self, obj: &Self::Type) {
// Call the parent class' ::constructed() implementation first
@@ -297,11 +235,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: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("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!(
@@ -316,7 +258,7 @@ impl ObjectImpl for SineSrc {
let _ = obj.post_message(gst::message::Latency::builder().src(obj).build());
}
- subclass::Property("freq", ..) => {
+ "freq" => {
let mut settings = self.settings.lock().unwrap();
let freq = value.get_some().expect("type checked upstream");
gst_info!(
@@ -328,7 +270,7 @@ impl ObjectImpl for SineSrc {
);
settings.freq = freq;
}
- subclass::Property("volume", ..) => {
+ "volume" => {
let mut settings = self.settings.lock().unwrap();
let volume = value.get_some().expect("type checked upstream");
gst_info!(
@@ -340,7 +282,7 @@ impl ObjectImpl for SineSrc {
);
settings.volume = volume;
}
- subclass::Property("mute", ..) => {
+ "mute" => {
let mut settings = self.settings.lock().unwrap();
let mute = value.get_some().expect("type checked upstream");
gst_info!(
@@ -352,7 +294,7 @@ impl ObjectImpl for SineSrc {
);
settings.mute = mute;
}
- subclass::Property("is-live", ..) => {
+ "is-live" => {
let mut settings = self.settings.lock().unwrap();
let is_live = value.get_some().expect("type checked upstream");
gst_info!(
@@ -370,27 +312,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: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("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()
}
- subclass::Property("freq", ..) => {
+ "freq" => {
let settings = self.settings.lock().unwrap();
settings.freq.to_value()
}
- subclass::Property("volume", ..) => {
+ "volume" => {
let settings = self.settings.lock().unwrap();
settings.volume.to_value()
}
- subclass::Property("mute", ..) => {
+ "mute" => {
let settings = self.settings.lock().unwrap();
settings.mute.to_value()
}
- subclass::Property("is-live", ..) => {
+ "is-live" => {
let settings = self.settings.lock().unwrap();
settings.is_live.to_value()
}
@@ -401,6 +341,62 @@ impl ObjectImpl for SineSrc {
// Implementation of gst::Element virtual methods
impl ElementImpl for SineSrc {
+ // 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
+ // without having to load the plugin in memory.
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Sine Wave Source",
+ "Source/Audio",
+ "Creates a sine wave",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ // Create and add pad templates for our sink and source pad. These
+ // are later used for actually creating the pads and beforehand
+ // already provide information to GStreamer about all possible
+ // pads that could exist for this type.
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ // 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_str(),
+ &gst_audio::AUDIO_FORMAT_F64.to_str(),
+ ]),
+ ),
+ ("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,
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
// Called whenever the state of the element should be changed. This allows for
// starting up the element, allocating/deallocating resources or shutting down
// the element again.
diff --git a/utils/fallbackswitch/src/fallbacksrc/custom_source/imp.rs b/utils/fallbackswitch/src/fallbacksrc/custom_source/imp.rs
index edca3ed73..895390248 100644
--- a/utils/fallbackswitch/src/fallbacksrc/custom_source/imp.rs
+++ b/utils/fallbackswitch/src/fallbacksrc/custom_source/imp.rs
@@ -35,16 +35,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("source", |name| {
- glib::ParamSpec::object(
- name,
- "Source",
- "Source",
- gst::Element::static_type(),
- glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT_ONLY,
- )
-})];
-
struct Stream {
source_pad: gst::Pad,
ghost_pad: gst::GhostPad,
@@ -67,6 +57,7 @@ impl ObjectSubclass for CustomSource {
const NAME: &'static str = "FallbackSrcCustomSource";
type Type = super::CustomSource;
type ParentType = gst::Bin;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -82,35 +73,32 @@ impl ObjectSubclass for CustomSource {
}),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- let src_pad_template = gst::PadTemplate::new(
- "audio_%u",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "video_%u",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for CustomSource {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::object(
+ "source",
+ "Source",
+ "Source",
+ gst::Element::static_type(),
+ glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT_ONLY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("source", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "source" => {
let source = value.get::<gst::Element>().unwrap().unwrap();
self.source.set(source.clone()).unwrap();
obj.add(&source).unwrap();
@@ -129,6 +117,30 @@ impl ObjectImpl for CustomSource {
}
impl ElementImpl for CustomSource {
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let audio_src_pad_template = gst::PadTemplate::new(
+ "audio_%u",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ let video_src_pad_template = gst::PadTemplate::new(
+ "video_%u",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ vec![audio_src_pad_template, video_src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
#[allow(clippy::single_match)]
fn change_state(
&self,
diff --git a/utils/fallbackswitch/src/fallbacksrc/imp.rs b/utils/fallbackswitch/src/fallbacksrc/imp.rs
index 89eccc497..f4ceb1ebb 100644
--- a/utils/fallbackswitch/src/fallbacksrc/imp.rs
+++ b/utils/fallbackswitch/src/fallbacksrc/imp.rs
@@ -177,137 +177,11 @@ pub struct FallbackSrc {
state: Mutex<Option<State>>,
}
-static PROPERTIES: [subclass::Property; 13] = [
- subclass::Property("enable-audio", |name| {
- glib::ParamSpec::boolean(
- name,
- "Enable Audio",
- "Enable the audio stream, this will output silence if there's no audio in the configured URI",
- true,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("enable-video", |name| {
- glib::ParamSpec::boolean(
- name,
- "Enable Video",
- "Enable the video stream, this will output black or the fallback video if there's no video in the configured URI",
- true,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("uri", |name| {
- glib::ParamSpec::string(name, "URI", "URI to use", None, glib::ParamFlags::READWRITE)
- }),
- subclass::Property("source", |name| {
- glib::ParamSpec::object(
- name,
- "Source",
- "Source to use instead of the URI",
- gst::Element::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("fallback-uri", |name| {
- glib::ParamSpec::string(
- name,
- "Fallback URI",
- "Fallback URI to use for video in case the main stream doesn't work",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("timeout", |name| {
- glib::ParamSpec::uint64(
- name,
- "Timeout",
- "Timeout for switching to the fallback URI",
- 0,
- std::u64::MAX,
- 5 * gst::SECOND_VAL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("restart-timeout", |name| {
- glib::ParamSpec::uint64(
- name,
- "Timeout",
- "Timeout for restarting an active source",
- 0,
- std::u64::MAX,
- 5 * gst::SECOND_VAL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("retry-timeout", |name| {
- glib::ParamSpec::uint64(
- name,
- "Retry Timeout",
- "Timeout for stopping after repeated failure",
- 0,
- std::u64::MAX,
- 60 * gst::SECOND_VAL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("restart-on-eos", |name| {
- glib::ParamSpec::boolean(
- name,
- "Restart on EOS",
- "Restart source on EOS",
- false,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("status", |name| {
- glib::ParamSpec::enum_(
- name,
- "Status",
- "Current source status",
- Status::static_type(),
- Status::Stopped as i32,
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("min-latency", |name| {
- glib::ParamSpec::uint64(
- name,
- "Minimum Latency",
- "When the main source has a higher latency than the fallback source \
- this allows to configure a minimum latency that would be configured \
- if initially the fallback is enabled",
- 0,
- std::u64::MAX,
- 0,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("buffer-duration", |name| {
- glib::ParamSpec::int64(
- name,
- "Buffer Duration",
- "Buffer duration when buffering streams (-1 default value)",
- -1,
- std::i64::MAX,
- -1,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("statistics", |name| {
- glib::ParamSpec::boxed(
- name,
- "Statistics",
- "Various statistics",
- gst::Structure::static_type(),
- glib::ParamFlags::READABLE,
- )
- }),
-];
-
impl ObjectSubclass for FallbackSrc {
const NAME: &'static str = "FallbackSrc";
type Type = super::FallbackSrc;
type ParentType = gst::Bin;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -319,58 +193,125 @@ impl ObjectSubclass for FallbackSrc {
state: Mutex::new(None),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Fallback Source",
- "Generic/Source",
- "Live source with uridecodebin3 or custom source, and fallback image stream",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let src_pad_template = gst::PadTemplate::new(
- "audio",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "video",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
-
- klass.add_signal_with_class_handler_and_accumulator(
- "update-uri",
- glib::SignalFlags::RUN_LAST | glib::SignalFlags::ACTION,
- &[String::static_type()],
- String::static_type(),
- |_token, args| {
- // Simplify return the input by default
- Some(args[1].clone())
- },
- |_hint, ret, value| {
- *ret = value.clone();
- false
- },
- );
- }
}
impl ObjectImpl for FallbackSrc {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boolean(
+ "enable-audio",
+ "Enable Audio",
+ "Enable the audio stream, this will output silence if there's no audio in the configured URI",
+ true,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "enable-video",
+ "Enable Video",
+ "Enable the video stream, this will output black or the fallback video if there's no video in the configured URI",
+ true,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string("uri", "URI", "URI to use", None, glib::ParamFlags::READWRITE),
+ glib::ParamSpec::object(
+ "source",
+ "Source",
+ "Source to use instead of the URI",
+ gst::Element::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::string(
+ "fallback-uri",
+ "Fallback URI",
+ "Fallback URI to use for video in case the main stream doesn't work",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "timeout",
+ "Timeout",
+ "Timeout for switching to the fallback URI",
+ 0,
+ std::u64::MAX,
+ 5 * gst::SECOND_VAL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "restart-timeout",
+ "Timeout",
+ "Timeout for restarting an active source",
+ 0,
+ std::u64::MAX,
+ 5 * gst::SECOND_VAL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "retry-timeout",
+ "Retry Timeout",
+ "Timeout for stopping after repeated failure",
+ 0,
+ std::u64::MAX,
+ 60 * gst::SECOND_VAL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "restart-on-eos",
+ "Restart on EOS",
+ "Restart source on EOS",
+ false,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::enum_(
+ "status",
+ "Status",
+ "Current source status",
+ Status::static_type(),
+ Status::Stopped as i32,
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::uint64(
+ "min-latency",
+ "Minimum Latency",
+ "When the main source has a higher latency than the fallback source \
+ this allows to configure a minimum latency that would be configured \
+ if initially the fallback is enabled",
+ 0,
+ std::u64::MAX,
+ 0,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int64(
+ "buffer-duration",
+ "Buffer Duration",
+ "Buffer duration when buffering streams (-1 default value)",
+ -1,
+ std::i64::MAX,
+ -1,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "statistics",
+ "Statistics",
+ "Various statistics",
+ gst::Structure::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
+ ]
+ });
- match *prop {
- subclass::Property("enable-audio", ..) => {
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "enable-audio" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -382,7 +323,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.enable_audio = new_value;
}
- subclass::Property("enable-video", ..) => {
+ "enable-video" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -394,7 +335,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.enable_video = new_value;
}
- subclass::Property("uri", ..) => {
+ "uri" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get().expect("type checked upstream");
gst_info!(
@@ -406,7 +347,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.uri = new_value;
}
- subclass::Property("source", ..) => {
+ "source" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get().expect("type checked upstream");
gst_info!(
@@ -418,7 +359,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.source = new_value;
}
- subclass::Property("fallback-uri", ..) => {
+ "fallback-uri" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get().expect("type checked upstream");
gst_info!(
@@ -430,7 +371,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.fallback_uri = new_value;
}
- subclass::Property("timeout", ..) => {
+ "timeout" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -442,7 +383,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.timeout = new_value;
}
- subclass::Property("restart-timeout", ..) => {
+ "restart-timeout" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -454,7 +395,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.restart_timeout = new_value;
}
- subclass::Property("retry-timeout", ..) => {
+ "retry-timeout" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -466,7 +407,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.retry_timeout = new_value;
}
- subclass::Property("restart-on-eos", ..) => {
+ "restart-on-eos" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -478,7 +419,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.restart_on_eos = new_value;
}
- subclass::Property("min-latency", ..) => {
+ "min-latency" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -490,7 +431,7 @@ impl ObjectImpl for FallbackSrc {
);
settings.min_latency = new_value;
}
- subclass::Property("buffer-duration", ..) => {
+ "buffer-duration" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -509,47 +450,45 @@ impl ObjectImpl for FallbackSrc {
// Called whenever a value of a property is read. It can be called
// at any time from any thread.
#[allow(clippy::blocks_in_if_conditions)]
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("enable-audio", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "enable-audio" => {
let settings = self.settings.lock().unwrap();
settings.enable_audio.to_value()
}
- subclass::Property("enable-video", ..) => {
+ "enable-video" => {
let settings = self.settings.lock().unwrap();
settings.enable_video.to_value()
}
- subclass::Property("uri", ..) => {
+ "uri" => {
let settings = self.settings.lock().unwrap();
settings.uri.to_value()
}
- subclass::Property("source", ..) => {
+ "source" => {
let settings = self.settings.lock().unwrap();
settings.source.to_value()
}
- subclass::Property("fallback-uri", ..) => {
+ "fallback-uri" => {
let settings = self.settings.lock().unwrap();
settings.fallback_uri.to_value()
}
- subclass::Property("timeout", ..) => {
+ "timeout" => {
let settings = self.settings.lock().unwrap();
settings.timeout.to_value()
}
- subclass::Property("restart-timeout", ..) => {
+ "restart-timeout" => {
let settings = self.settings.lock().unwrap();
settings.restart_timeout.to_value()
}
- subclass::Property("retry-timeout", ..) => {
+ "retry-timeout" => {
let settings = self.settings.lock().unwrap();
settings.retry_timeout.to_value()
}
- subclass::Property("restart-on-eos", ..) => {
+ "restart-on-eos" => {
let settings = self.settings.lock().unwrap();
settings.restart_on_eos.to_value()
}
- subclass::Property("status", ..) => {
+ "status" => {
let state_guard = self.state.lock().unwrap();
// If we have no state then we'r stopped
@@ -601,19 +540,42 @@ impl ObjectImpl for FallbackSrc {
// Otherwise we're running now
Status::Running.to_value()
}
- subclass::Property("min-latency", ..) => {
+ "min-latency" => {
let settings = self.settings.lock().unwrap();
settings.min_latency.to_value()
}
- subclass::Property("buffer-duration", ..) => {
+ "buffer-duration" => {
let settings = self.settings.lock().unwrap();
settings.buffer_duration.to_value()
}
- subclass::Property("statistics", ..) => self.get_stats().to_value(),
+ "statistics" => self.get_stats().to_value(),
_ => unimplemented!(),
}
}
+ fn signals() -> &'static [glib::subclass::Signal] {
+ static SIGNALS: Lazy<Vec<glib::subclass::Signal>> = Lazy::new(|| {
+ vec![glib::subclass::Signal::builder(
+ "update-uri",
+ &[String::static_type()],
+ String::static_type(),
+ )
+ .action()
+ .class_handler(|_token, args| {
+ // Simply return the input by default
+ Some(args[1].clone())
+ })
+ .accumulator(|_hint, ret, value| {
+ // First signal handler wins
+ *ret = value.clone();
+ false
+ })
+ .build()]
+ });
+
+ SIGNALS.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -624,6 +586,43 @@ impl ObjectImpl for FallbackSrc {
}
impl ElementImpl for FallbackSrc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Fallback Source",
+ "Generic/Source",
+ "Live source with uridecodebin3 or custom source, and fallback image stream",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let audio_src_pad_template = gst::PadTemplate::new(
+ "audio",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ let video_src_pad_template = gst::PadTemplate::new(
+ "video",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ vec![audio_src_pad_template, video_src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
#[allow(clippy::single_match)]
fn change_state(
&self,
diff --git a/utils/fallbackswitch/src/fallbacksrc/video_fallback/imp.rs b/utils/fallbackswitch/src/fallbacksrc/video_fallback/imp.rs
index 02892a35f..20f2964ed 100644
--- a/utils/fallbackswitch/src/fallbacksrc/video_fallback/imp.rs
+++ b/utils/fallbackswitch/src/fallbacksrc/video_fallback/imp.rs
@@ -35,29 +35,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
)
});
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("uri", |name| {
- glib::ParamSpec::string(
- name,
- "URI",
- "URI to use for video in case the main stream doesn't work",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("min-latency", |name| {
- glib::ParamSpec::uint64(
- name,
- "Minimum Latency",
- "Minimum Latency",
- 0,
- std::u64::MAX,
- 0,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
#[derive(Debug, Clone)]
struct Settings {
uri: Option<String>,
@@ -89,6 +66,7 @@ impl ObjectSubclass for VideoFallbackSource {
const NAME: &'static str = "FallbackSrcVideoFallbackSource";
type Type = super::VideoFallbackSource;
type ParentType = gst::Bin;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -105,26 +83,43 @@ impl ObjectSubclass for VideoFallbackSource {
settings: Mutex::new(Settings::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &gst::Caps::new_any(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for VideoFallbackSource {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "uri",
+ "URI",
+ "URI to use for video in case the main stream doesn't work",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "min-latency",
+ "Minimum Latency",
+ "Minimum Latency",
+ 0,
+ std::u64::MAX,
+ 0,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("uri", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "uri" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get().expect("type checked upstream");
gst_info!(
@@ -136,7 +131,7 @@ impl ObjectImpl for VideoFallbackSource {
);
settings.uri = new_value;
}
- subclass::Property("min-latency", ..) => {
+ "min-latency" => {
let mut settings = self.settings.lock().unwrap();
let new_value = value.get_some().expect("type checked upstream");
gst_info!(
@@ -152,15 +147,13 @@ impl ObjectImpl for VideoFallbackSource {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("uri", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "uri" => {
let settings = self.settings.lock().unwrap();
settings.uri.to_value()
}
- subclass::Property("min-latency", ..) => {
+ "min-latency" => {
let settings = self.settings.lock().unwrap();
settings.min_latency.to_value()
}
@@ -178,6 +171,22 @@ impl ObjectImpl for VideoFallbackSource {
}
impl ElementImpl for VideoFallbackSource {
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &gst::Caps::new_any(),
+ )
+ .unwrap();
+
+ vec![src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
#[allow(clippy::single_match)]
fn change_state(
&self,
diff --git a/utils/fallbackswitch/src/fallbackswitch/imp.rs b/utils/fallbackswitch/src/fallbackswitch/imp.rs
index 93a125708..39350b1a0 100644
--- a/utils/fallbackswitch/src/fallbackswitch/imp.rs
+++ b/utils/fallbackswitch/src/fallbackswitch/imp.rs
@@ -123,58 +123,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 5] = [
- subclass::Property("timeout", |name| {
- glib::ParamSpec::uint64(
- name,
- "Timeout",
- "Timeout in nanoseconds",
- 0,
- std::u64::MAX,
- DEFAULT_TIMEOUT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("active-pad", |name| {
- glib::ParamSpec::object(
- name,
- "Active Pad",
- "Currently active pad. Writes are ignored if auto-switch=true",
- gst::Pad::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("auto-switch", |name| {
- glib::ParamSpec::boolean(
- name,
- "Automatically switch pads",
- "Automatically switch pads (If true, prefer primary sink, otherwise manual selection via the active-pad property)",
- DEFAULT_AUTO_SWITCH,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("primary-health", |name| {
- glib::ParamSpec::enum_(
- name,
- "Primary stream state",
- "Reports the health of the primary stream on the sink pad",
- StreamHealth::static_type(),
- DEFAULT_STREAM_HEALTH as i32,
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("fallback-health", |name| {
- glib::ParamSpec::enum_(
- name,
- "Fallback stream state",
- "Reports the health of the fallback stream on the fallback_sink pad",
- StreamHealth::static_type(),
- DEFAULT_STREAM_HEALTH as i32,
- glib::ParamFlags::READABLE,
- )
- }),
-];
-
impl OutputState {
fn get_health(
&self,
@@ -697,6 +645,7 @@ impl ObjectSubclass for FallbackSwitch {
const NAME: &'static str = "FallbackSwitch";
type Type = super::FallbackSwitch;
type ParentType = gst_base::Aggregator;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -717,62 +666,72 @@ impl ObjectSubclass for FallbackSwitch {
settings: Mutex::new(Settings::default()),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Fallback Switch",
- "Generic",
- "Allows switching to a fallback input after a given timeout",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::with_gtype(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- gst_base::AggregatorPad::static_type(),
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::with_gtype(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- gst_base::AggregatorPad::static_type(),
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let fallbacksink_pad_template = gst::PadTemplate::with_gtype(
- "fallback_sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Request,
- &caps,
- gst_base::AggregatorPad::static_type(),
- )
- .unwrap();
- klass.add_pad_template(fallbacksink_pad_template);
+impl ObjectImpl for FallbackSwitch {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::uint64(
+ "timeout",
+ "Timeout",
+ "Timeout in nanoseconds",
+ 0,
+ std::u64::MAX,
+ DEFAULT_TIMEOUT,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::object(
+ "active-pad",
+ "Active Pad",
+ "Currently active pad. Writes are ignored if auto-switch=true",
+ gst::Pad::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "auto-switch",
+ "Automatically switch pads",
+ "Automatically switch pads (If true, prefer primary sink, otherwise manual selection via the active-pad property)",
+ DEFAULT_AUTO_SWITCH,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::enum_(
+ "primary-health",
+ "Primary stream state",
+ "Reports the health of the primary stream on the sink pad",
+ StreamHealth::static_type(),
+ DEFAULT_STREAM_HEALTH as i32,
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::enum_(
+ "fallback-health",
+ "Fallback stream state",
+ "Reports the health of the fallback stream on the fallback_sink pad",
+ StreamHealth::static_type(),
+ DEFAULT_STREAM_HEALTH as i32,
+ glib::ParamFlags::READABLE,
+ ),
+ ]
+ });
- klass.install_properties(&PROPERTIES);
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for FallbackSwitch {
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
obj.add_pad(&self.primary_sinkpad).unwrap();
}
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("timeout", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "timeout" => {
let mut settings = self.settings.lock().unwrap();
let timeout = value.get_some().expect("type checked upstream");
gst_info!(
@@ -785,7 +744,7 @@ impl ObjectImpl for FallbackSwitch {
settings.timeout = timeout;
drop(settings);
}
- subclass::Property("active-pad", ..) => {
+ "active-pad" => {
let settings = self.settings.lock().unwrap();
if settings.auto_switch {
gst_warning!(
@@ -804,7 +763,7 @@ impl ObjectImpl for FallbackSwitch {
}
drop(settings);
}
- subclass::Property("auto-switch", ..) => {
+ "auto-switch" => {
let mut settings = self.settings.lock().unwrap();
settings.auto_switch = value.get_some().expect("type checked upstream");
}
@@ -812,27 +771,25 @@ impl ObjectImpl for FallbackSwitch {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("timeout", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "timeout" => {
let settings = self.settings.lock().unwrap();
settings.timeout.to_value()
}
- subclass::Property("active-pad", ..) => {
+ "active-pad" => {
let active_pad = self.active_sinkpad.lock().unwrap().clone();
active_pad.to_value()
}
- subclass::Property("auto-switch", ..) => {
+ "auto-switch" => {
let settings = self.settings.lock().unwrap();
settings.auto_switch.to_value()
}
- subclass::Property("primary-health", ..) => {
+ "primary-health" => {
let state = self.output_state.lock().unwrap();
state.primary.stream_health.to_value()
}
- subclass::Property("fallback-health", ..) => {
+ "fallback-health" => {
let state = self.output_state.lock().unwrap();
state.fallback.stream_health.to_value()
}
@@ -842,6 +799,59 @@ impl ObjectImpl for FallbackSwitch {
}
impl ElementImpl for FallbackSwitch {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Fallback Switch",
+ "Generic",
+ "Allows switching to a fallback input after a given timeout",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::with_gtype(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ gst_base::AggregatorPad::static_type(),
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::with_gtype(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ gst_base::AggregatorPad::static_type(),
+ )
+ .unwrap();
+
+ let fallbacksink_pad_template = gst::PadTemplate::with_gtype(
+ "fallback_sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Request,
+ &caps,
+ gst_base::AggregatorPad::static_type(),
+ )
+ .unwrap();
+
+ vec![
+ src_pad_template,
+ sink_pad_template,
+ fallbacksink_pad_template,
+ ]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn request_new_pad(
&self,
element: &Self::Type,
diff --git a/utils/togglerecord/src/togglerecord/imp.rs b/utils/togglerecord/src/togglerecord/imp.rs
index e61406489..37246dbef 100644
--- a/utils/togglerecord/src/togglerecord/imp.rs
+++ b/utils/togglerecord/src/togglerecord/imp.rs
@@ -47,27 +47,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("record", |name| {
- glib::ParamSpec::boolean(
- name,
- "Record",
- "Enable/disable recording",
- DEFAULT_RECORD,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("recording", |name| {
- glib::ParamSpec::boolean(
- name,
- "Recording",
- "Whether recording is currently taking place",
- DEFAULT_RECORD,
- glib::ParamFlags::READABLE,
- )
- }),
-];
-
#[derive(Clone)]
struct Stream {
sinkpad: gst::Pad,
@@ -1642,6 +1621,7 @@ impl ObjectSubclass for ToggleRecord {
const NAME: &'static str = "RsToggleRecord";
type Type = super::ToggleRecord;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1720,62 +1700,41 @@ impl ObjectSubclass for ToggleRecord {
pads: Mutex::new(pads),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.install_properties(&PROPERTIES);
-
- klass.set_metadata(
- "Toggle Record",
- "Generic",
- "Valve that ensures multiple streams start/end at the same time",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let caps = gst::Caps::new_any();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "src_%u",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink_%u",
- gst::PadDirection::Sink,
- gst::PadPresence::Request,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for ToggleRecord {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::boolean(
+ "record",
+ "Record",
+ "Enable/disable recording",
+ DEFAULT_RECORD,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "recording",
+ "Recording",
+ "Whether recording is currently taking place",
+ DEFAULT_RECORD,
+ glib::ParamFlags::READABLE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("record", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "record" => {
let mut settings = self.settings.lock();
let record = value.get_some().expect("type checked upstream");
gst_debug!(
@@ -1792,15 +1751,13 @@ impl ObjectImpl for ToggleRecord {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("record", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "record" => {
let settings = self.settings.lock();
settings.record.to_value()
}
- subclass::Property("recording", ..) => {
+ "recording" => {
let rec_state = self.state.lock();
(rec_state.recording_state == RecordingState::Recording).to_value()
}
@@ -1817,6 +1774,65 @@ impl ObjectImpl for ToggleRecord {
}
impl ElementImpl for ToggleRecord {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Toggle Record",
+ "Generic",
+ "Valve that ensures multiple streams start/end at the same time",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_any();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let secondary_src_pad_template = gst::PadTemplate::new(
+ "src_%u",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &caps,
+ )
+ .unwrap();
+
+ let secondary_sink_pad_template = gst::PadTemplate::new(
+ "sink_%u",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Request,
+ &caps,
+ )
+ .unwrap();
+
+ vec![
+ src_pad_template,
+ sink_pad_template,
+ secondary_src_pad_template,
+ secondary_sink_pad_template,
+ ]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/cdg/src/cdgdec/imp.rs b/video/cdg/src/cdgdec/imp.rs
index 64cbbbf5e..6893478ce 100644
--- a/video/cdg/src/cdgdec/imp.rs
+++ b/video/cdg/src/cdgdec/imp.rs
@@ -32,6 +32,7 @@ impl ObjectSubclass for CdgDec {
const NAME: &'static str = "CdgDec";
type Type = super::CdgDec;
type ParentType = gst_video::VideoDecoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -43,48 +44,58 @@ impl ObjectSubclass for CdgDec {
output_info: Mutex::new(None),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "CDG decoder",
- "Decoder/Video",
- "CDG decoder",
- "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
- );
-
- let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- ("format", &gst_video::VideoFormat::Rgba.to_str()),
- ("width", &(CDG_WIDTH as i32)),
- ("height", &(CDG_HEIGHT as i32)),
- ("framerate", &gst::Fraction::new(0, 1)),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- }
}
impl ObjectImpl for CdgDec {}
-impl ElementImpl for CdgDec {}
+impl ElementImpl for CdgDec {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "CDG decoder",
+ "Decoder/Video",
+ "CDG decoder",
+ "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple("video/x-cdg", &[("parsed", &true)]);
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ ("format", &gst_video::VideoFormat::Rgba.to_str()),
+ ("width", &(CDG_WIDTH as i32)),
+ ("height", &(CDG_HEIGHT as i32)),
+ ("framerate", &gst::Fraction::new(0, 1)),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl VideoDecoderImpl for CdgDec {
fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/video/cdg/src/cdgparse/imp.rs b/video/cdg/src/cdgparse/imp.rs
index 697575b59..756dee536 100644
--- a/video/cdg/src/cdgparse/imp.rs
+++ b/video/cdg/src/cdgparse/imp.rs
@@ -39,6 +39,7 @@ impl ObjectSubclass for CdgParse {
const NAME: &'static str = "CdgParse";
type Type = super::CdgParse;
type ParentType = gst_base::BaseParse;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -47,48 +48,58 @@ impl ObjectSubclass for CdgParse {
fn new() -> Self {
Self
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "CDG parser",
- "Codec/Parser/Video",
- "CDG parser",
- "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
- );
-
- let sink_caps = gst::Caps::new_simple("video/x-cdg", &[]);
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple(
- "video/x-cdg",
- &[
- ("width", &(CDG_WIDTH as i32)),
- ("height", &(CDG_HEIGHT as i32)),
- ("framerate", &gst::Fraction::new(0, 1)),
- ("parsed", &true),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- }
}
impl ObjectImpl for CdgParse {}
-impl ElementImpl for CdgParse {}
+impl ElementImpl for CdgParse {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "CDG parser",
+ "Codec/Parser/Video",
+ "CDG parser",
+ "Guillaume Desmottes <guillaume.desmottes@collabora.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple("video/x-cdg", &[]);
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple(
+ "video/x-cdg",
+ &[
+ ("width", &(CDG_WIDTH as i32)),
+ ("height", &(CDG_HEIGHT as i32)),
+ ("framerate", &gst::Fraction::new(0, 1)),
+ ("parsed", &true),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
fn bytes_to_time(bytes: Bytes) -> gst::ClockTime {
match bytes {
diff --git a/video/closedcaption/src/ccdetect/imp.rs b/video/closedcaption/src/ccdetect/imp.rs
index ae736de70..6506a1b2a 100644
--- a/video/closedcaption/src/ccdetect/imp.rs
+++ b/video/closedcaption/src/ccdetect/imp.rs
@@ -77,38 +77,6 @@ pub struct CCDetect {
state: Mutex<Option<State>>,
}
-static PROPERTIES: [subclass::Property; 3] = [
- subclass::Property("window", |name| {
- glib::ParamSpec::uint64(
- name,
- "Window",
- "Window of time (in ns) to determine if captions exist in the stream",
- 0,
- u64::MAX,
- DEFAULT_WINDOW,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("cc608", |name| {
- glib::ParamSpec::boolean(
- name,
- "cc608",
- "Whether CEA608 captions (CC1/CC3) have been detected",
- DEFAULT_CC608,
- glib::ParamFlags::READABLE,
- )
- }),
- subclass::Property("cc708", |name| {
- glib::ParamSpec::boolean(
- name,
- "cc608",
- "Whether CEA708 captions (cc_data) have been detected",
- DEFAULT_CC708,
- glib::ParamFlags::READABLE,
- )
- }),
-];
-
#[derive(Debug, Clone, Copy)]
struct CCPacketContents {
cc608: bool,
@@ -387,6 +355,7 @@ impl ObjectSubclass for CCDetect {
const NAME: &'static str = "CCDetect";
type Type = super::CCDetect;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -398,58 +367,50 @@ impl ObjectSubclass for CCDetect {
state: Mutex::new(None),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Closed Caption Detect",
- "Filter/Video/ClosedCaption/Detect",
- "Detect if valid closed captions are present in a stream",
- "Matthew Waters <matthew@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
- let s = gst::Structure::builder("closedcaption/x-cea-708")
- .field("format", &gst::List::new(&[&"cc_data", &"cdp"]))
- .build();
- caps.append_structure(s);
- }
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- klass.install_properties(&PROPERTIES);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::AlwaysInPlace,
- true,
- true,
- );
- }
}
impl ObjectImpl for CCDetect {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::uint64(
+ "window",
+ "Window",
+ "Window of time (in ns) to determine if captions exist in the stream",
+ 0,
+ u64::MAX,
+ DEFAULT_WINDOW,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boolean(
+ "cc608",
+ "cc608",
+ "Whether CEA608 captions (CC1/CC3) have been detected",
+ DEFAULT_CC608,
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::boolean(
+ "cc708",
+ "cc608",
+ "Whether CEA708 captions (cc_data) have been detected",
+ DEFAULT_CC708,
+ glib::ParamFlags::READABLE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("window", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "window" => {
let mut settings = self.settings.lock().unwrap();
settings.window = value.get_some().expect("type checked upstream");
}
@@ -457,19 +418,17 @@ impl ObjectImpl for CCDetect {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("window", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "window" => {
let settings = self.settings.lock().unwrap();
settings.window.to_value()
}
- subclass::Property("cc608", ..) => {
+ "cc608" => {
let settings = self.settings.lock().unwrap();
settings.cc608.to_value()
}
- subclass::Property("cc708", ..) => {
+ "cc708" => {
let settings = self.settings.lock().unwrap();
settings.cc708.to_value()
}
@@ -478,9 +437,60 @@ impl ObjectImpl for CCDetect {
}
}
-impl ElementImpl for CCDetect {}
+impl ElementImpl for CCDetect {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Closed Caption Detect",
+ "Filter/Video/ClosedCaption/Detect",
+ "Detect if valid closed captions are present in a stream",
+ "Matthew Waters <matthew@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+ let s = gst::Structure::builder("closedcaption/x-cea-708")
+ .field("format", &gst::List::new(&[&"cc_data", &"cdp"]))
+ .build();
+ caps.append_structure(s);
+ }
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for CCDetect {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::AlwaysInPlace;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = true;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = true;
+
fn transform_ip_passthrough(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/cea608overlay/imp.rs b/video/closedcaption/src/cea608overlay/imp.rs
index e40016735..17530446b 100644
--- a/video/closedcaption/src/cea608overlay/imp.rs
+++ b/video/closedcaption/src/cea608overlay/imp.rs
@@ -388,6 +388,7 @@ impl ObjectSubclass for Cea608Overlay {
const NAME: &'static str = "RsCea608Overlay";
type Type = super::Cea608Overlay;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -424,38 +425,6 @@ impl ObjectSubclass for Cea608Overlay {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Cea 608 overlay",
- "Video/Overlay/Subtitle",
- "Renders CEA 608 closed caption meta over raw video frames",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst_video::VideoFormat::iter_raw()
- .into_video_caps()
- .unwrap()
- .build();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- }
}
impl ObjectImpl for Cea608Overlay {
@@ -468,6 +437,48 @@ impl ObjectImpl for Cea608Overlay {
}
impl ElementImpl for Cea608Overlay {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Cea 608 overlay",
+ "Video/Overlay/Subtitle",
+ "Renders CEA 608 closed caption meta over raw video frames",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst_video::VideoFormat::iter_raw()
+ .into_video_caps()
+ .unwrap()
+ .build();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/cea608tott/imp.rs b/video/closedcaption/src/cea608tott/imp.rs
index b32745e46..cbd4e35cd 100644
--- a/video/closedcaption/src/cea608tott/imp.rs
+++ b/video/closedcaption/src/cea608tott/imp.rs
@@ -375,6 +375,7 @@ impl ObjectSubclass for Cea608ToTt {
const NAME: &'static str = "Cea608ToTt";
type Type = super::Cea608ToTt;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -411,56 +412,6 @@ impl ObjectSubclass for Cea608ToTt {
state: AtomicRefCell::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "CEA-608 to TT",
- "Generic",
- "Converts CEA-608 Closed Captions to SRT/VTT timed text",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
-
- // WebVTT
- let s = gst::Structure::builder("application/x-subtitle-vtt").build();
- caps.append_structure(s);
-
- // SRT
- let s = gst::Structure::builder("application/x-subtitle").build();
- caps.append_structure(s);
-
- // Raw timed text
- let s = gst::Structure::builder("text/x-raw")
- .field("format", &"utf8")
- .build();
- caps.append_structure(s);
- }
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let caps = gst::Caps::builder("closedcaption/x-cea-608")
- .field("format", &"raw")
- .build();
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for Cea608ToTt {
@@ -473,6 +424,66 @@ impl ObjectImpl for Cea608ToTt {
}
impl ElementImpl for Cea608ToTt {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "CEA-608 to TT",
+ "Generic",
+ "Converts CEA-608 Closed Captions to SRT/VTT timed text",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+
+ // WebVTT
+ let s = gst::Structure::builder("application/x-subtitle-vtt").build();
+ caps.append_structure(s);
+
+ // SRT
+ let s = gst::Structure::builder("application/x-subtitle").build();
+ caps.append_structure(s);
+
+ // Raw timed text
+ let s = gst::Structure::builder("text/x-raw")
+ .field("format", &"utf8")
+ .build();
+ caps.append_structure(s);
+ }
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("closedcaption/x-cea-608")
+ .field("format", &"raw")
+ .build();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/mcc_enc/imp.rs b/video/closedcaption/src/mcc_enc/imp.rs
index dd63bba59..e76eebb74 100644
--- a/video/closedcaption/src/mcc_enc/imp.rs
+++ b/video/closedcaption/src/mcc_enc/imp.rs
@@ -69,27 +69,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("uuid", |name| {
- glib::ParamSpec::string(
- name,
- "UUID",
- "UUID for the output file",
- None,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("creation-date", |name| {
- glib::ParamSpec::boxed(
- name,
- "Creation Date",
- "Creation date for the output file",
- glib::DateTime::static_type(),
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
pub struct MccEnc {
srcpad: gst::Pad,
sinkpad: gst::Pad,
@@ -470,6 +449,7 @@ impl ObjectSubclass for MccEnc {
const NAME: &'static str = "RsMccEnc";
type Type = super::MccEnc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -519,74 +499,45 @@ impl ObjectSubclass for MccEnc {
settings: Mutex::new(Settings::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Mcc Encoder",
- "Encoder/ClosedCaption",
- "Encodes MCC Closed Caption Files",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
-
- let framerates = gst::List::new(&[
- &gst::Fraction::new(24, 1),
- &gst::Fraction::new(25, 1),
- &gst::Fraction::new(30000, 1001),
- &gst::Fraction::new(30, 1),
- &gst::Fraction::new(50, 1),
- &gst::Fraction::new(60000, 1001),
- &gst::Fraction::new(60, 1),
- ]);
-
- let s = gst::Structure::builder("closedcaption/x-cea-708")
- .field("format", &"cdp")
- .field("framerate", &framerates)
- .build();
- caps.append_structure(s);
-
- let s = gst::Structure::builder("closedcaption/x-cea-608")
- .field("format", &"s334-1a")
- .field("framerate", &framerates)
- .build();
- caps.append_structure(s);
- }
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let caps = gst::Caps::builder("application/x-mcc").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for MccEnc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::string(
+ "uuid",
+ "UUID",
+ "UUID for the output file",
+ None,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::boxed(
+ "creation-date",
+ "Creation Date",
+ "Creation date for the output file",
+ glib::DateTime::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("uuid", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "uuid" => {
let mut settings = self.settings.lock().unwrap();
settings.uuid = value.get().expect("type checked upstream");
}
- subclass::Property("creation-date", ..) => {
+ "creation-date" => {
let mut settings = self.settings.lock().unwrap();
settings.creation_date = value.get().expect("type checked upstream");
}
@@ -594,15 +545,13 @@ impl ObjectImpl for MccEnc {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("uuid", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "uuid" => {
let settings = self.settings.lock().unwrap();
settings.uuid.to_value()
}
- subclass::Property("creation-date", ..) => {
+ "creation-date" => {
let settings = self.settings.lock().unwrap();
settings.creation_date.to_value()
}
@@ -619,6 +568,70 @@ impl ObjectImpl for MccEnc {
}
impl ElementImpl for MccEnc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Mcc Encoder",
+ "Encoder/ClosedCaption",
+ "Encodes MCC Closed Caption Files",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+
+ let framerates = gst::List::new(&[
+ &gst::Fraction::new(24, 1),
+ &gst::Fraction::new(25, 1),
+ &gst::Fraction::new(30000, 1001),
+ &gst::Fraction::new(30, 1),
+ &gst::Fraction::new(50, 1),
+ &gst::Fraction::new(60000, 1001),
+ &gst::Fraction::new(60, 1),
+ ]);
+
+ let s = gst::Structure::builder("closedcaption/x-cea-708")
+ .field("format", &"cdp")
+ .field("framerate", &framerates)
+ .build();
+ caps.append_structure(s);
+
+ let s = gst::Structure::builder("closedcaption/x-cea-608")
+ .field("format", &"s334-1a")
+ .field("framerate", &framerates)
+ .build();
+ caps.append_structure(s);
+ }
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-mcc").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/mcc_parse/imp.rs b/video/closedcaption/src/mcc_parse/imp.rs
index 43ddfff06..2c35b33bf 100644
--- a/video/closedcaption/src/mcc_parse/imp.rs
+++ b/video/closedcaption/src/mcc_parse/imp.rs
@@ -1122,6 +1122,7 @@ impl ObjectSubclass for MccParse {
const NAME: &'static str = "RsMccParse";
type Type = super::MccParse;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1184,56 +1185,6 @@ impl ObjectSubclass for MccParse {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Mcc Parse",
- "Parser/ClosedCaption",
- "Parses MCC Closed Caption Files",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
- let framerate = gst::FractionRange::new(
- gst::Fraction::new(1, std::i32::MAX),
- gst::Fraction::new(std::i32::MAX, 1),
- );
-
- let s = gst::Structure::builder("closedcaption/x-cea-708")
- .field("format", &"cdp")
- .field("framerate", &framerate)
- .build();
- caps.append_structure(s);
-
- let s = gst::Structure::builder("closedcaption/x-cea-608")
- .field("format", &"s334-1a")
- .field("framerate", &framerate)
- .build();
- caps.append_structure(s);
- }
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let caps = gst::Caps::builder("application/x-mcc")
- .field("version", &gst::List::new(&[&1i32, &2i32]))
- .build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for MccParse {
@@ -1246,6 +1197,66 @@ impl ObjectImpl for MccParse {
}
impl ElementImpl for MccParse {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Mcc Parse",
+ "Parser/ClosedCaption",
+ "Parses MCC Closed Caption Files",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+ let framerate = gst::FractionRange::new(
+ gst::Fraction::new(1, std::i32::MAX),
+ gst::Fraction::new(std::i32::MAX, 1),
+ );
+
+ let s = gst::Structure::builder("closedcaption/x-cea-708")
+ .field("format", &"cdp")
+ .field("framerate", &framerate)
+ .build();
+ caps.append_structure(s);
+
+ let s = gst::Structure::builder("closedcaption/x-cea-608")
+ .field("format", &"s334-1a")
+ .field("framerate", &framerate)
+ .build();
+ caps.append_structure(s);
+ }
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-mcc")
+ .field("version", &gst::List::new(&[&1i32, &2i32]))
+ .build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/scc_enc/imp.rs b/video/closedcaption/src/scc_enc/imp.rs
index bf45bd0c2..caca4d0d5 100644
--- a/video/closedcaption/src/scc_enc/imp.rs
+++ b/video/closedcaption/src/scc_enc/imp.rs
@@ -337,6 +337,7 @@ impl ObjectSubclass for SccEnc {
const NAME: &'static str = "RsSccEnc";
type Type = super::SccEnc;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -385,40 +386,6 @@ impl ObjectSubclass for SccEnc {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Scc Encoder",
- "Encoder/ClosedCaption",
- "Encodes SCC Closed Caption Files",
- "Sebastian Dröge <sebastian@centricular.com>, Jordan Petridis <jordan@centricular.com>",
- );
-
- let framerates =
- gst::List::new(&[&gst::Fraction::new(30000, 1001), &gst::Fraction::new(30, 1)]);
- let caps = gst::Caps::builder("closedcaption/x-cea-608")
- .field("format", &"raw")
- .field("framerate", &framerates)
- .build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let caps = gst::Caps::builder("application/x-scc").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- }
}
impl ObjectImpl for SccEnc {
@@ -431,6 +398,50 @@ impl ObjectImpl for SccEnc {
}
impl ElementImpl for SccEnc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Scc Encoder",
+ "Encoder/ClosedCaption",
+ "Encodes SCC Closed Caption Files",
+ "Sebastian Dröge <sebastian@centricular.com>, Jordan Petridis <jordan@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let framerates =
+ gst::List::new(&[&gst::Fraction::new(30000, 1001), &gst::Fraction::new(30, 1)]);
+ let caps = gst::Caps::builder("closedcaption/x-cea-608")
+ .field("format", &"raw")
+ .field("framerate", &framerates)
+ .build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-scc").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/scc_parse/imp.rs b/video/closedcaption/src/scc_parse/imp.rs
index b22562a80..8f5a2d576 100644
--- a/video/closedcaption/src/scc_parse/imp.rs
+++ b/video/closedcaption/src/scc_parse/imp.rs
@@ -1002,6 +1002,7 @@ impl ObjectSubclass for SccParse {
const NAME: &'static str = "RsSccParse";
type Type = super::SccParse;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -1064,41 +1065,6 @@ impl ObjectSubclass for SccParse {
state: Mutex::new(State::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Scc Parse",
- "Parser/ClosedCaption",
- "Parses SCC Closed Caption Files",
- "Sebastian Dröge <sebastian@centricular.com>, Jordan Petridis <jordan@centricular.com>",
- );
-
- let caps = gst::Caps::builder("closedcaption/x-cea-608")
- .field("format", &"raw")
- .field(
- "framerate",
- &gst::List::new(&[&gst::Fraction::new(30000, 1001), &gst::Fraction::new(30, 1)]),
- )
- .build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let caps = gst::Caps::builder("application/x-scc").build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for SccParse {
@@ -1111,6 +1077,54 @@ impl ObjectImpl for SccParse {
}
impl ElementImpl for SccParse {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Scc Parse",
+ "Parser/ClosedCaption",
+ "Parses SCC Closed Caption Files",
+ "Sebastian Dröge <sebastian@centricular.com>, Jordan Petridis <jordan@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::builder("closedcaption/x-cea-608")
+ .field("format", &"raw")
+ .field(
+ "framerate",
+ &gst::List::new(&[
+ &gst::Fraction::new(30000, 1001),
+ &gst::Fraction::new(30, 1),
+ ]),
+ )
+ .build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-scc").build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/tttocea608/imp.rs b/video/closedcaption/src/tttocea608/imp.rs
index ebb9aa731..cab504e4e 100644
--- a/video/closedcaption/src/tttocea608/imp.rs
+++ b/video/closedcaption/src/tttocea608/imp.rs
@@ -95,17 +95,6 @@ const DEFAULT_FPS_D: i32 = 1;
const DEFAULT_MODE: Cea608Mode = Cea608Mode::RollUp2;
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("mode", |name| {
- glib::ParamSpec::enum_(
- name,
- "Mode",
- "Which mode to operate in",
- Cea608Mode::static_type(),
- DEFAULT_MODE as i32,
- glib::ParamFlags::READWRITE,
- )
-})];
-
#[derive(Debug, Clone)]
struct Settings {
mode: Cea608Mode,
@@ -958,6 +947,7 @@ impl ObjectSubclass for TtToCea608 {
const NAME: &'static str = "TtToCea608";
type Type = super::TtToCea608;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -995,61 +985,24 @@ impl ObjectSubclass for TtToCea608 {
settings: Mutex::new(Settings::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "TT to CEA-608",
- "Generic",
- "Converts timed text to CEA-608 Closed Captions",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
-
- let s = gst::Structure::new_empty("text/x-raw");
- caps.append_structure(s);
-
- let s = gst::Structure::builder("application/x-json")
- .field("format", &"cea608")
- .build();
- caps.append_structure(s);
- }
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let framerate = gst::FractionRange::new(
- gst::Fraction::new(1, std::i32::MAX),
- gst::Fraction::new(std::i32::MAX, 1),
- );
-
- let caps = gst::Caps::builder("closedcaption/x-cea-608")
- .field("format", &"raw")
- .field("framerate", &framerate)
- .build();
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for TtToCea608 {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::enum_(
+ "mode",
+ "Mode",
+ "Which mode to operate in",
+ Cea608Mode::static_type(),
+ DEFAULT_MODE as i32,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -1057,11 +1010,15 @@ impl ObjectImpl for TtToCea608 {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("mode", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "mode" => {
let mut settings = self.settings.lock().unwrap();
settings.mode = value
.get_some::<Cea608Mode>()
@@ -1071,11 +1028,9 @@ impl ObjectImpl for TtToCea608 {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("mode", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "mode" => {
let settings = self.settings.lock().unwrap();
settings.mode.to_value()
}
@@ -1085,6 +1040,66 @@ impl ObjectImpl for TtToCea608 {
}
impl ElementImpl for TtToCea608 {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "TT to CEA-608",
+ "Generic",
+ "Converts timed text to CEA-608 Closed Captions",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+
+ let s = gst::Structure::new_empty("text/x-raw");
+ caps.append_structure(s);
+
+ let s = gst::Structure::builder("application/x-json")
+ .field("format", &"cea608")
+ .build();
+ caps.append_structure(s);
+ }
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let framerate = gst::FractionRange::new(
+ gst::Fraction::new(1, std::i32::MAX),
+ gst::Fraction::new(std::i32::MAX, 1),
+ );
+
+ let caps = gst::Caps::builder("closedcaption/x-cea-608")
+ .field("format", &"raw")
+ .field("framerate", &framerate)
+ .build();
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+
fn change_state(
&self,
element: &Self::Type,
diff --git a/video/closedcaption/src/tttojson/imp.rs b/video/closedcaption/src/tttojson/imp.rs
index c31664cd1..659df5bb4 100644
--- a/video/closedcaption/src/tttojson/imp.rs
+++ b/video/closedcaption/src/tttojson/imp.rs
@@ -37,17 +37,6 @@ static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
const DEFAULT_MODE: Cea608Mode = Cea608Mode::RollUp2;
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("mode", |name| {
- glib::ParamSpec::enum_(
- name,
- "Mode",
- "Which mode to operate in",
- Cea608Mode::static_type(),
- DEFAULT_MODE as i32,
- glib::ParamFlags::READWRITE,
- )
-})];
-
#[derive(Debug, Clone)]
struct Settings {
mode: Cea608Mode,
@@ -156,12 +145,54 @@ impl TtToJson {
}
}
-impl ElementImpl for TtToJson {}
+impl ElementImpl for TtToJson {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Timed text to JSON encoder",
+ "Encoder/ClosedCaption",
+ "Encodes Timed Text to JSON",
+ "Mathieu Duponchelle <mathieu@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::builder("text/x-raw")
+ .field("format", &"utf8")
+ .build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("application/x-json").build();
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl ObjectSubclass for TtToJson {
const NAME: &'static str = "RsTtToJson";
type Type = super::TtToJson;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -195,42 +226,24 @@ impl ObjectSubclass for TtToJson {
settings: Mutex::new(Settings::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Timed text to JSON encoder",
- "Encoder/ClosedCaption",
- "Encodes Timed Text to JSON",
- "Mathieu Duponchelle <mathieu@centricular.com>",
- );
-
- let caps = gst::Caps::builder("text/x-raw")
- .field("format", &"utf8")
- .build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let caps = gst::Caps::builder("application/x-json").build();
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for TtToJson {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::enum_(
+ "mode",
+ "Mode",
+ "Which mode to operate in",
+ Cea608Mode::static_type(),
+ DEFAULT_MODE as i32,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
@@ -238,11 +251,15 @@ impl ObjectImpl for TtToJson {
obj.add_pad(&self.srcpad).unwrap();
}
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("mode", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "mode" => {
let mut settings = self.settings.lock().unwrap();
settings.mode = value
.get_some::<Cea608Mode>()
@@ -252,11 +269,9 @@ impl ObjectImpl for TtToJson {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("mode", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "mode" => {
let settings = self.settings.lock().unwrap();
settings.mode.to_value()
}
diff --git a/video/dav1d/src/dav1ddec/imp.rs b/video/dav1d/src/dav1ddec/imp.rs
index fb1a258d0..c17501194 100644
--- a/video/dav1d/src/dav1ddec/imp.rs
+++ b/video/dav1d/src/dav1ddec/imp.rs
@@ -349,6 +349,7 @@ impl ObjectSubclass for Dav1dDec {
const NAME: &'static str = "RsDav1dDec";
type Type = super::Dav1dDec;
type ParentType = gst_video::VideoDecoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -364,54 +365,64 @@ impl ObjectSubclass for Dav1dDec {
}),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "Dav1d AV1 Decoder",
- "Codec/Decoder/Video",
- "Decode AV1 video streams with dav1d",
- "Philippe Normand <philn@igalia.com>",
- );
+impl ObjectImpl for Dav1dDec {}
- let sink_caps = gst::Caps::new_simple("video/x-av1", &[]);
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- ("format", &gst::List::from_owned(video_output_formats())),
- ("width", &gst::IntRange::<i32>::new(1, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(1, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
- ),
- ],
- );
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
+impl ElementImpl for Dav1dDec {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "Dav1d AV1 Decoder",
+ "Codec/Decoder/Video",
+ "Decode AV1 video streams with dav1d",
+ "Philippe Normand <philn@igalia.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
}
-}
-impl ObjectImpl for Dav1dDec {}
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple("video/x-av1", &[]);
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
-impl ElementImpl for Dav1dDec {}
+ let src_caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ ("format", &gst::List::from_owned(video_output_formats())),
+ ("width", &gst::IntRange::<i32>::new(1, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(1, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl VideoDecoderImpl for Dav1dDec {
fn start(&self, element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/video/flavors/src/flvdemux/imp.rs b/video/flavors/src/flvdemux/imp.rs
index 540f6c7ea..6f4b8d553 100644
--- a/video/flavors/src/flvdemux/imp.rs
+++ b/video/flavors/src/flvdemux/imp.rs
@@ -124,6 +124,7 @@ impl ObjectSubclass for FlvDemux {
const NAME: &'static str = "RsFlvDemux";
type Type = super::FlvDemux;
type ParentType = gst::Element;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -176,100 +177,6 @@ impl ObjectSubclass for FlvDemux {
flow_combiner: Mutex::new(gst_base::UniqueFlowCombiner::new()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "FLV Demuxer",
- "Codec/Demuxer",
- "Demuxes FLV Streams",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
-
- caps.append(
- gst::Caps::builder("audio/mpeg")
- .field("mpegversion", &1i32)
- .build(),
- );
- caps.append(
- gst::Caps::builder("audio/x-raw")
- .field("layout", &"interleaved")
- .field("format", &gst::List::new(&[&"U8", &"S16LE"]))
- .build(),
- );
- caps.append(
- gst::Caps::builder("audio/x-adpcm")
- .field("layout", &"swf")
- .build(),
- );
- caps.append(gst::Caps::builder("audio/x-nellymoser").build());
- caps.append(gst::Caps::builder("audio/x-alaw").build());
- caps.append(gst::Caps::builder("audio/x-mulaw").build());
- caps.append(
- gst::Caps::builder("audio/mpeg")
- .field("mpegversion", &4i32)
- .field("framed", &true)
- .field("stream-format", &"raw")
- .build(),
- );
- caps.append(gst::Caps::builder("audio/x-speex").build());
- }
- let audiosrc_pad_template = gst::PadTemplate::new(
- "audio",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(audiosrc_pad_template);
-
- let mut caps = gst::Caps::new_empty();
- {
- let caps = caps.get_mut().unwrap();
-
- caps.append(
- gst::Caps::builder("video/x-flash-video")
- .field("flvversion", &1i32)
- .build(),
- );
- caps.append(gst::Caps::builder("video/x-flash-screen").build());
- caps.append(gst::Caps::builder("video/x-vp6-flash").build());
- caps.append(gst::Caps::builder("video/x-vp6-flash-alpha").build());
- caps.append(gst::Caps::builder("video/x-flash-screen2").build());
- caps.append(
- gst::Caps::builder("video/x-h264")
- .field("stream-format", &"avc")
- .build(),
- );
- caps.append(gst::Caps::builder("video/x-h263").build());
- caps.append(
- gst::Caps::builder("video/mpeg")
- .field("mpegversion", &4i32)
- .build(),
- );
- }
- let videosrc_pad_template = gst::PadTemplate::new(
- "video",
- gst::PadDirection::Src,
- gst::PadPresence::Sometimes,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(videosrc_pad_template);
-
- let caps = gst::Caps::builder("video/x-flv").build();
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
- }
}
impl ObjectImpl for FlvDemux {
@@ -280,7 +187,114 @@ impl ObjectImpl for FlvDemux {
}
}
-impl ElementImpl for FlvDemux {}
+impl ElementImpl for FlvDemux {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "FLV Demuxer",
+ "Codec/Demuxer",
+ "Demuxes FLV Streams",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+
+ caps.append(
+ gst::Caps::builder("audio/mpeg")
+ .field("mpegversion", &1i32)
+ .build(),
+ );
+ caps.append(
+ gst::Caps::builder("audio/x-raw")
+ .field("layout", &"interleaved")
+ .field("format", &gst::List::new(&[&"U8", &"S16LE"]))
+ .build(),
+ );
+ caps.append(
+ gst::Caps::builder("audio/x-adpcm")
+ .field("layout", &"swf")
+ .build(),
+ );
+ caps.append(gst::Caps::builder("audio/x-nellymoser").build());
+ caps.append(gst::Caps::builder("audio/x-alaw").build());
+ caps.append(gst::Caps::builder("audio/x-mulaw").build());
+ caps.append(
+ gst::Caps::builder("audio/mpeg")
+ .field("mpegversion", &4i32)
+ .field("framed", &true)
+ .field("stream-format", &"raw")
+ .build(),
+ );
+ caps.append(gst::Caps::builder("audio/x-speex").build());
+ }
+ let audiosrc_pad_template = gst::PadTemplate::new(
+ "audio",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &caps,
+ )
+ .unwrap();
+
+ let mut caps = gst::Caps::new_empty();
+ {
+ let caps = caps.get_mut().unwrap();
+
+ caps.append(
+ gst::Caps::builder("video/x-flash-video")
+ .field("flvversion", &1i32)
+ .build(),
+ );
+ caps.append(gst::Caps::builder("video/x-flash-screen").build());
+ caps.append(gst::Caps::builder("video/x-vp6-flash").build());
+ caps.append(gst::Caps::builder("video/x-vp6-flash-alpha").build());
+ caps.append(gst::Caps::builder("video/x-flash-screen2").build());
+ caps.append(
+ gst::Caps::builder("video/x-h264")
+ .field("stream-format", &"avc")
+ .build(),
+ );
+ caps.append(gst::Caps::builder("video/x-h263").build());
+ caps.append(
+ gst::Caps::builder("video/mpeg")
+ .field("mpegversion", &4i32)
+ .build(),
+ );
+ }
+ let videosrc_pad_template = gst::PadTemplate::new(
+ "video",
+ gst::PadDirection::Src,
+ gst::PadPresence::Sometimes,
+ &caps,
+ )
+ .unwrap();
+
+ let caps = gst::Caps::builder("video/x-flv").build();
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![
+ audiosrc_pad_template,
+ videosrc_pad_template,
+ sink_pad_template,
+ ]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl FlvDemux {
fn sink_activate(
diff --git a/video/gif/src/gifenc/imp.rs b/video/gif/src/gifenc/imp.rs
index effcd020a..c97a6ee34 100644
--- a/video/gif/src/gifenc/imp.rs
+++ b/video/gif/src/gifenc/imp.rs
@@ -81,18 +81,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 1] = [subclass::Property("repeat", |name| {
- glib::ParamSpec::int(
- name,
- "Repeat",
- "Repeat (-1 to loop forever, 0 .. n finite repetitions)",
- -1,
- std::u16::MAX as i32,
- DEFAULT_REPEAT,
- glib::ParamFlags::READWRITE,
- )
-})];
-
struct State {
video_info: gst_video::VideoInfo,
cache: Arc<CacheBuffer>,
@@ -146,6 +134,7 @@ impl ObjectSubclass for GifEnc {
const NAME: &'static str = "GifEnc";
type Type = super::GifEnc;
type ParentType = gst_video::VideoEncoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -157,69 +146,34 @@ impl ObjectSubclass for GifEnc {
settings: Mutex::new(Default::default()),
}
}
-
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "GIF encoder",
- "Encoder/Video",
- "GIF encoder",
- "Markus Ebner <info@ebner-markus.de>",
- );
-
- let sink_caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_video::VideoFormat::Rgb.to_str(),
- &gst_video::VideoFormat::Rgba.to_str(),
- ]),
- ),
- ("width", &gst::IntRange::<i32>::new(1, std::u16::MAX as i32)),
- (
- "height",
- &gst::IntRange::<i32>::new(1, std::u16::MAX as i32),
- ),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(1, 1),
- // frame-delay timing in gif is a multiple of 10ms -> max 100fps
- gst::Fraction::new(100, 1),
- ),
- ),
- ],
- );
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple("image/gif", &[]);
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
}
impl ObjectImpl for GifEnc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::int(
+ "repeat",
+ "Repeat",
+ "Repeat (-1 to loop forever, 0 .. n finite repetitions)",
+ -1,
+ std::u16::MAX as i32,
+ DEFAULT_REPEAT,
+ glib::ParamFlags::READWRITE,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("repeat", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "repeat" => {
let mut settings = self.settings.lock().unwrap();
settings.repeat = value.get_some().expect("type checked upstream");
}
@@ -227,11 +181,9 @@ impl ObjectImpl for GifEnc {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("repeat", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "repeat" => {
let settings = self.settings.lock().unwrap();
settings.repeat.to_value()
}
@@ -240,7 +192,70 @@ impl ObjectImpl for GifEnc {
}
}
-impl ElementImpl for GifEnc {}
+impl ElementImpl for GifEnc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "GIF encoder",
+ "Encoder/Video",
+ "GIF encoder",
+ "Markus Ebner <info@ebner-markus.de>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_video::VideoFormat::Rgb.to_str(),
+ &gst_video::VideoFormat::Rgba.to_str(),
+ ]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(1, std::u16::MAX as i32)),
+ (
+ "height",
+ &gst::IntRange::<i32>::new(1, std::u16::MAX as i32),
+ ),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(1, 1),
+ // frame-delay timing in gif is a multiple of 10ms -> max 100fps
+ gst::Fraction::new(100, 1),
+ ),
+ ),
+ ],
+ );
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple("image/gif", &[]);
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl VideoEncoderImpl for GifEnc {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/video/hsv/src/hsvdetector/imp.rs b/video/hsv/src/hsvdetector/imp.rs
index a82400fa0..03e047411 100644
--- a/video/hsv/src/hsvdetector/imp.rs
+++ b/video/hsv/src/hsvdetector/imp.rs
@@ -55,76 +55,6 @@ impl Default for Settings {
}
}
-// Metadata for the properties
-static PROPERTIES: [subclass::Property; 6] = [
- subclass::Property("hue-ref", |name| {
- glib::ParamSpec::float(
- name,
- "Hue reference",
- "Hue reference in degrees",
- f32::MIN,
- f32::MAX,
- DEFAULT_HUE_REF,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("hue-var", |name| {
- glib::ParamSpec::float(
- name,
- "Hue variation",
- "Allowed hue variation from the reference hue angle, in degrees",
- 0.0,
- 180.0,
- DEFAULT_HUE_VAR,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("saturation-ref", |name| {
- glib::ParamSpec::float(
- name,
- "Saturation reference",
- "Reference saturation value",
- 0.0,
- 1.0,
- DEFAULT_SATURATION_REF,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("saturation-var", |name| {
- glib::ParamSpec::float(
- name,
- "Saturation variation",
- "Allowed saturation variation from the reference value",
- 0.0,
- 1.0,
- DEFAULT_SATURATION_VAR,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("value-ref", |name| {
- glib::ParamSpec::float(
- name,
- "Value reference",
- "Reference value value",
- 0.0,
- 1.0,
- DEFAULT_VALUE_REF,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("value-var", |name| {
- glib::ParamSpec::float(
- name,
- "Value variation",
- "Allowed value variation from the reference value",
- 0.0,
- 1.0,
- DEFAULT_VALUE_VAR,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
// Stream-specific state, i.e. video format configuration
struct State {
in_info: gst_video::VideoInfo,
@@ -149,6 +79,7 @@ impl ObjectSubclass for HsvDetector {
const NAME: &'static str = "HsvDetector";
type Type = super::HsvDetector;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -162,90 +93,81 @@ impl ObjectSubclass for HsvDetector {
state: AtomicRefCell::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "HSV detector",
- "Filter/Effect/Converter/Video",
- "Works within the HSV colorspace to mark positive pixels",
- "Julien Bardagi <julien.bardagi@gmail.com>",
- );
-
- // src pad capabilities
- let caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[&gst_video::VideoFormat::Rgba.to_str()]),
+impl ObjectImpl for HsvDetector {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::float(
+ "hue-ref",
+ "Hue reference",
+ "Hue reference in degrees",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_HUE_REF,
+ glib::ParamFlags::READWRITE,
),
- ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
+ glib::ParamSpec::float(
+ "hue-var",
+ "Hue variation",
+ "Allowed hue variation from the reference hue angle, in degrees",
+ 0.0,
+ 180.0,
+ DEFAULT_HUE_VAR,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
-
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- // sink pad capabilities
- let caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[&gst_video::VideoFormat::Rgbx.to_str()]),
+ glib::ParamSpec::float(
+ "saturation-ref",
+ "Saturation reference",
+ "Reference saturation value",
+ 0.0,
+ 1.0,
+ DEFAULT_SATURATION_REF,
+ glib::ParamFlags::READWRITE,
),
- ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
+ glib::ParamSpec::float(
+ "saturation-var",
+ "Saturation variation",
+ "Allowed saturation variation from the reference value",
+ 0.0,
+ 1.0,
+ DEFAULT_SATURATION_VAR,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
+ glib::ParamSpec::float(
+ "value-ref",
+ "Value reference",
+ "Reference value value",
+ 0.0,
+ 1.0,
+ DEFAULT_VALUE_REF,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::float(
+ "value-var",
+ "Value variation",
+ "Allowed value variation from the reference value",
+ 0.0,
+ 1.0,
+ DEFAULT_VALUE_VAR,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::NeverInPlace,
- false,
- false,
- );
+ PROPERTIES.as_ref()
}
-}
-
-impl ObjectImpl for HsvDetector {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
- match *prop {
- subclass::Property("hue-ref", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "hue-ref" => {
let mut settings = self.settings.lock().unwrap();
let hue_ref = value.get_some().expect("type checked upstream");
gst_info!(
@@ -257,7 +179,7 @@ impl ObjectImpl for HsvDetector {
);
settings.hue_ref = hue_ref;
}
- subclass::Property("hue-var", ..) => {
+ "hue-var" => {
let mut settings = self.settings.lock().unwrap();
let hue_var = value.get_some().expect("type checked upstream");
gst_info!(
@@ -269,7 +191,7 @@ impl ObjectImpl for HsvDetector {
);
settings.hue_var = hue_var;
}
- subclass::Property("saturation-ref", ..) => {
+ "saturation-ref" => {
let mut settings = self.settings.lock().unwrap();
let saturation_ref = value.get_some().expect("type checked upstream");
gst_info!(
@@ -281,7 +203,7 @@ impl ObjectImpl for HsvDetector {
);
settings.saturation_ref = saturation_ref;
}
- subclass::Property("saturation-var", ..) => {
+ "saturation-var" => {
let mut settings = self.settings.lock().unwrap();
let saturation_var = value.get_some().expect("type checked upstream");
gst_info!(
@@ -293,7 +215,7 @@ impl ObjectImpl for HsvDetector {
);
settings.saturation_var = saturation_var;
}
- subclass::Property("value-ref", ..) => {
+ "value-ref" => {
let mut settings = self.settings.lock().unwrap();
let value_ref = value.get_some().expect("type checked upstream");
gst_info!(
@@ -305,7 +227,7 @@ impl ObjectImpl for HsvDetector {
);
settings.value_ref = value_ref;
}
- subclass::Property("value-var", ..) => {
+ "value-var" => {
let mut settings = self.settings.lock().unwrap();
let value_var = value.get_some().expect("type checked upstream");
gst_info!(
@@ -323,31 +245,29 @@ impl ObjectImpl for HsvDetector {
// 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: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("hue-ref", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "hue-ref" => {
let settings = self.settings.lock().unwrap();
settings.hue_ref.to_value()
}
- subclass::Property("hue-var", ..) => {
+ "hue-var" => {
let settings = self.settings.lock().unwrap();
settings.hue_var.to_value()
}
- subclass::Property("saturation-ref", ..) => {
+ "saturation-ref" => {
let settings = self.settings.lock().unwrap();
settings.saturation_ref.to_value()
}
- subclass::Property("saturation-var", ..) => {
+ "saturation-var" => {
let settings = self.settings.lock().unwrap();
settings.saturation_var.to_value()
}
- subclass::Property("value-ref", ..) => {
+ "value-ref" => {
let settings = self.settings.lock().unwrap();
settings.value_ref.to_value()
}
- subclass::Property("value-var", ..) => {
+ "value-var" => {
let settings = self.settings.lock().unwrap();
settings.value_var.to_value()
}
@@ -356,9 +276,90 @@ impl ObjectImpl for HsvDetector {
}
}
-impl ElementImpl for HsvDetector {}
+impl ElementImpl for HsvDetector {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "HSV detector",
+ "Filter/Effect/Converter/Video",
+ "Works within the HSV colorspace to mark positive pixels",
+ "Julien Bardagi <julien.bardagi@gmail.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[&gst_video::VideoFormat::Rgba.to_str()]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ // sink pad capabilities
+ let caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[&gst_video::VideoFormat::Rgbx.to_str()]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for HsvDetector {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::NeverInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
fn transform_caps(
&self,
element: &Self::Type,
diff --git a/video/hsv/src/hsvfilter/imp.rs b/video/hsv/src/hsvfilter/imp.rs
index 3329f3cbc..bbbb2180a 100644
--- a/video/hsv/src/hsvfilter/imp.rs
+++ b/video/hsv/src/hsvfilter/imp.rs
@@ -51,65 +51,6 @@ impl Default for Settings {
}
}
-// Metadata for the properties
-static PROPERTIES: [subclass::Property; 5] = [
- subclass::Property("hue-shift", |name| {
- glib::ParamSpec::float(
- name,
- "Hue shift",
- "Hue shifting in degrees",
- f32::MIN,
- f32::MAX,
- DEFAULT_HUE_SHIFT,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("saturation-mul", |name| {
- glib::ParamSpec::float(
- name,
- "Saturation multiplier",
- "Saturation multiplier to apply to the saturation value (before offset)",
- f32::MIN,
- f32::MAX,
- DEFAULT_SATURATION_MUL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("saturation-off", |name| {
- glib::ParamSpec::float(
- name,
- "Saturation offset",
- "Saturation offset to add to the saturation value (after multiplier)",
- f32::MIN,
- f32::MAX,
- DEFAULT_SATURATION_OFF,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("value-mul", |name| {
- glib::ParamSpec::float(
- name,
- "Value multiplier",
- "Value multiplier to apply to the value (before offset)",
- f32::MIN,
- f32::MAX,
- DEFAULT_VALUE_MUL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("value-off", |name| {
- glib::ParamSpec::float(
- name,
- "Value offset",
- "Value offset to add to the value (after multiplier)",
- f32::MIN,
- f32::MAX,
- DEFAULT_VALUE_OFF,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
// Stream-specific state, i.e. video format configuration
struct State {
info: gst_video::VideoInfo,
@@ -133,6 +74,7 @@ impl ObjectSubclass for HsvFilter {
const NAME: &'static str = "HsvFilter";
type Type = super::HsvFilter;
type ParentType = gst_base::BaseTransform;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -146,70 +88,72 @@ impl ObjectSubclass for HsvFilter {
state: AtomicRefCell::new(None),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "HSV filter",
- "Filter/Effect/Converter/Video",
- "Works within the HSV colorspace to apply tranformations to incoming frames",
- "Julien Bardagi <julien.bardagi@gmail.com>",
- );
-
- // src pad capabilities
- let caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[&gst_video::VideoFormat::Rgbx.to_str()]),
+impl ObjectImpl for HsvFilter {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::float(
+ "hue-shift",
+ "Hue shift",
+ "Hue shifting in degrees",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_HUE_SHIFT,
+ glib::ParamFlags::READWRITE,
),
- ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(i32::MAX, 1),
- ),
+ glib::ParamSpec::float(
+ "saturation-mul",
+ "Saturation multiplier",
+ "Saturation multiplier to apply to the saturation value (before offset)",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_SATURATION_MUL,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
+ glib::ParamSpec::float(
+ "saturation-off",
+ "Saturation offset",
+ "Saturation offset to add to the saturation value (after multiplier)",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_SATURATION_OFF,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::float(
+ "value-mul",
+ "Value multiplier",
+ "Value multiplier to apply to the value (before offset)",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_VALUE_MUL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::float(
+ "value-off",
+ "Value offset",
+ "Value offset to add to the value (after multiplier)",
+ f32::MIN,
+ f32::MAX,
+ DEFAULT_VALUE_OFF,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- // Install all our properties
- klass.install_properties(&PROPERTIES);
-
- klass.configure(
- gst_base::subclass::BaseTransformMode::AlwaysInPlace,
- false,
- false,
- );
+ PROPERTIES.as_ref()
}
-}
-impl ObjectImpl for HsvFilter {
- fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("hue-shift", ..) => {
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "hue-shift" => {
let mut settings = self.settings.lock().unwrap();
let hue_shift = value.get_some().expect("type checked upstream");
gst_info!(
@@ -221,7 +165,7 @@ impl ObjectImpl for HsvFilter {
);
settings.hue_shift = hue_shift;
}
- subclass::Property("saturation-mul", ..) => {
+ "saturation-mul" => {
let mut settings = self.settings.lock().unwrap();
let saturation_mul = value.get_some().expect("type checked upstream");
gst_info!(
@@ -233,7 +177,7 @@ impl ObjectImpl for HsvFilter {
);
settings.saturation_mul = saturation_mul;
}
- subclass::Property("saturation-off", ..) => {
+ "saturation-off" => {
let mut settings = self.settings.lock().unwrap();
let saturation_off = value.get_some().expect("type checked upstream");
gst_info!(
@@ -245,7 +189,7 @@ impl ObjectImpl for HsvFilter {
);
settings.saturation_off = saturation_off;
}
- subclass::Property("value-mul", ..) => {
+ "value-mul" => {
let mut settings = self.settings.lock().unwrap();
let value_mul = value.get_some().expect("type checked upstream");
gst_info!(
@@ -257,7 +201,7 @@ impl ObjectImpl for HsvFilter {
);
settings.value_mul = value_mul;
}
- subclass::Property("value-off", ..) => {
+ "value-off" => {
let mut settings = self.settings.lock().unwrap();
let value_off = value.get_some().expect("type checked upstream");
gst_info!(
@@ -275,27 +219,25 @@ impl ObjectImpl for HsvFilter {
// 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: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("hue-shift", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "hue-shift" => {
let settings = self.settings.lock().unwrap();
settings.hue_shift.to_value()
}
- subclass::Property("saturation-mul", ..) => {
+ "saturation-mul" => {
let settings = self.settings.lock().unwrap();
settings.saturation_mul.to_value()
}
- subclass::Property("saturation-off", ..) => {
+ "saturation-off" => {
let settings = self.settings.lock().unwrap();
settings.saturation_off.to_value()
}
- subclass::Property("value-mul", ..) => {
+ "value-mul" => {
let settings = self.settings.lock().unwrap();
settings.value_mul.to_value()
}
- subclass::Property("value-off", ..) => {
+ "value-off" => {
let settings = self.settings.lock().unwrap();
settings.value_off.to_value()
}
@@ -304,9 +246,71 @@ impl ObjectImpl for HsvFilter {
}
}
-impl ElementImpl for HsvFilter {}
+impl ElementImpl for HsvFilter {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "HSV filter",
+ "Filter/Effect/Converter/Video",
+ "Works within the HSV colorspace to apply tranformations to incoming frames",
+ "Julien Bardagi <julien.bardagi@gmail.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ // src pad capabilities
+ let caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[&gst_video::VideoFormat::Rgbx.to_str()]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(0, i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl BaseTransformImpl for HsvFilter {
+ const MODE: gst_base::subclass::BaseTransformMode =
+ gst_base::subclass::BaseTransformMode::AlwaysInPlace;
+ const PASSTHROUGH_ON_SAME_CAPS: bool = false;
+ const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
+
fn get_unit_size(&self, _element: &Self::Type, caps: &gst::Caps) -> Option<usize> {
gst_video::VideoInfo::from_caps(caps)
.map(|info| info.size())
diff --git a/video/rav1e/src/rav1enc/imp.rs b/video/rav1e/src/rav1enc/imp.rs
index be43ee4d4..2974a662f 100644
--- a/video/rav1e/src/rav1enc/imp.rs
+++ b/video/rav1e/src/rav1enc/imp.rs
@@ -60,117 +60,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 10] = [
- subclass::Property("speed-preset", |name| {
- glib::ParamSpec::uint(
- name,
- "Speed Preset",
- "Speed preset (10 fastest, 0 slowest)",
- 0,
- 10,
- DEFAULT_SPEED_PRESET,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("low-latency", |name| {
- glib::ParamSpec::boolean(
- name,
- "Low Latency",
- "Low Latency",
- DEFAULT_LOW_LATENCY,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("min-key-frame-interval", |name| {
- glib::ParamSpec::uint64(
- name,
- "Min Key Frame Interval",
- "Min Key Frame Interval",
- 0,
- std::u64::MAX,
- DEFAULT_MIN_KEY_FRAME_INTERVAL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("max-key-frame-interval", |name| {
- glib::ParamSpec::uint64(
- name,
- "Max Key Frame Interval",
- "Max Key Frame Interval",
- 0,
- std::u64::MAX,
- DEFAULT_MAX_KEY_FRAME_INTERVAL,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("bitrate", |name| {
- glib::ParamSpec::int(
- name,
- "Bitrate",
- "Bitrate",
- 0,
- std::i32::MAX,
- DEFAULT_BITRATE,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("quantizer", |name| {
- glib::ParamSpec::uint(
- name,
- "Quantizer",
- "Quantizer",
- 0,
- std::u32::MAX,
- DEFAULT_QUANTIZER as u32,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("tile-cols", |name| {
- glib::ParamSpec::uint(
- name,
- "Tile Cols",
- "Tile Cols",
- 0,
- std::u32::MAX,
- DEFAULT_TILE_COLS as u32,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("tile-rows", |name| {
- glib::ParamSpec::uint(
- name,
- "Tile Rows",
- "Tile Rows",
- 0,
- std::u32::MAX,
- DEFAULT_TILE_ROWS as u32,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("tiles", |name| {
- glib::ParamSpec::uint(
- name,
- "Tiles",
- "Tiles",
- 0,
- std::u32::MAX,
- DEFAULT_TILES as u32,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("threads", |name| {
- glib::ParamSpec::uint(
- name,
- "Threads",
- "Threads",
- 0,
- std::u32::MAX,
- DEFAULT_THREADS as u32,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
enum Context {
Eight(rav1e::Context<u8>),
Sixteen(rav1e::Context<u16>),
@@ -319,6 +208,7 @@ impl ObjectSubclass for Rav1Enc {
const NAME: &'static str = "Rav1Enc";
type Type = super::Rav1Enc;
type ParentType = gst_video::VideoEncoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -330,112 +220,154 @@ impl ObjectSubclass for Rav1Enc {
settings: Mutex::new(Default::default()),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "rav1e AV1 encoder",
- "Encoder/Video",
- "rav1e AV1 encoder",
- "Sebastian Dröge <sebastian@centricular.com>",
- );
-
- let sink_caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_video::VideoFormat::I420.to_str(),
- &gst_video::VideoFormat::Y42b.to_str(),
- &gst_video::VideoFormat::Y444.to_str(),
- &gst_video::VideoFormat::I42010le.to_str(),
- &gst_video::VideoFormat::I42210le.to_str(),
- &gst_video::VideoFormat::Y44410le.to_str(),
- &gst_video::VideoFormat::I42012le.to_str(),
- &gst_video::VideoFormat::I42212le.to_str(),
- &gst_video::VideoFormat::Y44412le.to_str(),
- // &gst_video::VideoFormat::Gray8.to_str(),
- ]),
+impl ObjectImpl for Rav1Enc {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::uint(
+ "speed-preset",
+ "Speed Preset",
+ "Speed preset (10 fastest, 0 slowest)",
+ 0,
+ 10,
+ DEFAULT_SPEED_PRESET,
+ glib::ParamFlags::READWRITE,
),
- ("width", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(0, 1),
- gst::Fraction::new(std::i32::MAX, 1),
- ),
+ glib::ParamSpec::boolean(
+ "low-latency",
+ "Low Latency",
+ "Low Latency",
+ DEFAULT_LOW_LATENCY,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple("video/x-av1", &[]);
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
-
- klass.install_properties(&PROPERTIES);
- }
-}
+ glib::ParamSpec::uint64(
+ "min-key-frame-interval",
+ "Min Key Frame Interval",
+ "Min Key Frame Interval",
+ 0,
+ std::u64::MAX,
+ DEFAULT_MIN_KEY_FRAME_INTERVAL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint64(
+ "max-key-frame-interval",
+ "Max Key Frame Interval",
+ "Max Key Frame Interval",
+ 0,
+ std::u64::MAX,
+ DEFAULT_MAX_KEY_FRAME_INTERVAL,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::int(
+ "bitrate",
+ "Bitrate",
+ "Bitrate",
+ 0,
+ std::i32::MAX,
+ DEFAULT_BITRATE,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "quantizer",
+ "Quantizer",
+ "Quantizer",
+ 0,
+ std::u32::MAX,
+ DEFAULT_QUANTIZER as u32,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "tile-cols",
+ "Tile Cols",
+ "Tile Cols",
+ 0,
+ std::u32::MAX,
+ DEFAULT_TILE_COLS as u32,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "tile-rows",
+ "Tile Rows",
+ "Tile Rows",
+ 0,
+ std::u32::MAX,
+ DEFAULT_TILE_ROWS as u32,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "tiles",
+ "Tiles",
+ "Tiles",
+ 0,
+ std::u32::MAX,
+ DEFAULT_TILES as u32,
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::uint(
+ "threads",
+ "Threads",
+ "Threads",
+ 0,
+ std::u32::MAX,
+ DEFAULT_THREADS as u32,
+ glib::ParamFlags::READWRITE,
+ ),
+ ]
+ });
-impl ObjectImpl for Rav1Enc {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("speed-preset", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "speed-preset" => {
let mut settings = self.settings.lock().unwrap();
settings.speed_preset = value.get_some().expect("type checked upstream");
}
- subclass::Property("low-latency", ..) => {
+ "low-latency" => {
let mut settings = self.settings.lock().unwrap();
settings.low_latency = value.get_some().expect("type checked upstream");
}
- subclass::Property("min-key-frame-interval", ..) => {
+ "min-key-frame-interval" => {
let mut settings = self.settings.lock().unwrap();
settings.min_key_frame_interval = value.get_some().expect("type checked upstream");
}
- subclass::Property("max-key-frame-interval", ..) => {
+ "max-key-frame-interval" => {
let mut settings = self.settings.lock().unwrap();
settings.max_key_frame_interval = value.get_some().expect("type checked upstream");
}
- subclass::Property("bitrate", ..) => {
+ "bitrate" => {
let mut settings = self.settings.lock().unwrap();
settings.bitrate = value.get_some().expect("type checked upstream");
}
- subclass::Property("quantizer", ..) => {
+ "quantizer" => {
let mut settings = self.settings.lock().unwrap();
settings.quantizer =
value.get_some::<u32>().expect("type checked upstream") as usize;
}
- subclass::Property("tile-cols", ..) => {
+ "tile-cols" => {
let mut settings = self.settings.lock().unwrap();
settings.tile_cols =
value.get_some::<u32>().expect("type checked upstream") as usize;
}
- subclass::Property("tile-rows", ..) => {
+ "tile-rows" => {
let mut settings = self.settings.lock().unwrap();
settings.tile_rows =
value.get_some::<u32>().expect("type checked upstream") as usize;
}
- subclass::Property("tiles", ..) => {
+ "tiles" => {
let mut settings = self.settings.lock().unwrap();
settings.tiles = value.get_some::<u32>().expect("type checked upstream") as usize;
}
- subclass::Property("threads", ..) => {
+ "threads" => {
let mut settings = self.settings.lock().unwrap();
settings.threads = value.get_some::<u32>().expect("type checked upstream") as usize;
}
@@ -443,47 +375,45 @@ impl ObjectImpl for Rav1Enc {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("speed-preset", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "speed-preset" => {
let settings = self.settings.lock().unwrap();
settings.speed_preset.to_value()
}
- subclass::Property("low-latency", ..) => {
+ "low-latency" => {
let settings = self.settings.lock().unwrap();
settings.low_latency.to_value()
}
- subclass::Property("min-key-frame-interval", ..) => {
+ "min-key-frame-interval" => {
let settings = self.settings.lock().unwrap();
settings.min_key_frame_interval.to_value()
}
- subclass::Property("max-key-frame-interval", ..) => {
+ "max-key-frame-interval" => {
let settings = self.settings.lock().unwrap();
settings.max_key_frame_interval.to_value()
}
- subclass::Property("bitrate", ..) => {
+ "bitrate" => {
let settings = self.settings.lock().unwrap();
settings.bitrate.to_value()
}
- subclass::Property("quantizer", ..) => {
+ "quantizer" => {
let settings = self.settings.lock().unwrap();
(settings.quantizer as u32).to_value()
}
- subclass::Property("tile-cols", ..) => {
+ "tile-cols" => {
let settings = self.settings.lock().unwrap();
(settings.tile_cols as u32).to_value()
}
- subclass::Property("tile-rows", ..) => {
+ "tile-rows" => {
let settings = self.settings.lock().unwrap();
(settings.tile_rows as u32).to_value()
}
- subclass::Property("tiles", ..) => {
+ "tiles" => {
let settings = self.settings.lock().unwrap();
(settings.tiles as u32).to_value()
}
- subclass::Property("threads", ..) => {
+ "threads" => {
let settings = self.settings.lock().unwrap();
(settings.threads as u32).to_value()
}
@@ -492,7 +422,74 @@ impl ObjectImpl for Rav1Enc {
}
}
-impl ElementImpl for Rav1Enc {}
+impl ElementImpl for Rav1Enc {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "rav1e AV1 encoder",
+ "Encoder/Video",
+ "rav1e AV1 encoder",
+ "Sebastian Dröge <sebastian@centricular.com>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_video::VideoFormat::I420.to_str(),
+ &gst_video::VideoFormat::Y42b.to_str(),
+ &gst_video::VideoFormat::Y444.to_str(),
+ &gst_video::VideoFormat::I42010le.to_str(),
+ &gst_video::VideoFormat::I42210le.to_str(),
+ &gst_video::VideoFormat::Y44410le.to_str(),
+ &gst_video::VideoFormat::I42012le.to_str(),
+ &gst_video::VideoFormat::I42212le.to_str(),
+ &gst_video::VideoFormat::Y44412le.to_str(),
+ // &gst_video::VideoFormat::Gray8.to_str(),
+ ]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(0, 1),
+ gst::Fraction::new(std::i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple("video/x-av1", &[]);
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![src_pad_template, sink_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl VideoEncoderImpl for Rav1Enc {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {
diff --git a/video/rspng/src/pngenc/imp.rs b/video/rspng/src/pngenc/imp.rs
index 068564f1a..42e5854a5 100644
--- a/video/rspng/src/pngenc/imp.rs
+++ b/video/rspng/src/pngenc/imp.rs
@@ -100,29 +100,6 @@ impl Default for Settings {
}
}
-static PROPERTIES: [subclass::Property; 2] = [
- subclass::Property("compression-level", |name| {
- glib::ParamSpec::enum_(
- name,
- "Compression level",
- "Selects the compression algorithm to use",
- CompressionLevel::static_type(),
- DEFAULT_COMPRESSION_LEVEL as i32,
- glib::ParamFlags::READWRITE,
- )
- }),
- subclass::Property("filter", |name| {
- glib::ParamSpec::enum_(
- name,
- "Filter",
- "Selects the filter type to applied",
- FilterType::static_type(),
- DEFAULT_FILTER_TYPE as i32,
- glib::ParamFlags::READWRITE,
- )
- }),
-];
-
struct State {
video_info: gst_video::VideoInfo,
cache: Arc<CacheBuffer>,
@@ -192,6 +169,7 @@ impl ObjectSubclass for PngEncoder {
const NAME: &'static str = "PngEncoder";
type Type = super::PngEncoder;
type ParentType = gst_video::VideoEncoder;
+ type Interfaces = ();
type Instance = gst::subclass::ElementInstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
@@ -203,72 +181,49 @@ impl ObjectSubclass for PngEncoder {
settings: Mutex::new(Default::default()),
}
}
+}
- fn class_init(klass: &mut Self::Class) {
- klass.set_metadata(
- "PNG encoder",
- "Encoder/Video",
- "PNG encoder",
- "Natanael Mojica <neithanmo@gmail>",
- );
-
- let sink_caps = gst::Caps::new_simple(
- "video/x-raw",
- &[
- (
- "format",
- &gst::List::new(&[
- &gst_video::VideoFormat::Gray8.to_str(),
- &gst_video::VideoFormat::Gray16Be.to_str(),
- &gst_video::VideoFormat::Rgb.to_str(),
- &gst_video::VideoFormat::Rgba.to_str(),
- ]),
+impl ObjectImpl for PngEncoder {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::enum_(
+ "compression-level",
+ "Compression level",
+ "Selects the compression algorithm to use",
+ CompressionLevel::static_type(),
+ DEFAULT_COMPRESSION_LEVEL as i32,
+ glib::ParamFlags::READWRITE,
),
- ("width", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- ("height", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
- (
- "framerate",
- &gst::FractionRange::new(
- gst::Fraction::new(1, 1),
- gst::Fraction::new(std::i32::MAX, 1),
- ),
+ glib::ParamSpec::enum_(
+ "filter",
+ "Filter",
+ "Selects the filter type to applied",
+ FilterType::static_type(),
+ DEFAULT_FILTER_TYPE as i32,
+ glib::ParamFlags::READWRITE,
),
- ],
- );
- let sink_pad_template = gst::PadTemplate::new(
- "sink",
- gst::PadDirection::Sink,
- gst::PadPresence::Always,
- &sink_caps,
- )
- .unwrap();
- klass.add_pad_template(sink_pad_template);
-
- let src_caps = gst::Caps::new_simple("image/png", &[]);
- let src_pad_template = gst::PadTemplate::new(
- "src",
- gst::PadDirection::Src,
- gst::PadPresence::Always,
- &src_caps,
- )
- .unwrap();
- klass.add_pad_template(src_pad_template);
- klass.install_properties(&PROPERTIES);
- }
-}
+ ]
+ });
-impl ObjectImpl for PngEncoder {
- fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
- let prop = &PROPERTIES[id];
+ PROPERTIES.as_ref()
+ }
- match *prop {
- subclass::Property("compression-level", ..) => {
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.get_name() {
+ "compression-level" => {
let mut settings = self.settings.lock();
settings.compression = value
.get_some::<CompressionLevel>()
.expect("type checked upstream");
}
- subclass::Property("filter", ..) => {
+ "filter" => {
let mut settings = self.settings.lock();
settings.filter = value
.get_some::<FilterType>()
@@ -278,15 +233,13 @@ impl ObjectImpl for PngEncoder {
}
}
- fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
- let prop = &PROPERTIES[id];
-
- match *prop {
- subclass::Property("compression-level", ..) => {
+ fn get_property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.get_name() {
+ "compression-level" => {
let settings = self.settings.lock();
settings.compression.to_value()
}
- subclass::Property("filter", ..) => {
+ "filter" => {
let settings = self.settings.lock();
settings.filter.to_value()
}
@@ -295,7 +248,68 @@ impl ObjectImpl for PngEncoder {
}
}
-impl ElementImpl for PngEncoder {}
+impl ElementImpl for PngEncoder {
+ fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
+ static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
+ gst::subclass::ElementMetadata::new(
+ "PNG encoder",
+ "Encoder/Video",
+ "PNG encoder",
+ "Natanael Mojica <neithanmo@gmail>",
+ )
+ });
+
+ Some(&*ELEMENT_METADATA)
+ }
+
+ fn pad_templates() -> &'static [gst::PadTemplate] {
+ static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
+ let sink_caps = gst::Caps::new_simple(
+ "video/x-raw",
+ &[
+ (
+ "format",
+ &gst::List::new(&[
+ &gst_video::VideoFormat::Gray8.to_str(),
+ &gst_video::VideoFormat::Gray16Be.to_str(),
+ &gst_video::VideoFormat::Rgb.to_str(),
+ &gst_video::VideoFormat::Rgba.to_str(),
+ ]),
+ ),
+ ("width", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ ("height", &gst::IntRange::<i32>::new(1, std::i32::MAX)),
+ (
+ "framerate",
+ &gst::FractionRange::new(
+ gst::Fraction::new(1, 1),
+ gst::Fraction::new(std::i32::MAX, 1),
+ ),
+ ),
+ ],
+ );
+ let sink_pad_template = gst::PadTemplate::new(
+ "sink",
+ gst::PadDirection::Sink,
+ gst::PadPresence::Always,
+ &sink_caps,
+ )
+ .unwrap();
+
+ let src_caps = gst::Caps::new_simple("image/png", &[]);
+ let src_pad_template = gst::PadTemplate::new(
+ "src",
+ gst::PadDirection::Src,
+ gst::PadPresence::Always,
+ &src_caps,
+ )
+ .unwrap();
+
+ vec![sink_pad_template, src_pad_template]
+ });
+
+ PAD_TEMPLATES.as_ref()
+ }
+}
impl VideoEncoderImpl for PngEncoder {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {