[Spice-commits] 3 commits - src/channel-display-gst.c subprojects/spice-common

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 3 08:39:38 UTC 2023


 src/channel-display-gst.c |  238 +++++++++++++++++++++++++++++++++++++++++-----
 subprojects/spice-common  |    2 
 2 files changed, 216 insertions(+), 24 deletions(-)

New commits:
commit a5ff1b1414e6392119f21f3028abbf5828da8f5f
Author: Vivek Kasireddy <vivek.kasireddy at intel.com>
Date:   Wed Nov 1 22:34:24 2023 -0700

    channel-display-gst: Use h/w based decoders with Intel GPUs if possible
    
    We first try to detect if an Intel GPU is available (by looking into
    udev's database) and then probe Gstreamer's registry cache to see
    if there is h/w based decoder (element) available for the incoming
    video codec format. If both these conditions are satisfied (i.e,
    Intel Media SDK Gstreamer plugin (libgstmsdk.so) and associated
    libraries are properly installed), we then create a simple decode
    pipeline using appropriate h/w based decoder and post-processor
    elements instead of relying on playbin -- which may not be able to
    auto-select these elements.
    
    For example, if the incoming codec format is h264, we then create
    a pipeline using msdkh264dec and vaapipostproc elements instead of
    avdec_h264 and videoconvert.
    
    Cc: Frediano Ziglio <freddy77 at gmail.com>
    Cc: Gerd Hoffmann <kraxel at redhat.com>
    Cc: Marc-André Lureau <marcandre.lureau at redhat.com>
    Cc: Dongwon Kim <dongwon.kim at intel.com>
    Signed-off-by: Vivek Kasireddy <vivek.kasireddy at intel.com>
    Signed-off-by: Hazwan Arif Mazlan <hazwan.arif.mazlan at intel.com>
    Signed-off-by: Jin Chung Teng <jin.chung.teng at intel.com>
    Acked-by: Frediano Ziglio <freddy77 at gmail.com>

diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
index 923c7c4..3b372dc 100644
--- a/src/channel-display-gst.c
+++ b/src/channel-display-gst.c
@@ -20,6 +20,7 @@
 #include "spice-common.h"
 #include "spice-channel-priv.h"
 #include "common/recorder.h"
+#include "common/udev.h"
 
 #include "channel-display-priv.h"
 
@@ -492,13 +493,221 @@ deep_element_added_cb(GstBin *pipeline, GstBin *bin, GstElement *element,
     }
 }
 
