summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Olbrich <m.olbrich@pengutronix.de>2020-06-19 09:23:52 +0200
committerMichael Olbrich <m.olbrich@pengutronix.de>2020-07-31 14:02:33 +0200
commit24be7b8aaec7dd427652236b8d4f4af4e35024be (patch)
treed6917b95b195d5da3d97f47c6f4e141e79945d9d
parent283fceac0b048fe95c6a15b2690d818ece2a519e (diff)
test: vaapicontext: support wayland display
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 <vjaquez@igalia.com> Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/342>
-rw-r--r--tests/examples/meson.build3
-rw-r--r--tests/examples/test-vaapicontext.c146
2 files changed, 116 insertions, 33 deletions
diff --git a/tests/examples/meson.build b/tests/examples/meson.build
index 0a61f7d0..e7b1dee5 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 ed5b4504..5b467956 100644
--- a/tests/examples/test-vaapicontext.c
+++ b/tests/examples/test-vaapicontext.c
@@ -23,14 +23,17 @@
#include <gst/video/videooverlay.h>
#include <va/va.h>
+
#include <gtk/gtk.h>
-#include <X11/Xlib.h>
-#include <va/va_x11.h>
#ifdef GDK_WINDOWING_X11
+#include <X11/Xlib.h>
#include <gdk/gdkx.h>
-#else
-#error "X11 is not supported in GTK+"
+#include <va/va_x11.h>
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <va/va_wayland.h>
#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);