gst/gstbin.c: Fix annoying bug in the sorted iterator where a sink that is not really a sink (when it has downstream ...

Original commit message from CVS:
* gst/gstbin.c: (add_to_queue), (remove_from_queue), (clear_queue),
(update_degree), (gst_bin_sort_iterator_next):
Fix annoying bug in the sorted iterator where a sink that is not really
a sink (when it has downstream links) screwed up the iterator.
* tests/check/gst/gstbin.c: (GST_START_TEST), (gst_bin_suite):
Unit test to verify the fix.
This commit is contained in:
Wim Taymans 2007-08-16 10:27:16 +00:00
parent 4f98b744d2
commit 5059e9f8bd
3 changed files with 87 additions and 3 deletions

View file

@ -1,3 +1,13 @@
2007-08-16 Wim Taymans <wim.taymans@gmail.com>
* gst/gstbin.c: (add_to_queue), (remove_from_queue), (clear_queue),
(update_degree), (gst_bin_sort_iterator_next):
Fix annoying bug in the sorted iterator where a sink that is not really
a sink (when it has downstream links) screwed up the iterator.
* tests/check/gst/gstbin.c: (GST_START_TEST), (gst_bin_suite):
Unit test to verify the fix.
2007-08-16 Wim Taymans <wim.taymans@gmail.com>
* gst/gstmessage.h:

View file

@ -1566,12 +1566,22 @@ typedef struct _GstBinSortIterator
static void
add_to_queue (GstBinSortIterator * bit, GstElement * element)
{
GST_DEBUG_OBJECT (bit->bin, "%s add to queue", GST_ELEMENT_NAME (element));
GST_DEBUG_OBJECT (bit->bin, "adding '%s' to queue",
GST_ELEMENT_NAME (element));
gst_object_ref (element);
g_queue_push_tail (bit->queue, element);
HASH_SET_DEGREE (bit, element, -1);
}
static void
remove_from_queue (GstBinSortIterator * bit, GstElement * element)
{
GST_DEBUG_OBJECT (bit->bin, "removing '%s' from queue",
GST_ELEMENT_NAME (element));
g_queue_remove (bit->queue, element);
gst_object_unref (element);
}
/* clear the queue, unref all objects as we took a ref when
* we added them to the queue */
static void
@ -1581,10 +1591,14 @@ clear_queue (GQueue * queue)
while ((p = g_queue_pop_head (queue)))
gst_object_unref (p);
}
/* set all degrees to 0. Elements marked as a sink are
* added to the queue immediatly. */
* added to the queue immediatly. Since we only look at the SINK flag of the
* element, it is possible that we add non-sinks to the queue. These will be
* removed from the queue again when we can prove that it provides data for some
* other element. */
static void
reset_degree (GstElement * element, GstBinSortIterator * bit)
{
@ -1636,6 +1650,13 @@ update_degree (GstElement * element, GstBinSortIterator * bit)
gint old_deg, new_deg;
old_deg = HASH_GET_DEGREE (bit, peer_element);
/* check to see if we added an element as sink that was not really a
* sink because it was connected to some other element. */
if (old_deg == -1) {
remove_from_queue (bit, peer_element);
old_deg = 0;
}
new_deg = old_deg + bit->mode;
GST_DEBUG_OBJECT (bit->bin,
@ -1701,7 +1722,9 @@ gst_bin_sort_iterator_next (GstBinSortIterator * bit, gpointer * result)
if ((best = bit->best)) {
if (bit->best_deg != 0) {
/* we don't fail on this one yet */
g_warning ("loop detected in the graph !!");
GST_WARNING_OBJECT (bin, "loop dected in graph");
g_warning ("loop detected in the graph of bin %s!!",
GST_ELEMENT_NAME (bin));
}
/* best unhandled element, schedule as next element */
GST_DEBUG_OBJECT (bin, "queue empty, next best: %s",

View file

@ -834,6 +834,56 @@ GST_START_TEST (test_children_state_change_order_two_sink)
GST_END_TEST;
GST_START_TEST (test_iterate_sorted)
{
GstElement *src, *tee, *identity, *sink1, *sink2, *pipeline, *bin;
GstIterator *it;
gpointer elem;
pipeline = gst_pipeline_new (NULL);
fail_unless (pipeline != NULL, "Could not create pipeline");
bin = gst_bin_new (NULL);
fail_unless (bin != NULL, "Could not create bin");
src = gst_element_factory_make ("fakesrc", NULL);
fail_if (src == NULL, "Could not create fakesrc");
tee = gst_element_factory_make ("tee", NULL);
fail_if (tee == NULL, "Could not create tee");
sink1 = gst_element_factory_make ("fakesink", NULL);
fail_if (sink1 == NULL, "Could not create fakesink1");
gst_bin_add_many (GST_BIN (bin), src, tee, sink1, NULL);
fail_unless (gst_element_link (src, tee) == TRUE);
fail_unless (gst_element_link (tee, sink1) == TRUE);
identity = gst_element_factory_make ("identity", NULL);
fail_if (identity == NULL, "Could not create identity");
sink2 = gst_element_factory_make ("fakesink", NULL);
fail_if (sink2 == NULL, "Could not create fakesink2");
gst_bin_add_many (GST_BIN (pipeline), bin, identity, sink2, NULL);
fail_unless (gst_element_link (tee, identity) == TRUE);
fail_unless (gst_element_link (identity, sink2) == TRUE);
it = gst_bin_iterate_sorted (GST_BIN (pipeline));
fail_unless (gst_iterator_next (it, &elem) == GST_ITERATOR_OK);
fail_unless (elem == sink2);
fail_unless (gst_iterator_next (it, &elem) == GST_ITERATOR_OK);
fail_unless (elem == identity);
fail_unless (gst_iterator_next (it, &elem) == GST_ITERATOR_OK);
fail_unless (elem == bin);
gst_object_unref (pipeline);
}
GST_END_TEST;
Suite *
gst_bin_suite (void)
{
@ -853,6 +903,7 @@ gst_bin_suite (void)
tcase_add_test (tc_chain, test_watch_for_state_change);
tcase_add_test (tc_chain, test_add_linked);
tcase_add_test (tc_chain, test_add_self);
tcase_add_test (tc_chain, test_iterate_sorted);
return s;
}