waylandsink: create and maintain the subsurface inside the sink
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Fri, 23 May 2014 15:18:32 +0000 (18:18 +0300)
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>
Tue, 17 Jun 2014 11:51:27 +0000 (13:51 +0200)
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
ext/wayland/wldisplay.c
ext/wayland/wldisplay.h
ext/wayland/wlwindow.c
ext/wayland/wlwindow.h

index 1a37d6d..9730ccc 100644 (file)
@@ -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, "
@@ -772,6 +776,28 @@ 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)
+{
+  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)
 {
   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
@@ -791,33 +817,11 @@ 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)
 {
   GstWaylandSink *sink = GST_WAYLAND_SINK (video);
index 07ce07b..0e2e91e 100644 (file)
@@ -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) {
index 95c11cb..0224406 100644 (file)
@@ -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;
index 41ee571..c3e513a 100644 (file)
@@ -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);
@@ -118,6 +122,23 @@ 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 *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;
 }
index cfeb5c4..ca30fda 100644 (file)
@@ -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