glstereosplit: support gl display changes
authorMatthew Waters <matthew@centricular.com>
Tue, 4 Feb 2020 03:19:21 +0000 (14:19 +1100)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 3 Mar 2020 02:11:52 +0000 (02:11 +0000)
ext/gl/gstglstereosplit.c
ext/gl/gstglstereosplit.h

index 933f3c5..421772a 100644 (file)
@@ -85,6 +85,7 @@ static gboolean stereosplit_src_query (GstPad * pad, GstObject * parent,
 static gboolean stereosplit_src_event (GstPad * pad, GstObject * parent,
     GstEvent * event);
 static gboolean ensure_context (GstGLStereoSplit * self);
+static gboolean ensure_context_unlocked (GstGLStereoSplit * self);
 
 static void
 gst_gl_stereosplit_class_init (GstGLStereoSplitClass * klass)
@@ -136,6 +137,8 @@ gst_gl_stereosplit_init (GstGLStereoSplit * self)
   gst_element_add_pad (GST_ELEMENT (self), self->right_pad);
 
   self->viewconvert = gst_gl_view_convert_new ();
+
+  g_rec_mutex_init (&self->context_lock);
 }
 
 static void
@@ -155,6 +158,8 @@ stereosplit_finalize (GstGLStereoSplit * self)
   if (self->viewconvert)
     gst_object_replace ((GstObject **) & self->viewconvert, NULL);
 
+  g_rec_mutex_clear (&self->context_lock);
+
   klass->finalize ((GObject *) (self));
 }
 
@@ -162,13 +167,37 @@ static void
 stereosplit_set_context (GstElement * element, GstContext * context)
 {
   GstGLStereoSplit *stereosplit = GST_GL_STEREOSPLIT (element);
+  GstGLDisplay *old_display, *new_display;
 
+  g_rec_mutex_lock (&stereosplit->context_lock);
+  GST_DEBUG_OBJECT (element, "set context of %" GST_PTR_FORMAT, context);
+  old_display =
+      stereosplit->display ? gst_object_ref (stereosplit->display) : NULL;
   gst_gl_handle_set_context (element, context, &stereosplit->display,
       &stereosplit->other_context);
 
   if (stereosplit->display)
     gst_gl_display_filter_gl_api (stereosplit->display, SUPPORTED_GL_APIS);
 
+  new_display =
+      stereosplit->display ? gst_object_ref (stereosplit->display) : NULL;
+
+  if (old_display && new_display) {
+    if (old_display != new_display) {
+      gst_clear_object (&stereosplit->context);
+      gst_gl_view_convert_set_context (stereosplit->viewconvert, NULL);
+      GST_INFO_OBJECT (stereosplit, "display changed to %" GST_PTR_FORMAT,
+          new_display);
+      if (ensure_context_unlocked (stereosplit)) {
+        gst_gl_view_convert_set_context (stereosplit->viewconvert,
+            stereosplit->context);
+      }
+    }
+  }
+  gst_clear_object (&old_display);
+  gst_clear_object (&new_display);
+  g_rec_mutex_unlock (&stereosplit->context_lock);
+
   GST_ELEMENT_CLASS (gst_gl_stereosplit_parent_class)->set_context (element,
       context);
 }
@@ -181,11 +210,13 @@ stereosplit_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
+      g_rec_mutex_lock (&stereosplit->context_lock);
       if (!gst_gl_ensure_element_data (element, &stereosplit->display,
               &stereosplit->other_context))
         return GST_STATE_CHANGE_FAILURE;
 
       gst_gl_display_filter_gl_api (stereosplit->display, SUPPORTED_GL_APIS);
+      g_rec_mutex_unlock (&stereosplit->context_lock);
       break;
     default:
       break;
@@ -197,15 +228,10 @@ stereosplit_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_NULL:
-      if (stereosplit->other_context) {
-        gst_object_unref (stereosplit->other_context);
-        stereosplit->other_context = NULL;
-      }
-
-      if (stereosplit->display) {
-        gst_object_unref (stereosplit->display);
-        stereosplit->display = NULL;
-      }
+      g_rec_mutex_lock (&stereosplit->context_lock);
+      gst_clear_object (&stereosplit->other_context);
+      gst_clear_object (&stereosplit->display);
+      g_rec_mutex_unlock (&stereosplit->context_lock);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       stereosplit_reset (stereosplit);
@@ -223,10 +249,6 @@ stereosplit_transform_caps (GstGLStereoSplit * self, GstPadDirection direction,
 {
   GstCaps *next_caps;
 
-  /* FIXME: Is this the right way to ensure a context here ? */
-  if (!ensure_context (self))
-    return NULL;
-
   next_caps =
       gst_gl_view_convert_transform_caps (self->viewconvert, direction, caps,
       NULL);
@@ -317,6 +339,11 @@ stereosplit_set_output_caps (GstGLStereoSplit * split, GstCaps * sinkcaps)
    * left right pad to either left/mono and right/mono, as they prefer
    */
 
+  if (!ensure_context (split)) {
+    res = FALSE;
+    goto fail;
+  }
+
   /* Calculate what downstream can collectively support */
   left =
       stereosplit_get_src_caps (split, split->left_pad,
@@ -384,6 +411,7 @@ stereosplit_set_output_caps (GstGLStereoSplit * split, GstCaps * sinkcaps)
     goto fail;
   }
 
+  g_rec_mutex_lock (&split->context_lock);
   gst_gl_view_convert_set_context (split->viewconvert, split->context);
 
   tridcaps = gst_caps_make_writable (tridcaps);
@@ -392,12 +420,14 @@ stereosplit_set_output_caps (GstGLStereoSplit * split, GstCaps * sinkcaps)
   tridcaps = gst_caps_fixate (tridcaps);
 
   if (!gst_gl_view_convert_set_caps (split->viewconvert, sinkcaps, tridcaps)) {
+    g_rec_mutex_unlock (&split->context_lock);
     GST_ERROR_OBJECT (split, "Failed to set caps on converter");
     goto fail;
   }
 
   /* FIXME: Provide left and right caps to do_bufferpool */
   stereosplit_do_bufferpool (split, left);
+  g_rec_mutex_unlock (&split->context_lock);
 
   res = TRUE;
 
@@ -412,28 +442,46 @@ fail:
 }
 
 static gboolean
-_find_local_gl_context (GstGLStereoSplit * split)
+_find_local_gl_context_unlocked (GstGLStereoSplit * split)
 {
+  GstGLContext *context = split->context;
+
   if (gst_gl_query_local_gl_context (GST_ELEMENT (split), GST_PAD_SRC,
-          &split->context))
-    return TRUE;
+          &context)) {
+    if (context->display == split->display) {
+      split->context = context;
+      return TRUE;
+    }
+    if (context != split->context)
+      gst_clear_object (&context);
+  }
+  context = split->context;
   if (gst_gl_query_local_gl_context (GST_ELEMENT (split), GST_PAD_SINK,
-          &split->context))
-    return TRUE;
+          &context)) {
+    if (context->display == split->display) {
+      split->context = context;
+      return TRUE;
+    }
+    if (context != split->context)
+      gst_clear_object (&context);
+  }
   return FALSE;
 }
 
 static gboolean
