[852/906] use GstContext for GstGLDisplay propogation

implements the hooks required in GstElement::set_context and the context query
This commit is contained in:
Matthew Waters 2013-11-13 10:43:16 +11:00 committed by Tim-Philipp Müller
parent f15206082a
commit 64fad7a6d2
6 changed files with 335 additions and 32 deletions

View file

@ -28,11 +28,13 @@
#include "gl.h" #include "gl.h"
#include "gstgldisplay.h" #include "gstgldisplay.h"
GST_DEBUG_CATEGORY_STATIC (gst_context);
GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
#define GST_CAT_DEFAULT gst_gl_display_debug #define GST_CAT_DEFAULT gst_gl_display_debug
#define DEBUG_INIT \ #define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (gst_gl_display_debug, "gldisplay", 0, "opengl display"); GST_DEBUG_CATEGORY_INIT (gst_gl_display_debug, "gldisplay", 0, "opengl display"); \
GST_DEBUG_CATEGORY_GET (gst_context, "GST_CONTEXT");
G_DEFINE_TYPE_WITH_CODE (GstGLDisplay, gst_gl_display, G_TYPE_OBJECT, G_DEFINE_TYPE_WITH_CODE (GstGLDisplay, gst_gl_display, G_TYPE_OBJECT,
DEBUG_INIT); DEBUG_INIT);
@ -66,6 +68,8 @@ gst_gl_display_init (GstGLDisplay * display)
display->gl_api = GST_GL_API_NONE; display->gl_api = GST_GL_API_NONE;
GST_TRACE ("init %p", display);
gst_gl_memory_init (); gst_gl_memory_init ();
} }
@ -79,6 +83,8 @@ gst_gl_display_finalize (GObject * object)
display->context = NULL; display->context = NULL;
} }
GST_TRACE ("finalize %p", object);
G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object); G_OBJECT_CLASS (gst_gl_display_parent_class)->finalize (object);
} }
@ -142,6 +148,11 @@ gst_context_set_gl_display (GstContext * context, GstGLDisplay * display)
{ {
GstStructure *s; GstStructure *s;
g_return_if_fail (context != NULL);
GST_CAT_LOG (gst_context, "setting GstGLDisplay(%p) on context(%p)", display,
context);
s = gst_context_writable_structure (context); s = gst_context_writable_structure (context);
gst_structure_set (s, GST_GL_DISPLAY_CONTEXT_TYPE, GST_TYPE_GL_DISPLAY, gst_structure_set (s, GST_GL_DISPLAY_CONTEXT_TYPE, GST_TYPE_GL_DISPLAY,
display, NULL); display, NULL);
@ -151,8 +162,17 @@ gboolean
gst_context_get_gl_display (GstContext * context, GstGLDisplay ** display) gst_context_get_gl_display (GstContext * context, GstGLDisplay ** display)
{ {
const GstStructure *s; const GstStructure *s;
gboolean ret;
g_return_val_if_fail (display != NULL, FALSE);
g_return_val_if_fail (context != NULL, FALSE);
s = gst_context_get_structure (context); s = gst_context_get_structure (context);
return gst_structure_get (s, GST_GL_DISPLAY_CONTEXT_TYPE, ret = gst_structure_get (s, GST_GL_DISPLAY_CONTEXT_TYPE,
GST_TYPE_GL_DISPLAY, display, NULL); GST_TYPE_GL_DISPLAY, display, NULL);
GST_CAT_LOG (gst_context, "got GstGLDisplay(%p) from context(%p)", *display,
context);
return ret;
} }

View file

@ -62,6 +62,8 @@ static void gst_gl_filter_set_property (GObject * object, guint prop_id,
static void gst_gl_filter_get_property (GObject * object, guint prop_id, static void gst_gl_filter_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static void gst_gl_filter_set_context (GstElement * element,
GstContext * context);
static gboolean gst_gl_filter_query (GstBaseTransform * trans, static gboolean gst_gl_filter_query (GstBaseTransform * trans,
GstPadDirection direction, GstQuery * query); GstPadDirection direction, GstQuery * query);
static GstCaps *gst_gl_filter_transform_caps (GstBaseTransform * bt, static GstCaps *gst_gl_filter_transform_caps (GstBaseTransform * bt,
@ -112,6 +114,8 @@ gst_gl_filter_class_init (GstGLFilterClass * klass)
gst_gl_filter_decide_allocation; gst_gl_filter_decide_allocation;
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_filter_get_unit_size; GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_filter_get_unit_size;
element_class->set_context = gst_gl_filter_set_context;
g_object_class_install_property (gobject_class, PROP_OTHER_CONTEXT, g_object_class_install_property (gobject_class, PROP_OTHER_CONTEXT,
g_param_spec_object ("other-context", g_param_spec_object ("other-context",
"External OpenGL context", "External OpenGL context",
@ -176,6 +180,14 @@ gst_gl_filter_get_property (GObject * object, guint prop_id,
} }
} }
static void
gst_gl_filter_set_context (GstElement * element, GstContext * context)
{
GstGLFilter *filter = GST_GL_FILTER (element);
gst_gl_handle_set_context (element, context, &filter->display);
}
static gboolean static gboolean
gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction, gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction,
GstQuery * query) GstQuery * query)
@ -186,13 +198,19 @@ gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction,
filter = GST_GL_FILTER (trans); filter = GST_GL_FILTER (trans);
switch (GST_QUERY_TYPE (query)) { switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
res = gst_gl_handle_context_query ((GstElement *) filter, query,
&filter->display);
break;
}
case GST_QUERY_CUSTOM: case GST_QUERY_CUSTOM:
{ {
GstStructure *structure = gst_query_writable_structure (query); GstStructure *structure = gst_query_writable_structure (query);
if (direction == GST_PAD_SINK && if (direction == GST_PAD_SINK &&
gst_structure_has_name (structure, "gstgldisplay")) { gst_structure_has_name (structure, "gstglcontext")) {
gst_structure_set (structure, "gstgldisplay", G_TYPE_POINTER, gst_structure_set (structure, "gstglcontext", G_TYPE_POINTER,
filter->display, NULL); filter->context, NULL);
res = TRUE; res = TRUE;
} else } else
res = res =
@ -243,6 +261,10 @@ gst_gl_filter_reset (GstGLFilter * filter)
if (filter->other_context) if (filter->other_context)
gst_object_unref (filter->other_context); gst_object_unref (filter->other_context);
filter->other_context = NULL; filter->other_context = NULL;
if (filter->context)
gst_object_unref (filter->context);
filter->context = NULL;
} }
static gboolean static gboolean
@ -251,28 +273,29 @@ gst_gl_filter_start (GstBaseTransform * bt)
GstGLFilter *filter = GST_GL_FILTER (bt); GstGLFilter *filter = GST_GL_FILTER (bt);
GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
GstStructure *structure; GstStructure *structure;
GstQuery *display_query; GstQuery *context_query;
const GValue *id_value; const GValue *id_value;
structure = gst_structure_new_empty ("gstgldisplay"); if (!gst_gl_ensure_display (filter, &filter->display))
display_query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); return FALSE;
if (!gst_pad_peer_query (bt->srcpad, display_query)) { 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 GST_WARNING
("Could not query GstGLDisplay from downstream (peer query failed)"); ("Could not query GstGLContext from downstream (peer query failed)");
} }
id_value = gst_structure_get_value (structure, "gstgldisplay"); id_value = gst_structure_get_value (structure, "gstglcontext");
if (G_VALUE_HOLDS_POINTER (id_value)) { if (G_VALUE_HOLDS_POINTER (id_value)) {
/* at least one gl element is after in our gl chain */ /* at least one gl element is after in our gl chain */
filter->display = filter->context =
gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); gst_object_ref (GST_GL_CONTEXT (g_value_get_pointer (id_value)));
filter->context = gst_gl_display_get_context (filter->display);
} else { } else {
GError *error = NULL; GError *error = NULL;
GST_INFO ("Creating GstGLDisplay"); GST_INFO ("Creating GstGLContext");
filter->display = gst_gl_display_new ();
filter->context = gst_gl_context_new (filter->display); filter->context = gst_gl_context_new (filter->display);
if (!gst_gl_context_create (filter->context, filter->other_context, &error)) { if (!gst_gl_context_create (filter->context, filter->other_context, &error)) {
@ -282,6 +305,8 @@ gst_gl_filter_start (GstBaseTransform * bt)
} }
} }
gst_query_unref (context_query);
if (filter_class->onStart) if (filter_class->onStart)
filter_class->onStart (filter); filter_class->onStart (filter);
@ -1067,6 +1092,9 @@ gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf,
filter = GST_GL_FILTER (bt); filter = GST_GL_FILTER (bt);
filter_class = GST_GL_FILTER_GET_CLASS (bt); filter_class = GST_GL_FILTER_GET_CLASS (bt);
if (!gst_gl_ensure_display (filter, &filter->display))
return GST_FLOW_NOT_NEGOTIATED;
g_assert (filter_class->filter || filter_class->filter_texture); g_assert (filter_class->filter || filter_class->filter_texture);
if (filter_class->filter) if (filter_class->filter)

View file

@ -65,7 +65,6 @@ struct _GstGLFilter
GstBufferPool *pool; GstBufferPool *pool;
GstGLDisplay *display; GstGLDisplay *display;
GstGLContext *context;
GstVideoInfo in_info; GstVideoInfo in_info;
GstVideoInfo out_info; GstVideoInfo out_info;
@ -81,6 +80,7 @@ struct _GstGLFilter
GstGLShader *default_shader; GstGLShader *default_shader;
GstGLContext *context;
GstGLContext *other_context; GstGLContext *other_context;
}; };

