diff --git a/gst-libs/gst/gl/gstglbasesrc.c b/gst-libs/gst/gl/gstglbasesrc.c index ebec0f3e02..28a64448e3 100644 --- a/gst-libs/gst/gl/gstglbasesrc.c +++ b/gst-libs/gst/gl/gstglbasesrc.c @@ -54,6 +54,8 @@ struct _GstGLBaseSrcPrivate gboolean negotiated; gboolean gl_result; gboolean gl_started; + + GRecMutex context_lock; }; /* Properties */ @@ -70,6 +72,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGLBaseSrc, gst_gl_base_src, "glbasesrc", 0, "glbasesrc element"); ); +static void gst_gl_base_src_finalize (GObject * object); static void gst_gl_base_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_gl_base_src_get_property (GObject * object, guint prop_id, @@ -98,6 +101,8 @@ static void gst_gl_base_src_default_gl_stop (GstGLBaseSrc * src); static gboolean gst_gl_base_src_default_fill_gl_memory (GstGLBaseSrc * src, GstGLMemory * mem); +static gboolean gst_gl_base_src_find_gl_context_unlocked (GstGLBaseSrc * src); + static void gst_gl_base_src_class_init (GstGLBaseSrcClass * klass) { @@ -106,6 +111,7 @@ gst_gl_base_src_class_init (GstGLBaseSrcClass * klass) GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + gobject_class->finalize = gst_gl_base_src_finalize; gobject_class->set_property = gst_gl_base_src_set_property; gobject_class->get_property = gst_gl_base_src_get_property; @@ -142,12 +148,23 @@ gst_gl_base_src_init (GstGLBaseSrc * src) { src->priv = gst_gl_base_src_get_instance_private (src); src->priv->timestamp_offset = 0; + g_rec_mutex_init (&src->priv->context_lock); /* we operate in time */ gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME); gst_base_src_set_live (GST_BASE_SRC (src), FALSE); } +static void +gst_gl_base_src_finalize (GObject * object) +{ + GstGLBaseSrc *src = GST_GL_BASE_SRC (object); + + g_rec_mutex_clear (&src->priv->context_lock); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + static void gst_gl_base_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) @@ -184,7 +201,7 @@ gst_gl_base_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) { GstGLBaseSrc *glbasesrc = GST_GL_BASE_SRC (bsrc); - GST_DEBUG ("setcaps"); + GST_DEBUG_OBJECT (bsrc, "set caps %" GST_PTR_FORMAT, caps); if (!gst_video_info_from_caps (&glbasesrc->out_info, caps)) goto wrong_caps; @@ -198,7 +215,7 @@ gst_gl_base_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) /* ERRORS */ wrong_caps: { - GST_WARNING ("wrong caps"); + GST_WARNING_OBJECT (bsrc, "wrong caps"); return FALSE; } } @@ -208,12 +225,27 @@ gst_gl_base_src_set_context (GstElement * element, GstContext * context) { GstGLBaseSrc *src = GST_GL_BASE_SRC (element); GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src); + GstGLDisplay *old_display, *new_display; + g_rec_mutex_lock (&src->priv->context_lock); + old_display = src->display ? gst_object_ref (src->display) : NULL; gst_gl_handle_set_context (element, context, &src->display, &src->priv->other_context); - if (src->display) gst_gl_display_filter_gl_api (src->display, klass->supported_gl_api); + new_display = src->display ? gst_object_ref (src->display) : NULL; + + if (old_display && new_display) { + if (old_display != new_display) { + gst_clear_object (&src->context); + if (gst_gl_base_src_find_gl_context_unlocked (src)) { + gst_pad_mark_reconfigure (GST_BASE_SRC_PAD (src)); + } + } + } + gst_clear_object (&old_display); + gst_clear_object (&new_display); + g_rec_mutex_unlock (&src->priv->context_lock); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -229,9 +261,13 @@ gst_gl_base_src_query (GstBaseSrc * bsrc, GstQuery * query) switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { - if (gst_gl_handle_context_query ((GstElement *) src, query, - src->display, src->context, src->priv->other_context)) - return TRUE; + gboolean ret; + g_rec_mutex_lock (&src->priv->context_lock); + ret = gst_gl_handle_context_query ((GstElement *) src, query, + src->display, src->context, src->priv->other_context); + g_rec_mutex_unlock (&src->priv->context_lock); + if (ret) + return ret; break; } case GST_QUERY_CONVERT: @@ -288,6 +324,7 @@ gst_gl_base_src_gl_start (GstGLContext * context, gpointer data) GstGLBaseSrc *src = GST_GL_BASE_SRC (data); GstGLBaseSrcClass *src_class = GST_GL_BASE_SRC_GET_CLASS (src); + GST_INFO_OBJECT (src, "starting"); gst_gl_insert_debug_marker (src->context, "starting element %s", GST_OBJECT_NAME (src)); @@ -305,9 +342,12 @@ gst_gl_base_src_gl_stop (GstGLContext * context, gpointer data) GstGLBaseSrc *src = GST_GL_BASE_SRC (data); GstGLBaseSrcClass *src_class = GST_GL_BASE_SRC_GET_CLASS (src); + GST_INFO_OBJECT (src, "stopping"); gst_gl_insert_debug_marker (src->context, "stopping element %s", GST_OBJECT_NAME (src)); + src->priv->out_tex = NULL; + if (src->priv->gl_started) src_class->gl_stop (src); @@ -325,6 +365,7 @@ _fill_gl (GstGLContext * context, GstGLBaseSrc * src) { GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src); + GST_TRACE_OBJECT (src, "filling gl memory %p", src->priv->out_tex); src->priv->gl_result = klass->fill_gl_memory (src, src->priv->out_tex); } @@ -336,6 +377,7 @@ gst_gl_base_src_fill (GstPushSrc * psrc, GstBuffer * buffer) GstVideoFrame out_frame; GstGLSyncMeta *sync_meta; + g_rec_mutex_lock (&src->priv->context_lock); if (G_UNLIKELY (!src->priv->negotiated || !src->context)) goto not_negotiated; @@ -353,10 +395,6 @@ gst_gl_base_src_fill (GstPushSrc * psrc, GstBuffer * buffer) gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _fill_gl, src); - if (!src->priv->gl_result) { - gst_video_frame_unmap (&out_frame); - goto gl_error; - } gst_video_frame_unmap (&out_frame); if (!src->priv->gl_result) goto gl_error; @@ -364,6 +402,7 @@ gst_gl_base_src_fill (GstPushSrc * psrc, GstBuffer * buffer) sync_meta = gst_buffer_get_gl_sync_meta (buffer); if (sync_meta) gst_gl_sync_meta_set_sync_point (sync_meta, src->context); + g_rec_mutex_unlock (&src->priv->context_lock); GST_BUFFER_TIMESTAMP (buffer) = src->priv->timestamp_offset + src->running_time; @@ -386,18 +425,21 @@ gst_gl_base_src_fill (GstPushSrc * psrc, GstBuffer * buffer) gl_error: { + g_rec_mutex_unlock (&src->priv->context_lock); GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (_("failed to draw pattern")), (_("A GL error occurred"))); return GST_FLOW_NOT_NEGOTIATED; } not_negotiated: { + g_rec_mutex_unlock (&src->priv->context_lock); GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), (_("format wasn't negotiated before get function"))); return GST_FLOW_NOT_NEGOTIATED; } eos: { + g_rec_mutex_unlock (&src->priv->context_lock); GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d", (gint) src->priv->n_frames); return GST_FLOW_EOS; @@ -421,6 +463,7 @@ gst_gl_base_src_stop (GstBaseSrc * basesrc) { GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc); + g_rec_mutex_lock (&src->priv->context_lock); gst_caps_replace (&src->out_caps, NULL); if (src->context) { @@ -430,6 +473,7 @@ gst_gl_base_src_stop (GstBaseSrc * basesrc) gst_object_unref (src->context); } src->context = NULL; + g_rec_mutex_unlock (&src->priv->context_lock); return TRUE; } @@ -437,25 +481,29 @@ gst_gl_base_src_stop (GstBaseSrc * basesrc) static gboolean _find_local_gl_context (GstGLBaseSrc * src) { - if (gst_gl_query_local_gl_context (GST_ELEMENT (src), GST_PAD_SRC, - &src->context)) - return TRUE; + GstGLContext *context = src->context; + + if (gst_gl_query_local_gl_context (GST_ELEMENT (src), GST_PAD_SRC, &context)) { + if (context->display == src->display) { + src->context = context; + return TRUE; + } + if (context != src->context) + gst_clear_object (&context); + } return FALSE; } static gboolean -gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) +gst_gl_base_src_find_gl_context_unlocked (GstGLBaseSrc * src) { - GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc); GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src); - GstBufferPool *pool = NULL; - GstStructure *config; - GstCaps *caps; - guint min, max, size; - gboolean update_pool; GError *error = NULL; gboolean new_context = FALSE; + GST_DEBUG_OBJECT (src, "attempting to find an OpenGL context, existing %" + GST_PTR_FORMAT, src->context); + if (!src->context) new_context = TRUE; @@ -487,6 +535,7 @@ gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) } while (!gst_gl_display_add_context (src->display, src->context)); GST_OBJECT_UNLOCK (src->display); } + GST_INFO_OBJECT (src, "found OpenGL context %" GST_PTR_FORMAT, src->context); if (new_context || !src->priv->gl_started) { if (src->priv->gl_started) @@ -504,47 +553,6 @@ gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) goto error; } - gst_query_parse_allocation (query, &caps, NULL); - - if (gst_query_get_n_allocation_pools (query) > 0) { - gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); - - update_pool = TRUE; - } else { - GstVideoInfo vinfo; - - gst_video_info_init (&vinfo); - gst_video_info_from_caps (&vinfo, caps); - size = vinfo.size; - min = max = 0; - update_pool = FALSE; - } - - if (!pool || !GST_IS_GL_BUFFER_POOL (pool)) { - /* can't use this pool */ - if (pool) - gst_object_unref (pool); - pool = gst_gl_buffer_pool_new (src->context); - } - config = gst_buffer_pool_get_config (pool); - - gst_buffer_pool_config_set_params (config, caps, size, min, max); - gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); - if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL)) - gst_buffer_pool_config_add_option (config, - GST_BUFFER_POOL_OPTION_GL_SYNC_META); - gst_buffer_pool_config_add_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META); - - gst_buffer_pool_set_config (pool, config); - - if (update_pool) - gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); - else - gst_query_add_allocation_pool (query, pool, size, min, max); - - gst_object_unref (pool); - return TRUE; unsupported_gl_api: @@ -583,6 +591,70 @@ error: } } +static gboolean +gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) +{ + GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc); + GstGLContext *context; + GstBufferPool *pool = NULL; + GstStructure *config; + GstCaps *caps; + guint min, max, size; + gboolean update_pool; + + g_rec_mutex_lock (&src->priv->context_lock); + if (!gst_gl_base_src_find_gl_context_unlocked (src)) { + g_rec_mutex_unlock (&src->priv->context_lock); + return FALSE; + } + context = gst_object_ref (src->context); + g_rec_mutex_unlock (&src->priv->context_lock); + + gst_query_parse_allocation (query, &caps, NULL); + + if (gst_query_get_n_allocation_pools (query) > 0) { + gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); + + update_pool = TRUE; + } else { + GstVideoInfo vinfo; + + gst_video_info_init (&vinfo); + gst_video_info_from_caps (&vinfo, caps); + size = vinfo.size; + min = max = 0; + update_pool = FALSE; + } + + if (!pool || !GST_IS_GL_BUFFER_POOL (pool)) { + /* can't use this pool */ + if (pool) + gst_object_unref (pool); + pool = gst_gl_buffer_pool_new (context); + } + config = gst_buffer_pool_get_config (pool); + + gst_buffer_pool_config_set_params (config, caps, size, min, max); + gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); + if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL)) + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_GL_SYNC_META); + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META); + + gst_buffer_pool_set_config (pool, config); + + if (update_pool) + gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); + else + gst_query_add_allocation_pool (query, pool, size, min, max); + + gst_object_unref (pool); + gst_object_unref (context); + + return TRUE; +} + static GstStateChangeReturn gst_gl_base_src_change_state (GstElement * element, GstStateChange transition) { @@ -599,15 +671,10 @@ gst_gl_base_src_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: - if (src->priv->other_context) { - gst_object_unref (src->priv->other_context); - src->priv->other_context = NULL; - } - - if (src->display) { - gst_object_unref (src->display); - src->display = NULL; - } + g_rec_mutex_lock (&src->priv->context_lock); + gst_clear_object (&src->priv->other_context); + gst_clear_object (&src->display); + g_rec_mutex_unlock (&src->priv->context_lock); break; default: break;