From: <wt...@fr...> - 2005-06-30 09:41:32
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wtay Date: Thu Jun 30 2005 02:41:28 PDT Log message: * gst/gstbin.c: (clear_queue), (remove_all_from_queue), (gst_bin_change_state): Lame attempt at making the state change function a bit more readable. Modified files: . : ChangeLog gst : gstbin.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1203&r2=1.1204 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/gstbin.c.diff?r1=1.235&r2=1.236 ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1203 retrieving revision 1.1204 diff -u -d -r1.1203 -r1.1204 --- ChangeLog 30 Jun 2005 09:33:45 -0000 1.1203 +++ ChangeLog 30 Jun 2005 09:41:15 -0000 1.1204 @@ -1,5 +1,13 @@ 2005-06-30 Wim Taymans <wi...@fl...> + * gst/gstbin.c: (clear_queue), (remove_all_from_queue), + (gst_bin_change_state): + Probes are gone. + Lame attempt at making the state change function a bit + more readable. + +2005-06-30 Wim Taymans <wi...@fl...> * docs/design/part-clocks.txt: * docs/design/part-element-sink.txt: * docs/design/part-events.txt: Index: gstbin.c RCS file: /cvs/gstreamer/gstreamer/gst/gstbin.c,v retrieving revision 1.235 retrieving revision 1.236 diff -u -d -r1.235 -r1.236 --- gstbin.c 28 Jun 2005 09:58:56 -0000 1.235 +++ gstbin.c 30 Jun 2005 09:41:15 -0000 1.236 @@ -1047,6 +1047,27 @@ return result; } +static void +clear_queue (GQueue * queue, gboolean unref) +{ + gpointer p; + while ((p = g_queue_pop_head (queue))) + if (unref) + gst_object_unref (p); +} +remove_all_from_queue (GQueue * queue, gpointer elem, gboolean unref) + while ((p = g_queue_find (queue, elem))) { + gst_object_unref (elem); + g_queue_delete_link (queue, p); + } /* this function is called with the STATE_LOCK held. It works * as follows: * @@ -1062,6 +1083,7 @@ * MT safe. */ +/* FIXME, make me more elegant */ static GstElementStateReturn gst_bin_change_state (GstElement * element) { @@ -1099,7 +1121,14 @@ /* first step, find all sink elements, these are the elements * without (linked) source pads. */ GST_LOCK (bin); restart: + /* make sure queues are empty, they could be filled when + * restarting. */ + clear_queue (elem_queue, TRUE); + clear_queue (semi_queue, TRUE); + clear_queue (temp, TRUE); children = bin->children; children_cookie = bin->children_cookie; while (children) { @@ -1117,30 +1146,25 @@ } GST_LOCK (bin); - if (G_UNLIKELY (children_cookie != bin->children_cookie)) { - /* undo what we had */ - g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL); - g_queue_foreach (semi_queue, (GFunc) gst_object_unref, NULL); - g_queue_foreach (temp, (GFunc) gst_object_unref, NULL); - while (g_queue_pop_head (elem_queue)); - while (g_queue_pop_head (semi_queue)); - while (g_queue_pop_head (temp)); + if (G_UNLIKELY (children_cookie != bin->children_cookie)) goto restart; - } - children = g_list_next (children); } GST_UNLOCK (bin); + /* after this point new elements can be added/removed from the + * bin. We operate on the snapshot taken above. Applications + * should serialize their add/remove and set_state. */ /* now change state for semi sink elements first so add them in * front of the other elements */ g_queue_foreach (temp, (GFunc) append_child, semi_queue); - g_queue_free (temp); + clear_queue (temp, FALSE); - /* can be the case for a bin like ( identity ) */ + /* if we don't have real sinks, we continue with the other elements */ if (g_queue_is_empty (elem_queue) && !g_queue_is_empty (semi_queue)) { GQueue *q = elem_queue; + /* we swap the queues as oposed to copy them over */ elem_queue = semi_queue; semi_queue = q; @@ -1153,20 +1177,8 @@ /* take element */ qelement = g_queue_pop_head (elem_queue); - /* we don't need it in the semi_queue anymore */ - g_queue_remove_all (semi_queue, qelement); - /* if queue is empty now, continue with a non-sink */ - if (g_queue_is_empty (elem_queue)) { - GstElement *non_sink; - GST_DEBUG ("sinks and upstream elements exhausted"); - non_sink = g_queue_pop_head (semi_queue); - if (non_sink) { - GST_DEBUG ("found lefover non-sink %s", GST_OBJECT_NAME (non_sink)); - g_queue_push_tail (elem_queue, non_sink); - } + /* we don't need any duplicates in the other queue anymore */ + remove_all_from_queue (semi_queue, qelement, TRUE); /* queue all elements connected to the sinkpads of this element */ GST_LOCK (qelement); @@ -1189,31 +1201,24 @@ /* see if this element is in the bin we are currently handling */ parent = gst_object_get_parent (GST_OBJECT_CAST (peer_elem)); - if (parent && parent == GST_OBJECT_CAST (bin)) { - GList *oldelem; + if (parent) { + if (parent == GST_OBJECT_CAST (bin)) { + GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, + "adding element %s to queue", GST_ELEMENT_NAME (peer_elem)); - GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "adding element %s to queue", GST_ELEMENT_NAME (peer_elem)); + /* make sure we don't have duplicates */ + remove_all_from_queue (semi_queue, peer_elem, TRUE); + remove_all_from_queue (elem_queue, peer_elem, TRUE); - /* make sure we don't have duplicates */ - while ((oldelem = g_queue_find (semi_queue, peer_elem))) { - gst_object_unref (peer_elem); - g_queue_delete_link (semi_queue, oldelem); - } - while ((oldelem = g_queue_find (elem_queue, peer_elem))) { + /* was reffed before pushing on the queue by the + * gst_object_get_parent() call we used to get the element. */ + g_queue_push_tail (elem_queue, peer_elem); + } else { + "not adding element %s to queue, it is in another bin", + GST_ELEMENT_NAME (peer_elem)); gst_object_unref (peer_elem); - g_queue_delete_link (elem_queue, oldelem); } - /* was reffed before pushing on the queue by the - * gst_object_get_parent() call we used to get the element. */ - g_queue_push_tail (elem_queue, peer_elem); - } else { - "not adding element %s to queue, it is in another bin", - GST_ELEMENT_NAME (peer_elem)); - gst_object_unref (peer_elem); - } - if (parent) { gst_object_unref (parent); } } @@ -1228,11 +1233,23 @@ locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE); GST_UNLOCK (qelement); + /* skip locked elements */ if (G_UNLIKELY (locked)) goto next_element; + /* set base time on element */ qelement->base_time = element->base_time; ret = gst_element_set_state (qelement, pending); + /* the set state could have cause elements to be added/removed, + * we support that. */ + GST_LOCK (bin); + if (G_UNLIKELY (children_cookie != bin->children_cookie)) { + gst_object_unref (qelement); + goto restart; + } + GST_UNLOCK (bin); switch (ret) { case GST_STATE_SUCCESS: GST_CAT_DEBUG (GST_CAT_STATES, @@ -1268,6 +1285,18 @@ next_element: gst_object_unref (qelement); + /* if queue is empty now, continue with a non-sink */ + if (g_queue_is_empty (elem_queue)) { + GstElement *non_sink; + GST_DEBUG ("sinks and upstream elements exhausted"); + non_sink = g_queue_pop_head (semi_queue); + if (non_sink) { + GST_DEBUG ("found lefover non-sink %s", GST_OBJECT_NAME (non_sink)); + g_queue_push_tail (elem_queue, non_sink); + } if (have_no_preroll) { @@ -1275,25 +1304,23 @@ } else if (have_async) { ret = GST_STATE_ASYNC; } else { - if ((ret = parent_class->change_state (element)) == GST_STATE_SUCCESS) { - /* we can commit the state change now */ - gst_element_commit_state (element); + ret = parent_class->change_state (element); GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element, - "done changing bin's state from %s to %s, now in %s", + "done changing bin's state from %s to %s, now in %s, ret %d", gst_element_state_get_name (old_state), gst_element_state_get_name (pending), - gst_element_state_get_name (GST_STATE (element))); + gst_element_state_get_name (GST_STATE (element)), ret); exit: /* release refcounts in queue, should normally be empty unless we * had an error. */ - g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL); g_queue_free (elem_queue); - g_queue_foreach (semi_queue, (GFunc) gst_object_unref, NULL); g_queue_free (semi_queue); + g_queue_free (temp); return ret; |