View file

@ -60,6 +60,8 @@ static gboolean gst_gl_mixer_sink_event (GstCollectPads * pads,
GstCollectData * cdata, GstEvent * event, GstGLMixer * mix); GstCollectData * cdata, GstEvent * event, GstGLMixer * mix);
static gboolean gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix, static gboolean gst_gl_mixer_src_setcaps (GstPad * pad, GstGLMixer * mix,
GstCaps * caps); GstCaps * caps);
static void gst_gl_mixer_set_context (GstElement * element,
GstContext * context);
enum enum
{ {
@ -346,15 +348,21 @@ gst_gl_mixer_sink_query (GstCollectPads * pads, GstCollectData * data,
ret = TRUE; ret = TRUE;
break; break;
} }
case GST_QUERY_CONTEXT:
{
ret = gst_gl_handle_context_query ((GstElement *) mix, query,
&mix->display);
break;
}
case GST_QUERY_CUSTOM: case GST_QUERY_CUSTOM:
{ {
/* mix is a sink in terms of gl chain, so we are sharing the gldisplay that /* mix is a sink in terms of gl chain, so we are sharing the gldisplay that
* comes from src pad with every display of the sink pads */ * comes from src pad with every display of the sink pads */
GstStructure *structure = gst_query_writable_structure (query); GstStructure *structure = gst_query_writable_structure (query);
if (gst_structure_has_name (structure, "gstgldisplay")) { if (gst_structure_has_name (structure, "gstglcontext")) {
gst_structure_set (structure, "gstgldisplay", G_TYPE_POINTER, gst_structure_set (structure, "gstglcontext", G_TYPE_POINTER,
mix->display, NULL); mix->context, NULL);
} else { } else {
ret = gst_collect_pads_query_default (pads, data, query, FALSE); ret = gst_collect_pads_query_default (pads, data, query, FALSE);
} }
@ -513,6 +521,7 @@ gst_gl_mixer_class_init (GstGLMixerClass * klass)
GST_DEBUG_FUNCPTR (gst_gl_mixer_request_new_pad); GST_DEBUG_FUNCPTR (gst_gl_mixer_request_new_pad);
element_class->release_pad = GST_DEBUG_FUNCPTR (gst_gl_mixer_release_pad); element_class->release_pad = GST_DEBUG_FUNCPTR (gst_gl_mixer_release_pad);
element_class->change_state = GST_DEBUG_FUNCPTR (gst_gl_mixer_change_state); element_class->change_state = GST_DEBUG_FUNCPTR (gst_gl_mixer_change_state);
element_class->set_context = GST_DEBUG_FUNCPTR (gst_gl_mixer_set_context);
/* Register the pad class */ /* Register the pad class */
g_type_class_ref (GST_TYPE_GL_MIXER_PAD); g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
@ -845,6 +854,14 @@ gst_gl_mixer_read_qos (GstGLMixer * mix, gdouble * proportion,
GST_OBJECT_UNLOCK (mix); GST_OBJECT_UNLOCK (mix);
} }
static void
gst_gl_mixer_set_context (GstElement * element, GstContext * context)
{
GstGLMixer *mix = GST_GL_MIXER (element);
gst_gl_handle_set_context (element, context, &mix->display);
}
static gboolean static gboolean
gst_gl_mixer_src_query (GstPad * pad, GstObject * parent, GstQuery * query) gst_gl_mixer_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
{ {
@ -852,6 +869,12 @@ gst_gl_mixer_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
gboolean res = FALSE; gboolean res = FALSE;
switch (GST_QUERY_TYPE (query)) { switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
{
res = gst_gl_handle_context_query ((GstElement *) mix, query,
&mix->display);
break;
}
case GST_QUERY_POSITION: case GST_QUERY_POSITION:
{ {
GstFormat format; GstFormat format;
@ -918,27 +941,29 @@ gst_gl_mixer_activate (GstGLMixer * mix, gboolean activate)
{ {
if (activate) { if (activate) {
GstStructure *structure; GstStructure *structure;
GstQuery *display_query; GstQuery *context_query;
const GValue *id_value; const GValue *id_value;
structure = gst_structure_new_empty ("gstgldisplay"); if (!gst_gl_ensure_display (mix, &mix->display)) {
display_query = gst_query_new_custom (GST_QUERY_CUSTOM, structure); return FALSE;
if (!gst_pad_peer_query (mix->srcpad, display_query)) {
GST_WARNING
("Could not query GstGLDisplay from downstream (peer query failed)");
} }
id_value = gst_structure_get_value (structure, "gstgldisplay"); 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)) { if (G_VALUE_HOLDS_POINTER (id_value)) {
mix->display = mix->context =
gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); gst_object_ref (GST_GL_CONTEXT (g_value_get_pointer (id_value)));
mix->context = gst_gl_display_get_context (mix->display);
} else { } else {
GError *error = NULL; GError *error = NULL;
GST_INFO ("Creating GstGLDisplay"); GST_INFO ("Creating GstGLDisplay");
mix->display = gst_gl_display_new ();
mix->context = gst_gl_context_new (mix->display); mix->context = gst_gl_context_new (mix->display);
gst_gl_display_set_context (mix->display, mix->context); gst_gl_display_set_context (mix->display, mix->context);

View file

@ -365,3 +365,227 @@ gst_gl_context_del_shader (GstGLContext * context, GstGLShader * shader)
{ {
gst_object_unref (shader); gst_object_unref (shader);
} }
static gboolean
gst_gl_display_found (GstElement * element, GstGLDisplay * display)
{
if (display) {
GST_INFO_OBJECT (element, "already have a display (%p)", display);
return TRUE;
}
return FALSE;
}
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
static gboolean
context_pad_query (const GValue * item, GValue * value, gpointer user_data)
{
GstPad *pad = g_value_get_object (item);
GstQuery *query = user_data;
gboolean res;
res = gst_pad_peer_query (pad, query);
if (res) {
g_value_set_boolean (value, TRUE);
return FALSE;
}
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed");
return TRUE;
}
static gboolean
run_context_query (GstElement * element, GstQuery * query,
GstPadDirection direction)
{
GstIterator *it;
GstIteratorFoldFunction func = context_pad_query;
GValue res = { 0 };
g_value_init (&res, G_TYPE_BOOLEAN);
g_value_set_boolean (&res, FALSE);
/* Ask neighbor */
if (direction == GST_PAD_SRC)
it = gst_element_iterate_src_pads (element);
else
it = gst_element_iterate_sink_pads (element);
while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
return g_value_get_boolean (&res);
}
static void
gst_gl_display_context_prepare (GstElement * element,
GstGLDisplay ** display_ptr)
{
GstContext *ctxt;
GstQuery *query;
if (!GST_CAT_CONTEXT)
GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
/* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
* check if downstream already has a context of the specific type
* 2b) Query upstream as above.
*/
ctxt = NULL;
query = gst_query_new_context (GST_GL_DISPLAY_CONTEXT_TYPE);
if (run_context_query (element, query, GST_PAD_SRC)) {
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%p) in downstream query", ctxt);
gst_query_parse_context (query, &ctxt);
} else if (run_context_query (element, query, GST_PAD_SINK)) {
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%p) in upstream query", ctxt);
gst_query_parse_context (query, &ctxt);
} else {
/* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
* the required context type and afterwards check if a
* usable context was set now as in 1). The message could
* be handled by the parent bins of the element and the
* application.
*/
GstMessage *msg;
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting need context message");
msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
GST_GL_DISPLAY_CONTEXT_TYPE);
gst_element_post_message (element, msg);
}
/*
* Whomever responds to the need-context message performs a
* GstElement::set_context() with the required context in which the element
* is required to update the display_ptr or call gst_gl_handle_set_context().
*/
if (ctxt) {
if (gst_context_has_context_type (ctxt, GST_GL_DISPLAY_CONTEXT_TYPE)) {
gst_context_get_gl_display (ctxt, display_ptr);
}
}
gst_query_unref (query);
}
/* 4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT
* message.
*/
static void
gst_gl_display_context_propagate (GstElement * element, GstGLDisplay * display)
{
GstContext *context;
GstMessage *msg;
if (!display) {
GST_ERROR_OBJECT (element, "Could not get GL display connection");
return;
}
context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display (context, display);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting have context (%p) message with display (%p)", context, display);
msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
gst_element_post_message (GST_ELEMENT_CAST (element), msg);
}
gboolean
gst_gl_ensure_display (gpointer element, GstGLDisplay ** display_ptr)
{
GstGLDisplay *display;
g_return_val_if_fail (element != NULL, FALSE);
g_return_val_if_fail (display_ptr != NULL, FALSE);
/* 1) Check if the element already has a context of the specific
* type.
*/
display = *display_ptr;
if (gst_gl_display_found (element, display))
return TRUE;
gst_gl_display_context_prepare (element, display_ptr);
/* Neighbour found and it updated the display */
if (gst_gl_display_found (element, *display_ptr))
return TRUE;
/* If no neighboor, or application not interested, use system default */
display = gst_gl_display_new ();
*display_ptr = display;
gst_gl_display_context_propagate (element, display);
return display != NULL;
}
gboolean
gst_gl_handle_set_context (GstElement * element, GstContext * context,
GstGLDisplay ** display)
{
GstGLDisplay *replacement = NULL;
const gchar *context_type;
g_return_val_if_fail (display, FALSE);
if (!context)
return FALSE;
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
if (!gst_context_get_gl_display (context, &replacement)) {
GST_WARNING_OBJECT (element, "Failed to get display from context");
return FALSE;
}
}
if (replacement)
gst_object_replace ((GstObject **) display, (GstObject *) replacement);
return TRUE;
}
gboolean
gst_gl_handle_context_query (GstElement * element, GstQuery * query,
GstGLDisplay ** display)
{
gboolean res = FALSE;
const gchar *context_type;
GstContext *context, *old_context;
g_return_val_if_fail (element != NULL, FALSE);
g_return_val_if_fail (query != NULL, FALSE);
g_return_val_if_fail (display != NULL, FALSE);
gst_query_parse_context_type (query, &context_type);
if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
gst_query_parse_context (query, &old_context);
if (old_context)
context = gst_context_copy (old_context);
else
context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display (context, *display);
gst_query_set_context (query, context);
gst_context_unref (context);
res = *display != NULL;
}
return res;
}

View file

@ -102,4 +102,10 @@ gboolean gst_gl_context_check_framebuffer_status (GstGLContext * context);
void gst_gl_context_set_error (GstGLContext * context, const char * format, ...); void gst_gl_context_set_error (GstGLContext * context, const char * format, ...);
gchar *gst_gl_context_get_error (void); gchar *gst_gl_context_get_error (void);
gboolean gst_gl_ensure_display (gpointer element, GstGLDisplay **display_ptr);
gboolean gst_gl_handle_set_context (GstElement * element, GstContext * context,
GstGLDisplay ** display);
gboolean gst_gl_handle_context_query (GstElement * element, GstQuery * query,
GstGLDisplay ** display);
#endif /* __GST_GL_UTILS_H__ */ #endif /* __GST_GL_UTILS_H__ */