From 40a0fb9794e50b1f036c9bc68e540196934fa8c7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 8 Jul 2004 15:24:20 +0000 Subject: [PATCH] Implemented group splitting and rechaining. Original commit message from CVS: * gst/schedulers/gstoptimalscheduler.c: (chain_recursively_migrate_group), (create_group), (schedule_group), (gst_opt_scheduler_pad_link), (group_elements_set_visited), (element_get_reachables_func), (element_get_reachables), (group_can_reach_group), (debug_element), (rechain_group), (group_migrate_connected), (gst_opt_scheduler_pad_unlink): * testsuite/schedulers/Makefile.am: Implemented group splitting and rechaining. Fixes 143777 and 143777-2 in the testsuite. --- ChangeLog | 13 + gst/schedulers/gstoptimalscheduler.c | 316 +++++++++++++-------- tests/old/testsuite/schedulers/Makefile.am | 4 +- testsuite/schedulers/Makefile.am | 4 +- 4 files changed, 215 insertions(+), 122 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b0e9fbffc..35c619d594 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2004-07-08 Wim Taymans + + * gst/schedulers/gstoptimalscheduler.c: + (chain_recursively_migrate_group), (create_group), + (schedule_group), (gst_opt_scheduler_pad_link), + (group_elements_set_visited), (element_get_reachables_func), + (element_get_reachables), (group_can_reach_group), (debug_element), + (rechain_group), (group_migrate_connected), + (gst_opt_scheduler_pad_unlink): + * testsuite/schedulers/Makefile.am: + Implemented group splitting and rechaining. + Fixes 143777 and 143777-2 in the testsuite. + 2004-07-08 Thomas Vander Stichele * gst/autoplug/gstspideridentity.c: (gst_spider_identity_chain): diff --git a/gst/schedulers/gstoptimalscheduler.c b/gst/schedulers/gstoptimalscheduler.c index d4a712dcb1..e27458fb4e 100644 --- a/gst/schedulers/gstoptimalscheduler.c +++ b/gst/schedulers/gstoptimalscheduler.c @@ -44,8 +44,10 @@ GST_DEBUG_CATEGORY_STATIC (debug_scheduler); #define GST_ELEMENT_COTHREAD_STOPPING GST_ELEMENT_SCHEDULER_PRIVATE1 #define GST_ELEMENT_IS_COTHREAD_STOPPING(element) GST_FLAG_IS_SET((element), GST_ELEMENT_COTHREAD_STOPPING) -#define GST_ELEMENT_INTERRUPTED GST_ELEMENT_SCHEDULER_PRIVATE2 -#define GST_ELEMENT_IS_INTERRUPTED(element) GST_FLAG_IS_SET((element), GST_ELEMENT_INTERRUPTED) +#define GST_ELEMENT_VISITED GST_ELEMENT_SCHEDULER_PRIVATE2 +#define GST_ELEMENT_IS_VISITED(element) GST_FLAG_IS_SET((element), GST_ELEMENT_VISITED) +#define GST_ELEMENT_SET_VISITED(element) GST_FLAG_SET((element), GST_ELEMENT_VISITED) +#define GST_ELEMENT_UNSET_VISITED(element) GST_FLAG_UNSET((element), GST_ELEMENT_VISITED) typedef struct _GstOptScheduler GstOptScheduler; typedef struct _GstOptSchedulerClass GstOptSchedulerClass; @@ -777,12 +779,9 @@ chain_recursively_migrate_group (GstOptSchedulerChain * chain, add_to_chain (chain, group); /* then follow all links */ - links = group->group_links; - while (links) { + for (links = group->group_links; links; links = g_slist_next (links)) { GstOptSchedulerGroupLink *link = (GstOptSchedulerGroupLink *) links->data; - links = g_slist_next (links); - chain_recursively_migrate_group (chain, OTHER_GROUP_LINK (link, group)); } } @@ -823,7 +822,7 @@ create_group (GstOptSchedulerChain * chain, GstElement * element, group->flags = GST_OPT_SCHEDULER_GROUP_DISABLED; group->type = type; - add_to_group (group, element, FALSE); + add_to_group (group, element, TRUE); add_to_chain (chain, group); group = unref_group (group); /* ...and sink. */ @@ -1087,7 +1086,7 @@ schedule_group (GstOptSchedulerGroup * group) { if (!group->entry) { GST_INFO ("not scheduling group %p without entry", group); - return FALSE; + return TRUE; } #ifdef USE_COTHREADS if (group->cothread) @@ -1971,6 +1970,8 @@ gst_opt_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, GST_DEBUG ("setting \"%s\" as entry point of _get-based group %p", GST_ELEMENT_NAME (src_element), group); + + setup_group_scheduler (osched, group); } break; } @@ -2042,21 +2043,42 @@ gst_opt_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, } } -/* - * checks if an element is still linked to some other element in the group. - * no checking is done on the brokenpad arg - */ -static gboolean -element_has_link_with_group (GstElement * element, GstOptSchedulerGroup * group, +static void +group_elements_set_visited (GstOptSchedulerGroup * group, gboolean visited) +{ + GSList *elements; + + for (elements = group->elements; elements; elements = g_slist_next (elements)) { + GstElement *element = GST_ELEMENT (elements->data); + + if (visited) { + GST_ELEMENT_SET_VISITED (element); + } else { + GST_ELEMENT_UNSET_VISITED (element); + } + } +} + +static GList * +element_get_reachables_func (GstElement * element, GstOptSchedulerGroup * group, GstPad * brokenpad) { - gboolean linked = FALSE; + GList *result = NULL; const GList *pads; - /* see if the element has no more links to the peer group */ + /* if no element or element not in group or been there, return NULL */ + if (element == NULL || g_slist_find (group->elements, element) == NULL || + GST_ELEMENT_IS_VISITED (element)) + return NULL; + + GST_ELEMENT_SET_VISITED (element); + + result = g_list_prepend (result, element); + pads = gst_element_get_pad_list (element); - while (pads && !linked) { + while (pads) { GstPad *pad = GST_PAD (pads->data); + GstPad *peer; pads = g_list_next (pads); @@ -2064,27 +2086,40 @@ element_has_link_with_group (GstElement * element, GstOptSchedulerGroup * group, if (!GST_IS_REAL_PAD (pad) || pad == brokenpad) continue; - if (GST_PAD_PEER (pad)) { + peer = GST_PAD_PEER (pad); + if (!GST_IS_REAL_PAD (peer) || peer == brokenpad) + continue; + + if (peer) { GstElement *parent; - GstOptSchedulerGroup *parentgroup; + GList *res; - /* see in what group this element is */ - parent = GST_PAD_PARENT (GST_PAD_PEER (pad)); + parent = GST_PAD_PARENT (peer); - /* links with decoupled elements are valid */ - if (GST_ELEMENT_IS_DECOUPLED (parent)) { - linked = TRUE; - } else { - /* for non-decoupled elements we need to check the group */ - get_group (parent, &parentgroup); + res = element_get_reachables_func (parent, group, brokenpad); - /* if it's in the same group, we're still linked */ - if (parentgroup == group) - linked = TRUE; - } + result = g_list_concat (result, res); } } - return linked; + + return result; +} + +static GList * +element_get_reachables (GstElement * element, GstOptSchedulerGroup * group, + GstPad * brokenpad) +{ + GList *result; + + /* reset visited flags */ + group_elements_set_visited (group, FALSE); + + result = element_get_reachables_func (element, group, brokenpad); + + /* and reset visited flags again */ + group_elements_set_visited (group, FALSE); + + return result; } /* @@ -2127,7 +2162,7 @@ group_can_reach_group (GstOptSchedulerGroup * group, GST_LOG ("found link from %p to %p, count %d", group, other, link->count); - /* check if we can reach the target recursiveley */ + /* check if we can reach the target recursively */ reachable = group_can_reach_group (other, target); } /* unset the visited flag, note that this is not optimal as we might be checking @@ -2185,6 +2220,97 @@ group_inc_links_for_element (GstOptSchedulerGroup * group, GstElement * element) } } +static void +debug_element (GstElement * element, GstOptScheduler * osched) +{ + GST_LOG ("element %s", gst_element_get_name (element)); +} + +/* move this group in the chain of the groups it has links with */ +static void +rechain_group (GstOptSchedulerGroup * group) +{ + GstOptSchedulerChain *chain = NULL; + GSList *links; + + GST_LOG ("checking if this group needs rechaining"); + + /* follow all links */ + for (links = group->group_links; links; links = g_slist_next (links)) { + GstOptSchedulerGroupLink *link = (GstOptSchedulerGroupLink *) links->data; + GstOptSchedulerGroup *other; + + other = OTHER_GROUP_LINK (link, group); + GST_LOG ("found link with other group %p with chain %p", other, + other->chain); + + /* first time, take chain */ + if (chain == NULL) { + chain = other->chain; + } + /* second time, chain should be the same */ + else if (other->chain != chain) { + g_warning ("(internal error): chain inconsistency"); + } + } + if (!chain) { + GST_LOG ("no new chain found, not rechaining"); + } else if (chain != group->chain) { + GST_LOG ("need to move group %p to chain %p", group, chain); + /* remove from old chain */ + remove_from_chain (group->chain, group); + /* and move to new chain */ + add_to_chain (chain, group); + } else { + GST_LOG ("group %p is in correct chain %p", group, chain); + } +} + +/* migrate the element and all connected elements to a new group without looking at + * the brokenpad */ +static GstOptSchedulerGroup * +group_migrate_connected (GstOptScheduler * osched, GstElement * element, + GstOptSchedulerGroup * group, GstPad * brokenpad) +{ + GList *connected, *c; + GstOptSchedulerGroup *new_group = NULL; + GstOptSchedulerChain *chain; + + GST_LOG ("migrate connected elements to new group"); + connected = element_get_reachables (element, group, brokenpad); + GST_LOG ("elements to move to new group:"); + g_list_foreach (connected, (GFunc) debug_element, NULL); + + if (g_list_length (connected) == 1) { + remove_from_group (group, GST_ELEMENT (connected->data)); + GST_LOG ("not migrating to new group as the group is empty"); + return NULL; + } + + /* we create a new chain to hold the new group */ + chain = create_chain (osched); + + for (c = connected; c; c = g_list_next (c)) { + GstElement *element = GST_ELEMENT (c->data); + + remove_from_group (group, element); + if (new_group == NULL) { + new_group = + create_group (chain, element, GST_OPT_SCHEDULER_GROUP_UNKNOWN); + } else { + add_to_group (new_group, element, TRUE); + } + } + g_list_free (connected); + + /* at this point the new group lives in its own chain but might + * have to be merged with another chain, this happens when the new + * group has a link with another group in another chain */ + rechain_group (new_group); + + return new_group; +} + static void gst_opt_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad) @@ -2253,7 +2379,6 @@ gst_opt_scheduler_pad_unlink (GstScheduler * sched, } /* hard part, groups are equal */ else { - gboolean still_link1, still_link2; GstOptSchedulerGroup *group; /* since group1 == group2, it doesn't matter which group we take */ @@ -2261,96 +2386,51 @@ gst_opt_scheduler_pad_unlink (GstScheduler * sched, GST_LOG ("elements are in the same group %p", group); - /* check if the element is still linked to some other element in the group, - * we pass the pad that is broken up as an arg because a link on that pad - * is not valid anymore. - * Note that this check is only to make sure that a single element can be removed - * completely from the group, we also have to check for migrating several - * elements to a new group. */ - still_link1 = element_has_link_with_group (src_element, group, srcpad); - still_link2 = element_has_link_with_group (sink_element, group, sinkpad); - /* if there is still a link, we don't need to break this group */ - if (still_link1 && still_link2) { - GSList *l; - GList *m; - int linkcount; + if (group->entry == NULL) { + /* it doesn't really matter, we just have to make sure that both + * elements end up in another group if they are not connected */ + GST_LOG ("group %p has no entry, moving source element to new group", + group); + group_migrate_connected (osched, src_element, group, srcpad); + } else { + GList *reachables; - GST_LOG ("elements still have links with other elements in the group"); + GST_LOG ("group %p has entry %p", group, group->entry); - while (group && group->elements) - for (l = group->elements; l && l->data; l = l->next) { - GstElement *element = (GstElement *) l->data; + /* get of a list of all elements that are still managed by the old + * entry element */ + reachables = element_get_reachables (group->entry, group, srcpad); + GST_LOG ("elements still reachable from the entry:"); + g_list_foreach (reachables, (GFunc) debug_element, sched); - if (!element || !GST_IS_ELEMENT (element) || - GST_ELEMENT_IS_DECOUPLED (element)) - continue; + /* if the source is reachable from the entry, we can leave it in the group */ + if (g_list_find (reachables, src_element)) { + GST_LOG + ("source element still reachable from the entry, leaving in group"); + } else { + GST_LOG + ("source element not reachable from the entry, moving to new group"); + group_migrate_connected (osched, src_element, group, srcpad); + } - linkcount = 0; - GST_LOG ("Examining %s\n", GST_ELEMENT_NAME (element)); - for (m = GST_ELEMENT_PADS (element); m; m = m->next) { - GstPad *peer, *pad; - GstElement *parent; - GstOptSchedulerGroup *peer_group; - - pad = (GstPad *) m->data; - if (!pad || !GST_IS_REAL_PAD (pad)) - continue; - - peer = GST_PAD_PEER (pad); - if (!peer || !GST_IS_REAL_PAD (peer)) - continue; - - parent = GST_PAD_PARENT (GST_PAD_PEER (pad)); - get_group (parent, &peer_group); - if (peer_group && peer_group != group) { - GST_LOG ("pad %s is linked with %s\n", - GST_PAD_NAME (pad), GST_ELEMENT_NAME (parent)); - linkcount++; - } - } - - if (linkcount < 2) { - group = remove_from_group (group, element); - } - /* if linkcount == 2, it will be unlinked later on */ - else if (linkcount > 2) { - g_warning - ("opt: Can't handle element %s with 3 or more links, aborting", - GST_ELEMENT_NAME (element)); - return; - } - } - /* Peer element will be caught during next iteration */ - return; + /* if the sink is reachable from the entry, we can leave it in the group */ + if (g_list_find (reachables, sink_element)) { + GST_LOG + ("sink element still reachable from the entry, leaving in group"); + } else { + GST_LOG + ("sink element not reachable from the entry, moving to new group"); + group_migrate_connected (osched, sink_element, group, srcpad); + } + g_list_free (reachables); } - /* now check which one of the elements we can remove from the group */ - if (!still_link1) { - /* we only remove elements that are not the entry point of a loop based - * group and are not decoupled */ - if (!(group->entry == src_element && - group->type == GST_OPT_SCHEDULER_GROUP_LOOP) && - !GST_ELEMENT_IS_DECOUPLED (src_element)) { - GST_LOG ("el ement1 is separated from the group"); - - remove_from_group (group, src_element); - } else { - GST_LOG ("src_element is decoupled or entry in loop based group"); - } - } - - if (!still_link2) { - /* we only remove elements that are not the entry point of a loop based - * group and are not decoupled */ - if (!(group->entry == sink_element && - group->type == GST_OPT_SCHEDULER_GROUP_LOOP) && - !GST_ELEMENT_IS_DECOUPLED (sink_element)) { - GST_LOG ("sink_element is separated from the group"); - - remove_from_group (group, sink_element); - } else { - GST_LOG ("sink_element is decoupled or entry in loop based group"); - } + /* see if the old group is worthy of existance, loop based groups can hold + * one element */ + if (g_slist_length (group->elements) == 1 && + group->type != GST_OPT_SCHEDULER_GROUP_LOOP) { + GST_LOG ("removing last element from group"); + remove_from_group (group, GST_ELEMENT (group->elements->data)); } } } diff --git a/tests/old/testsuite/schedulers/Makefile.am b/tests/old/testsuite/schedulers/Makefile.am index 637386dc65..bec30900d0 100644 --- a/tests/old/testsuite/schedulers/Makefile.am +++ b/tests/old/testsuite/schedulers/Makefile.am @@ -4,12 +4,12 @@ tests_pass = \ unlink_src unlink_sink \ relink_src relink_sink \ unref_src unref_sink \ - 143777 + 143777 143777-2 # don't enable this one unless it actually works. # useless_iteration -tests_fail = 143777-2 +tests_fail = tests_ignore = unlink_src_SOURCES = unlink.c diff --git a/testsuite/schedulers/Makefile.am b/testsuite/schedulers/Makefile.am index 637386dc65..bec30900d0 100644 --- a/testsuite/schedulers/Makefile.am +++ b/testsuite/schedulers/Makefile.am @@ -4,12 +4,12 @@ tests_pass = \ unlink_src unlink_sink \ relink_src relink_sink \ unref_src unref_sink \ - 143777 + 143777 143777-2 # don't enable this one unless it actually works. # useless_iteration -tests_fail = 143777-2 +tests_fail = tests_ignore = unlink_src_SOURCES = unlink.c