-static gboolean create_pipeline(SpiceGstDecoder *decoder)
+static gchar *find_best_hw_plugin(const gchar *dec_name)
+{
+    static const char plugins[][8] = {"msdk", "va", "vaapi"};
+    GstRegistry *registry;
+    GstPluginFeature *feature;
+    gchar *feature_name;
+    int i;
+
+    registry = gst_registry_get();
+    if (!registry) {
+        return NULL;
+    }
+
+    for (i = 0; i < G_N_ELEMENTS(plugins); i++) {
+        feature_name = !dec_name ? g_strconcat(plugins[i], "postproc", NULL) :
+                       g_strconcat(plugins[i], dec_name, "dec", NULL);
+        feature = gst_registry_lookup_feature(registry, feature_name);
+        if (!feature) {
+            g_free(feature_name);
+            feature_name = NULL;
+            continue;
+        }
+        gst_object_unref(feature);
+        break;
+    }
+    return feature_name;
+}
+
+static bool launch_pipeline(SpiceGstDecoder *decoder)
 {
     GstBus *bus;
+
+    if (decoder->appsink) {
+        GstAppSinkCallbacks appsink_cbs = { NULL };
+        appsink_cbs.new_sample = new_sample;
+        gst_app_sink_set_callbacks(decoder->appsink, &appsink_cbs, decoder, NULL);
+        gst_app_sink_set_max_buffers(decoder->appsink, MAX_DECODED_FRAMES);
+        gst_app_sink_set_drop(decoder->appsink, FALSE);
+    }
+    bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipeline));
+    gst_bus_add_watch(bus, handle_pipeline_message, decoder);
+    gst_object_unref(bus);
+
+    decoder->clock = gst_pipeline_get_clock(GST_PIPELINE(decoder->pipeline));
+
+    if (gst_element_set_state(decoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+        SPICE_DEBUG("GStreamer error: Unable to set the pipeline to the playing state.");
+        free_pipeline(decoder);
+        return false;
+    }
+
+    return true;
+}
+
+static bool try_intel_hw_pipeline(SpiceGstDecoder *decoder)
+{
+    GstElement *pipeline = NULL, *src = NULL, *sink = NULL;
+    GstElement *parser = NULL, *hw_decoder = NULL, *vpp = NULL;
+    GstCaps *src_caps, *sink_caps;
+    int codec_type = decoder->base.codec_type;
+    const gchar *dec_name = gst_opts[codec_type].name;
+    gchar *hw_dec_name, *vpp_name, *parser_name;
+    bool use_parser;
+
+    use_parser = codec_type == SPICE_VIDEO_CODEC_TYPE_H264 ||
+                 codec_type == SPICE_VIDEO_CODEC_TYPE_H265;
+
+    src = gst_element_factory_make("appsrc", NULL);
+    if (!src) {
+        spice_warning("error upon creation of 'appsrc' element");
+        return false;
+    }
+    sink = gst_element_factory_make("appsink", NULL);
+    if (!sink) {
+        spice_warning("error upon creation of 'appsink' element");
+        goto err;
+    }
+
+    if (use_parser) {
+        parser_name = g_strconcat(dec_name, "parse", NULL);
+        parser = gst_element_factory_make(parser_name, NULL);
+        g_free(parser_name);
+        if (!parser) {
+            spice_warning("error upon creation of 'parser' element");
+            goto err;
+        }
+    }
+
+    hw_dec_name = find_best_hw_plugin(dec_name);
+    if (!hw_dec_name) {
+        spice_warning("error finding suitable plugin for decode");
+        goto err;
+    }
+    hw_decoder = gst_element_factory_make(hw_dec_name, NULL);
+    g_free(hw_dec_name);
+    if (!hw_decoder) {
+        spice_warning("error upon creation of 'decoder' element");
+        goto err;
+    }
+    vpp_name = find_best_hw_plugin(NULL);
+    if (!vpp_name) {
+        spice_warning("error finding suitable plugin for postproc");
+        goto err;
+    }
+    vpp = gst_element_factory_make(vpp_name, NULL);
+    g_free(vpp_name);
+    if (!vpp) {
+        spice_warning("error upon creation of 'vpp' element");
+        goto err;
+    }
+    g_object_set(vpp,
+                 "format", GST_VIDEO_FORMAT_BGRx,
+                 NULL);
+
+    pipeline = gst_pipeline_new(NULL);
+    if (!pipeline) {
+        spice_warning("error upon creation of 'pipeline' element");
+        goto err;
+    }
+
+    src_caps = gst_caps_from_string(gst_opts[codec_type].dec_caps);
+    g_object_set(src,
+                 "caps", src_caps,
+                 "is-live", TRUE,
+                 "format", GST_FORMAT_TIME,
+                 "max-bytes", G_GINT64_CONSTANT(0),
+                 "block", TRUE,
+                 NULL);
+    gst_caps_unref(src_caps);
+    decoder->appsrc = GST_APP_SRC(gst_object_ref(src));
+
+    sink_caps = gst_caps_from_string("video/x-raw,format=BGRx");
+    g_object_set(sink,
+                 "caps", sink_caps,
+                 "sync", FALSE,
+                 "drop", FALSE,
+                 NULL);
+    gst_caps_unref(sink_caps);
+    decoder->appsink = GST_APP_SINK(gst_object_ref(sink));
+
+    if (hand_pipeline_to_widget(decoder->base.stream,
+        GST_PIPELINE(pipeline))) {
+        spice_warning("error handing pipeline to widget");
+        goto err;
+    }
+
+    if (use_parser) {
+        gst_bin_add_many(GST_BIN(pipeline), src, parser, hw_decoder,
+                         vpp, sink, NULL);
+        if (!gst_element_link_many(src, parser, hw_decoder, vpp,
+                                   sink, NULL)) {
+            spice_warning("error linking elements");
+            /* No need to unref these elements anymore as their ownership
+             * would have transferred to the pipeline after gst_bin_add_many().
+             */
+            src = parser = hw_decoder = vpp = sink = NULL;
+            goto err;
+        }
+    } else {
+        gst_bin_add_many(GST_BIN(pipeline), src, hw_decoder,
+                         vpp, sink, NULL);
+        if (!gst_element_link_many(src, hw_decoder, vpp, sink, NULL)) {
+            spice_warning("error linking elements");
+            src = hw_decoder = vpp = sink = NULL;
+            goto err;
+        }
+    }
+
+    decoder->pipeline = pipeline;
+    return launch_pipeline(decoder);
+
+err:
+    if (decoder->appsink) {
+        gst_object_unref(decoder->appsink);
+        decoder->appsink = NULL;
+    }
+    if (decoder->appsrc) {
+        gst_object_unref(decoder->appsrc);
+        decoder->appsrc = NULL;
+    }
+    if (pipeline) {
+        gst_object_unref(pipeline);
+    }
+    if (vpp) {
+        gst_object_unref(vpp);
+    }
+    if (hw_decoder) {
+        gst_object_unref(hw_decoder);
+    }
+    if (parser) {
+        gst_object_unref(parser);
+    }
+    if (sink) {
+        gst_object_unref(sink);
+    }
+    if (src) {
+        gst_object_unref(src);
+    }
+    return false;
+}
+
+static gboolean create_pipeline(SpiceGstDecoder *decoder)
+{
     GstElement *playbin, *sink;
     SpiceGstPlayFlags flags;
     GstCaps *caps;
     static bool playbin3_supported = true;
+    GpuVendor vendor = spice_udev_detect_gpu(INTEL_VENDOR_ID);
+
+    if (vendor == VENDOR_GPU_DETECTED ||
+        vendor == VENDOR_GPU_UNKNOWN) {
+        if (try_intel_hw_pipeline(decoder)) {
+            return TRUE;
+        }
+    }
 
     playbin = playbin3_supported ?
               gst_element_factory_make("playbin3", "playbin") : NULL;
@@ -574,29 +783,9 @@ static gboolean create_pipeline(SpiceGstDecoder *decoder)
     g_warn_if_fail(decoder->appsrc == NULL);
     decoder->pipeline = playbin;
 
-    if (decoder->appsink) {
-        GstAppSinkCallbacks appsink_cbs = { NULL };
-        appsink_cbs.new_sample = new_sample;
-        gst_app_sink_set_callbacks(decoder->appsink, &appsink_cbs, decoder, NULL);
-        gst_app_sink_set_max_buffers(decoder->appsink, MAX_DECODED_FRAMES);
-        gst_app_sink_set_drop(decoder->appsink, FALSE);
-    }
-    bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipeline));
-    gst_bus_add_watch(bus, handle_pipeline_message, decoder);
-    gst_object_unref(bus);
-
-    decoder->clock = gst_pipeline_get_clock(GST_PIPELINE(decoder->pipeline));
-
-    if (gst_element_set_state(decoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
-        SPICE_DEBUG("GStreamer error: Unable to set the pipeline to the playing state.");
-        free_pipeline(decoder);
-        return FALSE;
-    }
-
-    return TRUE;
+    return launch_pipeline(decoder);
 }
 
