[Spice-commits] 2 commits - src/channel-display.c src/channel-display-gst.c src/channel-display-priv.h src/spice-marshal.txt src/spice-widget.c src/spice-widget-priv.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jan 3 13:53:13 UTC 2019


 src/channel-display-gst.c  |   30 ++----------
 src/channel-display-priv.h |    7 ++
 src/channel-display.c      |   42 ++++++++++-------
 src/spice-marshal.txt      |    2 
 src/spice-widget-priv.h    |    7 ++
 src/spice-widget.c         |  108 ++++++++++++++++++++++++++++++++++++++++-----
 6 files changed, 142 insertions(+), 54 deletions(-)

New commits:
commit 0c6d3735620a5d1a82c1c2a5adcc2d6c6f595719
Author: Snir Sheriber <ssheribe at redhat.com>
Date:   Thu Jan 3 15:22:37 2019 +0200

    Gstreamer: fix window resize when using GstVideoOverlay
    
    With previous patch changes it's now possible to call GstVideoOverlay
    interface functions in response to matching gtk events. This patch fixes
    the window resize and possibly other rendering issues.
    
    Signed-off-by: Snir Sheriber <ssheribe at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index e78fab4..3ff5be9 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -120,6 +120,10 @@ static void size_allocate(GtkWidget *widget, GtkAllocation *conf, gpointer data)
 static gboolean draw_event(GtkWidget *widget, cairo_t *cr, gpointer data);
 static void update_size_request(SpiceDisplay *display);
 static GdkDevice *spice_gdk_window_get_pointing_device(GdkWindow *window);
+#ifdef HAVE_GSTVIDEO
+static void gst_size_allocate(GtkWidget *widget, GdkRectangle *a, gpointer data);
+static gboolean gst_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data);
+#endif
 
 /* ---------------------------------------------------------------- */
 
@@ -649,8 +653,14 @@ static void spice_display_init(SpiceDisplay *display)
                      NULL);
     gtk_stack_add_named(d->stack, area, "gl-area");
 #endif
+#ifdef HAVE_GSTVIDEO
     area = gtk_drawing_area_new();
     gtk_stack_add_named(d->stack, area, "gst-area");
+    g_object_connect(area,
+                     "signal::draw", gst_draw_event, display,
+                     "signal::size-allocate", gst_size_allocate, display,
+                     NULL);
+#endif
 
     gtk_widget_show_all(widget);
 
@@ -2582,6 +2592,38 @@ static void gst_sync_bus_call(GstBus *bus, GstMessage *msg, SpiceDisplay *displa
 }
 #endif
 
+#ifdef HAVE_GSTVIDEO
+static gboolean gst_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+    SpiceDisplay *display = SPICE_DISPLAY(data);
+    SpiceDisplayPrivate *d = display->priv;
+    GstVideoOverlay *overlay = g_weak_ref_get(&d->overlay_weak_ref);
+
+    if (overlay) {
+        gst_video_overlay_expose(overlay);
+        gst_object_unref(overlay);
+        update_mouse_pointer(display);
+        return true;
+    }
+    return false;
+}
+
+void gst_size_allocate(GtkWidget *widget, GdkRectangle *a, gpointer data)
+{
+    SpiceDisplay *display = SPICE_DISPLAY(data);
+    SpiceDisplayPrivate *d = display->priv;
+    GstVideoOverlay *overlay = g_weak_ref_get(&d->overlay_weak_ref);
+
+    if (overlay) {
+        gint scale = gtk_widget_get_scale_factor(widget);
+
+        gst_video_overlay_set_render_rectangle(overlay, a->x * scale, a->y * scale,
+                                               a->width * scale, a->height * scale);
+        gst_object_unref(overlay);
+    }
+}
+#endif
+
 /* This callback should pass to the widget a pointer of the pipeline
  * so that we can set pipeline and overlay related calls from here.
  */
commit 8c5bf5dedab3cd5a9c7ac484c0d97d43aeb0056b
Author: Snir Sheriber <ssheribe at redhat.com>
Date:   Thu Jan 3 15:22:36 2019 +0200

    Gstreamer: Control GstVideoOverlay from the widget
    
    This patch is changing the way GstVideoOverlay is being set.
    Once pipeline is created a pointer is passed to the widget using
    GObject signal, so we can set there the overlay interface and call
    its functions from widget callbacks. This allows to solve issues
    like resizing the window.
    
    Signed-off-by: Snir Sheriber <ssheribe at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
