mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-05-20 17:28:49 +00:00
Update for glib/gstreamer bindings API changes
This commit is contained in:
parent
875c3efb91
commit
d4ce1a33f2
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()?;
|
||||
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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()]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Reference in a new issue