/* Update the buffer used to draw black borders. When we have viewporter * support, this is a scaled up 1x1 image, and without we need an black image * the size of the rendering areay. */ static void gst_wl_window_update_borders (GstWlWindow * window) { GstVideoFormat format; GstVideoInfo info; gint width, height; GstBuffer *buf; struct wl_buffer *wlbuf; GstWlBuffer *gwlbuf; GstAllocator *alloc; if (window->no_border_update) return; if (window->display->viewporter) { width = height = 1; window->no_border_update = TRUE; } else { width = window->render_rectangle.w; height = window->render_rectangle.h; } /* we want WL_SHM_FORMAT_XRGB8888 */ #if G_BYTE_ORDER == G_BIG_ENDIAN format = GST_VIDEO_FORMAT_xRGB; #else format = GST_VIDEO_FORMAT_BGRx; #endif /* draw the area_subsurface */ gst_video_info_set_format (&info, format, width, height); alloc = gst_wl_shm_allocator_get (); buf = gst_buffer_new_allocate (alloc, info.size, NULL); gst_buffer_memset (buf, 0, 0, info.size); wlbuf = gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0), window->display, &info); gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, window->display); gst_wl_buffer_attach (gwlbuf, window->area_surface_wrapper); /* at this point, the GstWlBuffer keeps the buffer * alive and will free it on wl_buffer::release */ gst_buffer_unref (buf); g_object_unref (alloc); }
static GstFlowReturn gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); GstBuffer *to_render; GstWlBuffer *wlbuffer; GstFlowReturn ret = GST_FLOW_OK; g_mutex_lock (&sink->render_lock); GST_LOG_OBJECT (sink, "render buffer %p", buffer); if (G_UNLIKELY (!sink->window)) { /* ask for window handle. Unlock render_lock while doing that because * set_window_handle & friends will lock it in this context */ g_mutex_unlock (&sink->render_lock); gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink)); g_mutex_lock (&sink->render_lock); 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); } } /* drop buffers until we get a frame callback */ if (g_atomic_int_get (&sink->redraw_pending) == TRUE) goto done; /* 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); if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) { GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, " "writing directly", buffer); to_render = buffer; } else { GstMemory *mem; struct wl_buffer *wbuf = NULL; GST_LOG_OBJECT (sink, "buffer %p does not have a wl_buffer from our " "display, creating it", buffer); mem = gst_buffer_peek_memory (buffer, 0); if (gst_is_wl_shm_memory (mem)) { wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); } if (wbuf) { gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); to_render = buffer; } else { GstMapInfo src; /* we don't know how to create a wl_buffer directly from the provided * memory, so we have to copy the data to a memory that we know how * to handle... */ GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying to wl_shm memory", buffer); /* sink->pool always exists (created in set_caps), but it may not * be active if upstream is not using it */ if (!gst_buffer_pool_is_active (sink->pool) && !gst_buffer_pool_set_active (sink->pool, TRUE)) goto activate_failed; ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL); if (ret != GST_FLOW_OK) goto no_buffer; /* the first time we acquire a buffer, * we need to attach a wl_buffer on it */ wlbuffer = gst_buffer_get_wl_buffer (to_render); if (G_UNLIKELY (!wlbuffer)) { mem = gst_buffer_peek_memory (to_render, 0); wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); if (G_UNLIKELY (!wbuf)) goto no_wl_buffer; gst_buffer_add_wl_buffer (to_render, wbuf, sink->display); } gst_buffer_map (buffer, &src, GST_MAP_READ); gst_buffer_fill (to_render, 0, src.data, src.size); gst_buffer_unmap (buffer, &src); } } /* drop double rendering */ if (G_UNLIKELY (to_render == sink->last_buffer)) { GST_LOG_OBJECT (sink, "Buffer already being rendered"); goto done; } gst_buffer_replace (&sink->last_buffer, to_render); render_last_buffer (sink); if (buffer != to_render) gst_buffer_unref (to_render); goto done; no_window_size: { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("Window has no size set"), ("Make sure you set the size after calling set_window_handle")); ret = GST_FLOW_ERROR; goto done; } no_buffer: { GST_WARNING_OBJECT (sink, "could not create buffer"); goto done; } no_wl_buffer: { GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory"); ret = GST_FLOW_ERROR; goto done; } activate_failed: { GST_ERROR_OBJECT (sink, "failed to activate bufferpool."); ret = GST_FLOW_ERROR; goto done; } done: { g_mutex_unlock (&sink->render_lock); return ret; } }
static GstWlWindow * 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; window = g_object_new (GST_TYPE_WL_WINDOW, NULL); window->display = g_object_ref (display); 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 (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; }