index bd2a9ff..2f556fe 100644
--- a/src/channel-display-gst.c
+++ b/src/channel-display-gst.c
@@ -43,8 +43,6 @@ typedef struct SpiceGstDecoder {
     GstElement *pipeline;
     GstClock *clock;
 
-    guintptr win_handle;
-
     /* ---------- Decoding and display queues ---------- */
 
     uint32_t last_mm_time;
@@ -334,20 +332,6 @@ static gboolean handle_pipeline_message(GstBus *bus, GstMessage *msg, gpointer v
         g_free(filename);
         break;
     }
-    case GST_MESSAGE_ELEMENT: {
-        if (gst_is_video_overlay_prepare_window_handle_message(msg)) {
-            GstVideoOverlay *overlay;
-
-            SPICE_DEBUG("prepare-window-handle msg received (handle: %" G_GUINTPTR_FORMAT")",
-                        decoder->win_handle);
-            if (decoder->win_handle != 0) {
-                overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg));
-                gst_video_overlay_set_window_handle(overlay, decoder->win_handle);
-                gst_video_overlay_handle_events(overlay, false);
-            }
-        }
-        break;
-    }
     default:
         /* not being handled */
         break;
@@ -396,14 +380,11 @@ static gboolean create_pipeline(SpiceGstDecoder *decoder)
         return FALSE;
     }
 
-    /* Will try to get window handle in order to apply the GstVideoOverlay
-     * interface, setting overlay to this window will happen only when
-     * prepare-window-handle message is received
+    /* Passing the pipeline to widget, try to get window handle and
+     * set the GstVideoOverlay interface, setting overlay to the window
+     * will happen only when prepare-window-handle message is received
      */
-    decoder->win_handle = get_window_handle(decoder->base.stream);
-    SPICE_DEBUG("Creating Gstreamer pipeline (handle for overlay %s)\n",
-                decoder->win_handle ? "received" : "not received");
-    if (decoder->win_handle == 0) {
+    if (!hand_pipeline_to_widget(decoder->base.stream, GST_PIPELINE(playbin))) {
         sink = gst_element_factory_make("appsink", "sink");
         if (sink == NULL) {
             spice_warning("error upon creation of 'appsink' element");
@@ -432,6 +413,7 @@ static gboolean create_pipeline(SpiceGstDecoder *decoder)
         GstRegistry *registry = NULL;
         GstPluginFeature *vaapisink = NULL;
 
+        SPICE_DEBUG("Video is presented using gstreamer's GstVideoOverlay interface");
         registry = gst_registry_get();
         if (registry) {
             vaapisink = gst_registry_lookup_feature(registry, "vaapisink");
@@ -572,7 +554,7 @@ static void spice_gst_decoder_destroy(VideoDecoder *video_decoder)
  * 3) As soon as the GStreamer pipeline no longer needs the compressed frame it
  *    will call frame->unref_data() to free it.
  *
- * If GstVideoOverlay is used (win_handle was obtained by pipeline creation):
+ * If GstVideoOverlay is used (window handle was obtained successfully at the widget):
  *   4) Decompressed frames will be renderd to widget directly from gstreamer's pipeline
  *      using some gstreamer sink plugin which implements the GstVideoOverlay interface
  *      (last step).
diff --git a/src/channel-display-priv.h b/src/channel-display-priv.h
index de5feea..72ad90f 100644
--- a/src/channel-display-priv.h
+++ b/src/channel-display-priv.h
@@ -31,6 +31,10 @@
 #include "common/quic.h"
 #include "common/rop3.h"
 
+#ifdef HAVE_GSTVIDEO
+#include "gst/gst.h"
+#endif
+
 G_BEGIN_DECLS
 
 typedef struct display_stream display_stream;
@@ -201,6 +205,9 @@ void stream_dropped_frame_on_playback(display_stream *st);
 #define SPICE_UNKNOWN_STRIDE 0
 void stream_display_frame(display_stream *st, SpiceFrame *frame, uint32_t width, uint32_t height, int stride, uint8_t* data);
 guintptr get_window_handle(display_stream *st);
+#ifdef HAVE_GSTVIDEO
+gboolean hand_pipeline_to_widget(display_stream *st,  GstPipeline *pipeline);
+#endif
 
 
 G_END_DECLS
diff --git a/src/channel-display.c b/src/channel-display.c
index fbcaf72..2a1d9d1 100644
--- a/src/channel-display.c
+++ b/src/channel-display.c
@@ -29,6 +29,9 @@
 #include "spice-session-priv.h"
 #include "channel-display-priv.h"
 #include "decode.h"
+#ifdef HAVE_GSTVIDEO
+#include "gst/gst.h"
+#endif
 
 /**
  * SECTION:channel-display
@@ -88,7 +91,7 @@ enum {
     SPICE_DISPLAY_INVALIDATE,
     SPICE_DISPLAY_MARK,
     SPICE_DISPLAY_GL_DRAW,
-    SPICE_DISPLAY_STREAMING_MODE,
+    SPICE_DISPLAY_OVERLAY,
 
     SPICE_DISPLAY_LAST_SIGNAL,
 };
@@ -453,26 +456,27 @@ static void spice_display_channel_class_init(SpiceDisplayChannelClass *klass)
                      G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
 
     /**
-     * SpiceDisplayChannel::streaming-mode:
+     * SpiceDisplayChannel::gst-video-overlay
      * @display: the #SpiceDisplayChannel that emitted the signal
-     * @streaming_mode: %TRUE when it's streaming mode
+     * @pipeline: pointer to gstreamer's pipeline
      *
-     * Return: handle for the display window if possible
+     * Return: valid window handle on success
      *
-     * The #SpiceDisplayChannel::streaming-mode signal is emitted when
-     * spice server is working in streaming mode.
+     * The #SpiceDisplayChannel::gst-video-overlay signal is emitted when
+     * pipeline is ready and can be passed to widget to regeister gstreamer
+     * overlay interface and other gstreamer callbacks.
      *
-     * Since 0.35
+     * Since 0.36
      **/
-    signals[SPICE_DISPLAY_STREAMING_MODE] =
-        g_signal_new("streaming-mode",
+    signals[SPICE_DISPLAY_OVERLAY] =
+        g_signal_new("gst-video-overlay",
                      G_OBJECT_CLASS_TYPE(gobject_class),
                      0, 0,
                      NULL, NULL,
-                     g_cclosure_user_marshal_POINTER__BOOLEAN,
-                     G_TYPE_POINTER,
+                     g_cclosure_user_marshal_BOOLEAN__POINTER,
+                     G_TYPE_BOOLEAN,
                      1,
-                     G_TYPE_BOOLEAN);
+                     GST_TYPE_PIPELINE);
 
     channel_set_handlers(SPICE_CHANNEL_CLASS(klass));
 }
@@ -1391,15 +1395,19 @@ void stream_display_frame(display_stream *st, SpiceFrame *frame,
     }
 }
 
