static void gst_wayland_sink_expose (GstVideoOverlay * overlay) { GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); g_return_if_fail (sink != NULL); GST_DEBUG_OBJECT (sink, "expose"); g_mutex_lock (&sink->render_lock); if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) { GST_DEBUG_OBJECT (sink, "redrawing last buffer"); render_last_buffer (sink); } g_mutex_unlock (&sink->render_lock); }
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 GstFlowReturn gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); GstBuffer *to_render; GstWlMeta *meta; 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) { /* inform the window about our caps */ gst_wl_window_set_video_info (sink->window, &sink->video_info); } else { /* 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)) goto no_window_size; meta = gst_buffer_get_wl_meta (buffer); if (meta && meta->pool->display == sink->display) { GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer); to_render = buffer; } else { GstMapInfo src; GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer); if (!sink->pool) goto no_pool; if (!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; gst_buffer_map (buffer, &src, GST_MAP_READ); gst_buffer_fill (to_render, 0, src.data, src.size); gst_buffer_unmap (buffer, &src); } 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 image"); goto done; } no_pool: { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("Internal error: can't allocate images"), ("We don't have a bufferpool negotiated")); 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; } }