static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) { GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); struct wl_surface *surface = (struct wl_surface *) handle; g_return_if_fail (sink != NULL); g_mutex_lock (&sink->render_lock); GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT, (void *) handle); g_clear_object (&sink->window); if (handle) { if (G_LIKELY (gst_wayland_sink_find_display (sink))) { /* we cannot use our own display with an external window handle */ if (G_UNLIKELY (sink->display->own_display)) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("Application did not provide a wayland display handle"), ("waylandsink cannot use an externally-supplied surface without " "an externally-supplied display handle. Consider providing a " "display handle from your application with GstContext")); } else { sink->window = gst_wl_window_new_in_surface (sink->display, surface); } } else { GST_ERROR_OBJECT (sink, "Failed to find display handle, " "ignoring window handle"); } } g_mutex_unlock (&sink->render_lock); }
static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) { GstWaylandSink *sink = GST_WAYLAND_SINK (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_wayland_sink_find_display (sink)) return GST_STATE_CHANGE_FAILURE; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: gst_buffer_replace (&sink->last_buffer, NULL); if (sink->window) { if (gst_wl_window_is_toplevel (sink->window)) { g_clear_object (&sink->window); } else { /* remove buffer from surface, show nothing */ gst_wl_window_render (sink->window, NULL, NULL); } } break; case GST_STATE_CHANGE_READY_TO_NULL: g_mutex_lock (&sink->display_lock); /* If we had a toplevel window, we most likely have our own connection * to the display too, and it is a good idea to disconnect and allow * potentially the application to embed us with GstVideoOverlay * (which requires to re-use the same display connection as the parent * surface). If we didn't have a toplevel window, then the display * connection that we have is definitely shared with the application * and it's better to keep it around (together with the window handle) * to avoid requesting them again from the application if/when we are * restarted (GstVideoOverlay behaves like that in other sinks) */ if (sink->display && !sink->window) { /* -> the window was toplevel */ g_clear_object (&sink->display); } g_mutex_unlock (&sink->display_lock); g_clear_object (&sink->pool); break; default: break; } return ret; }
static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) { GstWaylandSink *sink = GST_WAYLAND_SINK (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_wayland_sink_find_display (sink)) return GST_STATE_CHANGE_FAILURE; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: gst_buffer_replace (&sink->last_buffer, NULL); if (sink->window) { if (gst_wl_window_is_toplevel (sink->window)) { 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); } } break; case GST_STATE_CHANGE_READY_TO_NULL: g_mutex_lock (&sink->display_lock); /* If we had a toplevel window, we most likely have our own connection * to the display too, and it is a good idea to disconnect and allow * potentially the application to embed us with GstVideoOverlay * (which requires to re-use the same display connection as the parent * surface). If we didn't have a toplevel window, then the display * connection that we have is definitely shared with the application * and it's better to keep it around (together with the window handle) * to avoid requesting them again from the application if/when we are * restarted (GstVideoOverlay behaves like that in other sinks) */ if (sink->display && !sink->window) { /* -> the window was toplevel */ /* Force all buffers to return to the pool, regardless of * whether the compositor has released them or not. We are * going to kill the display, so we need to return all buffers * to be destroyed before this happens. * Note that this is done here instead of the pool destructor * because the buffers hold a reference to the pool. Also, * the buffers can only be unref'ed from the display's event loop * and the pool holds a reference to the display. If we drop * our references here, when the compositor releases the buffers, * they will be unref'ed from the event loop thread, which will * unref the pool and therefore the display, which will try to * stop the thread from within itself and cause a deadlock. */ if (sink->pool) { gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL (sink->pool)); } g_clear_object (&sink->display); g_clear_object (&sink->pool); } g_mutex_unlock (&sink->display_lock); break; default: break; } return ret; }