+#ifdef HAVE_GSTVIDEO
 G_GNUC_INTERNAL
-guintptr get_window_handle(display_stream *st)
+gboolean hand_pipeline_to_widget(display_stream *st, GstPipeline *pipeline)
 {
-   void* handle = 0;
+    gboolean res = false;
 
-   g_signal_emit(st->channel, signals[SPICE_DISPLAY_STREAMING_MODE], 0,
-                 st->surface->streaming_mode, &handle);
-   return st->surface->streaming_mode ? (guintptr)handle : 0;
+    if (st->surface->streaming_mode) {
+        g_signal_emit(st->channel, signals[SPICE_DISPLAY_OVERLAY], 0,
+                      pipeline, &res);
+    }
+    return res;
 }
+#endif
 
 /* after a sequence of 3 drops, push a report to the server, even
  * if the report window is bigger */
diff --git a/src/spice-marshal.txt b/src/spice-marshal.txt
index b3a8e69..92087c5 100644
--- a/src/spice-marshal.txt
+++ b/src/spice-marshal.txt
@@ -13,4 +13,4 @@ BOOLEAN:UINT,POINTER,UINT
 BOOLEAN:UINT,UINT
 VOID:OBJECT,OBJECT
 VOID:BOXED,BOXED
-POINTER:BOOLEAN
+BOOLEAN:POINTER
diff --git a/src/spice-widget-priv.h b/src/spice-widget-priv.h
index 96f6c1d..0264577 100644
--- a/src/spice-widget-priv.h
+++ b/src/spice-widget-priv.h
@@ -32,6 +32,10 @@
 #include "spice-common.h"
 #include "spice-gtk-session.h"
 
+#ifdef HAVE_GSTVIDEO
+#include <gst/video/videooverlay.h>
+#endif
+
 G_BEGIN_DECLS
 
 #define DISPLAY_DEBUG(display, fmt, ...) \
@@ -149,6 +153,9 @@ struct _SpiceDisplayPrivate {
     } egl;
 #endif // HAVE_EGL
     double scroll_delta_y;
+#ifdef HAVE_GSTVIDEO
+    GWeakRef overlay_weak_ref;
+#endif
 };
 
 int      spice_cairo_image_create                 (SpiceDisplay *display);
