From 24be7b8aaec7dd427652236b8d4f4af4e35024be Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Fri, 19 Jun 2020 09:23:52 +0200 Subject: [PATCH] test: vaapicontext: support wayland display MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit On Wayland, The whole gtk window is one Wayland surface. So gtk_widget_get_window() must be called on the top-level widget. For any other widget the following gdk_window_ensure_native() may create a new top-level Wayland surface that is never visible. As a result, the coordinates passed to gst_video_overlay_set_render_rectangle() must be relativ to the top-level window. Otherwise the video is placed incorrectly. Original-Patch-By: Víctor Manuel Jáquez Leal Part-of: --- tests/examples/meson.build | 3 +- tests/examples/test-vaapicontext.c | 146 +++++++++++++++++++++++++++++-------- 2 files changed, 116 insertions(+), 33 deletions(-) diff --git a/tests/examples/meson.build b/tests/examples/meson.build index 0a61f7d..e7b1dee 100644 --- a/tests/examples/meson.build +++ b/tests/examples/meson.build @@ -12,7 +12,7 @@ foreach example : examples install: false) endforeach -if USE_X11 +if USE_X11 and USE_WAYLAND if gtk_dep.found() executable('test-vaapicontext', 'test-vaapicontext.c', c_args : gstreamer_vaapi_args, @@ -22,6 +22,7 @@ if gtk_dep.found() libva_dep, x11_dep, gtk_dep, + libva_wayland_dep, libva_x11_dep ], install: false) endif diff --git a/tests/examples/test-vaapicontext.c b/tests/examples/test-vaapicontext.c index ed5b450..5b46795 100644 --- a/tests/examples/test-vaapicontext.c +++ b/tests/examples/test-vaapicontext.c @@ -23,14 +23,17 @@ #include #include + #include -#include -#include #ifdef GDK_WINDOWING_X11 +#include #include -#else -#error "X11 is not supported in GTK+" +#include +#endif +#ifdef GDK_WINDOWING_WAYLAND +#include +#include #endif static gboolean g_multisink; @@ -51,6 +54,8 @@ typedef struct _CustomData GstElement *pipeline; guintptr videoarea_handle[2]; GstObject *gstvaapidisplay; + GtkWidget *video_widget[2]; + GstVideoOverlay *overlay[2]; } AppData; static void @@ -71,26 +76,35 @@ button_rotate_cb (GtkWidget * widget, GstElement * elem) g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL); } -static Display * -get_x11_window_display (AppData * app) +static gpointer +get_native_display (AppData * app, gboolean * is_x11) { -#if defined(GDK_WINDOWING_X11) GdkDisplay *gdk_display; - Display *x11_display; gdk_display = gtk_widget_get_display (app->main_window); - x11_display = gdk_x11_display_get_xdisplay (gdk_display); - return x11_display; + +#if defined(GDK_WINDOWING_X11) + if (GDK_IS_X11_DISPLAY (gdk_display)) { + *is_x11 = TRUE; + return gdk_x11_display_get_xdisplay (gdk_display); + } else +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) { + *is_x11 = FALSE; + return gdk_wayland_display_get_wl_display (gdk_display); + } else #endif - g_error ("Running in a non-X11 environment"); + g_error ("Running in a non supported environment"); } static VADisplay -ensure_va_display (AppData * app) +ensure_va_display (AppData * app, gpointer native_display, gboolean is_x11) { if (app->va_display) return app->va_display; - app->va_display = vaGetDisplay (get_x11_window_display (app)); + app->va_display = is_x11 ? + vaGetDisplay (native_display) : vaGetDisplayWl (native_display); /* There's no need to call vaInitialize() since element does it * internally */ return app->va_display; @@ -102,23 +116,43 @@ create_vaapi_app_display_context (AppData * app, gboolean new_va_display) GstContext *context; GstStructure *s; VADisplay va_display; - Display *x11_display; + gpointer native_display = NULL; + const gchar *name = NULL; + gboolean is_x11; - x11_display = get_x11_window_display (app); + native_display = get_native_display (app, &is_x11); - if (new_va_display) - va_display = vaGetDisplay (x11_display); - else - va_display = ensure_va_display (app); + if (new_va_display) { + va_display = is_x11 ? + vaGetDisplay (native_display) : vaGetDisplayWl (native_display); + } else + va_display = ensure_va_display (app, native_display, is_x11); + + name = is_x11 ? "x11-display" : "wl-display"; context = gst_context_new ("gst.vaapi.app.Display", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "va-display", G_TYPE_POINTER, va_display, NULL); - gst_structure_set (s, "x11-display", G_TYPE_POINTER, x11_display, NULL); + gst_structure_set (s, name, G_TYPE_POINTER, native_display, NULL); return context; } +static void +get_allocation (GtkWidget * widget, GtkAllocation * allocation) +{ + GdkDisplay *display = gdk_display_get_default (); + + gtk_widget_get_allocation (widget, allocation); + + /* On Wayland the whole gtk window is one surface and the video is a + * subsurface of the top-level surface. So the position must be relative + * to the top-level window not relative to the parent widget */ + if (GDK_IS_WAYLAND_DISPLAY (display)) + gtk_widget_translate_coordinates (widget, gtk_widget_get_toplevel (widget), + 0, 0, &allocation->x, &allocation->y); +} + static GstBusSyncReply bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data) { @@ -158,15 +192,23 @@ bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data) break; } case GST_MESSAGE_ELEMENT:{ + GstVideoOverlay *overlay; + GtkAllocation allocation; + guint i; + if (!gst_is_video_overlay_prepare_window_handle_message (msg)) break; - if (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) - gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY - (GST_MESSAGE_SRC (msg)), app->videoarea_handle[1]); - else - gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY - (GST_MESSAGE_SRC (msg)), app->videoarea_handle[0]); + overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (msg)); + + i = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) ? 1 : 0; + + app->overlay[i] = overlay; + get_allocation (app->video_widget[i], &allocation); + gst_video_overlay_set_window_handle (overlay, app->videoarea_handle[i]); + gtk_widget_queue_draw_area (app->video_widget[i], 0, 0, allocation.width, + allocation.height); + break; } case GST_MESSAGE_HAVE_CONTEXT:{ @@ -228,16 +270,53 @@ realize_cb (GtkWidget * widget, gpointer data) { AppData *app = data; GdkWindow *window; + GdkDisplay *display; static guint counter = 0; -#if defined(GDK_WINDOWING_X11) - window = gtk_widget_get_window (widget); + display = gdk_display_get_default (); + +#ifdef GDK_WINDOWING_WAYLAND + /* On wayland gtk_widget_get_window() only works correctly for the + * toplevel widget. Otherwise a new wayland surface is created but + * never used and the video remains invisible. */ + if (GDK_IS_WAYLAND_DISPLAY (display)) + window = gtk_widget_get_window (app->main_window); + else +#endif + window = gtk_widget_get_window (widget); if (!gdk_window_ensure_native (window)) - g_error ("Couldn't create native window needed for GstXOverlay!"); + g_error ("Couldn't create native window needed for GstOverlay!"); - app->videoarea_handle[counter++ % 2] = GDK_WINDOW_XID (window); +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY (display)) { + app->videoarea_handle[counter++ % 2] = GDK_WINDOW_XID (window); + } else +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (display)) { + app->videoarea_handle[counter++ % 2] = + (guintptr) gdk_wayland_window_get_wl_surface (window); + } else #endif + g_error ("Unsupported GDK backend"); +} + +static void +draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data) +{ + AppData *app = data; + GtkAllocation allocation; + + get_allocation (widget, &allocation); + + gst_println ("draw_cb x %d, y %d, w %d, h %d\n", + allocation.x, allocation.y, allocation.width, allocation.height); + + if (app->overlay[0]) { + gst_video_overlay_set_render_rectangle (app->overlay[0], allocation.x, + allocation.y, allocation.width, allocation.height); + } } static GtkWidget * @@ -248,6 +327,7 @@ create_video_box (AppData * app) video_area = gtk_drawing_area_new (); gtk_widget_set_size_request (video_area, 640, 480); g_signal_connect (video_area, "realize", G_CALLBACK (realize_cb), app); + g_signal_connect (video_area, "draw", G_CALLBACK (draw_cb), app); return video_area; } @@ -288,7 +368,8 @@ build_ui (AppData * app) gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0); /* first video box */ - gtk_paned_pack1 (GTK_PANED (pane), create_video_box (app), TRUE, TRUE); + app->video_widget[0] = create_video_box (app); + gtk_paned_pack1 (GTK_PANED (pane), app->video_widget[0], TRUE, TRUE); /* rotate buttons */ bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); @@ -300,7 +381,8 @@ build_ui (AppData * app) if (g_multisink) { /* second video box */ - gtk_paned_pack2 (GTK_PANED (pane), create_video_box (app), TRUE, TRUE); + app->video_widget[1] = create_video_box (app); + gtk_paned_pack2 (GTK_PANED (pane), app->video_widget[1], TRUE, TRUE); gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink2"), TRUE, TRUE, 0); -- 2.7.4