mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 04:36:20 +00:00
gst/gstbin.c: Lame attempt at making the state change function a bit more readable.
Original commit message from CVS: * 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.
This commit is contained in:
parent
41b9a5264d
commit
a578cfd009
2 changed files with 93 additions and 58 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2005-06-30 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* 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 <wim@fluendo.com>
|
2005-06-30 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* docs/design/part-clocks.txt:
|
* docs/design/part-clocks.txt:
|
||||||
|
|
143
gst/gstbin.c
143
gst/gstbin.c
|
@ -1047,6 +1047,27 @@ gst_bin_iterate_state_order (GstBin * bin)
|
||||||
return result;
|
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);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
remove_all_from_queue (GQueue * queue, gpointer elem, gboolean unref)
|
||||||
|
{
|
||||||
|
gpointer p;
|
||||||
|
|
||||||
|
while ((p = g_queue_find (queue, elem))) {
|
||||||
|
if (unref)
|
||||||
|
gst_object_unref (elem);
|
||||||
|
g_queue_delete_link (queue, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* this function is called with the STATE_LOCK held. It works
|
/* this function is called with the STATE_LOCK held. It works
|
||||||
* as follows:
|
* as follows:
|
||||||
*
|
*
|
||||||
|
@ -1062,6 +1083,7 @@ gst_bin_iterate_state_order (GstBin * bin)
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
|
/* FIXME, make me more elegant */
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_bin_change_state (GstElement * element)
|
gst_bin_change_state (GstElement * element)
|
||||||
{
|
{
|
||||||
|
@ -1099,7 +1121,14 @@ gst_bin_change_state (GstElement * element)
|
||||||
/* first step, find all sink elements, these are the elements
|
/* first step, find all sink elements, these are the elements
|
||||||
* without (linked) source pads. */
|
* without (linked) source pads. */
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
|
|
||||||
restart:
|
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 = bin->children;
|
||||||
children_cookie = bin->children_cookie;
|
children_cookie = bin->children_cookie;
|
||||||
while (children) {
|
while (children) {
|
||||||
|
@ -1117,30 +1146,25 @@ restart:
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOCK (bin);
|
GST_LOCK (bin);
|
||||||
if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
|
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));
|
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
|
||||||
|
|
||||||
children = g_list_next (children);
|
children = g_list_next (children);
|
||||||
}
|
}
|
||||||
GST_UNLOCK (bin);
|
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
|
/* now change state for semi sink elements first so add them in
|
||||||
* front of the other elements */
|
* front of the other elements */
|
||||||
g_queue_foreach (temp, (GFunc) append_child, semi_queue);
|
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)) {
|
if (g_queue_is_empty (elem_queue) && !g_queue_is_empty (semi_queue)) {
|
||||||
GQueue *q = elem_queue;
|
GQueue *q = elem_queue;
|
||||||
|
|
||||||
|
/* we swap the queues as oposed to copy them over */
|
||||||
elem_queue = semi_queue;
|
elem_queue = semi_queue;
|
||||||
semi_queue = q;
|
semi_queue = q;
|
||||||
}
|
}
|
||||||
|
@ -1153,20 +1177,8 @@ restart:
|
||||||
|
|
||||||
/* take element */
|
/* take element */
|
||||||
qelement = g_queue_pop_head (elem_queue);
|
qelement = g_queue_pop_head (elem_queue);
|
||||||
/* we don't need it in the semi_queue anymore */
|
/* we don't need any duplicates in the other queue anymore */
|
||||||
g_queue_remove_all (semi_queue, qelement);
|
remove_all_from_queue (semi_queue, qelement, TRUE);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* queue all elements connected to the sinkpads of this element */
|
/* queue all elements connected to the sinkpads of this element */
|
||||||
GST_LOCK (qelement);
|
GST_LOCK (qelement);
|
||||||
|
@ -1189,31 +1201,24 @@ restart:
|
||||||
|
|
||||||
/* see if this element is in the bin we are currently handling */
|
/* see if this element is in the bin we are currently handling */
|
||||||
parent = gst_object_get_parent (GST_OBJECT_CAST (peer_elem));
|
parent = gst_object_get_parent (GST_OBJECT_CAST (peer_elem));
|
||||||
if (parent && parent == GST_OBJECT_CAST (bin)) {
|
|
||||||
GList *oldelem;
|
|
||||||
|
|
||||||
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 */
|
|
||||||
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))) {
|
|
||||||
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 {
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
|
||||||
"not adding element %s to queue, it is in another bin",
|
|
||||||
GST_ELEMENT_NAME (peer_elem));
|
|
||||||
gst_object_unref (peer_elem);
|
|
||||||
}
|
|
||||||
if (parent) {
|
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));
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
|
||||||
|
"not adding element %s to queue, it is in another bin",
|
||||||
|
GST_ELEMENT_NAME (peer_elem));
|
||||||
|
gst_object_unref (peer_elem);
|
||||||
|
}
|
||||||
gst_object_unref (parent);
|
gst_object_unref (parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1228,11 +1233,23 @@ restart:
|
||||||
locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE);
|
locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE);
|
||||||
GST_UNLOCK (qelement);
|
GST_UNLOCK (qelement);
|
||||||
|
|
||||||
|
/* skip locked elements */
|
||||||
if (G_UNLIKELY (locked))
|
if (G_UNLIKELY (locked))
|
||||||
goto next_element;
|
goto next_element;
|
||||||
|
|
||||||
|
/* set base time on element */
|
||||||
qelement->base_time = element->base_time;
|
qelement->base_time = element->base_time;
|
||||||
ret = gst_element_set_state (qelement, pending);
|
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) {
|
switch (ret) {
|
||||||
case GST_STATE_SUCCESS:
|
case GST_STATE_SUCCESS:
|
||||||
GST_CAT_DEBUG (GST_CAT_STATES,
|
GST_CAT_DEBUG (GST_CAT_STATES,
|
||||||
|
@ -1268,6 +1285,18 @@ restart:
|
||||||
}
|
}
|
||||||
next_element:
|
next_element:
|
||||||
gst_object_unref (qelement);
|
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) {
|
if (have_no_preroll) {
|
||||||
|
@ -1275,25 +1304,23 @@ restart:
|
||||||
} else if (have_async) {
|
} else if (have_async) {
|
||||||
ret = GST_STATE_ASYNC;
|
ret = GST_STATE_ASYNC;
|
||||||
} else {
|
} else {
|
||||||
if ((ret = parent_class->change_state (element)) == GST_STATE_SUCCESS) {
|
ret = parent_class->change_state (element);
|
||||||
/* we can commit the state change now */
|
|
||||||
gst_element_commit_state (element);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, 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 (old_state),
|
||||||
gst_element_state_get_name (pending),
|
gst_element_state_get_name (pending),
|
||||||
gst_element_state_get_name (GST_STATE (element)));
|
gst_element_state_get_name (GST_STATE (element)), ret);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* release refcounts in queue, should normally be empty unless we
|
/* release refcounts in queue, should normally be empty unless we
|
||||||
* had an error. */
|
* had an error. */
|
||||||
g_queue_foreach (elem_queue, (GFunc) gst_object_unref, NULL);
|
clear_queue (elem_queue, TRUE);
|
||||||
|
clear_queue (semi_queue, TRUE);
|
||||||
g_queue_free (elem_queue);
|
g_queue_free (elem_queue);
|
||||||
g_queue_foreach (semi_queue, (GFunc) gst_object_unref, NULL);
|
|
||||||
g_queue_free (semi_queue);
|
g_queue_free (semi_queue);
|
||||||
|
g_queue_free (temp);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue