diff --git a/ext/gl/gstglstereosplit.c b/ext/gl/gstglstereosplit.c index 933f3c5939..421772a613 100644 --- a/ext/gl/gstglstereosplit.c +++ b/ext/gl/gstglstereosplit.c @@ -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: @@ -484,10 +535,20 @@ 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; } diff --git a/ext/gl/gstglstereosplit.h b/ext/gl/gstglstereosplit.h index 279bd26810..08fbf0c15d 100644 --- a/ext/gl/gstglstereosplit.h +++ b/ext/gl/gstglstereosplit.h @@ -50,6 +50,8 @@ struct _GstGLStereoSplit GstGLContext *other_context; GstGLViewConvert *viewconvert; + + GRecMutex context_lock; }; struct _GstGLStereoSplitClass