glvideomixer: avoid gl resource race condition between different thread
authorWang Xin-yu (王昕宇) <comicfans44@gmail.com>
Fri, 15 Aug 2014 03:51:21 +0000 (23:51 -0400)
committerMatthew Waters <ystreet00@gmail.com>
Tue, 19 Aug 2014 07:00:58 +0000 (17:00 +1000)
https://bugzilla.gnome.org/show_bug.cgi?id=734830

ext/gl/gstglmixer.c

index 0d4d7e9..1420b83 100644 (file)
@@ -70,6 +70,10 @@ struct _GstGLMixerPrivate
   GstAllocator *allocator;
   GstAllocationParams params;
   GstQuery *query;
+
+  gboolean gl_resource_ready;
+  GMutex gl_resource_lock;
+  GCond gl_resource_cond;
 };
 
 G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_VIDEO_AGGREGATOR_PAD);
@@ -427,6 +431,9 @@ gst_gl_mixer_init (GstGLMixer * mix)
   mix->fbo = 0;
   mix->depthbuffer = 0;
 
+  mix->priv->gl_resource_ready = FALSE;
+  g_mutex_init (&mix->priv->gl_resource_lock);
+  g_cond_init (&mix->priv->gl_resource_cond);
   /* initialize variables */
   gst_gl_mixer_reset (mix);
 }
@@ -434,6 +441,10 @@ gst_gl_mixer_init (GstGLMixer * mix)
 static void
 gst_gl_mixer_finalize (GObject * object)
 {
+  GstGLMixerPrivate *priv = GST_GL_MIXER (object)->priv;
+
+  g_mutex_clear (&priv->gl_resource_lock);
+  g_cond_clear (&priv->gl_resource_cond);
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -641,6 +652,8 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query)
   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
 
+  g_mutex_lock (&mix->priv->gl_resource_lock);
+  mix->priv->gl_resource_ready = FALSE;
   if (mix->fbo) {
     gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer);
     mix->fbo = 0;
@@ -648,8 +661,11 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query)
   }
 
   if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height,
-          &mix->fbo, &mix->depthbuffer))
+          &mix->fbo, &mix->depthbuffer)) {
+    g_cond_signal (&mix->priv->gl_resource_cond);
+    g_mutex_unlock (&mix->priv->gl_resource_lock);
     goto context_error;
+  }
 
   if (mix->out_tex_id)
     gst_gl_context_del_texture (mix->context, &mix->out_tex_id);
@@ -659,6 +675,10 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query)
   if (mixer_class->set_caps)
     mixer_class->set_caps (mix, caps);
 
+  mix->priv->gl_resource_ready = TRUE;
+  g_cond_signal (&mix->priv->gl_resource_cond);
+  g_mutex_unlock (&mix->priv->gl_resource_lock);
+
   if (!pool)
     pool = gst_gl_buffer_pool_new (mix->context);
 
@@ -797,6 +817,7 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
   GstElement *element = GST_ELEMENT (mix);
   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
+  GstGLMixerPrivate *priv = mix->priv;
 
   GST_TRACE ("Processing buffers");
 
@@ -860,8 +881,22 @@ gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
     ++array_index;
   }
 
+  g_mutex_lock (&priv->gl_resource_lock);
+  if (!priv->gl_resource_ready)
+    g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
+
+  if (!priv->gl_resource_ready) {
+    g_mutex_unlock (&priv->gl_resource_lock);
+    GST_ERROR_OBJECT (mix,
+        "fbo used to render can't be created, do not run process_textures");
+    res = FALSE;
+    goto out;
+  }
+
   mix_class->process_textures (mix, mix->frames, out_tex);
 
+  g_mutex_unlock (&priv->gl_resource_lock);
+
   if (out_gl_wrapped) {
     if (!gst_gl_download_perform_with_data (mix->download, out_tex,
             out_frame.data)) {