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.
This commit is contained in:
George Kiagiadakis 2014-05-23 18:18:32 +03:00
parent b806313396
commit 07f671fcaf
5 changed files with 71 additions and 31 deletions

View 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, "
@ -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)
{

View 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) {

View 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;

View 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);
@ -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;
}

View 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