static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query) { gboolean res = FALSE; GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { res = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); break; } case GST_QUERY_CAPS: res = gst_gl_mixer_query_caps (agg->srcpad, agg, query); break; default: res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query); break; } return res; }
static void gst_gl_mixer_set_context (GstElement * element, GstContext * context) { GstGLMixer *mix = GST_GL_MIXER (element); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); gst_gl_handle_set_context (element, context, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); }
static void gst_gl_test_src_set_context (GstElement * element, GstContext * context) { GstGLTestSrc *src = GST_GL_TEST_SRC (element); gst_gl_handle_set_context (element, context, &src->display, &src->other_context); if (src->display) gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); }
static gboolean gst_gl_base_mixer_src_query (GstAggregator * agg, GstQuery * query) { gboolean res = FALSE; GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg); GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; res = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->priv->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, mix->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); res = mix->context != NULL; } GST_LOG_OBJECT (mix, "context query of type %s %i", context_type, res); if (res) return res; break; } default: break; } return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query); }
static void stereosplit_set_context (GstElement * element, GstContext * context) { GstGLStereoSplit *stereosplit = GST_GL_STEREOSPLIT (element); 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); GST_ELEMENT_CLASS (gst_gl_stereosplit_parent_class)->set_context (element, context); }
static gboolean gst_gtk_gl_sink_query (GstBaseSink * bsink, GstQuery * query) { GstGtkGLSink *gtk_sink = GST_GTK_GL_SINK (bsink); gboolean res = FALSE; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; res = gst_gl_handle_context_query ((GstElement *) gtk_sink, query, >k_sink->display, >k_sink->gtk_context); if (gtk_sink->display) gst_gl_display_filter_gl_api (gtk_sink->display, GST_GL_API_OPENGL3); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, gtk_sink->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); res = gtk_sink->context != NULL; } GST_LOG_OBJECT (gtk_sink, "context query of type %s %i", context_type, res); break; } default: res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query); break; } return res; }
static gboolean gst_gl_mixer_activate (GstGLMixer * mix, gboolean active) { GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); gboolean result = TRUE; if (active) { if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->other_context)) return FALSE; gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); } return result; }
static gboolean stereosplit_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstGLStereoSplit *split = GST_GL_STEREOSPLIT (parent); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; gboolean ret; ret = gst_gl_handle_context_query ((GstElement *) split, query, &split->display, &split->other_context); if (split->display) gst_gl_display_filter_gl_api (split->display, SUPPORTED_GL_APIS); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, split->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); ret = split->context != NULL; } GST_LOG_OBJECT (split, "context query of type %s %i", context_type, ret); if (ret) return ret; return gst_pad_query_default (pad, parent, query); } /* FIXME: Handle caps query */ default: return gst_pad_query_default (pad, parent, query); } }
static gboolean gst_gl_test_src_start (GstBaseSrc * basesrc) { GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc); if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) return FALSE; gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); src->running_time = 0; src->n_frames = 0; src->negotiated = FALSE; return TRUE; }
static GstStateChangeReturn gst_gl_base_mixer_change_state (GstElement * element, GstStateChange transition) { GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element); GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG_OBJECT (mix, "changing state: %s => %s", gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_gl_ensure_element_data (element, &mix->display, &mix->priv->other_context)) return GST_STATE_CHANGE_FAILURE; gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: if (mix->priv->other_context) { gst_object_unref (mix->priv->other_context); mix->priv->other_context = NULL; } if (mix->display) { gst_object_unref (mix->display); mix->display = NULL; } break; default: break; } return ret; }
static GstStateChangeReturn gst_gl_test_src_change_state (GstElement * element, GstStateChange transition) { GstGLTestSrc *src = GST_GL_TEST_SRC (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG_OBJECT (src, "changing state: %s => %s", gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_gl_ensure_element_data (element, &src->display, &src->other_context)) return GST_STATE_CHANGE_FAILURE; gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_READY_TO_NULL: if (src->other_context) { gst_object_unref (src->other_context); src->other_context = NULL; } if (src->display) { gst_object_unref (src->display); src->display = NULL; } break; default: break; } return ret; }
static GstStateChangeReturn stereosplit_change_state (GstElement * element, GstStateChange transition) { GstGLStereoSplit *stereosplit = GST_GL_STEREOSPLIT (element); GstStateChangeReturn result; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: 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); break; default: break; } result = GST_ELEMENT_CLASS (gst_gl_stereosplit_parent_class)->change_state (element, 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; } break; case GST_STATE_CHANGE_PAUSED_TO_READY: stereosplit_reset (stereosplit); break; default: break; } return result; }
static gboolean ensure_context (GstGLStereoSplit * self) { GError *error = NULL; 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); if (!self->context) { GST_OBJECT_LOCK (self->display); do { if (self->context) gst_object_unref (self->context); /* just get a GL context. we don't care */ self->context = gst_gl_display_get_gl_context_for_thread (self->display, NULL); if (!self->context) { if (!gst_gl_display_create_context (self->display, self->other_context, &self->context, &error)) { GST_OBJECT_UNLOCK (self->display); goto context_error; } } } while (!gst_gl_display_add_context (self->display, self->context)); GST_OBJECT_UNLOCK (self->display); } return TRUE; context_error: { GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return FALSE; } }
static gboolean gst_gl_test_src_query (GstBaseSrc * bsrc, GstQuery * query) { gboolean res = FALSE; GstGLTestSrc *src; src = GST_GL_TEST_SRC (bsrc); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; res = gst_gl_handle_context_query ((GstElement *) src, query, &src->display, &src->other_context); if (src->display) gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_TYPE_GL_CONTEXT, src->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); res = src->context != NULL; } GST_LOG_OBJECT (src, "context query of type %s %i", context_type, res); if (res) return res; break; } case GST_QUERY_CONVERT: { GstFormat src_fmt, dest_fmt; gint64 src_val, dest_val; gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); res = gst_video_info_convert (&src->out_info, src_fmt, src_val, dest_fmt, &dest_val); gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); return res; } default: break; } return GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query); }
static gboolean gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, GstQuery * query) { gboolean ret = FALSE; GstGLMixer *mix = GST_GL_MIXER (agg); GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CAPS: { GstCaps *filter, *caps; gst_query_parse_caps (query, &filter); caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter); gst_query_set_caps_result (query, caps); gst_caps_unref (caps); ret = TRUE; break; } case GST_QUERY_ACCEPT_CAPS: { GstCaps *caps; gst_query_parse_accept_caps (query, &caps); ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps); gst_query_set_accept_caps_result (query, ret); ret = TRUE; break; } case GST_QUERY_ALLOCATION: { GstQuery *decide_query = NULL; GST_OBJECT_LOCK (mix); if (G_UNLIKELY (!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_CONTEXT: { ret = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); break; } default: ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query); break; } return ret; }
static gboolean gst_gl_mixer_propose_allocation (GstGLMixer * mix, GstQuery * decide_query, GstQuery * query) { GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix); GstBufferPool *pool; GstStructure *config; GstCaps *caps; guint size = 0; gboolean need_pool; GError *error = NULL; GstStructure *gl_context; gchar *platform, *gl_apis; gpointer handle; GstAllocator *allocator = NULL; GstAllocationParams params; 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_element_data (mix, &mix->display, &mix->other_context)) return FALSE; gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); if (!mix->context) { mix->context = gst_gl_context_new (mix->display); if (!gst_gl_context_create (mix->context, mix->other_context, &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; } if (pool) { 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); if (mix->context->gl_vtable->FenceSync) gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0); gl_apis = gst_gl_api_to_string (gst_gl_context_get_gl_api (mix->context)); platform = gst_gl_platform_to_string (gst_gl_context_get_gl_platform (mix->context)); handle = (gpointer) gst_gl_context_get_gl_context (mix->context); gl_context = gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT, mix->context, "gst.gl.context.handle", G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform, "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context); g_free (gl_apis); g_free (platform); gst_structure_free (gl_context); gst_allocation_params_init (¶ms); allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR); gst_query_add_allocation_param (query, allocator, ¶ms); gst_object_unref (allocator); 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_base_mixer_decide_allocation (GstGLBaseMixer * mix, GstQuery * query) { GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix); GError *error = NULL; gboolean ret = TRUE; if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->priv->other_context)) return FALSE; gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); _find_local_gl_context (mix); if (!mix->context) { GST_OBJECT_LOCK (mix->display); do { if (mix->context) { gst_object_unref (mix->context); mix->context = NULL; } /* just get a GL context. we don't care */ mix->context = gst_gl_display_get_gl_context_for_thread (mix->display, NULL); if (!mix->context) { if (!gst_gl_display_create_context (mix->display, mix->priv->other_context, &mix->context, &error)) { GST_OBJECT_UNLOCK (mix->display); goto context_error; } } } while (!gst_gl_display_add_context (mix->display, mix->context)); GST_OBJECT_UNLOCK (mix->display); } { GstGLAPI current_gl_api = gst_gl_context_get_gl_api (mix->context); if ((current_gl_api & mix_class->supported_gl_api) == 0) goto unsupported_gl_api; } if (mix_class->decide_allocation) ret = mix_class->decide_allocation (mix, query); return ret; unsupported_gl_api: { GstGLAPI gl_api = gst_gl_context_get_gl_api (mix->context); gchar *gl_api_str = gst_gl_api_to_string (gl_api); gchar *supported_gl_api_str = gst_gl_api_to_string (mix_class->supported_gl_api); GST_ELEMENT_ERROR (mix, RESOURCE, BUSY, ("GL API's not compatible context: %s supported: %s", gl_api_str, supported_gl_api_str), (NULL)); g_free (supported_gl_api_str); g_free (gl_api_str); return FALSE; } context_error: { GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return FALSE; } }
static gboolean gst_gl_base_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, GstQuery * query) { gboolean ret = FALSE; GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg); GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix); GstGLBaseMixerPad *pad = GST_GL_BASE_MIXER_PAD (bpad); GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ALLOCATION: { GstQuery *decide_query = NULL; GST_OBJECT_LOCK (mix); if (G_UNLIKELY (!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 */ if (mix_class->propose_allocation) ret = mix_class->propose_allocation (mix, pad, decide_query, query); else ret = FALSE; if (decide_query) gst_query_unref (decide_query); GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query); return ret; } case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; ret = gst_gl_handle_context_query ((GstElement *) mix, query, &mix->display, &mix->priv->other_context); if (mix->display) gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, mix->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); ret = mix->context != NULL; } GST_LOG_OBJECT (mix, "context query of type %s %i", context_type, ret); if (ret) return ret; break; } default: break; } return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);; }
static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) { GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; GError *error = NULL; if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) return FALSE; gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); _find_local_gl_context (src); if (!src->context) { GST_OBJECT_LOCK (src->display); do { if (src->context) { gst_object_unref (src->context); src->context = NULL; } /* just get a GL context. we don't care */ src->context = gst_gl_display_get_gl_context_for_thread (src->display, NULL); if (!src->context) { if (!gst_gl_display_create_context (src->display, src->other_context, &src->context, &error)) { GST_OBJECT_UNLOCK (src->display); goto context_error; } } } while (!gst_gl_display_add_context (src->display, src->context)); GST_OBJECT_UNLOCK (src->display); } if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0) goto unsupported_gl_api; gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _src_generate_fbo_gl, src); if (!src->fbo) goto context_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_gl_test_src_init_shader (src); gst_object_unref (pool); return TRUE; unsupported_gl_api: { GstGLAPI gl_api = gst_gl_context_get_gl_api (src->context); gchar *gl_api_str = gst_gl_api_to_string (gl_api); gchar *supported_gl_api_str = gst_gl_api_to_string (SUPPORTED_GL_APIS); GST_ELEMENT_ERROR (src, RESOURCE, BUSY, ("GL API's not compatible context: %s supported: %s", gl_api_str, supported_gl_api_str), (NULL)); g_free (supported_gl_api_str); g_free (gl_api_str); return FALSE; } context_error: { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); if (src->context) gst_object_unref (src->context); src->context = NULL; return FALSE; } }
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; GstGLContext *other_context = NULL; GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix); gboolean same_downstream_gl_context = FALSE; if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->other_context)) return FALSE; gst_gl_display_filter_gl_api (mix->display, mixer_class->supported_gl_api); if (gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) { GstGLContext *context; const GstStructure *upload_meta_params; gpointer handle; gchar *type; gchar *apis; gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params); if (upload_meta_params) { if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT, &context, NULL) && context) { GstGLContext *old = mix->context; mix->context = context; if (old) gst_object_unref (old); same_downstream_gl_context = TRUE; } else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle", G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING, &type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL) && handle) { GstGLPlatform platform; GstGLAPI gl_apis; GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s", handle, type, apis); platform = gst_gl_platform_from_string (type); gl_apis = gst_gl_api_from_string (apis); if (gl_apis && platform) other_context = gst_gl_context_new_wrapped (mix->display, (guintptr) handle, platform, gl_apis); } } } if (mix->other_context) { if (!other_context) { other_context = mix->other_context; } else { GST_ELEMENT_WARNING (mix, LIBRARY, SETTINGS, ("%s", "Cannot share with more than one GL context"), ("%s", "Cannot share with more than one GL context")); } } if (!mix->context) { mix->context = gst_gl_context_new (mix->display); if (!gst_gl_context_create (mix->context, other_context, &error)) goto context_error; } 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; mix->depthbuffer = 0; } if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height, &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); gst_gl_context_gen_texture (mix->context, &mix->out_tex_id, GST_VIDEO_FORMAT_RGBA, out_width, out_height); gst_query_parse_allocation (query, &caps, NULL); 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 (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 || (!same_downstream_gl_context && gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL) && !gst_buffer_pool_has_option (pool, GST_BUFFER_POOL_OPTION_GL_SYNC_META))) { /* can't use this pool */ if (pool) gst_object_unref (pool); pool = gst_gl_buffer_pool_new (mix->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; context_error: { GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE; } }
static gboolean stereosplit_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { GstGLStereoSplit *split = GST_GL_STEREOSPLIT (parent); GST_DEBUG_OBJECT (split, "sink query %s", gst_query_type_get_name (GST_QUERY_TYPE (query))); switch (GST_QUERY_TYPE (query)) { case GST_QUERY_CONTEXT: { const gchar *context_type; GstContext *context, *old_context; gboolean ret; ret = gst_gl_handle_context_query ((GstElement *) split, query, &split->display, &split->other_context); if (split->display) gst_gl_display_filter_gl_api (split->display, SUPPORTED_GL_APIS); gst_query_parse_context_type (query, &context_type); if (g_strcmp0 (context_type, "gst.gl.local_context") == 0) { GstStructure *s; gst_query_parse_context (query, &old_context); if (old_context) context = gst_context_copy (old_context); else context = gst_context_new ("gst.gl.local_context", FALSE); s = gst_context_writable_structure (context); gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, split->context, NULL); gst_query_set_context (query, context); gst_context_unref (context); ret = split->context != NULL; } GST_LOG_OBJECT (split, "context query of type %s %i", context_type, ret); if (ret) return ret; return gst_pad_query_default (pad, parent, query); } case GST_QUERY_ALLOCATION: { return stereosplit_propose_allocation (split, query); } case GST_QUERY_ACCEPT_CAPS: { GstCaps *possible, *caps; gboolean allowed; gst_query_parse_accept_caps (query, &caps); if (!(possible = gst_pad_query_caps (split->sink_pad, caps))) return FALSE; allowed = gst_caps_is_subset (caps, possible); gst_caps_unref (possible); gst_query_set_accept_caps_result (query, allowed); return allowed; } case GST_QUERY_CAPS: { GstCaps *filter, *left, *right, *combined, *ret, *templ_caps; gst_query_parse_caps (query, &filter); /* Calculate what downstream can collectively support */ if (!(left = gst_pad_peer_query_caps (split->left_pad, NULL))) return FALSE; if (!(right = gst_pad_peer_query_caps (split->right_pad, NULL))) return FALSE; /* Strip out multiview mode and flags that might break the * intersection, since we can convert. * We could keep downstream preferred flip/flopping and list * separated as preferred in the future which might * theoretically allow us an easier conversion, but it's not essential */ left = strip_mview_fields (left, GST_VIDEO_MULTIVIEW_FLAGS_NONE); right = strip_mview_fields (right, GST_VIDEO_MULTIVIEW_FLAGS_NONE); combined = gst_caps_intersect (left, right); gst_caps_unref (left); gst_caps_unref (right); /* Intersect peer caps with our template formats */ templ_caps = gst_pad_get_pad_template_caps (split->left_pad); ret = gst_caps_intersect_full (combined, templ_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (templ_caps); gst_caps_unref (combined); combined = ret; if (!combined || gst_caps_is_empty (combined)) { gst_caps_unref (combined); return FALSE; } /* Convert from the src pad caps to input formats we support */ ret = stereosplit_transform_caps (split, GST_PAD_SRC, combined, filter); gst_caps_unref (combined); combined = ret; /* Intersect with the sink pad template then */ templ_caps = gst_pad_get_pad_template_caps (split->sink_pad); ret = gst_caps_intersect_full (combined, templ_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (templ_caps); GST_LOG_OBJECT (split, "Returning sink pad caps %" GST_PTR_FORMAT, ret); gst_query_set_caps_result (query, ret); return !gst_caps_is_empty (ret); } default: return gst_pad_query_default (pad, parent, query); } }