-ensure_context (GstGLStereoSplit * self)
+ensure_context_unlocked (GstGLStereoSplit * self)
 {
   GError *error = NULL;
 
+  GST_DEBUG_OBJECT (self, "attempting to find an OpenGL context, existing %"
+      GST_PTR_FORMAT, self->context);
+
   if (!gst_gl_ensure_element_data (self, &self->display, &self->other_context))
     return FALSE;
 
   gst_gl_display_filter_gl_api (self->display, SUPPORTED_GL_APIS);
 
-  _find_local_gl_context (self);
+  _find_local_gl_context_unlocked (self);
 
   if (!self->context) {
     GST_OBJECT_LOCK (self->display);
@@ -460,6 +508,9 @@ ensure_context (GstGLStereoSplit * self)
       goto unsupported_gl_api;
   }
 
+  GST_INFO_OBJECT (self, "found OpenGL context %" GST_PTR_FORMAT,
+      self->context);
+
   return TRUE;
 
 unsupported_gl_api:
@@ -485,9 +536,19 @@ context_error:
 }
 
 static gboolean
+ensure_context (GstGLStereoSplit * self)
+{
+  gboolean ret;
+  g_rec_mutex_lock (&self->context_lock);
+  ret = ensure_context_unlocked (self);
+  g_rec_mutex_unlock (&self->context_lock);
+  return ret;
+}
+
+static gboolean
 stereosplit_decide_allocation (GstGLStereoSplit * self, GstQuery * query)
 {
-  if (!ensure_context (self))
+  if (!ensure_context_unlocked (self))
     return FALSE;
 
   return TRUE;
@@ -497,7 +558,6 @@ stereosplit_decide_allocation (GstGLStereoSplit * self, GstQuery * query)
 static gboolean
 stereosplit_propose_allocation (GstGLStereoSplit * self, GstQuery * query)
 {
-
   if (!gst_gl_ensure_element_data (self, &self->display, &self->other_context))
     return FALSE;
 
@@ -537,22 +597,32 @@ stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf)
 
   GST_LOG_OBJECT (split, "chaining buffer %" GST_PTR_FORMAT, buf);
 
+  gst_buffer_ref (buf);
+
+  g_rec_mutex_lock (&split->context_lock);
+
   if (gst_gl_view_convert_submit_input_buffer (split->viewconvert,
           GST_BUFFER_IS_DISCONT (buf), buf) != GST_FLOW_OK) {
+    g_rec_mutex_unlock (&split->context_lock);
     GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s",
             "Failed to 3d convert buffer"),
         ("Could not get submit input buffer"));
+    gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
 
   ret = gst_gl_view_convert_get_output (split->viewconvert, &split_buffer);
+  g_rec_mutex_unlock (&split->context_lock);
   if (ret != GST_FLOW_OK) {
     GST_ELEMENT_ERROR (split, RESOURCE, NOT_FOUND, ("%s",
             "Failed to 3d convert buffer"), ("Could not get output buffer"));
+    gst_buffer_unref (buf);
     return GST_FLOW_ERROR;
   }
-  if (split_buffer == NULL)
+  if (split_buffer == NULL) {
+    gst_buffer_unref (buf);
     return GST_FLOW_OK;         /* Need another input buffer */
+  }
 
   left = gst_buffer_new ();
   gst_buffer_copy_into (left, buf,
@@ -571,6 +641,7 @@ stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf)
   gst_buffer_unref (left);
   if (G_UNLIKELY (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)) {
     gst_buffer_unref (split_buffer);
+    gst_buffer_unref (buf);
     return ret;
   }
 
@@ -587,6 +658,7 @@ stereosplit_chain (GstPad * pad, GstGLStereoSplit * split, GstBuffer * buf)
   ret = gst_pad_push (split->right_pad, gst_buffer_ref (right));
   gst_buffer_unref (right);
   gst_buffer_unref (split_buffer);
+  gst_buffer_unref (buf);
   return ret;
 }
 
index 279bd26..08fbf0c 100644 (file)
@@ -50,6 +50,8 @@ struct _GstGLStereoSplit
   GstGLContext      *other_context;
 
   GstGLViewConvert    *viewconvert;
+
+  GRecMutex            context_lock;
 };
 
 struct _GstGLStereoSplitClass