[Spice-devel] [PATCH spice-gtk] Gstreamer: Control GstVideoOverlay from the widget

Christophe Fergeau cfergeau at redhat.com
Mon Dec 10 10:01:48 UTC 2018


Hey,

On Sun, Dec 09, 2018 at 03:26:30PM +0200, Snir Sheriber wrote:
> 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. By doing that, issues like
> resizing the window were solved.
> 
> Signed-off-by: Snir Sheriber <ssheribe at redhat.com>
> ---
> 
> This patch is replacing the streaming-mode signal but this signal was never documented
> so it should not be an issue.
> 
> ---
>  src/channel-display-gst.c  |  24 ++------
>  src/channel-display-priv.h |   1 +
>  src/channel-display.c      |  35 ++++++------
>  src/spice-marshal.txt      |   2 +-
>  src/spice-widget-priv.h    |   8 +++
>  src/spice-widget.c         | 111 +++++++++++++++++++++++++++++++++----
>  6 files changed, 135 insertions(+), 46 deletions(-)
> 
> diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
> index 2c07f35..f079132 100644
> --- a/src/channel-display-gst.c
> +++ b/src/channel-display-gst.c
> @@ -334,20 +334,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,11 +382,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);
> +    decoder->win_handle = hand_pipeline_to_widget(decoder->base.stream, GST_PIPELINE(playbin));

As far as I can tell, you don't really need the value of the win_handle,
you only need to know whether spice-gtk is going to use an overlay or
not, so hand_pipeline_to_widget could probably just return a boolean.

> @@ -453,26 +453,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_cclosure_user_marshal_POINTER__POINTER,
>                       G_TYPE_POINTER,
>                       1,
> -                     G_TYPE_BOOLEAN);
> +                     G_TYPE_POINTER);

This should be GST_TYPE_PIPELINE.

>  
>      channel_set_handlers(SPICE_CHANNEL_CLASS(klass));
>  }
> @@ -1391,13 +1392,15 @@ void stream_display_frame(display_stream *st, SpiceFrame *frame,
>      }
>  }
>  
> -guintptr get_window_handle(display_stream *st)
> +guintptr hand_pipeline_to_widget(display_stream *st, gpointer pipeline)
>  {
> -   void* handle = 0;
> +    void* handle = NULL;
>  
> -   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, &handle);
> +    }
> +    return (guintptr)handle;
>  }
>  
>  /* after a sequence of 3 drops, push a report to the server, even
> @@ -2115,10 +2125,23 @@ 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
> +    SpiceDisplayPrivate *d = display->priv;
> +
> +    if (d->overlay)
> +        gst_object_unref(d->overlay);
> +    d->overlay = NULL;
> +
> +    if (d->pipeline)
> +        gst_object_unref(d->pipeline);
> +    d->pipeline = NULL;

This could be

g_clear_pointer(&d->overlay, gst_object_unref);
g_clear_pointer(&d->pipeline, gst_object_unref);



>  #endif
>  
>      GTK_WIDGET_CLASS(spice_display_parent_class)->unrealize(widget);
> @@ -2547,21 +2570,89 @@ 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 GstBusSyncReply handle_pipeline_message_sync(GstBus *bus, GstMessage *msg, gpointer data)
>  {
> -#ifdef GDK_WINDOWING_X11
> +    switch(GST_MESSAGE_TYPE(msg)) {
> +    case GST_MESSAGE_ELEMENT: {
> +        if (gst_is_video_overlay_prepare_window_handle_message(msg)) {
> +            if (!g_getenv("DISABLE_GSTVIDEOOVERLAY") &&
> +                GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
> +                SpiceDisplay *display = data;
> +                GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(display));
> +
> +                if (window && gdk_window_ensure_native(window)) {
> +                    SpiceDisplayPrivate *d = display->priv;
> +
> +                    d->overlay = gst_object_ref(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg)));
> +                    gst_video_overlay_set_window_handle(d->overlay, (uintptr_t)GDK_WINDOW_XID(window)); // moving to widget
> +                    gst_video_overlay_handle_events(d->overlay, false);
> +                    return GST_BUS_DROP;
> +                }
> +            }
> +        }
> +        break;
> +    }
> +    default:
> +        /* not being handled */
> +        break;
> +    }
> +    return GST_BUS_PASS;
> +}
> +#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;
> +    g_return_val_if_fail(d != NULL, false);
> +
> +    if (d->overlay) {
> +        gst_video_overlay_expose(d->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;
> +
> +    if (d->overlay) {
> +        gint scale = 1;
> +
> +        scale = gtk_widget_get_scale_factor(widget);
> +        gst_video_overlay_set_render_rectangle(d->overlay, a->x * scale, a->y * scale, a->width * scale, a->height * scale);
> +    }
> +}

I'm under the impression these 2 callbacks could be added in a follow-up
patch? Or is there going to be regression in spice-gtk behaviour if they
are not part of the patch adding the gst-video-overlay signal?

Christophe

> +#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 void* set_overlay(SpiceChannel *channel, void* pipeline_ptr, gpointer data)
> +{
> +#if defined(HAVE_GSTVIDEO) && defined(GDK_WINDOWING_X11)
>      SpiceDisplay *display = data;
>      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;
>  
> +        gtk_stack_set_visible_child_name(d->stack, "gst-area");
>          window = gtk_widget_get_window(GTK_WIDGET(display));
>          if (window && gdk_window_ensure_native(window)) {
> -            gtk_stack_set_visible_child_name(d->stack, "gst-area");
> +            GstBus *bus;
> +
> +            d->pipeline = GST_ELEMENT(gst_object_ref(pipeline_ptr));
> +            bus = gst_pipeline_get_bus(GST_PIPELINE(d->pipeline));
> +            gst_bus_set_sync_handler (bus, (GstBusSyncHandler) handle_pipeline_message_sync, data, NULL);
> +            gst_object_unref(bus);
>              return (void*)(uintptr_t)GDK_WINDOW_XID(window);
>          }
>      }
> @@ -2936,8 +3027,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);
> -- 
> 2.19.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20181210/25a7489f/attachment-0001.sig>


More information about the Spice-devel mailing list