Update for glib/gstreamer bindings API changes

This commit is contained in:
Sebastian Dröge 2021-01-21 20:21:29 +02:00
parent 875c3efb91
commit d4ce1a33f2
54 changed files with 5202 additions and 4716 deletions

View file

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

View file

@ -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);
klass.install_properties(&PROPERTIES);
}
}
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,
),
]
});
PROPERTIES.as_ref()
}
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,

View file

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

View file

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

View file

@ -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>",
);
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 ObjectImpl for ClaxonDec {}
impl ElementImpl for ClaxonDec {}
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)
}
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]
});
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

View file

@ -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>",
);
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,
);
}
}
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 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,
),
]
});
PROPERTIES.as_ref()
}
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()?;

View file

@ -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>",
);
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 ObjectImpl for LewtonDec {}
impl ElementImpl for LewtonDec {}
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)
}
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]
});
PAD_TEMPLATES.as_ref()
}
}
impl AudioDecoderImpl for LewtonDec {
fn stop(&self, _element: &Self::Type) -> Result<(), gst::ErrorMessage> {

View file

@ -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()]
}
}

View file

@ -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()]
}
}

View file

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

View file

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

View file

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

View file

@ -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,
),
]
});
match *prop {
subclass::Property("context", ..) => {
PROPERTIES.as_ref()
}
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,

View file

@ -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,
),
]
});
match *prop {
subclass::Property("latency", ..) => {
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()
}
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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,
)]
});
match *prop {
glib::subclass::Property("context", ..) => {
PROPERTIES.as_ref()
}
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,
)]
});
match *prop {
glib::subclass::Property("sender", ..) => {
PROPERTIES.as_ref()
}
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,

View file

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

View file

@ -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>",
);
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);
}
}
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,
),
]
});
PROPERTIES.as_ref()
}
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,

View file

@ -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>",
);
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 S3Sink {
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(
"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) */
),
]
});
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("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> {

View file

@ -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,
)]
});
match *prop {
subclass::Property("uri", ..) => {
PROPERTIES.as_ref()
}
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 {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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),
),
),
],
);
// 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),
),
),
],
);
// 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,
);
}
}
// 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,
),
glib::ParamSpec::uint(
"shift",
"Shift",
"Shift grayscale output (wrapping around)",
0,
255,
DEFAULT_SHIFT,
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("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.
//

View file

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

View file

@ -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,
)]
});
match *prop {
subclass::Property("source", ..) => {
PROPERTIES.as_ref()
}
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,

View file

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

View file

@ -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,
),
]
});
match *prop {
subclass::Property("uri", ..) => {
PROPERTIES.as_ref()
}
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,

View file

@ -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);
klass.install_properties(&PROPERTIES);
}
}
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,
),
]
});
PROPERTIES.as_ref()
}
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,

View file

@ -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,
),
]
});
match *prop {
subclass::Property("record", ..) => {
PROPERTIES.as_ref()
}
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,

View file

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

View file

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

View file

@ -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,
),
]
});
match *prop {
subclass::Property("window", ..) => {
PROPERTIES.as_ref()
}
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,

View file

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

View file

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

View file

@ -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,
),
]
});
match *prop {
subclass::Property("uuid", ..) => {
PROPERTIES.as_ref()
}
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,

View file

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

View file

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

View file

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

View file

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

View file

@ -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()
}

View file

@ -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>",
);
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 ObjectImpl for Dav1dDec {}
impl ElementImpl for Dav1dDec {}
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)
}
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();
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> {

View file

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

View file

@ -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,
)]
});
match *prop {
subclass::Property("repeat", ..) => {
PROPERTIES.as_ref()
}
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> {

View file

@ -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()]),
),
("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();
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()]),
),
("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();
klass.add_pad_template(sink_pad_template);
// Install all our properties
klass.install_properties(&PROPERTIES);
klass.configure(
gst_base::subclass::BaseTransformMode::NeverInPlace,
false,
false,
);
}
}
impl ObjectImpl for HsvDetector {
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::float(
"hue-ref",
"Hue reference",
"Hue reference in degrees",
f32::MIN,
f32::MAX,
DEFAULT_HUE_REF,
glib::ParamFlags::READWRITE,
),
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,
),
glib::ParamSpec::float(
"saturation-ref",
"Saturation reference",
"Reference saturation value",
0.0,
1.0,
DEFAULT_SATURATION_REF,
glib::ParamFlags::READWRITE,
),
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,
),
]
});
match *prop {
subclass::Property("hue-ref", ..) => {
PROPERTIES.as_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,

View file

@ -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()]),
),
("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();
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,
);
}
}
impl ObjectImpl for HsvFilter {
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::float(
"hue-shift",
"Hue shift",
"Hue shifting in degrees",
f32::MIN,
f32::MAX,
DEFAULT_HUE_SHIFT,
glib::ParamFlags::READWRITE,
),
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,
),
]
});
match *prop {
subclass::Property("hue-shift", ..) => {
PROPERTIES.as_ref()
}
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())

View file

@ -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(),
]),
),
("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();
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);
}
}
impl ObjectImpl for Rav1Enc {
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::uint(
"speed-preset",
"Speed Preset",
"Speed preset (10 fastest, 0 slowest)",
0,
10,
DEFAULT_SPEED_PRESET,
glib::ParamFlags::READWRITE,
),
glib::ParamSpec::boolean(
"low-latency",
"Low Latency",
"Low Latency",
DEFAULT_LOW_LATENCY,
glib::ParamFlags::READWRITE,
),
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,
),
]
});
match *prop {
subclass::Property("speed-preset", ..) => {
PROPERTIES.as_ref()
}
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> {

View file

@ -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(),
]),
),
("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();
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];
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,
),
glib::ParamSpec::enum_(
"filter",
"Filter",
"Selects the filter type to applied",
FilterType::static_type(),
DEFAULT_FILTER_TYPE as i32,
glib::ParamFlags::READWRITE,
),
]
});
match *prop {
subclass::Property("compression-level", ..) => {
PROPERTIES.as_ref()
}
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> {