From 07f671fcaf4d2956cba920fe19ce394607ec10e0 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Fri, 23 May 2014 18:18:32 +0300 Subject: [PATCH] waylandsink: create and maintain the subsurface inside the sink This means that the given surface in set_window_handle can now be the window's top-level surface on top of which waylandsink creates its own subsurface for rendering the video. This has many advantages: * We can maintain aspect ratio by overlaying the subsurface in the center of the given area and fill the parent surface's area black in case we need to draw borders (instead of adding another subsurface inside the subsurface given from the application, so, less subsurfaces) * We can more easily support toolkits without subsurfaces (see gtk) * We can get properly use gst_video_overlay_set_render_rectangle as our api to set the video area size from the application and therefore remove gst_wayland_video_set_surface_size. --- ext/wayland/gstwaylandsink.c | 58 +++++++++++++++++++----------------- ext/wayland/wldisplay.c | 6 ++++ ext/wayland/wldisplay.h | 1 + ext/wayland/wlwindow.c | 29 ++++++++++++++++-- ext/wayland/wlwindow.h | 8 +++-- 5 files changed, 71 insertions(+), 31 deletions(-) diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index 1a37d6d0be..9730ccc113 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -100,13 +100,13 @@ static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface); static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle); +static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, + gint x, gint y, gint w, gint h); static void gst_wayland_sink_expose (GstVideoOverlay * overlay); /* WaylandVideo interface */ static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface); -static void gst_wayland_sink_set_surface_size (GstWaylandVideo * video, - gint w, gint h); static void gst_wayland_sink_pause_rendering (GstWaylandVideo * video); static void gst_wayland_sink_resume_rendering (GstWaylandVideo * video); @@ -616,12 +616,15 @@ render_last_buffer (GstWaylandSink * sink) src.h = sink->video_height; dst.w = sink->window->width; dst.h = sink->window->height; - gst_video_sink_center_rect (src, dst, &res, FALSE); + gst_video_sink_center_rect (src, dst, &res, TRUE); + if (sink->window->subsurface) + wl_subsurface_set_position (sink->window->subsurface, + sink->window->x + res.x, sink->window->y + res.y); wl_viewport_set_destination (sink->window->viewport, res.w, res.h); wl_surface_attach (surface, meta->wbuffer, 0, 0); - wl_surface_damage (surface, 0, 0, res.w, res.h); + wl_surface_damage (surface, 0, 0, dst.w, dst.h); wl_surface_commit (surface); wl_display_flush (sink->display->display); @@ -732,6 +735,7 @@ static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface) { iface->set_window_handle = gst_wayland_sink_set_window_handle; + iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle; iface->expose = gst_wayland_sink_expose; } @@ -760,7 +764,7 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) "an externally-supplied display handle. Consider providing a " "display handle from your application with GstContext")); } else { - sink->window = gst_wl_window_new_from_surface (sink->display, surface); + sink->window = gst_wl_window_new_in_surface (sink->display, surface); } } else { GST_ERROR_OBJECT (sink, "Failed to find display handle, " @@ -771,6 +775,28 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) GST_OBJECT_UNLOCK (sink); } +static void +gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, + gint x, gint y, gint w, gint h) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + + g_return_if_fail (sink != NULL); + + GST_OBJECT_LOCK (sink); + if (!sink->window) { + GST_OBJECT_UNLOCK (sink); + GST_WARNING_OBJECT (sink, + "set_render_rectangle called without window, ignoring"); + return; + } + + GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d", + x, y, w, h); + gst_wl_window_set_size (sink->window, x, y, w, h); + GST_OBJECT_UNLOCK (sink); +} + static void gst_wayland_sink_expose (GstVideoOverlay * overlay) { @@ -791,32 +817,10 @@ gst_wayland_sink_expose (GstVideoOverlay * overlay) static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface) { - iface->set_surface_size = gst_wayland_sink_set_surface_size; iface->pause_rendering = gst_wayland_sink_pause_rendering; iface->resume_rendering = gst_wayland_sink_resume_rendering; } -static void -gst_wayland_sink_set_surface_size (GstWaylandVideo * video, gint w, gint h) -{ - GstWaylandSink *sink = GST_WAYLAND_SINK (video); - - g_return_if_fail (sink != NULL); - g_return_if_fail (sink->window != NULL); - - GST_OBJECT_LOCK (sink); - if (!sink->window) { - GST_OBJECT_UNLOCK (sink); - GST_WARNING_OBJECT (sink, - "set_surface_size called without window, ignoring"); - return; - } - - GST_DEBUG_OBJECT (sink, "changing window size to %d x %d", w, h); - gst_wl_window_set_size (sink->window, w, h); - GST_OBJECT_UNLOCK (sink); -} - static void gst_wayland_sink_pause_rendering (GstWaylandVideo * video) { diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c index 07ce07b82f..0e2e91e7d8 100644 --- a/ext/wayland/wldisplay.c +++ b/ext/wayland/wldisplay.c @@ -69,6 +69,9 @@ gst_wl_display_finalize (GObject * gobject) if (self->compositor) wl_compositor_destroy (self->compositor); + if (self->subcompositor) + wl_subcompositor_destroy (self->subcompositor); + if (self->registry) wl_registry_destroy (self->registry); @@ -135,6 +138,9 @@ registry_handle_global (void *data, struct wl_registry *registry, if (g_strcmp0 (interface, "wl_compositor") == 0) { self->compositor = wl_registry_bind (registry, id, &wl_compositor_interface, MIN (version, 3)); + } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) { + self->subcompositor = + wl_registry_bind (registry, id, &wl_subcompositor_interface, 1); } else if (g_strcmp0 (interface, "wl_shell") == 0) { self->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1); } else if (g_strcmp0 (interface, "wl_shm") == 0) { diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h index 95c11cb252..0224406672 100644 --- a/ext/wayland/wldisplay.h +++ b/ext/wayland/wldisplay.h @@ -48,6 +48,7 @@ struct _GstWlDisplay /* globals */ struct wl_registry *registry; struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; struct wl_shell *shell; struct wl_shm *shm; struct wl_scaler *scaler; diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c index 41ee5710b6..c3e513adda 100644 --- a/ext/wayland/wlwindow.c +++ b/ext/wayland/wlwindow.c @@ -84,6 +84,10 @@ gst_wl_window_finalize (GObject * gobject) wl_surface_destroy (self->surface); } + if (self->subsurface) { + wl_subsurface_destroy (self->subsurface); + } + g_clear_object (&self->display); G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); @@ -98,7 +102,7 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, gint width, gint height) wl_compositor_create_surface (display->compositor)); window->own_surface = TRUE; - gst_wl_window_set_size (window, width, height); + gst_wl_window_set_size (window, 0, 0, width, height); window->shell_surface = wl_shell_get_shell_surface (display->shell, window->surface); @@ -117,6 +121,23 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, gint width, gint height) return window; } +GstWlWindow * +gst_wl_window_new_in_surface (GstWlDisplay * display, + struct wl_surface * parent) +{ + GstWlWindow *window; + + window = gst_wl_window_new_from_surface (display, + wl_compositor_create_surface (display->compositor)); + window->own_surface = TRUE; + + window->subsurface = wl_subcompositor_get_subsurface (display->subcompositor, + window->surface, parent); + wl_subsurface_set_desync (window->subsurface); + + return window; +} + GstWlWindow * gst_wl_window_new_from_surface (GstWlDisplay * display, struct wl_surface * surface) @@ -128,6 +149,8 @@ gst_wl_window_new_from_surface (GstWlDisplay * display, window = g_object_new (GST_TYPE_WL_WINDOW, NULL); window->display = g_object_ref (display); + window->x = 0; + window->y = 0; window->width = 0; window->height = 0; @@ -172,10 +195,12 @@ gst_wl_window_is_toplevel (GstWlWindow * window) } void -gst_wl_window_set_size (GstWlWindow * window, gint w, gint h) +gst_wl_window_set_size (GstWlWindow * window, gint x, gint y, gint w, gint h) { g_return_if_fail (window != NULL); + window->x = x; + window->y = y; window->width = w; window->height = h; } diff --git a/ext/wayland/wlwindow.h b/ext/wayland/wlwindow.h index cfeb5c417d..ca30fdad63 100644 --- a/ext/wayland/wlwindow.h +++ b/ext/wayland/wlwindow.h @@ -41,9 +41,10 @@ struct _GstWlWindow GstWlDisplay *display; struct wl_surface *surface; + struct wl_subsurface *subsurface; struct wl_viewport *viewport; struct wl_shell_surface *shell_surface; - gint width, height; + gint x, y, width, height; gboolean own_surface; }; @@ -56,6 +57,8 @@ GType gst_wl_window_get_type (void); GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display, gint width, gint height); +GstWlWindow *gst_wl_window_new_in_surface (GstWlDisplay * display, + struct wl_surface * parent); GstWlWindow *gst_wl_window_new_from_surface (GstWlDisplay * display, struct wl_surface * surface); @@ -63,7 +66,8 @@ GstWlDisplay *gst_wl_window_get_display (GstWlWindow * window); struct wl_surface *gst_wl_window_get_wl_surface (GstWlWindow * window); gboolean gst_wl_window_is_toplevel (GstWlWindow *window); -void gst_wl_window_set_size (GstWlWindow * window, gint w, gint h); +void gst_wl_window_set_size (GstWlWindow * window, gint x, gint y, gint w, + gint h); G_END_DECLS