OUTDATED -------- Plan generation happens at transition from NULL to READY (and PLAYING to READY right now, need to fix that). By way of some logic in gst_bin_change_state(), gst_bin_create_plan() is only called for the outer Bin, usually a Pipeline. This keeps things from getting nasty later on. A major new concept in plan generation is that of the 'manager'. This is the element that is reponsible for running a given element. In general, Pipelines and Threads are the only managing-capable elements (have the MANAGER flag set), since they are the only ones with real scheduling authority (because they have a process context to play with, basically). gst_bin_set_manager() is called to set the manager element of the bin and all it's children and their children. However, there's one important trick: it won't recurse into child Bins that have the MANAGER flag set. This avoids some highly redundant recursion. When create_plan() is called on the outside Pipeline, the first thing it does is call set_manager(self,self). As noted above, this recursion will not proceed into child Bins that have the MANAGER flag set. The next step is to recursively generate the plan (yes, head-recursive). This gives child Bins the opportunity to generate their plan first, causing a inside-to-outside sequence. This matches the way the scheduling is arranged now, where the plan for a Src/Connection outside a Bin is handled by that Bin, not it's parent. But we must be very careful not to stomp on that plan in the parent Bin. Because create_plan() is called on all Bins, but we can only set up scheduling state in MANAGER bins, create_plan() must perform create_plan() recursion, but not do anything else *unless* the MANAGER bit is set. It shouldn't even call set_manager() unless it's a MANAGER itself, because calling it otherwise would waste time doing the work again. Basically, from the standpoing of setting the manager, create_plan() recursion starts it when the current Bin is a MANAGER, and set_manager() stops when it finds the next one. create_plan()'s further recursion eventually starts the process back up again furtuer down the hierarchy, until everything is covered. For all MANAGER Bins, the last step is to actually create the scheduling plan. This is still one of the nastiest chunks of code in the whole project, and probably will do nothing but get worse from now on (it got better recently, but only because I took a chainsaw to the code and broke everthing...). It will remain similar to what it is now, but with some definite differences. First task is now to find all the elements that we're responsible for. This is normally a recursive process, because the structure is an arbitrary tree. However, something like the following should work (bin is self): GSList *elements = NULL; GList *children; GSList *waiting_bins = NULL; GstBin *waiting_bin; waiting_bins = g_slist_prepend (waiting_bins,bin); while (waiting_bins) { // retrieve the top of the stack and pop it waiting_bin = GST_BIN (waiting_bins->data); waiting_bins = g_slist_remove (waiting_bins,waiting_bin); // walk the list of elements, and find bins children = waiting_bin->children; while (children) { // add it to the list of elements elements = g_slist_prepend (elements, children->data); // if it's a bin and it's not a managing bin, // shove it on the list of bins to recurse into if (GST_IS_BIN (children->data) && !GST_FLAG_IS_SET (GST_ELEMENT (children->data))) waiting_bins = g_slist_prepend (waiting_bins,children->data); children = g_list_next (children); } } The code makes the assumption that the manager of every element is the same until such time as a different managing parent appears in the hierarchy. This is the result of the aforementioned nested recursion of create_plan() and set_manager(), but may not remain the case forever. The above loop should probably be slightly re-written to work solely on whether or not the Bin in question is the element's manager. This means that the child Bins are *always* recursed into, in case there's a rogue element inside of one of them that's supposed to be managed. At the same time all the elements managed by this bin are found (i.e. in the inner loop), we can determine some useful bits of information, such as testing for several cases that require the use of cothreads. The availability of manager information at this point may aid significantly in this decision. Finally, the scheduling plan is generated, based on all the elements to be managed by the Bin (the list of which may span several 'generations' of Bins and elements). Elements which have peers in child self-managed Bins are left alone on for the pad in that makes that connection. This should keep the parent Bins from stepping all over state set up by the child Bins, by establishing clear implicit ownership on the pad level, based on the managing Bins' relationship to the pad.