diff --git a/src/spice-widget.c b/src/spice-widget.c
index 9bb4221..e78fab4 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -2115,10 +2115,16 @@ static void realize(GtkWidget *widget)
 
 static void unrealize(GtkWidget *widget)
 {
-    spice_cairo_image_destroy(SPICE_DISPLAY(widget));
+    SpiceDisplay *display = SPICE_DISPLAY(widget);
+
+    spice_cairo_image_destroy(display);
 #if HAVE_EGL
-    if (SPICE_DISPLAY(widget)->priv->egl.context_ready)
-        spice_egl_unrealize_display(SPICE_DISPLAY(widget));
+    if (display->priv->egl.context_ready) {
+        spice_egl_unrealize_display(display);
+    }
+#endif
+#ifdef HAVE_GSTVIDEO
+    g_weak_ref_set(&display->priv->overlay_weak_ref, NULL);
 #endif
 
     GTK_WIDGET_CLASS(spice_display_parent_class)->unrealize(widget);
@@ -2547,26 +2553,62 @@ static void queue_draw_area(SpiceDisplay *display, gint x, gint y,
                                x, y, width, height);
 }
 
-static void* prepare_streaming_mode(SpiceChannel *channel, bool streaming_mode, gpointer data)
+#if defined(HAVE_GSTVIDEO) && defined(GDK_WINDOWING_X11)
+static void gst_sync_bus_call(GstBus *bus, GstMessage *msg, SpiceDisplay *display)
 {
-#ifdef GDK_WINDOWING_X11
-    SpiceDisplay *display = data;
+    switch(GST_MESSAGE_TYPE(msg)) {
+    case GST_MESSAGE_ELEMENT: {
+        if (gst_is_video_overlay_prepare_window_handle_message(msg) &&
+            !g_getenv("DISABLE_GSTVIDEOOVERLAY") &&
+            GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
+            GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(display));
+
+            if (window && gdk_window_ensure_native(window)) {
+                SpiceDisplayPrivate *d = display->priv;
+
+                GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg));
+                g_weak_ref_set(&d->overlay_weak_ref, overlay);
+                gst_video_overlay_set_window_handle(overlay, (uintptr_t)GDK_WINDOW_XID(window));
+                gst_video_overlay_handle_events(overlay, false);
+                return;
+            }
+        }
+        break;
+    }
+    default:
+        /* not being handled */
+        break;
+    }
+}
+#endif
+
+/* This callback should pass to the widget a pointer of the pipeline
+ * so that we can set pipeline and overlay related calls from here.
+ */
+static gboolean set_overlay(SpiceChannel *channel, void* pipeline_ptr, SpiceDisplay *display)
+{
+#if defined(HAVE_GSTVIDEO) && defined(GDK_WINDOWING_X11)
     SpiceDisplayPrivate *d = display->priv;
 
-    /* GstVideoOverlay will currently be used only under x */
+    /* GstVideoOverlay is currently used only under x */
     if (!g_getenv("DISABLE_GSTVIDEOOVERLAY") &&
-        streaming_mode &&
         GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
         GdkWindow *window;
 
         window = gtk_widget_get_window(GTK_WIDGET(display));
         if (window && gdk_window_ensure_native(window)) {
+            GstBus *bus;
+
             gtk_stack_set_visible_child_name(d->stack, "gst-area");
-            return (void*)(uintptr_t)GDK_WINDOW_XID(window);
+            bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_ptr));
+            gst_bus_enable_sync_message_emission(bus);
+            g_signal_connect(bus, "sync-message", G_CALLBACK(gst_sync_bus_call), display);
+            gst_object_unref(bus);
+            return true;
         }
     }
 #endif
-    return NULL;
+    return false;
 }
 
 static void invalidate(SpiceChannel *channel,
@@ -2936,8 +2978,8 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, SpiceDisplay *di
         spice_g_signal_connect_object(channel, "notify::monitors",
                                       G_CALLBACK(spice_display_widget_update_monitor_area),
                                       display, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
-        spice_g_signal_connect_object(channel, "streaming-mode",
-                                      G_CALLBACK(prepare_streaming_mode), display, G_CONNECT_AFTER);
+        spice_g_signal_connect_object(channel, "gst-video-overlay",
+                                      G_CALLBACK(set_overlay), display, G_CONNECT_AFTER);
         if (spice_display_channel_get_primary(channel, 0, &primary)) {
             primary_create(channel, primary.format, primary.width, primary.height,
                            primary.stride, primary.shmid, primary.data, display);


More information about the Spice-commits mailing list