* </variablelist>
*
* A #GstBin will by default forward any event sent to it to all sink elements.
- * If all the sinks return TRUE, the bin will also return TRUE, else FALSE is
- * returned. If no sinks are in the bin, the event handler will return TRUE.
+ * If all the sinks return %TRUE, the bin will also return %TRUE, else %FALSE is
+ * returned. If no sinks are in the bin, the event handler will return %TRUE.
*
* </para>
* </refsect2>
- *
- * Last reviewed on 2012-03-28 (0.11.3)
*/
#include "gst_private.h"
gboolean message_forward;
gboolean posted_eos;
+ gboolean posted_playing;
+
+ GList *contexts;
};
typedef struct
static GstStateChangeReturn gst_bin_change_state_func (GstElement * element,
GstStateChange transition);
-static void gst_bin_state_changed (GstElement * element, GstState oldstate,
- GstState newstate, GstState pending);
+static gboolean gst_bin_post_message (GstElement * element, GstMessage * msg);
static GstStateChangeReturn gst_bin_get_state_func (GstElement * element,
GstState * state, GstState * pending, GstClockTime timeout);
static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
static GstBusSyncReply bin_bus_handler (GstBus * bus,
GstMessage * message, GstBin * bin);
static gboolean gst_bin_query (GstElement * element, GstQuery * query);
+static void gst_bin_set_context (GstElement * element, GstContext * context);
static gboolean gst_bin_do_latency_func (GstBin * bin);
/**
* GstBin:async-handling:
*
- * If set to #TRUE, the bin will handle asynchronous state changes.
+ * If set to %TRUE, the bin will handle asynchronous state changes.
* This should be used only if the bin subclass is modifying the state
* of its children on its own.
*/
* @bin: the #GstBin
*
* Will be emitted when the bin needs to perform latency calculations. This
- * signal is only emited for toplevel bins or when async-handling is
+ * signal is only emitted for toplevel bins or when async-handling is
* enabled.
*
* Only one signal handler is invoked. If no signals are connected, the
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_bin_change_state_func);
- gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed);
+ gstelement_class->post_message = GST_DEBUG_FUNCPTR (gst_bin_post_message);
gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func);
#if 0
gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func);
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_bin_send_event);
gstelement_class->query = GST_DEBUG_FUNCPTR (gst_bin_query);
+ gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_bin_set_context);
klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
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);
}
/**
* gst_bin_new:
- * @name: the name of the new bin
+ * @name: (allow-none): the name of the new bin
*
* Creates a new bin with the given name.
*
guint i;
for (i = 0; i < 32; i++)
- if (types & (1 << i))
- GST_DEBUG_OBJECT (bin, " %s", gst_message_type_get_name (1 << i));
+ if (types & (1U << i))
+ GST_DEBUG_OBJECT (bin, " %s", gst_message_type_get_name (1U << i));
}
#endif
}
*
* call with bin LOCK */
static gboolean
-is_stream_start (GstBin * bin, guint32 * seqnum)
+is_stream_start (GstBin * bin, guint32 * seqnum, gboolean * have_group_id,
+ guint * group_id)
{
gboolean result;
- gint n_stream_start = 0;
GList *walk, *msgs;
+ guint tmp_group_id;
+ gboolean first = TRUE, same_group_id = TRUE;
+ *have_group_id = TRUE;
+ *group_id = 0;
result = TRUE;
for (walk = bin->children; walk; walk = g_list_next (walk)) {
GstElement *element;
GST_MESSAGE_STREAM_START))) {
GST_DEBUG ("sink '%s' posted STREAM_START", GST_ELEMENT_NAME (element));
*seqnum = gst_message_get_seqnum (GST_MESSAGE_CAST (msgs->data));
- n_stream_start++;
+ if (gst_message_parse_group_id (GST_MESSAGE_CAST (msgs->data),
+ &tmp_group_id)) {
+ if (first) {
+ first = FALSE;
+ *group_id = tmp_group_id;
+ } else {
+ if (tmp_group_id != *group_id)
+ same_group_id = FALSE;
+ }
+ } else {
+ *have_group_id = FALSE;
+ }
} else {
GST_DEBUG ("sink '%s' did not post STREAM_START yet",
GST_ELEMENT_NAME (element));
}
}
+ /* If all have a group_id we only consider this stream started
+ * if all group ids were the same and all sinks posted a stream-start
+ * message */
+ if (*have_group_id)
+ return same_group_id && result;
+ /* otherwise consider this stream started after all sinks
+ * have reported stream-start for backward compatibility.
+ * FIXME 2.0: This should go away! */
return result;
}
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));
* 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)
*
* MT safe.
*
- * Returns: TRUE if the element could be added, FALSE if
+ * Returns: %TRUE if the element could be added, %FALSE if
* the bin does not want to accept the element.
*/
gboolean
*
* MT safe.
*
- * Returns: TRUE if the element could be removed, FALSE if
+ * Returns: %TRUE if the element could be removed, %FALSE if
* the bin does not want to remove the element.
*/
gboolean
*
* Gets an iterator for the elements in this bin.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_elements (GstBin * bin)
* Gets an iterator for the elements in this bin.
* This iterator recurses into GstBin children.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_recurse (GstBin * bin)
* Gets an iterator for all elements in the bin that have the
* #GST_ELEMENT_FLAG_SINK flag set.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_sinks (GstBin * bin)
* Gets an iterator for all elements in the bin that have the
* #GST_ELEMENT_FLAG_SOURCE flag set.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_sources (GstBin * bin)
}
}
-/* get next element in iterator. the returned element has the
- * refcount increased */
+/* get next element in iterator. */
static GstIteratorResult
gst_bin_sort_iterator_next (GstBinSortIterator * bit, GValue * result)
{
* This function is used internally to perform the state changes
* of the bin elements and for clock selection.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_sorted (GstBin * bin)
return res;
}
-static void
-gst_bin_state_changed (GstElement * element, GstState oldstate,
- GstState newstate, GstState pending)
+static gboolean
+gst_bin_post_message (GstElement * element, GstMessage * msg)
{
GstElementClass *pklass = (GstElementClass *) parent_class;
+ gboolean ret;
- if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING)
- bin_do_eos (GST_BIN_CAST (element));
+ ret = pklass->post_message (element, gst_message_ref (msg));
- if (pklass->state_changed)
- pklass->state_changed (element, oldstate, newstate, pending);
+ if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STATE_CHANGED &&
+ GST_MESSAGE_SRC (msg) == GST_OBJECT_CAST (element)) {
+ GstState newstate, pending;
+
+ gst_message_parse_state_changed (msg, NULL, &newstate, &pending);
+ if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING) {
+ GST_BIN_CAST (element)->priv->posted_playing = TRUE;
+ bin_do_eos (GST_BIN_CAST (element));
+ } else {
+ GST_BIN_CAST (element)->priv->posted_playing = FALSE;
+ }
+ }
+
+ gst_message_unref (msg);
+
+ return ret;
+}
+
+static void
+reset_state (const GValue * data, gpointer user_data)
+{
+ GstElement *e = g_value_get_object (data);
+ GstState state = GPOINTER_TO_INT (user_data);
+
+ if (gst_element_set_state (e, state) == GST_STATE_CHANGE_FAILURE)
+ GST_WARNING_OBJECT (e, "Failed to switch back down to %s",
+ gst_element_state_get_name (state));
}
static GstStateChangeReturn
GST_DEBUG_OBJECT (element, "clearing all cached messages");
bin_remove_messages (bin, NULL, GST_MESSAGE_ANY);
GST_OBJECT_UNLOCK (bin);
- if (current == GST_STATE_PAUSED)
- if (!(gst_bin_src_pads_activate (bin, FALSE)))
- goto activate_failure;
+ /* We might not have reached PAUSED yet due to async errors,
+ * make sure to always deactivate the pads nonetheless */
+ if (!(gst_bin_src_pads_activate (bin, FALSE)))
+ 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;
if (parent == GST_OBJECT_CAST (element)) {
/* element is still in bin, really error now */
gst_object_unref (parent);
- goto done;
+ goto undo;
}
/* child removed from bin, let the resync code redo the state
* change */
"failure (de)activating src pads");
return GST_STATE_CHANGE_FAILURE;
}
+
+undo:
+ {
+ if (current < next) {
+ GstIterator *it = gst_bin_iterate_sorted (GST_BIN (element));
+ GstIteratorResult ret;
+
+ GST_DEBUG_OBJECT (element,
+ "Bin failed to change state, switching children back to %s",
+ gst_element_state_get_name (current));
+ do {
+ ret =
+ gst_iterator_foreach (it, &reset_state, GINT_TO_POINTER (current));
+ } while (ret == GST_ITERATOR_RESYNC);
+ gst_iterator_free (it);
+ }
+ goto done;
+ }
}
/*
* This function is a utility event handler for seek events.
- * It will send the event to all sinks or sources depending on the
- * event-direction.
+ * It will send the event to all sinks or sources and appropriate
+ * ghost pads depending on the event-direction.
*
* Applications are free to override this behaviour and
* implement their own seek handler, but this will work for
switch (gst_iterator_next (iter, &data)) {
case GST_ITERATOR_OK:
{
- GstElement *child = g_value_get_object (&data);;
+ GstElement *child = g_value_get_object (&data);
gst_event_ref (event);
res &= gst_element_send_event (child, event);
}
g_value_unset (&data);
gst_iterator_free (iter);
+
+ if (GST_EVENT_IS_DOWNSTREAM (event)) {
+ iter = gst_element_iterate_sink_pads (GST_ELEMENT (bin));
+ GST_DEBUG_OBJECT (bin, "Sending %s event to sink pads",
+ GST_EVENT_TYPE_NAME (event));
+ } else {
+ iter = gst_element_iterate_src_pads (GST_ELEMENT (bin));
+ GST_DEBUG_OBJECT (bin, "Sending %s event to src pads",
+ GST_EVENT_TYPE_NAME (event));
+ }
+
+ done = FALSE;
+ while (!done) {
+ switch (gst_iterator_next (iter, &data)) {
+ case GST_ITERATOR_OK:
+ {
+ GstPad *pad = g_value_get_object (&data);
+
+ gst_event_ref (event);
+ res &= gst_pad_send_event (pad, event);
+ GST_LOG_OBJECT (pad, "After handling %s event: %d",
+ GST_EVENT_TYPE_NAME (event), res);
+ break;
+ }
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (iter);
+ res = TRUE;
+ break;
+ case GST_ITERATOR_DONE:
+ done = TRUE;
+ break;
+ case GST_ITERATOR_ERROR:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ g_value_unset (&data);
+ gst_iterator_free (iter);
gst_event_unref (event);
return res;
*/
eos = GST_STATE (bin) == GST_STATE_PLAYING
&& GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING
- && is_eos (bin, &seqnum);
+ && bin->priv->posted_playing && is_eos (bin, &seqnum);
GST_OBJECT_UNLOCK (bin);
if (eos
{
guint32 seqnum = 0;
gboolean stream_start;
+ gboolean have_group_id = FALSE;
+ guint group_id = 0;
GST_OBJECT_LOCK (bin);
/* If all sinks are STREAM_START we forward the STREAM_START message
* to the parent bin or application
*/
- stream_start = is_stream_start (bin, &seqnum);
+ stream_start = is_stream_start (bin, &seqnum, &have_group_id, &group_id);
GST_OBJECT_UNLOCK (bin);
if (stream_start) {
tmessage = gst_message_new_stream_start (GST_OBJECT_CAST (bin));
gst_message_set_seqnum (tmessage, seqnum);
+ if (have_group_id)
+ gst_message_set_group_id (tmessage, group_id);
+
GST_DEBUG_OBJECT (bin,
"all sinks posted STREAM_START, posting seqnum #%" G_GUINT32_FORMAT,
seqnum);
}
}
-/* must be called with the object lock. This function releases the lock to post
- * the message. */
+/* must be called without the object lock as it posts messages */
static void
bin_do_message_forward (GstBin * bin, GstMessage * message)
{
GST_DEBUG_OBJECT (bin, "pass %s message upward",
GST_MESSAGE_TYPE_NAME (message));
- GST_OBJECT_UNLOCK (bin);
/* we need to convert these messages to element messages so that our parent
* bin can easily ignore them and so that the application can easily
"message", GST_TYPE_MESSAGE, message, NULL));
gst_element_post_message (GST_ELEMENT_CAST (bin), forwarded);
+ }
+}
- GST_OBJECT_LOCK (bin);
+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:
* result so we can answer it quicker the next time. Any element that
* changes its duration marks our cached values invalid.
* This message is also posted upwards. This is currently disabled
- * because too many elements don't post DURATION messages when the
- * duration changes.
+ * because too many elements don't post DURATION_CHANGED messages when
+ * the duration changes.
*
* GST_MESSAGE_CLOCK_LOST: This message is posted by an element when it
* can no longer provide a clock. The default bin behaviour is to
{
/* collect all eos messages from the children */
- GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
+ GST_OBJECT_LOCK (bin);
/* ref message for future use */
bin_replace_message (bin, message, GST_MESSAGE_EOS);
GST_OBJECT_UNLOCK (bin);
gst_message_parse_segment_start (message, &format, &position);
seqnum = gst_message_get_seqnum (message);
- GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
+
+ GST_OBJECT_LOCK (bin);
/* if this is the first segment-start, post to parent but not to the
* application */
if (!find_message (bin, NULL, GST_MESSAGE_SEGMENT_START) &&
gst_message_parse_segment_done (message, &format, &position);
seqnum = gst_message_get_seqnum (message);
- GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
+
+ GST_OBJECT_LOCK (bin);
bin_replace_message (bin, message, GST_MESSAGE_SEGMENT_START);
/* if there are no more segment_start messages, everybody posted
* a segment_done and we can post one on the bus. */
* for duration, we will recalculate. */
#if 0
GST_OBJECT_LOCK (bin);
- bin_remove_messages (bin, NULL, GST_MESSAGE_DURATION);
+ bin_remove_messages (bin, NULL, GST_MESSAGE_DURATION_CHANGED);
GST_OBJECT_UNLOCK (bin);
#endif
goto forward;
{
GstClock **provided_clock_p;
GstElement **clock_provider_p;
- gboolean playing, provided, forward;
+ gboolean playing, toplevel, provided, forward;
GstClock *clock;
gst_message_parse_clock_lost (message, &clock);
GST_OBJECT_LOCK (bin);
bin->clock_dirty = TRUE;
/* if we lost the clock that we provided, post to parent but
- * only if we are PLAYING. */
+ * only if we are not a top-level bin or PLAYING.
+ * The reason for this is that applications should be able
+ * to PAUSE/PLAY if they receive this message without worrying
+ * about the state of the pipeline. */
provided = (clock == bin->provided_clock);
playing = (GST_STATE (bin) == GST_STATE_PLAYING);
- forward = playing & provided;
+ toplevel = GST_OBJECT_PARENT (bin) == NULL;
+ forward = provided && (playing || !toplevel);
if (provided) {
GST_DEBUG_OBJECT (bin,
"Lost clock %" GST_PTR_FORMAT " provided by %" GST_PTR_FORMAT,
GST_DEBUG_OBJECT (bin, "ASYNC_START message %p, %s", message,
src ? GST_OBJECT_NAME (src) : "(NULL)");
- GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
+ GST_OBJECT_LOCK (bin);
/* we ignore the message if we are going to <= READY */
if ((target = GST_STATE_TARGET (bin)) <= GST_STATE_READY)
goto ignore_start_message;
gst_message_parse_async_done (message, &running_time);
- GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message);
+ GST_OBJECT_LOCK (bin);
/* ignore messages if we are shutting down */
if ((target = GST_STATE_TARGET (bin)) <= GST_STATE_READY)
goto ignore_done_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;
}
static gboolean
bin_query_duration_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
- GstElement *item = g_value_get_object (vitem);
+ gboolean res = FALSE;
+ GstObject *item = g_value_get_object (vitem);
+ if (GST_IS_PAD (item))
+ res = gst_pad_query (GST_PAD (item), fold->query);
+ else
+ res = gst_element_query (GST_ELEMENT (item), fold->query);
- if (gst_element_query (item, fold->query)) {
+ if (res) {
gint64 duration;
g_value_set_boolean (ret, TRUE);
static gboolean
bin_query_position_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
- GstElement *item = g_value_get_object (vitem);
+ gboolean res = FALSE;
+ GstObject *item = g_value_get_object (vitem);
+ if (GST_IS_PAD (item))
+ res = gst_pad_query (GST_PAD (item), fold->query);
+ else
+ res = gst_element_query (GST_ELEMENT (item), fold->query);
- if (gst_element_query (item, fold->query)) {
+ if (res) {
gint64 position;
g_value_set_boolean (ret, TRUE);
static gboolean
bin_query_latency_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
- GstElement *item = g_value_get_object (vitem);
-
- if (gst_element_query (item, fold->query)) {
+ gboolean res = FALSE;
+ GstObject *item = g_value_get_object (vitem);
+ if (GST_IS_PAD (item))
+ res = gst_pad_query (GST_PAD (item), fold->query);
+ else
+ res = gst_element_query (GST_ELEMENT (item), fold->query);
+ if (res) {
GstClockTime min, max;
gboolean live;
fold->max = max;
else if (max < fold->max)
fold->max = max;
- if (fold->live == FALSE)
+ if (!fold->live)
fold->live = live;
}
} else {
static gboolean
bin_query_generic_fold (const GValue * vitem, GValue * ret, QueryFold * fold)
{
- GstElement *item = g_value_get_object (vitem);
- gboolean res;
-
- if ((res = gst_element_query (item, fold->query))) {
+ gboolean res = FALSE;
+ GstObject *item = g_value_get_object (vitem);
+ if (GST_IS_PAD (item))
+ res = gst_pad_query (GST_PAD (item), fold->query);
+ else
+ res = gst_element_query (GST_ELEMENT (item), fold->query);
+ if (res) {
g_value_set_boolean (ret, TRUE);
GST_DEBUG_OBJECT (item, "answered query %p", fold->query);
}
return !res;
}
+/* Perform a query iteration for the given bin. The query is stored in
+ * QueryFold and iter should be either a GstPad iterator or a
+ * GstElement iterator. */
+static gboolean
+bin_iterate_fold (GstBin * bin, GstIterator * iter, QueryInitFunction fold_init,
+ QueryDoneFunction fold_done, GstIteratorFoldFunction fold_func,
+ QueryFold * fold_data, gboolean default_return)
+{
+ gboolean res = default_return;
+ GValue ret = { 0 };
+ /* set the result of the query to FALSE initially */
+ g_value_init (&ret, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&ret, res);
+
+ while (TRUE) {
+ GstIteratorResult ires;
+
+ ires = gst_iterator_fold (iter, fold_func, &ret, fold_data);
+
+ switch (ires) {
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (iter);
+ if (fold_init)
+ fold_init (bin, fold_data);
+ g_value_set_boolean (&ret, res);
+ break;
+ case GST_ITERATOR_OK:
+ case GST_ITERATOR_DONE:
+ res = g_value_get_boolean (&ret);
+ if (fold_done != NULL && res)
+ fold_done (bin, fold_data);
+ goto done;
+ default:
+ res = FALSE;
+ goto done;
+ }
+ }
+done:
+ return res;
+}
+
static gboolean
gst_bin_query (GstElement * element, GstQuery * query)
{
GstBin *bin = GST_BIN_CAST (element);
GstIterator *iter;
+ gboolean default_return = FALSE;
gboolean res = FALSE;
+ gboolean src_pads_query_result = FALSE;
GstIteratorFoldFunction fold_func;
QueryInitFunction fold_init = NULL;
QueryDoneFunction fold_done = NULL;
QueryFold fold_data;
- GValue ret = { 0 };
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
for (cached = bin->messages; cached; cached = g_list_next (cached)) {
GstMessage *message = (GstMessage *) cached->data;
- if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_DURATION &&
+ if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_DURATION_CHANGED &&
GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (bin)) {
GstFormat format;
gint64 duration;
fold_func = (GstIteratorFoldFunction) bin_query_latency_fold;
fold_init = bin_query_min_max_init;
fold_done = bin_query_latency_done;
- res = TRUE;
+ default_return = TRUE;
break;
}
default:
fold_data.query = query;
- /* set the result of the query to FALSE initially */
- g_value_init (&ret, G_TYPE_BOOLEAN);
- g_value_set_boolean (&ret, res);
-
iter = gst_bin_iterate_sinks (bin);
GST_DEBUG_OBJECT (bin, "Sending query %p (type %s) to sink children",
query, GST_QUERY_TYPE_NAME (query));
if (fold_init)
fold_init (bin, &fold_data);
- while (TRUE) {
- GstIteratorResult ires;
+ res =
+ bin_iterate_fold (bin, iter, fold_init, fold_done, fold_func, &fold_data,
+ default_return);
+ gst_iterator_free (iter);
- ires = gst_iterator_fold (iter, fold_func, &ret, &fold_data);
+ if (!res) {
+ /* Query the source pads of the element */
+ iter = gst_element_iterate_src_pads (element);
+ src_pads_query_result =
+ bin_iterate_fold (bin, iter, fold_init, fold_done, fold_func,
+ &fold_data, default_return);
+ gst_iterator_free (iter);
- switch (ires) {
- case GST_ITERATOR_RESYNC:
- gst_iterator_resync (iter);
- if (fold_init)
- fold_init (bin, &fold_data);
- g_value_set_boolean (&ret, res);
- break;
- case GST_ITERATOR_OK:
- case GST_ITERATOR_DONE:
- res = g_value_get_boolean (&ret);
- if (fold_done != NULL && res)
- fold_done (bin, &fold_data);
- goto done;
- default:
- res = FALSE;
- goto done;
- }
+ if (src_pads_query_result)
+ res = TRUE;
}
-done:
- gst_iterator_free (iter);
GST_DEBUG_OBJECT (bin, "query %p result %d", query, res);
return res;
}
+static void
+set_context (const GValue * item, gpointer user_data)
+{
+ GstElement *element = g_value_get_object (item);
+
+ gst_element_set_context (element, user_data);
+}
+
+static void
+gst_bin_set_context (GstElement * element, GstContext * context)
+{
+ GstBin *bin;
+ GstIterator *children;
+
+ g_return_if_fail (GST_IS_BIN (element));
+
+ 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)
+ gst_iterator_resync (children);
+ gst_iterator_free (children);
+}
+
static gint
compare_name (const GValue * velement, const gchar * name)
{
* Gets the element with the given name from a bin. This
* function recurses into child bins.
*
- * Returns NULL if no element with the given name is found in the bin.
+ * Returns %NULL if no element with the given name is found in the bin.
*
* MT safe. Caller owns returned reference.
*
- * Returns: (transfer full): the #GstElement with the given name, or NULL
+ * Returns: (transfer full) (nullable): the #GstElement with the given
+ * name, or %NULL
*/
GstElement *
gst_bin_get_by_name (GstBin * bin, const gchar * name)
* Gets the element with the given name from this bin. If the
* element is not found, a recursion is performed on the parent bin.
*
- * Returns NULL if:
+ * Returns %NULL if:
* - no element with the given name is found in the bin
*
* MT safe. Caller owns returned reference.
*
- * Returns: (transfer full): the #GstElement with the given name, or NULL
+ * Returns: (transfer full) (nullable): the #GstElement with the given
+ * name, or %NULL
*/
GstElement *
gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
* The function recurses inside child bins. The iterator will yield a series
* of #GstElement that should be unreffed after use.
*
- * Each element yielded by the iterator will have its refcount increased, so
- * unref after use.
- *
* MT safe. Caller owns returned value.
*
- * Returns: (transfer full): a #GstIterator of #GstElement for all elements
- * in the bin implementing the given interface, or NULL
+ * Returns: (transfer full) (nullable): a #GstIterator of #GstElement
+ * for all elements in the bin implementing the given interface,
+ * or %NULL
*/
GstIterator *
gst_bin_iterate_all_by_interface (GstBin * bin, GType iface)