X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=gst%2Fgstbin.c;h=8e31a48fe80d6a9342895d355e3369a8a58ff9c3;hb=066b515985897495cae32fca5b7eeeec260c40c9;hp=665259e6c24f286c571643f460f0d87de9349ebf;hpb=91e13d4970a8860325bab361c7144bfa7c649c71;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstbin.c b/gst/gstbin.c index 665259e..8e31a48 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -221,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); @@ -1134,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; @@ -1162,7 +1162,8 @@ no_state_recalc: elem_name); g_signal_emit (bin, gst_bin_signals[ELEMENT_ADDED], 0, element); - gst_child_proxy_child_added ((GObject *) bin, (GObject *) element, elem_name); + gst_child_proxy_child_added ((GstChildProxy *) bin, (GObject *) element, + elem_name); g_free (elem_name); @@ -1268,16 +1269,18 @@ 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_FLAG_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_FLAG_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_FLAG_SINK); is_source = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_FLAG_SOURCE); provides_clock = @@ -1286,12 +1289,6 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) 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; @@ -1454,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", @@ -1474,30 +1471,25 @@ 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); - 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_FLAG_UNPARENTING); - GST_OBJECT_UNLOCK (element); - g_signal_emit (bin, gst_bin_signals[ELEMENT_REMOVED], 0, element); - gst_child_proxy_child_removed ((GObject *) bin, (GObject *) element, + gst_child_proxy_child_removed ((GstChildProxy *) bin, (GObject *) element, elem_name); g_free (elem_name); @@ -1511,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; - } } /** @@ -2152,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; @@ -2182,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 = @@ -2234,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 @@ -2648,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: @@ -2907,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; @@ -2935,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 */ @@ -3365,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); @@ -3393,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"); }