gstreamer/docs/random/omega/plan-generation

85 lines
4.9 KiB
Text
Raw Normal View History

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.