-
 /* ---------- VideoDecoder's public API ---------- */
 
 static void spice_gst_decoder_reschedule(VideoDecoder *video_decoder)
commit e2bcf5727bfda3dbe3dbaf2f71ee4f4970af4f57
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue Oct 31 11:10:01 2023 +0000

    gstreamer: Avoid dangling pointers in free_pipeline
    
    Although currently after free_pipeline we free the entire structure
    the name and the function suggests that we only free the pipeline.
    Also this is fixing a future possible problem with the series
    from Vivek Kasireddy reusing the SpiceGstDecoder for another
    pipeline if H/W encoder pipeline creation fails.
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>
    Acked-by: Vivek Kasireddy <vivek.kasireddy at intel.com>

diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
index 5c9927b..923c7c4 100644
--- a/src/channel-display-gst.c
+++ b/src/channel-display-gst.c
@@ -353,11 +353,14 @@ static void free_pipeline(SpiceGstDecoder *decoder)
 
     gst_element_set_state(decoder->pipeline, GST_STATE_NULL);
     gst_object_unref(decoder->appsrc);
+    decoder->appsrc = NULL;
     if (decoder->appsink) {
         gst_object_unref(decoder->appsink);
+        decoder->appsink = NULL;
     }
-    gst_object_unref(decoder->pipeline);
     gst_object_unref(decoder->clock);
+    decoder->clock = NULL;
+    gst_object_unref(decoder->pipeline);
     decoder->pipeline = NULL;
 }
 
commit fa9922f39ad82a6020818cc8fa75ac69fb62fb54
Author: Frediano Ziglio <freddy77 at gmail.com>
Date:   Tue Oct 17 10:57:59 2023 +0100

    Update spice-common submodule
    
    This brings in the following changes:
    
    Vivek Kasireddy (1):
          common: Add a udev helper to identify GPU Vendor
    
    Signed-off-by: Frediano Ziglio <freddy77 at gmail.com>

diff --git a/subprojects/spice-common b/subprojects/spice-common
index 58d375e..bb8f669 160000
--- a/subprojects/spice-common
+++ b/subprojects/spice-common
@@ -1 +1 @@
-Subproject commit 58d375e5eadc6fb9e587e99fd81adcb95d01e8d6
+Subproject commit bb8f66983af6b7f38dc80efa6b6ca8f34c2ab85e


More information about the Spice-commits mailing list