[Spice-devel] [PATCH spice-streaming-agent] gst-plugin: Allow the instantiation/configuration of multiple plugins
Kevin Pouget
kpouget at redhat.com
Thu Oct 17 11:54:59 UTC 2019
This patch allows the instantiation and the configuration of multiple
GStreamer plugins from the commandline.
One plugin will be instantiated for each 'gst.codec=VALUE' found in
the command line arguments.
A plugin can be instantiated by codec, with the default gstreamer
encoder: 'gst.codec=CODEC_TYPE' (eg, mjpeg/vp8/vp9/...), or with a
codec and an encoder 'gst.codec=CODEC_TYPE=ENCODER'.
A plugin can be configured in different ways (see WantOption()):
- without prefix (eg, framerate=30) for all the plugins,
- with the GStreamer property prefix:
- 'gst.prop=VALUE' for all the GStreamer plugins,
- 'gst.CODEC_TYPE.prop=VALUE' for all the GStreamer plugin using the
given codec type,
- 'gst.ENCODER.prop=VALUE' for the GStreamer plugin using the given
encoder.
The split between ParseOptions and UpdateOptions will later allow live
plugin reconfiguration (ie, without fully relaunching the
spice-streaming-agent).
Signed-off-by: Kevin Pouget <kpouget at redhat.com>
---
src/gst-plugin.cpp | 121 +++++++++++++++++++++++++++++++++++----------
1 file changed, 94 insertions(+), 27 deletions(-)
diff --git a/src/gst-plugin.cpp b/src/gst-plugin.cpp
index 922b90d..4b44d9d 100644
--- a/src/gst-plugin.cpp
+++ b/src/gst-plugin.cpp
@@ -33,7 +33,8 @@ namespace gstreamer_plugin {
struct GstreamerEncoderSettings
{
int fps = 25;
- SpiceVideoCodecType codec = SPICE_VIDEO_CODEC_TYPE_H264;
+ SpiceVideoCodecType codec;
+ std::string codec_name;
std::string encoder;
std::vector<std::pair<std::string, std::string>> prop_pairs;
};
@@ -86,12 +87,14 @@ class GstreamerPlugin final: public Plugin
public:
FrameCapture *CreateCapture() override;
unsigned Rank() override;
- void ParseOptions(const ConfigureOption *options);
+ void ParseOptions(const ConfigureOption *options, const std::string codec_value);
+ void UpdateOptions(const ConfigureOption *options);
SpiceVideoCodecType VideoCodecType() const override {
return settings.codec;
}
private:
GstreamerEncoderSettings settings;
+ bool WantOption(const std::string param_name, const std::string opt_name, bool gst_prfx);
};
GstElement *GstreamerFrameCapture::get_capture_plugin(const GstreamerEncoderSettings &settings)
@@ -420,45 +423,100 @@ unsigned GstreamerPlugin::Rank()
return SoftwareMin;
}
-void GstreamerPlugin::ParseOptions(const ConfigureOption *options)
+bool GstreamerPlugin::WantOption(const std::string param_name, const std::string opt_name,
+ bool gst_prfx)
+{
+ const std::string name;
+ std::vector <std::string> names;
+
+ names.push_back(param_name); // eg. framerate or gst.codec
+ names.push_back(settings.codec_name + "." + param_name); // eg. gst.vp8.prop
+
+ if (!settings.encoder.empty()) {
+ names.push_back(settings.encoder + "." + param_name); // eg. gst.vp8enc.prop
+ }
+
+ for (auto name: names) {
+ if (opt_name == (gst_prfx ? "gst." : "") + name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void GstreamerPlugin::UpdateOptions(const ConfigureOption *options)
{
for (; options->name; ++options) {
const std::string name = options->name;
const std::string value = options->value;
- if (name == "framerate") {
+ if (WantOption("framerate", name, false)) {
try {
settings.fps = std::stoi(value);
+
} catch (const std::exception &e) {
- throw std::runtime_error("Invalid value '" + value + "' for option 'framerate'.");
- }
- } else if (name == "gst.codec") {
- if (value == "h264") {
- settings.codec = SPICE_VIDEO_CODEC_TYPE_H264;
- } else if (value == "vp9") {
- settings.codec = SPICE_VIDEO_CODEC_TYPE_VP9;
- } else if (value == "vp8") {
- settings.codec = SPICE_VIDEO_CODEC_TYPE_VP8;
- } else if (value == "mjpeg") {
- settings.codec = SPICE_VIDEO_CODEC_TYPE_MJPEG;
- } else if (value == "h265") {
- settings.codec = SPICE_VIDEO_CODEC_TYPE_H265;
- } else {
- throw std::runtime_error("Invalid value '" + value + "' for option 'gst.codec'.");
+ throw std::runtime_error("Invalid value '" + value + "' "
+ "for option '" + name + "'.");
}
- } else if (name == "gst.encoder") {
- settings.encoder = value;
- } else if (name == "gst.prop") {
+ } else if (WantOption("prop", name, true)) {
size_t pos = value.find('=');
if (pos == 0 || pos >= value.size() - 1) {
gst_syslog(LOG_WARNING, "Property input is invalid ('%s' Ignored)", value.c_str());
continue;
}
- settings.prop_pairs.push_back(make_pair(value.substr(0, pos), value.substr(pos + 1)));
+ // add or update value in settings array
+ bool already_set = false;
+ const auto &new_name = value.substr(0, pos);
+ const auto &new_value = value.substr(pos + 1);
+
+ for (auto &prop : settings.prop_pairs) {
+ if (prop.first != new_name) {
+ continue;
+ }
+ prop.second = new_value;
+ already_set = true;
+ break;
+ }
+ if (!already_set) {
+ settings.prop_pairs.push_back(make_pair(new_name, new_value));
+ }
}
}
}
+void GstreamerPlugin::ParseOptions(const ConfigureOption *options,
+ const std::string codec_value)
+{
+ const std::string encoder_name;
+ size_t has_encoder = codec_value.find('=');
+
+ if (has_encoder != std::string::npos) {
+ settings.codec_name = codec_value.substr(0, has_encoder);
+ settings.encoder = codec_value.substr(has_encoder + 1);
+
+ } else {
+ settings.codec_name = codec_value;
+ }
+
+ if (settings.codec_name == "mjpeg") {
+ settings.codec = SPICE_VIDEO_CODEC_TYPE_MJPEG;
+ } else if (settings.codec_name == "h264") {
+ settings.codec = SPICE_VIDEO_CODEC_TYPE_H264;
+ } else if (settings.codec_name == "h265") {
+ settings.codec = SPICE_VIDEO_CODEC_TYPE_H265;
+ } else if (settings.codec_name == "vp8") {
+ settings.codec = SPICE_VIDEO_CODEC_TYPE_VP8;
+ } else if (settings.codec_name == "vp9") {
+ settings.codec = SPICE_VIDEO_CODEC_TYPE_VP9;
+ } else {
+ throw std::runtime_error("Invalid value '" + settings.codec_name +
+ "' for option 'gst.codec'.");
+ }
+
+ UpdateOptions(options);
+}
+
}}} //namespace spice::streaming_agent::gstreamer_plugin
using namespace spice::streaming_agent::gstreamer_plugin;
@@ -467,11 +525,20 @@ SPICE_STREAMING_AGENT_PLUGIN(agent)
{
gst_init(nullptr, nullptr);
- auto plugin = std::make_shared<GstreamerPlugin>();
+ bool has_plugins = false;
+ auto options = agent->Options();
+ for (; options->name; ++options) {
+ const std::string name = options->name;
+ const std::string value = options->value;
- plugin->ParseOptions(agent->Options());
+ if (name == "gst.codec") {
+ auto plugin = std::make_shared<GstreamerPlugin>();
- agent->Register(plugin);
+ plugin->ParseOptions(agent->Options(), value);
+ agent->Register(plugin);
+ has_plugins = true;
+ }
+ }
- return true;
+ return has_plugins;
}
--
2.21.0
More information about the Spice-devel
mailing list