[gst-devel] Plan generation plan

Erik Walthinsen omega at temple-baptist.com
Mon Dec 18 14:02:27 CET 2000


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.

         Erik Walthinsen <omega at cse.ogi.edu> - Staff Programmer @ OGI
        Quasar project - http://www.cse.ogi.edu/DISC/projects/quasar/
   Video4Linux Two drivers and stuff - http://www.cse.ogi.edu/~omega/v4l2/
        __
       /  \             SEUL: Simple End-User Linux - http://www.seul.org/
      |    | M E G A           Helping Linux become THE choice
      _\  /_                          for the home or office user





More information about the gstreamer-devel mailing list