X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fgstbin.c;h=8e31a48fe80d6a9342895d355e3369a8a58ff9c3;hb=066b515985897495cae32fca5b7eeeec260c40c9;hp=91526dc935cc9e38f7e4a6b936611476f40f5220;hpb=9c0d8ca71863814e6233740d3b1cb2eccfd1f3d1;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstbin.c b/gst/gstbin.c index 91526dc..8e31a48 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -154,28 +154,19 @@ * * * - * Last reviewed on 2006-04-28 (0.10.6) + * Last reviewed on 2012-03-28 (0.11.3) */ #include "gst_private.h" #include "gstevent.h" #include "gstbin.h" -#include "gstmarshal.h" #include "gstinfo.h" #include "gsterror.h" -#include "gstindex.h" -#include "gstindexfactory.h" #include "gstutils.h" #include "gstchildproxy.h" -/* latency is by default enabled now. - * live-preroll and no-live-preroll in the environment var GST_COMPAT - * to enables or disable it respectively. - */ -static gboolean enable_latency = TRUE; - GST_DEBUG_CATEGORY_STATIC (bin_debug); #define GST_CAT_DEFAULT bin_debug @@ -198,8 +189,11 @@ struct _GstBinPrivate guint32 structure_cookie; +#if 0 /* cached index */ GstIndex *index; +#endif + /* forward messages from our children */ gboolean message_forward; @@ -227,7 +221,7 @@ static void gst_bin_state_changed (GstElement * element, GstState oldstate, 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, - gboolean flag_pending, gboolean reset_time); + gboolean flag_pending, GstClockTime running_time); static void bin_handle_async_start (GstBin * bin); static void bin_push_state_continue (BinContinueData * data); static void bin_do_eos (GstBin * bin); @@ -235,8 +229,10 @@ static void bin_do_eos (GstBin * bin); static gboolean gst_bin_add_func (GstBin * bin, GstElement * element); static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element); +#if 0 static void gst_bin_set_index_func (GstElement * element, GstIndex * index); static GstIndex *gst_bin_get_index_func (GstElement * element); +#endif static GstClock *gst_bin_provide_clock_func (GstElement * element); static gboolean gst_bin_set_clock_func (GstElement * element, GstClock * clock); @@ -283,7 +279,6 @@ static guint gst_bin_signals[LAST_SIGNAL] = { 0 }; #define _do_init \ { \ - const gchar *compat; \ static const GInterfaceInfo iface_info = { \ gst_bin_child_proxy_init, \ NULL, \ @@ -294,20 +289,12 @@ static guint gst_bin_signals[LAST_SIGNAL] = { 0 }; GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD, \ "debugging info for the 'bin' container element"); \ \ - /* compatibility stuff */ \ - compat = g_getenv ("GST_COMPAT"); \ - if (compat != NULL) { \ - if (strstr (compat, "no-live-preroll")) \ - enable_latency = FALSE; \ - else if (strstr (compat, "live-preroll")) \ - enable_latency = TRUE; \ - } \ } #define gst_bin_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstBin, gst_bin, GST_TYPE_ELEMENT, _do_init); -static GstObject * +static GObject * gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy, guint index) { @@ -321,7 +308,7 @@ gst_bin_child_proxy_get_child_by_index (GstChildProxy * child_proxy, gst_object_ref (res); GST_OBJECT_UNLOCK (bin); - return res; + return (GObject *) res; } static guint @@ -403,7 +390,7 @@ gst_bin_class_init (GstBinClass * klass) gst_bin_signals[ELEMENT_ADDED] = g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL, - NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** * GstBin::element-removed: * @bin: the #GstBin @@ -414,7 +401,7 @@ gst_bin_class_init (GstBinClass * klass) gst_bin_signals[ELEMENT_REMOVED] = g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL, - NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); + NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT); /** * GstBin::do-latency: * @bin: the #GstBin @@ -436,7 +423,7 @@ gst_bin_class_init (GstBinClass * klass) gst_bin_signals[DO_LATENCY] = g_signal_new ("do-latency", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstBinClass, do_latency), - _gst_boolean_accumulator, NULL, gst_marshal_BOOLEAN__VOID, + _gst_boolean_accumulator, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 0, G_TYPE_NONE); /** @@ -470,8 +457,10 @@ gst_bin_class_init (GstBinClass * klass) GST_DEBUG_FUNCPTR (gst_bin_change_state_func); gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed); 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->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func); +#endif gstelement_class->provide_clock = GST_DEBUG_FUNCPTR (gst_bin_provide_clock_func); gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func); @@ -526,7 +515,6 @@ gst_bin_dispose (GObject * object) GstBus **child_bus_p = &bin->child_bus; GstClock **provided_clock_p = &bin->provided_clock; GstElement **clock_provider_p = &bin->clock_provider; - GstIndex **index_p = &bin->priv->index; GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose"); @@ -534,7 +522,6 @@ gst_bin_dispose (GObject * object) gst_object_replace ((GstObject **) child_bus_p, NULL); gst_object_replace ((GstObject **) provided_clock_p, NULL); gst_object_replace ((GstObject **) clock_provider_p, NULL); - gst_object_replace ((GstObject **) index_p, NULL); bin_remove_messages (bin, NULL, GST_MESSAGE_ANY); GST_OBJECT_UNLOCK (object); @@ -555,7 +542,7 @@ gst_bin_dispose (GObject * object) * * Creates a new bin with the given name. * - * Returns: (transfer full): a new #GstBin + * Returns: (transfer floating): a new #GstBin */ GstElement * gst_bin_new (const gchar * name) @@ -613,6 +600,7 @@ gst_bin_get_property (GObject * object, guint prop_id, } } +#if 0 /* return the cached index */ static GstIndex * gst_bin_get_index_func (GstElement * element) @@ -696,6 +684,7 @@ was_set: return; } } +#endif /* set the clock on all elements in this bin * @@ -741,6 +730,9 @@ gst_bin_set_clock_func (GstElement * element, GstClock * clock) g_value_unset (&data); gst_iterator_free (it); + if (res) + res = GST_ELEMENT_CLASS (parent_class)->set_clock (element, clock); + return res; } @@ -1042,7 +1034,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element) { gchar *elem_name; GstIterator *it; - gboolean is_sink, is_source; + gboolean is_sink, is_source, provides_clock, requires_clock; GstMessage *clock_message = NULL, *async_message = NULL; GstStateChangeReturn ret; @@ -1055,8 +1047,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element) /* get the element name to make sure it is unique in this bin. */ GST_OBJECT_LOCK (element); elem_name = g_strdup (GST_ELEMENT_NAME (element)); - is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK); - is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE); + is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK); + is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE); + provides_clock = + GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK); + requires_clock = + GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK); GST_OBJECT_UNLOCK (element); GST_OBJECT_LOCK (bin); @@ -1077,17 +1073,22 @@ gst_bin_add_func (GstBin * bin, GstElement * element) if (is_sink) { GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was sink", elem_name); - GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SINK); + GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SINK); } if (is_source) { GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "element \"%s\" was source", elem_name); - GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_IS_SOURCE); + GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_SOURCE); } - if (gst_element_provides_clock (element)) { + if (provides_clock) { GST_DEBUG_OBJECT (bin, "element \"%s\" can provide a clock", elem_name); clock_message = gst_message_new_clock_provide (GST_OBJECT_CAST (element), NULL, TRUE); + GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK); + } + if (requires_clock) { + GST_DEBUG_OBJECT (bin, "element \"%s\" requires a clock", elem_name); + GST_OBJECT_FLAG_SET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK); } bin->children = g_list_prepend (bin->children, element); @@ -1105,9 +1106,12 @@ gst_bin_add_func (GstBin * bin, GstElement * element) * that is not important right now. When the pipeline goes to PLAYING, * a new clock will be selected */ gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin)); + +#if 0 /* set the cached index on the children */ if (bin->priv->index) gst_element_set_index (element, bin->priv->index); +#endif ret = GST_STATE_RETURN (bin); /* no need to update the state if we are in error */ @@ -1130,7 +1134,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element) } case GST_STATE_CHANGE_NO_PREROLL: /* ignore all async elements we might have and commit our state */ - bin_handle_async_done (bin, ret, FALSE, FALSE); + bin_handle_async_done (bin, ret, FALSE, GST_CLOCK_TIME_NONE); break; case GST_STATE_CHANGE_FAILURE: break; @@ -1156,10 +1160,12 @@ no_state_recalc: GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"", elem_name); - g_free (elem_name); g_signal_emit (bin, gst_bin_signals[ELEMENT_ADDED], 0, element); - gst_child_proxy_child_added ((GstObject *) bin, (GstObject *) element); + gst_child_proxy_child_added ((GstChildProxy *) bin, (GObject *) element, + elem_name); + + g_free (elem_name); return TRUE; @@ -1252,7 +1258,8 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) { gchar *elem_name; GstIterator *it; - gboolean is_sink, is_source, othersink, othersource, found; + gboolean is_sink, is_source, provides_clock, requires_clock; + gboolean othersink, othersource, otherprovider, otherrequirer, found; GstMessage *clock_message = NULL; GstClock **provided_clock_p; GstElement **clock_provider_p; @@ -1262,28 +1269,31 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) GST_DEBUG_OBJECT (bin, "element :%s", GST_ELEMENT_NAME (element)); + GST_OBJECT_LOCK (bin); + GST_OBJECT_LOCK (element); - /* Check if the element is already being removed and immediately - * return */ - if (G_UNLIKELY (GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_UNPARENTING))) - goto already_removing; + elem_name = g_strdup (GST_ELEMENT_NAME (element)); + + if (GST_OBJECT_PARENT (element) != GST_OBJECT_CAST (bin)) + goto not_in_bin; + + /* remove the parent ref */ + GST_OBJECT_PARENT (element) = NULL; - GST_OBJECT_FLAG_SET (element, GST_ELEMENT_UNPARENTING); /* grab element name so we can print it */ - elem_name = g_strdup (GST_ELEMENT_NAME (element)); - is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK); - is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SOURCE); + is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK); + is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE); + provides_clock = + GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_PROVIDE_CLOCK); + requires_clock = + GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_REQUIRE_CLOCK); GST_OBJECT_UNLOCK (element); - /* unlink all linked pads */ - it = gst_element_iterate_pads (element); - gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL); - gst_iterator_free (it); - - GST_OBJECT_LOCK (bin); found = FALSE; othersink = FALSE; othersource = FALSE; + otherprovider = FALSE; + otherrequirer = FALSE; have_no_preroll = FALSE; /* iterate the elements, we collect which ones are async and no_preroll. We * also remove the element when we find it. */ @@ -1297,16 +1307,24 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) /* remove the element */ bin->children = g_list_delete_link (bin->children, walk); } else { - gboolean child_sink, child_source; + gboolean child_sink, child_source, child_provider, child_requirer; GST_OBJECT_LOCK (child); - child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK); - child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE); + child_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK); + child_source = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE); + child_provider = + GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_PROVIDE_CLOCK); + child_requirer = + GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_REQUIRE_CLOCK); /* when we remove a sink, check if there are other sinks. */ if (is_sink && !othersink && child_sink) othersink = TRUE; if (is_source && !othersource && child_source) othersource = TRUE; + if (provides_clock && !otherprovider && child_provider) + otherprovider = TRUE; + if (requires_clock && !otherrequirer && child_requirer) + otherrequirer = TRUE; /* check if we have NO_PREROLL children */ if (GST_STATE_RETURN (child) == GST_STATE_CHANGE_NO_PREROLL) have_no_preroll = TRUE; @@ -1327,14 +1345,23 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) if (is_sink && !othersink) { /* we're not a sink anymore */ GST_DEBUG_OBJECT (bin, "we removed the last sink"); - GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK); + GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SINK); } if (is_source && !othersource) { /* we're not a source anymore */ GST_DEBUG_OBJECT (bin, "we removed the last source"); - GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SOURCE); + GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_SOURCE); + } + if (provides_clock && !otherprovider) { + /* we're not a clock provider anymore */ + GST_DEBUG_OBJECT (bin, "we removed the last clock provider"); + GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_PROVIDE_CLOCK); + } + if (requires_clock && !otherrequirer) { + /* we're not a clock requirer anymore */ + GST_DEBUG_OBJECT (bin, "we removed the last clock requirer"); + GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_FLAG_REQUIRE_CLOCK); } - /* if the clock provider for this element is removed, we lost * the clock as well, we need to inform the parent of this @@ -1424,7 +1451,7 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) else ret = GST_STATE_CHANGE_SUCCESS; - bin_handle_async_done (bin, ret, FALSE, FALSE); + bin_handle_async_done (bin, ret, FALSE, GST_CLOCK_TIME_NONE); } else { GST_DEBUG_OBJECT (bin, "recalc state preroll: %d, other async: %d, this async %d", @@ -1444,32 +1471,28 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) GST_STATE_RETURN (bin) = ret; } no_state_recalc: + /* clear bus */ + gst_element_set_bus (element, NULL); + /* Clear the clock we provided to the element */ + gst_element_set_clock (element, NULL); GST_OBJECT_UNLOCK (bin); if (clock_message) gst_element_post_message (GST_ELEMENT_CAST (bin), clock_message); + /* unlink all linked pads */ + it = gst_element_iterate_pads (element); + gst_iterator_foreach (it, (GstIteratorForeachFunction) unlink_pads, NULL); + gst_iterator_free (it); + GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"", elem_name); - g_free (elem_name); - - gst_element_set_bus (element, NULL); - - /* Clear the clock we provided to the element */ - gst_element_set_clock (element, NULL); - - /* we ref here because after the _unparent() the element can be disposed - * and we still need it to reset the UNPARENTING flag and fire a signal. */ - gst_object_ref (element); - gst_object_unparent (GST_OBJECT_CAST (element)); - - GST_OBJECT_LOCK (element); - GST_OBJECT_FLAG_UNSET (element, GST_ELEMENT_UNPARENTING); - GST_OBJECT_UNLOCK (element); g_signal_emit (bin, gst_bin_signals[ELEMENT_REMOVED], 0, element); - gst_child_proxy_child_removed ((GstObject *) bin, (GstObject *) element); + gst_child_proxy_child_removed ((GstChildProxy *) bin, (GObject *) element, + elem_name); + g_free (elem_name); /* element is really out of our control now */ gst_object_unref (element); @@ -1480,16 +1503,11 @@ not_in_bin: { g_warning ("Element '%s' is not in bin '%s'", elem_name, GST_ELEMENT_NAME (bin)); + GST_OBJECT_UNLOCK (element); GST_OBJECT_UNLOCK (bin); g_free (elem_name); return FALSE; } -already_removing: - { - GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "already removing child"); - GST_OBJECT_UNLOCK (element); - return FALSE; - } } /** @@ -1626,7 +1644,7 @@ bin_element_is_sink (GstElement * child, GstBin * bin) /* we lock the child here for the remainder of the function to * get its name and flag safely. */ GST_OBJECT_LOCK (child); - is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK); + is_sink = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SINK); GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, "child %s %s sink", GST_OBJECT_NAME (child), is_sink ? "is" : "is not"); @@ -1649,7 +1667,7 @@ sink_iterator_filter (const GValue * vchild, GValue * vbin) * @bin: a #GstBin * * Gets an iterator for all elements in the bin that have the - * #GST_ELEMENT_IS_SINK flag set. + * #GST_ELEMENT_FLAG_SINK flag set. * * Each element yielded by the iterator will have its refcount increased, so * unref after use. @@ -1689,7 +1707,7 @@ bin_element_is_src (GstElement * child, GstBin * bin) /* we lock the child here for the remainder of the function to * get its name and other info safely. */ GST_OBJECT_LOCK (child); - is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_IS_SOURCE); + is_src = GST_OBJECT_FLAG_IS_SET (child, GST_ELEMENT_FLAG_SOURCE); GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin, "child %s %s src", GST_OBJECT_NAME (child), is_src ? "is" : "is not"); @@ -1712,7 +1730,7 @@ src_iterator_filter (const GValue * vchild, GValue * vbin) * @bin: a #GstBin * * Gets an iterator for all elements in the bin that have the - * #GST_ELEMENT_IS_SOURCE flag set. + * #GST_ELEMENT_FLAG_SOURCE flag set. * * Each element yielded by the iterator will have its refcount increased, so * unref after use. @@ -1863,7 +1881,7 @@ reset_degree (GstElement * element, GstBinSortIterator * bit) /* sinks are added right away */ GST_OBJECT_LOCK (element); - is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK); + is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SINK); GST_OBJECT_UNLOCK (element); if (is_sink) { @@ -2121,7 +2139,7 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element, GstState next) { GstStateChangeReturn ret; - GstState pending, child_current, child_pending; + GstState child_current, child_pending; gboolean locked; GList *found; @@ -2132,7 +2150,7 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element, GST_ELEMENT_START_TIME (element) = start_time; element->base_time = base_time; /* peel off the locked flag */ - locked = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_LOCKED_STATE); + locked = GST_ELEMENT_IS_LOCKED_STATE (element); /* Get the previous set_state result to preserve NO_PREROLL and ASYNC */ ret = GST_STATE_RETURN (element); child_current = GST_STATE (element); @@ -2151,17 +2169,81 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element, goto no_preroll; } - GST_OBJECT_LOCK (bin); - pending = GST_STATE_PENDING (bin); + GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, + "current %s pending %s, desired next %s", + gst_element_state_get_name (child_current), + gst_element_state_get_name (child_pending), + gst_element_state_get_name (next)); + + /* always recurse into bins so that we can set the base time */ + if (GST_IS_BIN (element)) + goto do_state; /* Try not to change the state of elements that are already in the state we're * going to */ - if (!(next == GST_STATE_PLAYING || child_pending != GST_STATE_VOID_PENDING || - (child_pending == GST_STATE_VOID_PENDING && - ((pending > child_current && next > child_current) || - (pending < child_current && next < child_current))))) + if (child_current == next && child_pending == GST_STATE_VOID_PENDING) { + /* child is already at the requested state, return previous return. Note that + * if the child has a pending state to next, we will still call the + * set_state function */ goto unneeded; + } else if (next > current) { + /* upward state change */ + if (child_pending == GST_STATE_VOID_PENDING) { + /* .. and the child is not busy doing anything */ + if (child_current > next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } else if (child_pending > child_current) { + /* .. and the child is busy going upwards */ + if (child_current >= next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } else { + /* .. and the child is busy going downwards */ + if (child_current > next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } + } else if (next < current) { + /* downward state change */ + if (child_pending == GST_STATE_VOID_PENDING) { + /* .. and the child is not busy doing anything */ + if (child_current < next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } else if (child_pending < child_current) { + /* .. and the child is busy going downwards */ + if (child_current <= next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } else { + /* .. and the child is busy going upwards */ + if (child_current < next) { + /* .. and is already past the requested state, assume it got there + * without error */ + ret = GST_STATE_CHANGE_SUCCESS; + goto unneeded; + } + } + } +do_state: + GST_OBJECT_LOCK (bin); /* the element was busy with an upwards async state change, we must wait for * an ASYNC_DONE message before we attemp to change the state. */ if ((found = @@ -2177,18 +2259,9 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element, if (next > current) { /* We found an async element check if we can force its state to change or * if we have to wait for it to preroll. */ - if (G_UNLIKELY (!enable_latency)) { - g_warning ("Future versions of GStreamer will wait for element \"%s\"\n" - "\tto preroll in order to perform correct latency calculations.\n" - "\tPlease verify that the application continues to work correctly by\n" - "\tsetting the environment variable GST_COMPAT to a value containing\n" - "\tthe string 'live-preroll'.", GST_ELEMENT_NAME (element)); - goto no_latency; - } goto was_busy; } } -no_latency: GST_OBJECT_UNLOCK (bin); no_preroll: @@ -2212,25 +2285,22 @@ locked: GST_STATE_UNLOCK (element); return ret; } -was_busy: - { - GST_DEBUG_OBJECT (element, "element was busy, delaying state change"); - GST_OBJECT_UNLOCK (bin); - GST_STATE_UNLOCK (element); - return GST_STATE_CHANGE_ASYNC; - } unneeded: { GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, - "skipping transition from %s to %s, since bin pending" - " is %s : last change state return follows", + "skipping transition from %s to %s", gst_element_state_get_name (child_current), - gst_element_state_get_name (next), - gst_element_state_get_name (pending)); - GST_OBJECT_UNLOCK (bin); + gst_element_state_get_name (next)); GST_STATE_UNLOCK (element); return ret; } +was_busy: + { + GST_DEBUG_OBJECT (element, "element was busy, delaying state change"); + GST_OBJECT_UNLOCK (bin); + GST_STATE_UNLOCK (element); + return GST_STATE_CHANGE_ASYNC; + } } /* gst_iterator_fold functions for pads_activate @@ -2626,7 +2696,8 @@ done: bin_remove_messages (bin, NULL, GST_MESSAGE_ASYNC_DONE); GST_DEBUG_OBJECT (bin, "async elements commited"); - bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE, FALSE); + bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, FALSE, + GST_CLOCK_TIME_NONE); } state_end: @@ -2885,7 +2956,7 @@ was_no_preroll: */ static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, - gboolean flag_pending, gboolean reset_time) + gboolean flag_pending, GstClockTime running_time) { GstState current, pending, target; GstStateChangeReturn old_ret; @@ -2913,7 +2984,7 @@ bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, target = GST_STATE_TARGET (bin); pending = GST_STATE_PENDING (bin) = target; - amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), reset_time); + amessage = gst_message_new_async_done (GST_OBJECT_CAST (bin), running_time); old_state = GST_STATE (bin); /* this is the state we should go to next */ @@ -3036,6 +3107,16 @@ bin_do_eos (GstBin * bin) && g_atomic_int_compare_and_exchange (&bin->priv->posted_eos, FALSE, TRUE)) { GstMessage *tmessage; + + /* Clear out any further messages, and reset posted_eos so we can + detect any new EOS that happens (eg, after a seek). Since all + sinks have now posted an EOS, there will be no further EOS events + seen unless there is a new logical EOS */ + GST_OBJECT_LOCK (bin); + bin_remove_messages (bin, NULL, GST_MESSAGE_EOS); + bin->priv->posted_eos = FALSE; + GST_OBJECT_UNLOCK (bin); + tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin)); gst_message_set_seqnum (tmessage, seqnum); GST_DEBUG_OBJECT (bin, @@ -3333,13 +3414,13 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message) } case GST_MESSAGE_ASYNC_DONE: { - gboolean reset_time; + GstClockTime running_time; GstState target; GST_DEBUG_OBJECT (bin, "ASYNC_DONE message %p, %s", message, src ? GST_OBJECT_NAME (src) : "(NULL)"); - gst_message_parse_async_done (message, &reset_time); + gst_message_parse_async_done (message, &running_time); GST_OBJECT_LOCK (bin); bin_do_message_forward (bin, message); @@ -3361,7 +3442,8 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message) * need to set the pending_done flag so that at the end of the state * change we can see if we need to verify pending async elements, hence * the TRUE argument here. */ - bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE, reset_time); + bin_handle_async_done (bin, GST_STATE_CHANGE_SUCCESS, TRUE, + running_time); } else { GST_DEBUG_OBJECT (bin, "there are more async elements pending"); }