diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c index e8e962659f..4f25982ad9 100644 --- a/gst-libs/gst/gl/gstglfilter.c +++ b/gst-libs/gst/gl/gstglfilter.c @@ -204,20 +204,6 @@ gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction, &filter->display); break; } - case GST_QUERY_CUSTOM: - { - GstStructure *structure = gst_query_writable_structure (query); - if (direction == GST_PAD_SINK && - gst_structure_has_name (structure, "gstglcontext")) { - gst_structure_set (structure, "gstglcontext", G_TYPE_POINTER, - filter->context, NULL); - res = TRUE; - } else - res = - GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction, - query); - break; - } default: res = GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction, @@ -272,41 +258,10 @@ gst_gl_filter_start (GstBaseTransform * bt) { GstGLFilter *filter = GST_GL_FILTER (bt); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); - GstStructure *structure; - GstQuery *context_query; - const GValue *id_value; if (!gst_gl_ensure_display (filter, &filter->display)) return FALSE; - structure = gst_structure_new_empty ("gstglcontext"); - context_query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); - - if (!gst_pad_peer_query (bt->srcpad, context_query)) { - GST_WARNING - ("Could not query GstGLContext from downstream (peer query failed)"); - } - - id_value = gst_structure_get_value (structure, "gstglcontext"); - if (G_VALUE_HOLDS_POINTER (id_value)) { - /* at least one gl element is after in our gl chain */ - filter->context = - gst_object_ref (GST_GL_CONTEXT (g_value_get_pointer (id_value))); - } else { - GError *error = NULL; - - GST_INFO ("Creating GstGLContext"); - filter->context = gst_gl_context_new (filter->display); - - if (!gst_gl_context_create (filter->context, filter->other_context, &error)) { - GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, - ("%s", error->message), (NULL)); - return FALSE; - } - } - - gst_query_unref (context_query); - if (filter_class->onStart) filter_class->onStart (filter); @@ -747,7 +702,6 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, { GstGLFilter *filter; GstGLFilterClass *filter_class; - guint in_width, in_height, out_width, out_height; filter = GST_GL_FILTER (bt); filter_class = GST_GL_FILTER_GET_CLASS (filter); @@ -757,35 +711,6 @@ gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, if (!gst_video_info_from_caps (&filter->out_info, outcaps)) goto wrong_caps; - in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); - in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); - out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); - - //blocking call, generate a FBO - if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height, - &filter->fbo, &filter->depthbuffer)) - goto display_error; - - gst_gl_context_gen_texture (filter->context, &filter->in_tex_id, - GST_VIDEO_FORMAT_RGBA, in_width, in_height); - - gst_gl_context_gen_texture (filter->context, &filter->out_tex_id, - GST_VIDEO_FORMAT_RGBA, out_width, out_height); - - if (filter_class->display_init_cb != NULL) { - gst_gl_context_thread_add (filter->context, gst_gl_filter_start_gl, filter); - } -#if 0 - if (!filter->display->isAlive) - goto error; -#endif - - if (filter_class->onInitFBO) { - if (!filter_class->onInitFBO (filter)) - goto error; - } - if (filter_class->set_caps) { if (!filter_class->set_caps (filter, incaps, outcaps)) goto error; @@ -802,14 +727,6 @@ wrong_caps: GST_WARNING ("Wrong caps"); return FALSE; } - -display_error: - { - GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, - ("%s", gst_gl_context_get_error ()), (NULL)); - return FALSE; - } - error: { return FALSE; @@ -826,6 +743,8 @@ gst_gl_filter_propose_allocation (GstBaseTransform * trans, GstCaps *caps; guint size; gboolean need_pool; + GError *error = NULL; + GstStructure *gl_context; gst_query_parse_allocation (query, &caps, &need_pool); @@ -851,6 +770,16 @@ gst_gl_filter_propose_allocation (GstBaseTransform * trans, } gst_structure_free (config); } + + if (!gst_gl_ensure_display (filter, &filter->display)) + return FALSE; + + if (!filter->context) { + filter->context = gst_gl_context_new (filter->display); + if (!gst_gl_context_create (filter->context, filter->other_context, &error)) + goto context_error; + } + if (pool == NULL && need_pool) { GstVideoInfo info; @@ -870,11 +799,17 @@ gst_gl_filter_propose_allocation (GstBaseTransform * trans, } /* we need at least 2 buffer because we hold on to the last one */ gst_query_add_allocation_pool (query, pool, size, 1, 0); + gst_object_unref (pool); /* we also support various metadata */ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); - gst_object_unref (pool); + gl_context = + gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext", + GST_GL_TYPE_CONTEXT, filter->context, NULL); + gst_query_add_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context); + gst_structure_free (gl_context); return TRUE; @@ -894,17 +829,27 @@ config_failed: GST_DEBUG_OBJECT (trans, "failed setting config"); return FALSE; } +context_error: + { + GST_ELEMENT_ERROR (trans, RESOURCE, NOT_FOUND, ("%s", error->message), + (NULL)); + return FALSE; + } } static gboolean gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) { GstGLFilter *filter = GST_GL_FILTER (trans); + GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; + guint idx; + GError *error = NULL; + guint in_width, in_height, out_width, out_height; gst_query_parse_allocation (query, &caps, NULL); @@ -922,6 +867,52 @@ gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) update_pool = FALSE; } + if (!gst_gl_ensure_display (filter, &filter->display)) + return FALSE; + + if (gst_query_find_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) { + GstGLContext *context; + const GstStructure *upload_meta_params; + + gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params); + if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext", + GST_GL_TYPE_CONTEXT, &context, NULL) && context) + gst_object_replace ((GstObject **) & filter->context, + (GstObject *) context); + } + + if (!filter->context) { + filter->context = gst_gl_context_new (filter->display); + if (!gst_gl_context_create (filter->context, filter->other_context, &error)) + goto context_error; + } + + in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); + in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); + out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); + out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); + + //blocking call, generate a FBO + if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height, + &filter->fbo, &filter->depthbuffer)) + goto context_error; + + gst_gl_context_gen_texture (filter->context, &filter->in_tex_id, + GST_VIDEO_FORMAT_RGBA, in_width, in_height); + + gst_gl_context_gen_texture (filter->context, &filter->out_tex_id, + GST_VIDEO_FORMAT_RGBA, out_width, out_height); + + if (filter_class->display_init_cb != NULL) { + gst_gl_context_thread_add (filter->context, gst_gl_filter_start_gl, filter); + } + + if (filter_class->onInitFBO) { + if (!filter_class->onInitFBO (filter)) + goto error; + } + if (!pool) pool = gst_gl_buffer_pool_new (filter->context); @@ -938,6 +929,19 @@ gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) gst_object_unref (pool); return TRUE; + +context_error: + { + GST_ELEMENT_ERROR (trans, RESOURCE, NOT_FOUND, ("%s", error->message), + (NULL)); + return FALSE; + } +error: + { + GST_ELEMENT_ERROR (trans, LIBRARY, INIT, + ("Subclass failed to initialize."), (NULL)); + return FALSE; + } } /** diff --git a/gst-libs/gst/gl/gstglmixer.c b/gst-libs/gst/gl/gstglmixer.c index 453f5a386d..31db30dc66 100644 --- a/gst-libs/gst/gl/gstglmixer.c +++ b/gst-libs/gst/gl/gstglmixer.c @@ -317,6 +317,108 @@ gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix, return ret; } +static gboolean +gst_gl_mixer_propose_allocation (GstGLMixer * mix, + GstQuery * decide_query, GstQuery * query) +{ + GstBufferPool *pool; + GstStructure *config; + GstCaps *caps; + guint size; + gboolean need_pool; + GError *error = NULL; + GstStructure *gl_context; + + gst_query_parse_allocation (query, &caps, &need_pool); + + if (caps == NULL) + goto no_caps; + + if ((pool = mix->priv->pool)) + gst_object_ref (pool); + + if (pool != NULL) { + GstCaps *pcaps; + + /* we had a pool, check caps */ + GST_DEBUG_OBJECT (mix, "check existing pool caps"); + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); + + if (!gst_caps_is_equal (caps, pcaps)) { + GST_DEBUG_OBJECT (mix, "pool has different caps"); + /* different caps, we can't use this pool */ + gst_object_unref (pool); + pool = NULL; + } + gst_structure_free (config); + } + + if (!gst_gl_ensure_display (mix, &mix->display)) + return FALSE; + + if (!mix->context) { + mix->context = gst_gl_context_new (mix->display); + if (!gst_gl_context_create (mix->context, NULL, &error)) + goto context_error; + } + + if (pool == NULL && need_pool) { + GstVideoInfo info; + + if (!gst_video_info_from_caps (&info, caps)) + goto invalid_caps; + + GST_DEBUG_OBJECT (mix, "create new pool"); + pool = gst_gl_buffer_pool_new (mix->context); + + /* the normal size of a frame */ + size = info.size; + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set_params (config, caps, size, 0, 0); + if (!gst_buffer_pool_set_config (pool, config)) + goto config_failed; + } + gst_query_add_allocation_pool (query, pool, size, 1, 0); + gst_object_unref (pool); + + /* we also support various metadata */ + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0); + + gl_context = + gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext", + GST_GL_TYPE_CONTEXT, mix->context, NULL); + gst_query_add_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context); + gst_structure_free (gl_context); + + return TRUE; + + /* ERRORS */ +no_caps: + { + GST_DEBUG_OBJECT (mix, "no caps specified"); + return FALSE; + } +invalid_caps: + { + GST_DEBUG_OBJECT (mix, "invalid caps specified"); + return FALSE; + } +config_failed: + { + GST_DEBUG_OBJECT (mix, "failed setting config"); + return FALSE; + } +context_error: + { + GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), + (NULL)); + return FALSE; + } +} + static gboolean gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data, GstQuery * query, GstGLMixer * mix) @@ -327,6 +429,35 @@ gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data, GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_ALLOCATION: + { + GstQuery *decide_query = NULL; + gboolean negotiated; + + GST_OBJECT_LOCK (mix); + if (G_UNLIKELY (!(negotiated = mix->priv->negotiated))) { + GST_DEBUG_OBJECT (mix, + "not negotiated yet, can't answer ALLOCATION query"); + GST_OBJECT_UNLOCK (mix); + return FALSE; + } + if ((decide_query = mix->priv->query)) + gst_query_ref (decide_query); + GST_OBJECT_UNLOCK (mix); + + GST_DEBUG_OBJECT (mix, + "calling propose allocation with query %" GST_PTR_FORMAT, + decide_query); + + /* pass the query to the propose_allocation vmethod if any */ + ret = gst_gl_mixer_propose_allocation (mix, decide_query, query); + + if (decide_query) + gst_query_unref (decide_query); + + GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query); + break; + } case GST_QUERY_CAPS: { GstCaps *filter, *caps; @@ -940,38 +1071,9 @@ static gboolean gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate) { if (activate) { - GstStructure *structure; - GstQuery *context_query; - const GValue *id_value; - if (!gst_gl_ensure_display (mix, &mix->display)) { return FALSE; } - - structure = gst_structure_new_empty ("gstglcontext"); - context_query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); - - if (!gst_pad_peer_query (mix->srcpad, context_query)) { - GST_WARNING - ("Could not query GstGLContext from downstream (peer query failed)"); - } - - id_value = gst_structure_get_value (structure, "gstglcontext"); - if (G_VALUE_HOLDS_POINTER (id_value)) { - mix->context = - gst_object_ref (GST_GL_CONTEXT (g_value_get_pointer (id_value))); - } else { - GError *error = NULL; - - GST_INFO ("Creating GstGLDisplay"); - mix->context = gst_gl_context_new (mix->display); - - if (!gst_gl_context_create (mix->context, 0, &error)) { - GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, - ("%s", error->message), (NULL)); - return FALSE; - } - } } return TRUE; @@ -980,11 +1082,15 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate) static gboolean gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) { + GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; + GError *error = NULL; + guint idx; + guint out_width, out_height; gst_query_parse_allocation (query, &caps, NULL); @@ -1002,6 +1108,41 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) update_pool = FALSE; } + if (!gst_gl_ensure_display (mix, &mix->display)) + return FALSE; + + if (gst_query_find_allocation_meta (query, + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) { + GstGLContext *context; + const GstStructure *upload_meta_params; + + gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params); + if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext", + GST_GL_TYPE_CONTEXT, &context, NULL) && context) + gst_object_replace ((GstObject **) & mix->context, (GstObject *) context); + } + + if (!mix->context) { + mix->context = gst_gl_context_new (mix->display); + if (!gst_gl_context_create (mix->context, NULL, &error)) + goto context_error; + } + + out_width = GST_VIDEO_INFO_WIDTH (&mix->out_info); + out_height = GST_VIDEO_INFO_HEIGHT (&mix->out_info); + + if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height, + &mix->fbo, &mix->depthbuffer)) + goto context_error; + + if (mix->out_tex_id) + gst_gl_context_del_texture (mix->context, &mix->out_tex_id); + gst_gl_context_gen_texture (mix->context, &mix->out_tex_id, + GST_VIDEO_FORMAT_RGBA, out_width, out_height); + + if (mixer_class->set_caps) + mixer_class->set_caps (mix, caps); + if (!pool) pool = gst_gl_buffer_pool_new (mix->context); @@ -1020,6 +1161,13 @@ gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query) gst_object_unref (pool); return TRUE; + +context_error: + { + GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), + (NULL)); + return FALSE; + } } /* takes ownership of the pool, allocator and query */ @@ -1122,16 +1270,14 @@ no_decide_allocation: static gboolean gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix, GstCaps * caps) { - GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix); GstGLMixerPrivate *priv = mix->priv; GstVideoInfo info; - guint out_width, out_height; gboolean ret = TRUE; GST_INFO_OBJECT (mix, "set src caps: %" GST_PTR_FORMAT, caps); if (!gst_video_info_from_caps (&info, caps)) { - ret = TRUE; + ret = FALSE; goto done; } @@ -1148,23 +1294,8 @@ gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix, GstCaps * caps) mix->out_info = info; - out_width = GST_VIDEO_INFO_WIDTH (&mix->out_info); - out_height = GST_VIDEO_INFO_HEIGHT (&mix->out_info); - - if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height, - &mix->fbo, &mix->depthbuffer)) - goto context_error; - - if (mix->out_tex_id) - gst_gl_context_del_texture (mix->context, &mix->out_tex_id); - gst_gl_context_gen_texture (mix->context, &mix->out_tex_id, - GST_VIDEO_FORMAT_RGBA, out_width, out_height); - GST_GL_MIXER_UNLOCK (mix); - if (mixer_class->set_caps) - mixer_class->set_caps (mix, caps); - ret = gst_pad_set_caps (mix->srcpad, caps); if (ret) @@ -1173,14 +1304,6 @@ done: priv->negotiated = ret; return ret; - -/* ERRORS */ -context_error: - { - GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, - ("%s", gst_gl_context_get_error ()), (NULL)); - return FALSE; - } } static GstPad *