...
 
Commits (6)
...@@ -483,9 +483,9 @@ fi ...@@ -483,9 +483,9 @@ fi
dnl Check for GTK for tests dnl Check for GTK for tests
USE_GTK=0 USE_GTK=0
AS_IF([test "x$BUILD_EXAMPLES" = "xyes" -a $USE_X11 -eq 1], AS_IF([test "x$BUILD_EXAMPLES" = "xyes" -a $USE_X11 -eq 1 -a $USE_WAYLAND -eq 1],
[AS_CASE([$with_gtk], [AS_CASE([$with_gtk],
[yes], [PKG_CHECK_MODULES([GTK3], [gtk+-3.0], [USE_GTK=1])], [yes], [PKG_CHECK_MODULES([GTK3], [gtk+-3.0 gtk+-x11-3.0 gtk+-wayland-3.0], [USE_GTK=1])],
[no], [], [no], [],
[PKG_CHECK_MODULES([GTK3], [gtk+-3.0], [USE_GTK=1], [USE_GTK=0])])]) [PKG_CHECK_MODULES([GTK3], [gtk+-3.0], [USE_GTK=1], [USE_GTK=0])])])
AS_IF([test $USE_GTK -eq 1], AS_IF([test $USE_GTK -eq 1],
......
...@@ -115,6 +115,9 @@ registry_handle_global (void *data, ...@@ -115,6 +115,9 @@ registry_handle_global (void *data,
if (strcmp (interface, "wl_compositor") == 0) if (strcmp (interface, "wl_compositor") == 0)
priv->compositor = priv->compositor =
wl_registry_bind (registry, id, &wl_compositor_interface, 1); wl_registry_bind (registry, id, &wl_compositor_interface, 1);
else if (g_strcmp0 (interface, "wl_subcompositor") == 0)
priv->subcompositor =
wl_registry_bind (registry, id, &wl_subcompositor_interface, 1);
else if (strcmp (interface, "wl_shell") == 0) else if (strcmp (interface, "wl_shell") == 0)
priv->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); priv->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
else if (strcmp (interface, "xdg_wm_base") == 0) { else if (strcmp (interface, "xdg_wm_base") == 0) {
......
...@@ -64,6 +64,7 @@ struct _GstVaapiDisplayWaylandPrivate ...@@ -64,6 +64,7 @@ struct _GstVaapiDisplayWaylandPrivate
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_shell *wl_shell; struct wl_shell *wl_shell;
struct xdg_wm_base *xdg_wm_base; struct xdg_wm_base *xdg_wm_base;
struct wl_subcompositor *subcompositor;
struct wl_output *output; struct wl_output *output;
struct wl_registry *registry; struct wl_registry *registry;
guint width; guint width;
......
...@@ -397,6 +397,30 @@ gst_vaapi_window_get_fullscreen (GstVaapiWindow * window) ...@@ -397,6 +397,30 @@ gst_vaapi_window_get_fullscreen (GstVaapiWindow * window)
return window->is_fullscreen; return window->is_fullscreen;
} }
/**
* gst_vaapi_window_set_render_rectangle:
* @window: a #GstVaapiWindow
* @x: the horizontal offset of the render area inside the window
* @y: the vertical offset of the render area inside the window
* @width: the width of the render area inside the window
* @height: the height of the render area inside the window
*
* Set information of the render area.
*/
void
gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y,
gint width, gint height)
{
const GstVaapiWindowClass *klass;
g_return_if_fail (window != NULL);
klass = GST_VAAPI_WINDOW_GET_CLASS (window);
if (klass->set_render_rect)
klass->set_render_rect (window, x, y, width, height);
}
/** /**
* gst_vaapi_window_set_fullscreen: * gst_vaapi_window_set_fullscreen:
* @window: a #GstVaapiWindow * @window: a #GstVaapiWindow
...@@ -528,10 +552,12 @@ gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height) ...@@ -528,10 +552,12 @@ gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height)
if (!GST_VAAPI_WINDOW_GET_CLASS (window)->resize (window, width, height)) if (!GST_VAAPI_WINDOW_GET_CLASS (window)->resize (window, width, height))
return; return;
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
gst_vaapi_video_pool_replace (&window->surface_pool, NULL); gst_vaapi_video_pool_replace (&window->surface_pool, NULL);
window->width = width; window->width = width;
window->height = height; window->height = height;
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
} }
static inline void static inline void
......
...@@ -86,6 +86,10 @@ gst_vaapi_window_set_height (GstVaapiWindow * window, guint height); ...@@ -86,6 +86,10 @@ gst_vaapi_window_set_height (GstVaapiWindow * window, guint height);
void void
gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height); gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height);
void
gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y,
gint width, gint height);
gboolean gboolean
gst_vaapi_window_put_surface (GstVaapiWindow * window, gst_vaapi_window_put_surface (GstVaapiWindow * window,
GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
......
...@@ -129,6 +129,7 @@ struct _GstVaapiWindowClass ...@@ -129,6 +129,7 @@ struct _GstVaapiWindowClass
guintptr (*get_colormap) (GstVaapiWindow * window); guintptr (*get_colormap) (GstVaapiWindow * window);
gboolean (*unblock) (GstVaapiWindow * window); gboolean (*unblock) (GstVaapiWindow * window);
gboolean (*unblock_cancel) (GstVaapiWindow * window); gboolean (*unblock_cancel) (GstVaapiWindow * window);
void (*set_render_rect) (GstVaapiWindow * window, gint x, gint y, gint width, gint height);
}; };
GstVaapiWindow * GstVaapiWindow *
......
...@@ -102,6 +102,7 @@ struct _GstVaapiWindowWaylandPrivate ...@@ -102,6 +102,7 @@ struct _GstVaapiWindowWaylandPrivate
struct xdg_toplevel *xdg_toplevel; struct xdg_toplevel *xdg_toplevel;
struct wl_shell_surface *wl_shell_surface; struct wl_shell_surface *wl_shell_surface;
struct wl_surface *surface; struct wl_surface *surface;
struct wl_subsurface *video_subsurface;
struct wl_region *opaque_region; struct wl_region *opaque_region;
struct wl_event_queue *event_queue; struct wl_event_queue *event_queue;
FrameState *last_frame; FrameState *last_frame;
...@@ -376,6 +377,10 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window, ...@@ -376,6 +377,10 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window,
g_return_val_if_fail (priv_display->xdg_wm_base || priv_display->wl_shell, g_return_val_if_fail (priv_display->xdg_wm_base || priv_display->wl_shell,
FALSE); FALSE);
priv->poll = gst_poll_new (TRUE);
gst_poll_fd_init (&priv->pollfd);
priv->is_shown = TRUE;
GST_VAAPI_WINDOW_LOCK_DISPLAY (window); GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->event_queue = wl_display_create_queue (priv_display->wl_display); priv->event_queue = wl_display_create_queue (priv_display->wl_display);
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window); GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
...@@ -389,6 +394,37 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window, ...@@ -389,6 +394,37 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window,
return FALSE; return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->surface, priv->event_queue); wl_proxy_set_queue ((struct wl_proxy *) priv->surface, priv->event_queue);
if (window->use_foreign_window) {
struct wl_surface *wl_surface;
if (priv_display->subcompositor) {
if (GST_VAAPI_OBJECT_ID (window) == VA_INVALID_ID) {
GST_ERROR ("Invalid window");
return FALSE;
}
wl_surface = (struct wl_surface *) GST_VAAPI_WINDOW_ID (window);
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->video_subsurface =
wl_subcompositor_get_subsurface (priv_display->subcompositor,
priv->surface, wl_surface);
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
if (!priv->video_subsurface)
return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->video_subsurface,
priv->event_queue);
wl_subsurface_set_position (priv->video_subsurface, 0, 0);
wl_subsurface_set_desync (priv->video_subsurface);
return TRUE;
} else {
GST_ERROR ("Wayland server does not support subsurfaces");
window->use_foreign_window = FALSE;
}
}
/* Prefer XDG-shell over deprecated wl_shell (if available) */ /* Prefer XDG-shell over deprecated wl_shell (if available) */
if (priv_display->xdg_wm_base) { if (priv_display->xdg_wm_base) {
/* Create the XDG surface. We make the toplevel on VaapiWindow::show() */ /* Create the XDG surface. We make the toplevel on VaapiWindow::show() */
...@@ -411,20 +447,14 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window, ...@@ -411,20 +447,14 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window,
return FALSE; return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface, wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface,
priv->event_queue); priv->event_queue);
wl_shell_surface_add_listener (priv->wl_shell_surface, wl_shell_surface_add_listener (priv->wl_shell_surface,
&shell_surface_listener, priv); &shell_surface_listener, priv);
wl_shell_surface_set_toplevel (priv->wl_shell_surface); wl_shell_surface_set_toplevel (priv->wl_shell_surface);
} }
priv->poll = gst_poll_new (TRUE);
gst_poll_fd_init (&priv->pollfd);
if (priv->fullscreen_on_show) if (priv->fullscreen_on_show)
gst_vaapi_window_wayland_set_fullscreen (window, TRUE); gst_vaapi_window_wayland_set_fullscreen (window, TRUE);
priv->is_shown = TRUE;
return TRUE; return TRUE;
} }
...@@ -470,6 +500,9 @@ gst_vaapi_window_wayland_resize (GstVaapiWindow * window, ...@@ -470,6 +500,9 @@ gst_vaapi_window_wayland_resize (GstVaapiWindow * window,
GstVaapiDisplayWaylandPrivate *const priv_display = GstVaapiDisplayWaylandPrivate *const priv_display =
GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window)); GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window));
if (window->use_foreign_window)
return TRUE;
GST_DEBUG ("resize window, new size %ux%u", width, height); GST_DEBUG ("resize window, new size %ux%u", width, height);
if (priv->opaque_region) if (priv->opaque_region)
...@@ -482,6 +515,22 @@ gst_vaapi_window_wayland_resize (GstVaapiWindow * window, ...@@ -482,6 +515,22 @@ gst_vaapi_window_wayland_resize (GstVaapiWindow * window,
return TRUE; return TRUE;
} }
void
gst_vaapi_window_wayland_set_render_rect (GstVaapiWindow * window, gint x,
gint y, gint width, gint height)
{
GstVaapiWindowWaylandPrivate *const priv =
GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
if (priv->video_subsurface)
wl_subsurface_set_position (priv->video_subsurface, x, y);
/* TODO: something to scale maybe */
return;
}
static inline gboolean static inline gboolean
frame_done (FrameState * frame) frame_done (FrameState * frame)
{ {
...@@ -590,12 +639,17 @@ gst_vaapi_window_wayland_render (GstVaapiWindow * window, ...@@ -590,12 +639,17 @@ gst_vaapi_window_wayland_render (GstVaapiWindow * window,
} }
/* Wait for the previous frame to complete redraw */ /* Wait for the previous frame to complete redraw */
if (!gst_vaapi_window_wayland_sync (window)) { if (!window->use_foreign_window) {
/* Release vpp surface if exists */ if (!gst_vaapi_window_wayland_sync (window)) {
if (priv->need_vpp && window->has_vpp) /* Release vpp surface if exists */
gst_vaapi_video_pool_put_object (window->surface_pool, surface); if (priv->need_vpp && window->has_vpp)
wl_buffer_destroy (buffer); gst_vaapi_video_pool_put_object (window->surface_pool, surface);
return !priv->sync_failed; wl_buffer_destroy (buffer);
return !priv->sync_failed;
}
} else {
if (priv->event_queue)
wl_display_roundtrip_queue (wl_display, priv->event_queue);
} }
frame = frame_state_new (window); frame = frame_state_new (window);
...@@ -670,6 +724,7 @@ gst_vaapi_window_wayland_class_init (GstVaapiWindowWaylandClass * klass) ...@@ -670,6 +724,7 @@ gst_vaapi_window_wayland_class_init (GstVaapiWindowWaylandClass * klass)
window_class->set_fullscreen = gst_vaapi_window_wayland_set_fullscreen; window_class->set_fullscreen = gst_vaapi_window_wayland_set_fullscreen;
window_class->unblock = gst_vaapi_window_wayland_unblock; window_class->unblock = gst_vaapi_window_wayland_unblock;
window_class->unblock_cancel = gst_vaapi_window_wayland_unblock_cancel; window_class->unblock_cancel = gst_vaapi_window_wayland_unblock_cancel;
window_class->set_render_rect = gst_vaapi_window_wayland_set_render_rect;
signals[SIZE_CHANGED] = g_signal_new ("size-changed", signals[SIZE_CHANGED] = g_signal_new ("size-changed",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
...@@ -702,3 +757,27 @@ gst_vaapi_window_wayland_new (GstVaapiDisplay * display, ...@@ -702,3 +757,27 @@ gst_vaapi_window_wayland_new (GstVaapiDisplay * display,
return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display, return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display,
GST_VAAPI_ID_INVALID, width, height); GST_VAAPI_ID_INVALID, width, height);
} }
/**
* gst_vaapi_window_wayland_new_with_surface:
* @display: a #GstVaapiDisplay
* @wl_surface: a Wayland surface pointer
*
* Creates a window with the specified @wl_surface. The window
* will be attached to the @display and remains invisible to the user
* until gst_vaapi_window_show() is called.
*
* Return value: the newly allocated #GstVaapiWindow object
*/
GstVaapiWindow *
gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display,
guintptr wl_surface)
{
g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL);
g_return_val_if_fail (wl_surface, NULL);
GST_DEBUG ("new window from surface 0x%" G_GUINTPTR_FORMAT, wl_surface);
return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display,
wl_surface, 0, 0);
}
...@@ -45,6 +45,10 @@ GstVaapiWindow * ...@@ -45,6 +45,10 @@ GstVaapiWindow *
gst_vaapi_window_wayland_new (GstVaapiDisplay * display, guint width, gst_vaapi_window_wayland_new (GstVaapiDisplay * display, guint width,
guint height); guint height);
GstVaapiWindow *
gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display,
guintptr wl_surface);
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowWayland, gst_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowWayland, gst_object_unref)
#endif #endif
......
...@@ -562,11 +562,31 @@ gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width, ...@@ -562,11 +562,31 @@ gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width,
return TRUE; return TRUE;
} }
static gboolean
gst_vaapisink_wayland_create_window_from_handle (GstVaapiSink * sink,
guintptr window)
{
GstVaapiDisplay *display;
if (!gst_vaapisink_ensure_display (sink))
return FALSE;
display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
if (sink->window == NULL || (guintptr) sink->window != window) {
gst_vaapi_window_replace (&sink->window, NULL);
sink->window = gst_vaapi_window_wayland_new_with_surface (display, window);
}
return sink->window != NULL;
}
static const inline GstVaapiSinkBackend * static const inline GstVaapiSinkBackend *
gst_vaapisink_backend_wayland (void) gst_vaapisink_backend_wayland (void)
{ {
static const GstVaapiSinkBackend GstVaapiSinkBackendWayland = { static const GstVaapiSinkBackend GstVaapiSinkBackendWayland = {
.create_window = gst_vaapisink_wayland_create_window, .create_window = gst_vaapisink_wayland_create_window,
.create_window_from_handle =
gst_vaapisink_wayland_create_window_from_handle,
.render_surface = gst_vaapisink_render_surface, .render_surface = gst_vaapisink_render_surface,
}; };
return &GstVaapiSinkBackendWayland; return &GstVaapiSinkBackendWayland;
...@@ -614,6 +634,11 @@ gst_vaapisink_video_overlay_set_render_rectangle (GstVideoOverlay * overlay, ...@@ -614,6 +634,11 @@ gst_vaapisink_video_overlay_set_render_rectangle (GstVideoOverlay * overlay,
display_rect->width = width; display_rect->width = width;
display_rect->height = height; display_rect->height = height;
if (gst_vaapisink_ensure_render_rect (sink, width, height) && sink->window) {
gst_vaapi_window_set_render_rectangle (sink->window, x, y, width, height);
gst_vaapi_window_set_size (sink->window, width, height);
}
GST_DEBUG ("render rect (%d,%d):%ux%u", GST_DEBUG ("render rect (%d,%d):%ux%u",
display_rect->x, display_rect->y, display_rect->x, display_rect->y,
display_rect->width, display_rect->height); display_rect->width, display_rect->height);
......
...@@ -37,6 +37,7 @@ test_vaapicontext_CFLAGS = \ ...@@ -37,6 +37,7 @@ test_vaapicontext_CFLAGS = \
$(X11_CFLAGS) \ $(X11_CFLAGS) \
$(LIBVA_CFLAGS) \ $(LIBVA_CFLAGS) \
$(LIBVA_X11_CFLAGS) \ $(LIBVA_X11_CFLAGS) \
$(LIBVA_WAYLAND_CFLAGS) \
$(NULL) $(NULL)
test_vaapicontext_LDADD = \ test_vaapicontext_LDADD = \
$(TEST_LIBS) \ $(TEST_LIBS) \
...@@ -44,6 +45,7 @@ test_vaapicontext_LDADD = \ ...@@ -44,6 +45,7 @@ test_vaapicontext_LDADD = \
$(X11_LIBS) \ $(X11_LIBS) \
$(LIBVA_LIBS) \ $(LIBVA_LIBS) \
$(LIBVA_X11_LIBS) \ $(LIBVA_X11_LIBS) \
$(LIBVA_WAYLAND_LIBS) \
$(NULL) $(NULL)
endif endif
......
...@@ -12,7 +12,7 @@ foreach example : examples ...@@ -12,7 +12,7 @@ foreach example : examples
install: false) install: false)
endforeach endforeach
if gtk_dep.found() if gtk_dep.found() and USE_WAYLAND and USE_X11
executable('test-vaapicontext', 'test-vaapicontext.c', executable('test-vaapicontext', 'test-vaapicontext.c',
c_args : gstreamer_vaapi_args, c_args : gstreamer_vaapi_args,
include_directories: [configinc, libsinc], include_directories: [configinc, libsinc],
...@@ -21,6 +21,7 @@ if gtk_dep.found() ...@@ -21,6 +21,7 @@ if gtk_dep.found()
libva_dep, libva_dep,
x11_dep, x11_dep,
gtk_dep, gtk_dep,
libva_wayland_dep,
libva_x11_dep ], libva_x11_dep ],
install: false) install: false)
endif endif
...@@ -23,24 +23,27 @@ ...@@ -23,24 +23,27 @@
#include <gst/video/videooverlay.h> #include <gst/video/videooverlay.h>
#include <va/va.h> #include <va/va.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <X11/Xlib.h>
#include <va/va_x11.h>
#ifdef GDK_WINDOWING_X11 #ifdef GDK_WINDOWING_X11
#include <X11/Xlib.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
#else #include <va/va_x11.h>
#error "X11 is not supported in GTK+" #endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#include <va/va_wayland.h>
#endif #endif
static gboolean g_multisink; static gboolean g_multisink;
static gchar *g_filepath; static gchar *g_filepath;
static GstElement *g_vaapisink;
static GOptionEntry g_options[] = { static GOptionEntry g_options[] = {
{"multi", 'm', 0, G_OPTION_ARG_NONE, &g_multisink, "test multiple vaapisink", {"multi", 'm', 0, G_OPTION_ARG_NONE, &g_multisink, "test multiple vaapisink",
NULL}, NULL},
{"file", 'f', 0, G_OPTION_ARG_STRING, &g_filepath, {"file", 'f', 0, G_OPTION_ARG_STRING, &g_filepath, "file path to play", NULL},
"file path to play (only mp4/h264)", NULL},
{NULL,} {NULL,}
}; };
...@@ -51,6 +54,8 @@ typedef struct _CustomData ...@@ -51,6 +54,8 @@ typedef struct _CustomData
GstElement *pipeline; GstElement *pipeline;
guintptr videoarea_handle[2]; guintptr videoarea_handle[2];
GstObject *gstvaapidisplay; GstObject *gstvaapidisplay;
GtkWidget *video_widget[2];
GstVideoOverlay *overlay[2];
} AppData; } AppData;
static void static void
...@@ -71,26 +76,35 @@ button_rotate_cb (GtkWidget * widget, GstElement * elem) ...@@ -71,26 +76,35 @@ button_rotate_cb (GtkWidget * widget, GstElement * elem)
g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL); g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL);
} }
static Display * static gpointer
get_x11_window_display (AppData * app) get_native_display (AppData * app, gboolean * is_x11)
{ {
#if defined(GDK_WINDOWING_X11)
GdkDisplay *gdk_display; GdkDisplay *gdk_display;
Display *x11_display;
gdk_display = gtk_widget_get_display (app->main_window); 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 #endif
g_error ("Running in a non-X11 environment"); #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 supported environment");
} }
static VADisplay static VADisplay
ensure_va_display (AppData * app) ensure_va_display (AppData * app, gpointer native_display, gboolean is_x11)
{ {
if (app->va_display) if (app->va_display)
return 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 /* There's no need to call vaInitialize() since element does it
* internally */ * internally */
return app->va_display; return app->va_display;
...@@ -102,19 +116,24 @@ create_vaapi_app_display_context (AppData * app, gboolean new_va_display) ...@@ -102,19 +116,24 @@ create_vaapi_app_display_context (AppData * app, gboolean new_va_display)
GstContext *context; GstContext *context;
GstStructure *s; GstStructure *s;
VADisplay va_display; VADisplay va_display;
Display *x11_display; gpointer native_display = NULL;
const gchar *name = NULL;
gboolean is_x11;
native_display = get_native_display (app, &is_x11);
x11_display = get_x11_window_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);
if (new_va_display) name = is_x11 ? "x11-display" : "wl-display";
va_display = vaGetDisplay (x11_display);
else
va_display = ensure_va_display (app);
context = gst_context_new ("gst.vaapi.app.Display", FALSE); context = gst_context_new ("gst.vaapi.app.Display", FALSE);
s = gst_context_writable_structure (context); s = gst_context_writable_structure (context);
gst_structure_set (s, "va-display", G_TYPE_POINTER, va_display, NULL); 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; return context;
} }
...@@ -158,15 +177,23 @@ bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data) ...@@ -158,15 +177,23 @@ bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data)
break; break;
} }
case GST_MESSAGE_ELEMENT:{ case GST_MESSAGE_ELEMENT:{
GstVideoOverlay *overlay;
GtkAllocation allocation;
guint i;
if (!gst_is_video_overlay_prepare_window_handle_message (msg)) if (!gst_is_video_overlay_prepare_window_handle_message (msg))
break; break;
if (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (msg));
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY
(GST_MESSAGE_SRC (msg)), app->videoarea_handle[1]); i = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) ? 1 : 0;
else
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY app->overlay[i] = overlay;
(GST_MESSAGE_SRC (msg)), app->videoarea_handle[0]); gtk_widget_get_allocation (app->video_widget[i], &allocation);
gst_video_overlay_set_window_handle (overlay, app->videoarea_handle[i]);
gst_video_overlay_set_render_rectangle (overlay, allocation.x,
allocation.y, allocation.width, allocation.height);
break; break;
} }
case GST_MESSAGE_HAVE_CONTEXT:{ case GST_MESSAGE_HAVE_CONTEXT:{
...@@ -205,21 +232,68 @@ bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data) ...@@ -205,21 +232,68 @@ bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data)
return GST_BUS_PASS; return GST_BUS_PASS;
} }
static void
play_cb (GtkButton * button, gpointer data)
{
AppData *app = data;
gst_element_set_state (app->pipeline, GST_STATE_PLAYING);
}
static void
null_cb (GtkButton * button, gpointer data)
{
AppData *app = data;
gst_element_set_state (app->pipeline, GST_STATE_NULL);
app->va_display = NULL;
}
static void static void
realize_cb (GtkWidget * widget, gpointer data) realize_cb (GtkWidget * widget, gpointer data)
{ {
AppData *app = data; AppData *app = data;
GdkWindow *window; GdkWindow *window;
GdkDisplay *display;
static guint counter = 0; static guint counter = 0;
#if defined(GDK_WINDOWING_X11)
window = gtk_widget_get_window (widget); window = gtk_widget_get_window (widget);
if (!gdk_window_ensure_native (window)) 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); display = gdk_display_get_default ();
#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 #endif
g_error ("Unsupported GDK backend");
}
static void
draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
{
AppData *app = data;
GtkAllocation allocation;
gtk_widget_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 * static GtkWidget *
...@@ -230,6 +304,7 @@ create_video_box (AppData * app) ...@@ -230,6 +304,7 @@ create_video_box (AppData * app)
video_area = gtk_drawing_area_new (); video_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (video_area, 640, 480); 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, "realize", G_CALLBACK (realize_cb), app);
g_signal_connect (video_area, "draw", G_CALLBACK (draw_cb), app);
return video_area; return video_area;
} }
...@@ -240,11 +315,14 @@ create_rotate_button (AppData * app, const gchar * name) ...@@ -240,11 +315,14 @@ create_rotate_button (AppData * app, const gchar * name)
GstElement *sink; GstElement *sink;
sink = gst_bin_get_by_name (GST_BIN (app->pipeline), name); sink = gst_bin_get_by_name (GST_BIN (app->pipeline), name);
if (!sink && !g_strcmp0 (name, "sink1"))
sink = g_vaapisink;
g_assert (sink); g_assert (sink);
rotate = gtk_button_new_with_label ("Rotate"); rotate = gtk_button_new_with_label ("Rotate");
g_signal_connect (rotate, "clicked", G_CALLBACK (button_rotate_cb), sink); g_signal_connect (rotate, "clicked", G_CALLBACK (button_rotate_cb), sink);
gst_object_unref (sink); if (sink != g_vaapisink)
gst_object_unref (sink);
return rotate; return rotate;
} }
...@@ -267,7 +345,8 @@ build_ui (AppData * app) ...@@ -267,7 +345,8 @@ build_ui (AppData * app)
gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
/* first video box */ /* 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 */ /* rotate buttons */
bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
...@@ -279,10 +358,21 @@ build_ui (AppData * app) ...@@ -279,10 +358,21 @@ build_ui (AppData * app)
if (g_multisink) { if (g_multisink) {
/* second video box */ /* 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"), gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink2"),
TRUE, TRUE, 0); TRUE, TRUE, 0);
} else {
GtkWidget *button;
button = gtk_button_new_with_label ("PLAYING");
gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
g_signal_connect (button, "clicked", G_CALLBACK (play_cb), app);
button = gtk_button_new_with_label ("NULL");
gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
g_signal_connect (button, "clicked", G_CALLBACK (null_cb), app);
} }
gtk_widget_show_all (mainwin); gtk_widget_show_all (mainwin);
...@@ -316,8 +406,8 @@ main (gint argc, gchar ** argv) ...@@ -316,8 +406,8 @@ main (gint argc, gchar ** argv)
app.pipeline = gst_parse_launch ("videotestsrc ! vaapih264enc ! " app.pipeline = gst_parse_launch ("videotestsrc ! vaapih264enc ! "
"vaapidecodebin ! vaapisink name=sink1", &error); "vaapidecodebin ! vaapisink name=sink1", &error);
} else { } else {
app.pipeline = gst_parse_launch ("filesrc name=src ! qtdemux ! h264parse ! " app.pipeline = gst_element_factory_make ("playbin", NULL);
"vaapidecodebin ! vaapisink name=sink1", &error); g_assert (app.pipeline);
} }
if (error) { if (error) {
...@@ -327,12 +417,10 @@ main (gint argc, gchar ** argv) ...@@ -327,12 +417,10 @@ main (gint argc, gchar ** argv)
} }
if (!g_multisink && g_filepath) { if (!g_multisink && g_filepath) {
GstElement *src; g_vaapisink = gst_element_factory_make ("vaapisink", "sink1");
g_assert (g_vaapisink);
src = gst_bin_get_by_name (GST_BIN (app.pipeline), "src"); g_object_set (app.pipeline, "uri", g_filepath, "video-sink", g_vaapisink,
g_assert (src); NULL);
g_object_set (src, "location", g_filepath, NULL);
gst_object_unref (src);
} }
build_ui (&app); build_ui (&app);
......