bin: Implement context caching and propagation again

This commit is contained in:
Sebastian Dröge 2013-09-17 14:25:10 +02:00
parent 51982d158a
commit 640a05ff60

View file

@ -198,6 +198,8 @@ struct _GstBinPrivate
gboolean message_forward;
gboolean posted_eos;
GList *contexts;
};
typedef struct
@ -530,6 +532,8 @@ gst_bin_dispose (GObject * object)
GST_STR_NULL (GST_OBJECT_NAME (object)));
}
g_list_free_full (bin->priv->contexts, (GDestroyNotify) gst_context_unref);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -1094,6 +1098,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
gboolean is_sink, is_source, provides_clock, requires_clock;
GstMessage *clock_message = NULL, *async_message = NULL;
GstStateChangeReturn ret;
GList *l;
GST_DEBUG_OBJECT (bin, "element :%s", GST_ELEMENT_NAME (element));
@ -1165,6 +1170,9 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
* a new clock will be selected */
gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
for (l = bin->priv->contexts; l; l = l->next)
gst_element_set_context (element, l->data);
#if 0
/* set the cached index on the children */
if (bin->priv->index)
@ -2576,9 +2584,30 @@ gst_bin_change_state_func (GstElement * element, GstStateChange transition)
goto activate_failure;
break;
case GST_STATE_NULL:
if (current == GST_STATE_READY)
if (current == GST_STATE_READY) {
GList *l;
if (!(gst_bin_src_pads_activate (bin, FALSE)))
goto activate_failure;
/* Remove all non-persistent contexts */
GST_OBJECT_LOCK (bin);
for (l = bin->priv->contexts; l;) {
GstContext *context = l->data;
if (!gst_context_is_persistent (context)) {
GList *next;
gst_context_unref (context);
next = l->next;
bin->priv->contexts = g_list_delete_link (bin->priv->contexts, l);
l = next;
} else {
l = l->next;
}
}
GST_OBJECT_UNLOCK (bin);
}
break;
default:
break;
@ -3269,6 +3298,34 @@ bin_do_message_forward (GstBin * bin, GstMessage * message)
}
}
static void
gst_bin_update_context (GstBin * bin, GstContext * context)
{
GList *l;
const gchar *context_type;
GST_OBJECT_LOCK (bin);
context_type = gst_context_get_context_type (context);
for (l = bin->priv->contexts; l; l = l->next) {
GstContext *tmp = l->data;
const gchar *tmp_type = gst_context_get_context_type (tmp);
/* Always store newest context but never replace
* a persistent one by a non-persistent one */
if (strcmp (context_type, tmp_type) == 0 &&
(gst_context_is_persistent (context) ||
!gst_context_is_persistent (tmp))) {
gst_context_replace ((GstContext **) & l->data, context);
break;
}
}
/* Not found? Add */
if (l != NULL)
bin->priv->contexts =
g_list_prepend (bin->priv->contexts, gst_context_ref (context));
GST_OBJECT_UNLOCK (bin);
}
/* handle child messages:
*
* This method is called synchronously when a child posts a message on
@ -3625,6 +3682,42 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
break;
}
case GST_MESSAGE_NEED_CONTEXT:{
const gchar *context_type;
GList *l;
gst_message_parse_context_type (message, &context_type);
GST_OBJECT_LOCK (bin);
for (l = bin->priv->contexts; l; l = l->next) {
GstContext *tmp = l->data;
const gchar *tmp_type = gst_context_get_context_type (tmp);
if (strcmp (context_type, tmp_type) == 0) {
gst_element_set_context (GST_ELEMENT (src), l->data);
break;
}
}
GST_OBJECT_UNLOCK (bin);
/* Forward if we couldn't answer the message */
if (l == NULL) {
goto forward;
} else {
gst_message_unref (message);
}
break;
}
case GST_MESSAGE_HAVE_CONTEXT:{
GstContext *context;
gst_message_parse_have_context (message, &context);
gst_bin_update_context (bin, context);
gst_context_unref (context);
goto forward;
break;
}
default:
goto forward;
}
@ -3989,6 +4082,8 @@ gst_bin_set_context (GstElement * element, GstContext * context)
bin = GST_BIN (element);
gst_bin_update_context (bin, context);
children = gst_bin_iterate_elements (bin);
while (gst_iterator_foreach (children, set_context,
context) == GST_ITERATOR_RESYNC);