g_clear_object (&sink->window);
} else {
/* remove buffer from surface, show nothing */
- wl_surface_attach (sink->window->surface, NULL, 0, 0);
- wl_surface_damage (sink->window->surface, 0, 0,
- sink->window->surface_width, sink->window->surface_height);
- wl_surface_commit (sink->window->surface);
- wl_display_flush (sink->display->display);
+ gst_wl_window_render (sink->window, NULL, NULL);
}
}
break;
render_last_buffer (GstWaylandSink * sink)
{
GstWlBuffer *wlbuffer;
+ const GstVideoInfo *info = NULL;
struct wl_surface *surface;
struct wl_callback *callback;
callback = wl_surface_frame (surface);
wl_callback_add_listener (callback, &frame_callback_listener, sink);
- gst_wl_buffer_attach (wlbuffer, sink->window);
- wl_surface_damage (surface, 0, 0, sink->window->surface_width,
- sink->window->surface_height);
-
- wl_surface_commit (surface);
- wl_display_flush (sink->display->display);
+ if (G_UNLIKELY (sink->video_info_changed)) {
+ info = &sink->video_info;
+ sink->video_info_changed = FALSE;
+ }
+ gst_wl_window_render (sink->window, wlbuffer, info);
}
static GstFlowReturn
gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
g_mutex_lock (&sink->render_lock);
- if (sink->window) {
- /* inform the window about our caps */
- gst_wl_window_set_video_info (sink->window, &sink->video_info);
- } else {
+ if (!sink->window) {
/* if we were not provided a window, create one ourselves */
sink->window =
gst_wl_window_new_toplevel (sink->display, &sink->video_info);
}
- sink->video_info_changed = FALSE;
}
/* drop buffers until we get a frame callback */
if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
goto done;
- if (G_UNLIKELY (sink->video_info_changed)) {
- gst_wl_window_set_video_info (sink->window, &sink->video_info);
- sink->video_info_changed = FALSE;
- }
-
- /* now that we have for sure set the video info on the window, it must have
- * a valid size, otherwise this means that the application has called
- * set_window_handle() without calling set_render_rectangle(), which is
- * absolutely necessary for us.
- */
- if (G_UNLIKELY (sink->window->surface_width == 0 ||
- sink->window->surface_height == 0))
+ /* make sure that the application has called set_render_rectangle() */
+ if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
goto no_window_size;
wlbuffer = gst_buffer_get_wl_buffer (buffer);
g_return_if_fail (sink != NULL);
g_mutex_lock (&sink->render_lock);
- if (!sink->window || !sink->window->subsurface) {
+ if (!sink->window || !sink->window->area_subsurface) {
g_mutex_unlock (&sink->render_lock);
GST_INFO_OBJECT (sink,
"begin_geometry_change called without window, ignoring");
return;
}
- wl_subsurface_set_sync (sink->window->subsurface);
+ wl_subsurface_set_sync (sink->window->area_subsurface);
g_mutex_unlock (&sink->render_lock);
}
g_return_if_fail (sink != NULL);
g_mutex_lock (&sink->render_lock);
- if (!sink->window || !sink->window->subsurface) {
+ if (!sink->window || !sink->window->area_subsurface) {
g_mutex_unlock (&sink->render_lock);
GST_INFO_OBJECT (sink,
"end_geometry_change called without window, ignoring");
return;
}
- wl_subsurface_set_desync (sink->window->subsurface);
+ wl_subsurface_set_desync (sink->window->area_subsurface);
g_mutex_unlock (&sink->render_lock);
}
#endif
#include "wlwindow.h"
+#include "wlshmallocator.h"
+#include "wlbuffer.h"
GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
#define GST_CAT_DEFAULT gstwayland_debug
wl_shell_surface_destroy (self->shell_surface);
}
- if (self->subsurface) {
- wl_subsurface_destroy (self->subsurface);
- }
+ wl_viewport_destroy (self->video_viewport);
+ wl_subsurface_destroy (self->video_subsurface);
+ wl_surface_destroy (self->video_surface);
- wl_viewport_destroy (self->viewport);
- wl_surface_destroy (self->surface);
+ if (self->area_subsurface) {
+ wl_subsurface_destroy (self->area_subsurface);
+ }
+ wl_viewport_destroy (self->area_viewport);
+ wl_surface_destroy (self->area_surface);
g_clear_object (&self->display);
}
static GstWlWindow *
-gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *surface)
+gst_wl_window_new_internal (GstWlDisplay * display)
{
GstWlWindow *window;
+ GstVideoInfo info;
+ GstBuffer *buf;
+ GstMapInfo mapinfo;
+ struct wl_buffer *wlbuf;
+ GstWlBuffer *gwlbuf;
struct wl_region *region;
- g_return_val_if_fail (surface != NULL, NULL);
-
window = g_object_new (GST_TYPE_WL_WINDOW, NULL);
window->display = g_object_ref (display);
- window->surface = surface;
- /* make sure the surface runs on our local queue */
- wl_proxy_set_queue ((struct wl_proxy *) surface, display->queue);
-
- window->viewport = wl_scaler_get_viewport (display->scaler, window->surface);
+ window->area_surface = wl_compositor_create_surface (display->compositor);
+ window->video_surface = wl_compositor_create_surface (display->compositor);
+
+ wl_proxy_set_queue ((struct wl_proxy *) window->area_surface, display->queue);
+ wl_proxy_set_queue ((struct wl_proxy *) window->video_surface,
+ display->queue);
+
+ /* embed video_surface in area_surface */
+ window->video_subsurface =
+ wl_subcompositor_get_subsurface (display->subcompositor,
+ window->video_surface, window->area_surface);
+ wl_subsurface_set_desync (window->video_subsurface);
+
+ window->area_viewport = wl_scaler_get_viewport (display->scaler,
+ window->area_surface);
+ window->video_viewport = wl_scaler_get_viewport (display->scaler,
+ window->video_surface);
+
+ /* draw the area_subsurface */
+ gst_video_info_set_format (&info,
+ /* we want WL_SHM_FORMAT_XRGB8888 */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+ GST_VIDEO_FORMAT_xRGB,
+#else
+ GST_VIDEO_FORMAT_BGRx,
+#endif
+ 1, 1);
+
+ buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info.size, NULL);
+ gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
+ *((guint32 *) mapinfo.data) = 0; /* paint it black */
+ gst_buffer_unmap (buf, &mapinfo);
+ wlbuf =
+ gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
+ display, &info);
+ gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
+ gst_wl_buffer_attach (gwlbuf, window->area_surface);
+
+ /* at this point, the GstWlBuffer keeps the buffer
+ * alive and will free it on wl_buffer::release */
+ gst_buffer_unref (buf);
/* do not accept input */
region = wl_compositor_create_region (display->compositor);
- wl_surface_set_input_region (surface, region);
+ wl_surface_set_input_region (window->area_surface, region);
+ wl_region_destroy (region);
+
+ region = wl_compositor_create_region (display->compositor);
+ wl_surface_set_input_region (window->video_surface, region);
wl_region_destroy (region);
return window;
}
GstWlWindow *
-gst_wl_window_new_toplevel (GstWlDisplay * display, GstVideoInfo * video_info)
+gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info)
{
GstWlWindow *window;
+ gint width;
- window = gst_wl_window_new_internal (display,
- wl_compositor_create_surface (display->compositor));
-
- gst_wl_window_set_video_info (window, video_info);
- gst_wl_window_set_render_rectangle (window, 0, 0, window->video_width,
- window->video_height);
+ window = gst_wl_window_new_internal (display);
+ /* go toplevel */
window->shell_surface = wl_shell_get_shell_surface (display->shell,
- window->surface);
+ window->area_surface);
if (window->shell_surface) {
wl_shell_surface_add_listener (window->shell_surface,
return NULL;
}
+ /* set the initial size to be the same as the reported video size */
+ width =
+ gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+ gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
+
return window;
}
struct wl_surface * parent)
{
GstWlWindow *window;
+ window = gst_wl_window_new_internal (display);
- window = gst_wl_window_new_internal (display,
- wl_compositor_create_surface (display->compositor));
-
- window->subsurface = wl_subcompositor_get_subsurface (display->subcompositor,
- window->surface, parent);
- wl_subsurface_set_desync (window->subsurface);
+ /* embed in parent */
+ window->area_subsurface =
+ wl_subcompositor_get_subsurface (display->subcompositor,
+ window->area_surface, parent);
+ wl_subsurface_set_desync (window->area_subsurface);
return window;
}
{
g_return_val_if_fail (window != NULL, NULL);
- return window->surface;
+ return window->video_surface;
}
gboolean
}
static void
-gst_wl_window_resize_internal (GstWlWindow * window, gboolean commit)
+gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit)
{
GstVideoRectangle src, res;
+ /* center the video_subsurface inside area_subsurface */
src.w = window->video_width;
src.h = window->video_height;
gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE);
- if (window->subsurface)
- wl_subsurface_set_position (window->subsurface,
- window->render_rectangle.x + res.x, window->render_rectangle.y + res.y);
- wl_viewport_set_destination (window->viewport, res.w, res.h);
+ wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
+ wl_viewport_set_destination (window->video_viewport, res.w, res.h);
if (commit) {
- wl_surface_damage (window->surface, 0, 0, res.w, res.h);
- wl_surface_commit (window->surface);
+ wl_surface_damage (window->video_surface, 0, 0, res.w, res.h);
+ wl_surface_commit (window->video_surface);
}
/* this is saved for use in wl_surface_damage */
}
void
-gst_wl_window_set_video_info (GstWlWindow * window, GstVideoInfo * info)
+gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer,
+ const GstVideoInfo * info)
{
- g_return_if_fail (window != NULL);
+ if (G_UNLIKELY (info)) {
+ window->video_width =
+ gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+ window->video_height = info->height;
- window->video_width =
- gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
- window->video_height = info->height;
+ wl_subsurface_set_sync (window->video_subsurface);
+ gst_wl_window_resize_video_surface (window, FALSE);
+ }
+
+ if (G_LIKELY (buffer))
+ gst_wl_buffer_attach (buffer, window->video_surface);
+ else
+ wl_surface_attach (window->video_surface, NULL, 0, 0);
+
+ wl_surface_damage (window->video_surface, 0, 0, window->surface_width,
+ window->surface_height);
+ wl_surface_commit (window->video_surface);
+
+ if (G_UNLIKELY (info)) {
+ /* commit also the parent (area_surface) in order to change
+ * the position of the video_subsurface */
+ wl_surface_damage (window->area_surface, 0, 0, window->render_rectangle.w,
+ window->render_rectangle.h);
+ wl_surface_commit (window->area_surface);
+ wl_subsurface_set_desync (window->video_subsurface);
+ }
- if (window->render_rectangle.w != 0)
- gst_wl_window_resize_internal (window, FALSE);
+ wl_display_flush (window->display->display);
}
void
window->render_rectangle.w = w;
window->render_rectangle.h = h;
+ /* position the area inside the parent - needs a parent commit to apply */
+ if (window->area_subsurface)
+ wl_subsurface_set_position (window->area_subsurface, x, y);
+
+ /* change the size of the area */
+ wl_viewport_set_destination (window->area_viewport, w, h);
+
+ if (window->video_width != 0) {
+ wl_subsurface_set_sync (window->video_subsurface);
+ gst_wl_window_resize_video_surface (window, TRUE);
+ }
+
+ wl_surface_damage (window->area_surface, 0, 0, w, h);
+ wl_surface_commit (window->area_surface);
+
if (window->video_width != 0)
- gst_wl_window_resize_internal (window, TRUE);
+ wl_subsurface_set_desync (window->video_subsurface);
}