mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
gtkglsink: Fix unsafe handling of buffer life time
We need to keep the active buffer (the one we have retreive a texture id from) otherwise it's racy and upstream may upload new content before we have rendered or during later redisplay.
This commit is contained in:
parent
9afab22dd9
commit
cf44f5013a
4 changed files with 65 additions and 39 deletions
|
@ -190,7 +190,6 @@ _apply_par (GtkGstBaseWidget * widget)
|
||||||
GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height);
|
GST_DEBUG ("scaling to %dx%d", widget->display_width, widget->display_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note, buffer is not refrence, it's only passed for pointer comparision */
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_queue_draw (GtkGstBaseWidget * widget)
|
_queue_draw (GtkGstBaseWidget * widget)
|
||||||
{
|
{
|
||||||
|
@ -202,7 +201,6 @@ _queue_draw (GtkGstBaseWidget * widget)
|
||||||
|
|
||||||
widget->v_info = widget->pending_v_info;
|
widget->v_info = widget->pending_v_info;
|
||||||
widget->negotiated = TRUE;
|
widget->negotiated = TRUE;
|
||||||
widget->new_buffer = TRUE;
|
|
||||||
|
|
||||||
_apply_par (widget);
|
_apply_par (widget);
|
||||||
|
|
||||||
|
@ -434,6 +432,7 @@ gtk_gst_base_widget_finalize (GObject * object)
|
||||||
{
|
{
|
||||||
GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object);
|
GtkGstBaseWidget *widget = GTK_GST_BASE_WIDGET (object);
|
||||||
|
|
||||||
|
gst_buffer_replace (&widget->pending_buffer, NULL);
|
||||||
gst_buffer_replace (&widget->buffer, NULL);
|
gst_buffer_replace (&widget->buffer, NULL);
|
||||||
g_mutex_clear (&widget->lock);
|
g_mutex_clear (&widget->lock);
|
||||||
g_weak_ref_clear (&widget->element);
|
g_weak_ref_clear (&widget->element);
|
||||||
|
@ -481,8 +480,7 @@ gtk_gst_base_widget_set_buffer (GtkGstBaseWidget * widget, GstBuffer * buffer)
|
||||||
|
|
||||||
GTK_GST_BASE_WIDGET_LOCK (widget);
|
GTK_GST_BASE_WIDGET_LOCK (widget);
|
||||||
|
|
||||||
gst_buffer_replace (&widget->buffer, buffer);
|
gst_buffer_replace (&widget->pending_buffer, buffer);
|
||||||
widget->new_buffer = TRUE;
|
|
||||||
|
|
||||||
if (!widget->draw_id) {
|
if (!widget->draw_id) {
|
||||||
widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
|
widget->draw_id = g_idle_add_full (G_PRIORITY_DEFAULT,
|
||||||
|
|
|
@ -53,9 +53,9 @@ struct _GtkGstBaseWidget
|
||||||
gint display_height;
|
gint display_height;
|
||||||
|
|
||||||
gboolean negotiated;
|
gboolean negotiated;
|
||||||
|
GstBuffer *pending_buffer;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
GstVideoInfo v_info;
|
GstVideoInfo v_info;
|
||||||
gboolean new_buffer;
|
|
||||||
|
|
||||||
/* resize */
|
/* resize */
|
||||||
gboolean pending_resize;
|
gboolean pending_resize;
|
||||||
|
|
|
@ -197,6 +197,13 @@ _redraw_texture (GtkGstGLWidget * gst_widget, guint tex)
|
||||||
gl->BindTexture (GL_TEXTURE_2D, 0);
|
gl->BindTexture (GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_draw_black (void)
|
||||||
|
{
|
||||||
|
glClearColor (0.0, 0.0, 0.0, 0.0);
|
||||||
|
glClear (GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||||
{
|
{
|
||||||
|
@ -205,25 +212,33 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||||
|
|
||||||
GTK_GST_BASE_WIDGET_LOCK (widget);
|
GTK_GST_BASE_WIDGET_LOCK (widget);
|
||||||
|
|
||||||
if (!priv->initted && priv->context)
|
if (!priv->context || !priv->other_context)
|
||||||
gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget));
|
goto done;
|
||||||
|
|
||||||
if (priv->initted && base_widget->negotiated && base_widget->buffer) {
|
|
||||||
GST_DEBUG ("rendering buffer %p with gdk context %p",
|
|
||||||
base_widget->buffer, context);
|
|
||||||
|
|
||||||
gst_gl_context_activate (priv->other_context, TRUE);
|
gst_gl_context_activate (priv->other_context, TRUE);
|
||||||
|
|
||||||
if (base_widget->new_buffer || priv->current_tex == 0) {
|
if (!priv->initted)
|
||||||
|
gtk_gst_gl_widget_init_redisplay (GTK_GST_GL_WIDGET (widget));
|
||||||
|
|
||||||
|
if (!priv->initted || !base_widget->negotiated) {
|
||||||
|
_draw_black ();
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Upload latest buffer */
|
||||||
|
if (base_widget->pending_buffer) {
|
||||||
|
GstBuffer *buffer = base_widget->pending_buffer;
|
||||||
GstVideoFrame gl_frame;
|
GstVideoFrame gl_frame;
|
||||||
GstGLSyncMeta *sync_meta;
|
GstGLSyncMeta *sync_meta;
|
||||||
|
|
||||||
if (!gst_video_frame_map (&gl_frame, &base_widget->v_info,
|
if (!gst_video_frame_map (&gl_frame, &base_widget->v_info, buffer,
|
||||||
base_widget->buffer, GST_MAP_READ | GST_MAP_GL)) {
|
GST_MAP_READ | GST_MAP_GL)) {
|
||||||
goto error;
|
_draw_black ();
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_meta = gst_buffer_get_gl_sync_meta (base_widget->buffer);
|
|
||||||
|
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
|
||||||
if (sync_meta) {
|
if (sync_meta) {
|
||||||
gst_gl_sync_meta_set_sync_point (sync_meta, priv->context);
|
gst_gl_sync_meta_set_sync_point (sync_meta, priv->context);
|
||||||
gst_gl_sync_meta_wait (sync_meta, priv->other_context);
|
gst_gl_sync_meta_wait (sync_meta, priv->other_context);
|
||||||
|
@ -232,17 +247,21 @@ gtk_gst_gl_widget_render (GtkGLArea * widget, GdkGLContext * context)
|
||||||
priv->current_tex = *(guint *) gl_frame.data[0];
|
priv->current_tex = *(guint *) gl_frame.data[0];
|
||||||
|
|
||||||
gst_video_frame_unmap (&gl_frame);
|
gst_video_frame_unmap (&gl_frame);
|
||||||
|
|
||||||
|
if (base_widget->buffer)
|
||||||
|
gst_buffer_unref (base_widget->buffer);
|
||||||
|
|
||||||
|
/* Keep the buffer to ensure current_tex stay valid */
|
||||||
|
base_widget->buffer = buffer;
|
||||||
|
base_widget->pending_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_DEBUG ("rendering buffer %p with gdk context %p",
|
||||||
|
base_widget->buffer, context);
|
||||||
|
|
||||||
_redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex);
|
_redraw_texture (GTK_GST_GL_WIDGET (widget), priv->current_tex);
|
||||||
base_widget->new_buffer = FALSE;
|
|
||||||
} else {
|
|
||||||
error:
|
|
||||||
/* FIXME: nothing to display */
|
|
||||||
glClearColor (0.0, 0.0, 0.0, 0.0);
|
|
||||||
glClear (GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
done:
|
||||||
if (priv->other_context)
|
if (priv->other_context)
|
||||||
gst_gl_context_activate (priv->other_context, FALSE);
|
gst_gl_context_activate (priv->other_context, FALSE);
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,15 @@ gtk_gst_widget_draw (GtkWidget * widget, cairo_t * cr)
|
||||||
|
|
||||||
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
|
GTK_GST_BASE_WIDGET_LOCK (gst_widget);
|
||||||
|
|
||||||
|
/* There is not much to optimize in term of redisplay, so simply swap the
|
||||||
|
* pending_buffer with the active buffer */
|
||||||
|
if (gst_widget->pending_buffer) {
|
||||||
|
if (gst_widget->buffer)
|
||||||
|
gst_buffer_unref (gst_widget->buffer);
|
||||||
|
gst_widget->buffer = gst_widget->pending_buffer;
|
||||||
|
gst_widget->pending_buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* failed to map the video frame */
|
/* failed to map the video frame */
|
||||||
if (gst_widget->negotiated && gst_widget->buffer
|
if (gst_widget->negotiated && gst_widget->buffer
|
||||||
&& gst_video_frame_map (&frame, &gst_widget->v_info,
|
&& gst_video_frame_map (&frame, &gst_widget->v_info,
|
||||||
|
|
Loading…
Reference in a new issue