static GstStateChangeReturn gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) { GstGLImageSink *glimage_sink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG ("change state"); glimage_sink = GST_GLIMAGE_SINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: g_atomic_int_set (&glimage_sink->to_quit, 0); if (!glimage_sink->display) { GstGLWindow *window; GError *error = NULL; if (!gst_gl_ensure_display (glimage_sink, &glimage_sink->display)) return GST_STATE_CHANGE_FAILURE; glimage_sink->context = gst_gl_context_new (glimage_sink->display); window = gst_gl_context_get_window (glimage_sink->context); if (!glimage_sink->window_id && !glimage_sink->new_window_id) gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (glimage_sink)); if (glimage_sink->window_id != glimage_sink->new_window_id) { glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_window_set_window_handle (window, glimage_sink->window_id); } if (!gst_gl_context_create (glimage_sink->context, glimage_sink->other_context, &error)) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); if (glimage_sink->display) { gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } gst_object_unref (glimage_sink->context); gst_object_unref (window); return GST_STATE_CHANGE_FAILURE; } /* setup callbacks */ gst_gl_window_set_resize_callback (window, GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_draw_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_draw), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_close_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_close), gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref); gst_object_unref (window); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: 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_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { /* mark the redisplay_texture as unavailable (=0) * to avoid drawing */ GST_GLIMAGE_SINK_LOCK (glimage_sink); glimage_sink->redisplay_texture = 0; GST_GLIMAGE_SINK_UNLOCK (glimage_sink); if (glimage_sink->upload) { gst_object_unref (glimage_sink->upload); glimage_sink->upload = NULL; } glimage_sink->window_id = 0; //but do not reset glimage_sink->new_window_id if (glimage_sink->pool) { gst_buffer_pool_set_active (glimage_sink->pool, FALSE); gst_object_unref (glimage_sink->pool); glimage_sink->pool = NULL; } GST_VIDEO_SINK_WIDTH (glimage_sink) = 1; GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1; if (glimage_sink->context) { GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context); gst_gl_window_send_message (window, GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink); gst_gl_window_set_resize_callback (window, NULL, NULL, NULL); gst_gl_window_set_draw_callback (window, NULL, NULL, NULL); gst_gl_window_set_close_callback (window, NULL, NULL, NULL); gst_object_unref (window); gst_object_unref (glimage_sink->context); glimage_sink->context = NULL; gst_object_unref (glimage_sink->display); glimage_sink->display = NULL; } break; } case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
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 gboolean _ensure_gl_setup (GstGLImageSink * gl_sink) { GError *error = NULL; if (!gst_gl_ensure_display (gl_sink, &gl_sink->display)) return FALSE; if (!gl_sink->context) { GstGLWindow *window; gl_sink->context = gst_gl_context_new (gl_sink->display); if (!gl_sink->context) goto context_creation_error; window = gst_gl_context_get_window (gl_sink->context); if (!gl_sink->window_id && !gl_sink->new_window_id) gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (gl_sink)); if (gl_sink->window_id != gl_sink->new_window_id) { gl_sink->window_id = gl_sink->new_window_id; gst_gl_window_set_window_handle (window, gl_sink->window_id); } if (!gst_gl_context_create (gl_sink->context, gl_sink->other_context, &error)) { gst_object_unref (window); goto context_error; } /* setup callbacks */ gst_gl_window_set_resize_callback (window, GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize), gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_draw_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_draw), gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref); gst_gl_window_set_close_callback (window, GST_GL_WINDOW_CB (gst_glimage_sink_on_close), gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref); gl_sink->key_sig_id = g_signal_connect (window, "key-event", G_CALLBACK (gst_glimage_sink_key_event_cb), gl_sink); gl_sink->mouse_sig_id = g_signal_connect (window, "mouse-event", G_CALLBACK (gst_glimage_sink_mouse_event_cb), gl_sink); gst_object_unref (window); } return TRUE; context_creation_error: { GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("Failed to create GL context"), (NULL)); return FALSE; } context_error: { GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); gst_object_unref (gl_sink->context); gl_sink->context = NULL; return FALSE; } }
static gboolean gst_pvrvideosink_setcaps (GstBaseSink * bsink, GstCaps * caps) { GstPVRVideoSink *pvrvideosink; GstVideoInfo info; GstStructure *structure; GstBufferPool *oldpool, *newpool; pvrvideosink = GST_PVRVIDEOSINK (bsink); GST_DEBUG_OBJECT (pvrvideosink, "sinkconnect possible caps with given caps %" GST_PTR_FORMAT, caps); if (!gst_video_info_from_caps (&info, caps)) goto invalid_format; GST_VIDEO_SINK_WIDTH (pvrvideosink) = info.width; GST_VIDEO_SINK_HEIGHT (pvrvideosink) = info.height; /* Notify application to set xwindow id now */ g_mutex_lock (pvrvideosink->flow_lock); if (!pvrvideosink->xwindow) { g_mutex_unlock (pvrvideosink->flow_lock); gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (pvrvideosink)); } else { g_mutex_unlock (pvrvideosink->flow_lock); } g_mutex_lock (pvrvideosink->flow_lock); if (!pvrvideosink->xwindow) pvrvideosink->xwindow = gst_pvrvideosink_create_window (pvrvideosink, GST_VIDEO_SINK_WIDTH (pvrvideosink), GST_VIDEO_SINK_HEIGHT (pvrvideosink)); g_mutex_unlock (pvrvideosink->flow_lock); pvrvideosink->info = info; /* After a resize, we want to redraw the borders in case the new frame size * doesn't cover the same area */ pvrvideosink->redraw_borders = TRUE; /* create a new pool for the new configuration */ newpool = gst_pvr_buffer_pool_new (GST_ELEMENT_CAST (pvrvideosink)); /* PVR needs at least 3 buffers */ structure = gst_buffer_pool_get_config (newpool); gst_buffer_pool_config_set (structure, caps, GST_VIDEO_INFO_SIZE (&info), 3, 0, 0, 15); if (!gst_buffer_pool_set_config (newpool, structure)) goto config_failed; oldpool = pvrvideosink->pool; pvrvideosink->pool = newpool; g_mutex_unlock (pvrvideosink->flow_lock); /* unref the old sink */ if (oldpool) { /* we don't deactivate, some elements might still be using it, it will * be deactivated when the last ref is gone */ gst_object_unref (oldpool); } return TRUE; config_failed: { GST_ERROR_OBJECT (pvrvideosink, "failed to set config."); g_mutex_unlock (pvrvideosink->flow_lock); return FALSE; } invalid_format: { GST_DEBUG_OBJECT (pvrvideosink, "Could not locate image format from caps %" GST_PTR_FORMAT, caps); return FALSE; } }
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; } }