Re: [Spice-devel] [PATCH 2/2] gstreamer-encoder: Use a h/w based encoder with Intel GPUs if possible (v3)
Il giorno lun 2 ott 2023 alle ore 06:41 Vivek Kasireddy ha scritto: > > Once it is determined that an Intel GPU is available/active (after > looking into udev's database), we try to see if there is a h/w > based encoder (element) available (in Gstreamer's registry cache) > for the user selected video codec. In other words, if we find that > the Intel Media SDK Gstreamer plugin (libgstmsdk.so) and associated > libraries (such as va or vaapi) are all installed properly, we add > the appropriate h/w based encoder and post-processor/converter > elements to the pipeline (along with any relevant options) instead > of the s/w based elements. > > For example, if the user selects h264 as the preferred codec format, > msdkh264enc and vapostproc will be preferred instead of x264enc > and videoconvert. > > v2: (addressed some review comments from Frediano) > - Moved the udev helper into spice-common > - Refactored the code to choose plugins in order msdk > va > vaapi > > v3: (Frediano) > - Added relevant encoder options for mjpeg and vp9 codecs (Jin Chung) > > Cc: Frediano Ziglio > Cc: Gerd Hoffmann > Cc: Marc-André Lureau > Cc: Dongwon Kim > Signed-off-by: Vivek Kasireddy > Co-developed-by: Jin Chung Teng > Co-developed-by: Hazwan Arif Mazlan > --- > server/gstreamer-encoder.c | 120 - > 1 file changed, 119 insertions(+), 1 deletion(-) > > diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c > index 1619672a..952c2e87 100644 > --- a/server/gstreamer-encoder.c > +++ b/server/gstreamer-encoder.c > @@ -31,6 +31,7 @@ > #include "red-common.h" > #include "video-encoder.h" > #include "utils.h" > +#include "common/udev.h" > > > #define SPICE_GST_DEFAULT_FPS 30 > @@ -913,6 +914,115 @@ static const gchar* get_gst_codec_name(const > SpiceGstEncoder *encoder) > } > } > > +static const char video_codecs[][8] = { > +{ "" }, > +{ "mjpeg" }, > +{ "vp8" }, > +{ "h264" }, > +{ "vp9" }, > +{ "h265" }, > +}; > + > +static bool gst_features_lookup(const gchar *feature_name) > +{ > +GstRegistry *registry; > +GstPluginFeature *feature; > + > +registry = gst_registry_get(); > +if (!registry) { > +return false; > +} > + > +feature = gst_registry_lookup_feature(registry, feature_name); > +if (!feature) { > +return false; > +} > + > +gst_object_unref(feature); > +return true; > +} > + > +static gchar *find_best_plugin(const gchar *codec_name) > +{ > +const char *plugins[3] = {"msdk", "va", "vaapi"}; > +gchar *feature_name; > +int i; > + > +for (i = 0; i < 3; i++) { > +feature_name = !codec_name ? g_strconcat(plugins[i], "postproc", > NULL) : > + g_strconcat(plugins[i], codec_name, "enc", NULL); > +if (!gst_features_lookup(feature_name)) { > +g_free(feature_name); > +feature_name = NULL; > +continue; > +} > +break; > +} > +return feature_name; > +} > + > +static gchar *get_gstenc_opts(gchar *encoder, const gchar *codec_name) > +{ > +gchar *gstenc_opts; > + > +if (strcmp(codec_name, "mjpeg") == 0) { > +return g_strdup(""); > +} > + > +if (strstr(encoder, "msdk")) { > +if (strcmp(codec_name, "vp9") == 0) { > +gstenc_opts = g_strdup("async-depth=1 b-frames=0 rate-control=3 > target-usage=7"); > +} else { > +gstenc_opts = g_strdup("async-depth=1 rate-control=3 gop-size=1 > tune=16 b-frames=0 target-usage=7 min-qp=15 max-qp=35"); > +} > +} else if (strstr(encoder, "vaapi")) { > +if (strcmp(codec_name, "vp9") == 0) { > +gstenc_opts = g_strdup("tune=3 rate-control=1"); > +} else { > +gstenc_opts = g_strdup("rate-control=cqp max-bframes=0 min-qp=15 > max-qp=35"); > +} > +} else { > +if (strcmp(codec_name, "vp9") == 0) { > +gstenc_opts = g_strdup("min-qp=15 max-qp=35 rate-control=16 > ref-frames=0 target-usage=7"); > +} else { > +gstenc_opts = g_strdup("rate-control=16 b-frames=0 > target-usage=7 min-qp=15 max-qp=35"); > +} > +} > +return gstenc_opts; > +} > + > +static void try_intel_hw_plugins(const gchar *codec_name, gchar **converter, > + gchar **gstenc_name, gchar **gstenc_opts) > +{ > +gchar *encoder, *vpp; > + > +if (strcmp(codec_name, "vp8") == 0) { > +return; > +} > + > +encoder = find_best_plugin(codec_name); > +if (!encoder) { > +return; > +} > +vpp = find_best_plugin(NULL); > +if (!vpp) { > +return; > +} > + > +g_free(*converter); > +g_free(*gstenc_name); > +g_free(*gstenc_opts); > +*gstenc_name = encoder; > +*gstenc_opts = get_gstenc_opts(encoder, codec_name); > + > +if (strstr(vpp, "vaapi")) { > +*converter = g_strconcat(vpp, " ! >
[Spice-devel] [PATCH 2/2] gstreamer-encoder: Use a h/w based encoder with Intel GPUs if possible (v3)
Once it is determined that an Intel GPU is available/active (after looking into udev's database), we try to see if there is a h/w based encoder (element) available (in Gstreamer's registry cache) for the user selected video codec. In other words, if we find that the Intel Media SDK Gstreamer plugin (libgstmsdk.so) and associated libraries (such as va or vaapi) are all installed properly, we add the appropriate h/w based encoder and post-processor/converter elements to the pipeline (along with any relevant options) instead of the s/w based elements. For example, if the user selects h264 as the preferred codec format, msdkh264enc and vapostproc will be preferred instead of x264enc and videoconvert. v2: (addressed some review comments from Frediano) - Moved the udev helper into spice-common - Refactored the code to choose plugins in order msdk > va > vaapi v3: (Frediano) - Added relevant encoder options for mjpeg and vp9 codecs (Jin Chung) Cc: Frediano Ziglio Cc: Gerd Hoffmann Cc: Marc-André Lureau Cc: Dongwon Kim Signed-off-by: Vivek Kasireddy Co-developed-by: Jin Chung Teng Co-developed-by: Hazwan Arif Mazlan --- server/gstreamer-encoder.c | 120 - 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index 1619672a..952c2e87 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -31,6 +31,7 @@ #include "red-common.h" #include "video-encoder.h" #include "utils.h" +#include "common/udev.h" #define SPICE_GST_DEFAULT_FPS 30 @@ -913,6 +914,115 @@ static const gchar* get_gst_codec_name(const SpiceGstEncoder *encoder) } } +static const char video_codecs[][8] = { +{ "" }, +{ "mjpeg" }, +{ "vp8" }, +{ "h264" }, +{ "vp9" }, +{ "h265" }, +}; + +static bool gst_features_lookup(const gchar *feature_name) +{ +GstRegistry *registry; +GstPluginFeature *feature; + +registry = gst_registry_get(); +if (!registry) { +return false; +} + +feature = gst_registry_lookup_feature(registry, feature_name); +if (!feature) { +return false; +} + +gst_object_unref(feature); +return true; +} + +static gchar *find_best_plugin(const gchar *codec_name) +{ +const char *plugins[3] = {"msdk", "va", "vaapi"}; +gchar *feature_name; +int i; + +for (i = 0; i < 3; i++) { +feature_name = !codec_name ? g_strconcat(plugins[i], "postproc", NULL) : + g_strconcat(plugins[i], codec_name, "enc", NULL); +if (!gst_features_lookup(feature_name)) { +g_free(feature_name); +feature_name = NULL; +continue; +} +break; +} +return feature_name; +} + +static gchar *get_gstenc_opts(gchar *encoder, const gchar *codec_name) +{ +gchar *gstenc_opts; + +if (strcmp(codec_name, "mjpeg") == 0) { +return g_strdup(""); +} + +if (strstr(encoder, "msdk")) { +if (strcmp(codec_name, "vp9") == 0) { +gstenc_opts = g_strdup("async-depth=1 b-frames=0 rate-control=3 target-usage=7"); +} else { +gstenc_opts = g_strdup("async-depth=1 rate-control=3 gop-size=1 tune=16 b-frames=0 target-usage=7 min-qp=15 max-qp=35"); +} +} else if (strstr(encoder, "vaapi")) { +if (strcmp(codec_name, "vp9") == 0) { +gstenc_opts = g_strdup("tune=3 rate-control=1"); +} else { +gstenc_opts = g_strdup("rate-control=cqp max-bframes=0 min-qp=15 max-qp=35"); +} +} else { +if (strcmp(codec_name, "vp9") == 0) { +gstenc_opts = g_strdup("min-qp=15 max-qp=35 rate-control=16 ref-frames=0 target-usage=7"); +} else { +gstenc_opts = g_strdup("rate-control=16 b-frames=0 target-usage=7 min-qp=15 max-qp=35"); +} +} +return gstenc_opts; +} + +static void try_intel_hw_plugins(const gchar *codec_name, gchar **converter, + gchar **gstenc_name, gchar **gstenc_opts) +{ +gchar *encoder, *vpp; + +if (strcmp(codec_name, "vp8") == 0) { +return; +} + +encoder = find_best_plugin(codec_name); +if (!encoder) { +return; +} +vpp = find_best_plugin(NULL); +if (!vpp) { +return; +} + +g_free(*converter); +g_free(*gstenc_name); +g_free(*gstenc_opts); +*gstenc_name = encoder; +*gstenc_opts = get_gstenc_opts(encoder, codec_name); + +if (strstr(vpp, "vaapi")) { +*converter = g_strconcat(vpp, " ! video/x-raw(memory:VASurface),format=NV12", NULL); +} else { +*converter = g_strconcat(vpp, " ! video/x-raw(memory:VAMemory),format=NV12", NULL); +} +g_free(vpp); +} + static gchar *get_gst_converter(void) { gchar *converter, *pref_format; @@ -932,7 +1042,7 @@ static gchar *get_gst_converter(void) static gboolean create_pipeline(SpiceGstEncoder *encoder) { gchar* converter =