--- /dev/null
+#FIG 3.2
+Landscape
+Center
+Metric
+A4
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 6 50 0 20 0.000 0 0 -1 0 0 5
+ 5895 3465 8460 3465 8460 5175 5895 5175 5895 3465
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 4905 1935 8640 1935 8640 5310 4905 5310 4905 1935
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 2610 1935 4815 1935 4815 5310 2610 5310 2610 1935
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 495 675 8685 675 8685 5400 495 5400 495 675
+2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5
+ 675 1935 2430 1935 2430 3465 675 3465 675 1935
+4 0 0 50 0 0 12 0.0000 4 180 615 6210 3915 GstPlay\001
+4 0 0 50 0 0 12 0.0000 4 180 1485 6480 4455 - GStreamer (glib2)\001
+4 0 0 50 0 0 12 0.0000 4 180 1470 5130 2250 Bonobo Component\001
+4 0 0 50 0 0 12 0.0000 4 135 1275 5130 2700 - sliders/buttons\001
+4 0 0 50 0 0 12 0.0000 4 135 1260 5130 2925 - Gtk/Gnome etc\001
+4 0 0 50 0 0 12 0.0000 4 180 1245 5130 3150 - uses libgstplay\001
+4 0 0 50 0 0 12 0.0000 4 180 1095 2700 945 GstMediaPlay\001
+4 0 0 50 0 0 12 0.0000 4 180 1785 2745 1170 - app using components\001
+4 0 0 50 0 0 12 0.0000 4 180 1440 2700 2160 Bonobo component\001
+4 0 0 50 0 0 12 0.0000 4 180 1035 2700 2610 - playlist etc..\001
+4 0 0 50 0 0 12 0.0000 4 180 1395 855 2160 Other components\001
+4 0 0 50 0 0 12 0.0000 4 135 705 855 2610 - encoder\001
+4 0 0 50 0 0 12 0.0000 4 135 540 855 2835 - editor\001
+4 0 0 50 0 0 12 0.0000 4 60 240 855 3060 - ...\001
--- /dev/null
+
+This short document gives some guidelines to plugin writers.
+
+
+chain-based plugins
+===================
+
+ - the plugin has a chain function on each sink pad (can be the same function)
+
+!
+! chain (GstPad *pad, GstBuffer *buffer)
+! {
+! MyElement *elem = MY_ELEMENT (gst_pad_get_parent (pad));
+! GstBuffer *new_buffer;
+!
+! ...
+! (process the buffer)
+! ...
+!
+! /* you can push as many buffers (0 or more) as you want */
+! while (!done) {
+! ...
+! (process some more
+! ...
+! gst_pad_push (elem->some_sink_pad, new_buffer);
+! ...
+! /* if you're like going to send a large amount of buffers
+! * it's a good idea to call _yield from time to time after
+! * the buffer has been pushed */
+! (optional gst_element_yield (GST_ELEMENT (elem)); )
+! }
+! }
+!
+
+ - chain based functions are usually easy and recommended.
+ - use gst_element_yield if you are going to push a lot of buffers.
+
+
+
+loop-based plugins
+==================
+
+ - one loop function for the element.
+ - required for bytestream based plugins.
+
+simple case
+-----------
+
+ - one pull at the start
+
+ - if you do something like this, you really should consider using a
+ chain function as it can be significantly optimised by the scheduler.
+
+!
+! loop (GstElement *element)
+! {
+! MyElement *elem = MY_ELEMENT (element);
+! GstBuffer *buffer;
+! GstBuffer *new_buffer;
+!
+! buffer = gst_pad_pull (elem->sinkpad);
+!
+! ...
+! (do something)
+! ...
+!
+! /* you can push as many buffers (0 or more) as you want */
+! while (!done) {
+! ...
+! (process some more
+! ...
+! gst_pad_push (elem->some_sink_pad, new_buffer);
+! ...
+! /* if you're like going to send a large amount of buffers
+! * it's a good idea to call _yield from time to time after
+! * the buffer has been pushed */
+! (optional gst_element_yield (GST_ELEMENT (elem)); )
+! }
+! }
+!
+
+DONT!!
+
+- infinite loop
+
+!
+! loop (element)
+! {
+! while (TRUE) {
+! ...
+! _pull ()
+! ...
+!
+! ...
+! _push ()
+! ...
+! }
+! }
+!
+
+* you can fix this by either:
+
+ - setting the GST_ELEMENT_INFINITE_LOOP flag on the element. this is
+ not recommended, if all plugins in the pipeline (or depending on the
+ pipeline, some plugins) have this flag, the pipeline will not run.
+ - calling break; from time to time to get out of the loop. (duh, then
+ it's not an infinite loop anymore). beware that the next time the loop
+ function is called, it will be started from the top.
+ - calling gst_element_yield() from time to time (see NOTES).
+ - this is fine (albeit rather useless, use a chain function):
+ !
+ ! loop (element)
+ ! {
+ ! ...
+ ! _pull ()
+ ! ...
+ !
+ ! ...
+ ! _push ()
+ ! ...
+ ! }
+ !
+ - so is this (albeit rather useless, consider removing the while and the _yield):
+ !
+ ! loop (element)
+ ! {
+ ! while (TRUE) {
+ ! ...
+ ! _pull ()
+ ! ...
+ !
+ ! ...
+ ! _push ()
+ ! ...
+ ! gst_element_yield (element);
+ ! }
+ ! }
+ !
+
+
+DONT!!
+
+- allocate data, loop, free data
+
+!
+! loop (element)
+! {
+!
+! (my funky malloc)
+!
+! while (TRUE) {
+!
+! ...
+! _pull ()
+! ...
+!
+! ...
+! _push ()
+! ...
+!
+! _yield ()
+! }
+!
+! (my funky free)
+!
+! }
+!
+
+ - the free will NEVER happen!.
+
+* You can fix this by:
+
+ - allocating/freeing data in the state change function
+ - you could think the following code would work too:
+ !
+ ! (*WRONG* example follows)
+ !
+ ! loop (element)
+ ! {
+ !
+ ! (my funky malloc)
+ !
+ ! while (TRUE) {
+ !
+ ! ...
+ ! _pull ()
+ ! if (EOS)
+ ! break;
+ !
+ ! ...
+ ! _push ()
+ ! ...
+ !
+ ! _yield ()
+ ! }
+ !
+ ! (my funky free)
+ !
+ ! }
+ !
+ but it'll only free the data if the pipeline was shut down with
+ and EOS so don't try it. Besides, on EOS, a state change will happen
+ anyway so free the data there.
+
+
+bytestream/multiple pull case
+-----------------------------
+
+ - same as the simple case, but you can't use a chain based function unless
+ you want to make things a little harder then they should be.
+
+
+complicated case
+----------------
+
+ - push and pull are completely mixed.
+ - the flow is usually something like this:
+
+!
+! loop (element)
+! {
+!
+! while (TRUE) {
+!
+! while (something) {
+! ...
+! do some _pull ()
+! ...
+! do some _push ()
+! ...
+! while (something_else) {
+! ...
+! if (testing)
+! do some _pull ()
+! ...
+! do some _push ()
+! }
+! }
+!
+! while (something_useful) {
+! ...
+! _push ()
+! ...
+! }
+! }
+! }
+!
+(example made complicated on purpose, but vorbisdec comes close)
+
+ - you cannot call break to avoid infinite loops and there are loops that
+ take a significant amount of time to execute, possibly pushing/pulling
+ a lot of buffers.
+
+* You can fix this by:
+
+ - inserting gst_element_yield () in sane places, don't exagerate because
+ every yield can potentially never return so you need to keep track of
+ allocations (see the NOTES below).
+
+
+
+NOTES:
+======
+
+ - a call to _yield() can never return. if you have data allocated on the
+ stack before the yield, keep a pointer to it in the element struct
+ and free it in the state change function.
+
+
+IMPLEMENATION DETAILS
+=====================
+
+The infinite loops are only problematic if the scheduler chooses to select
+the plugin as an entry point in the chain. _yield() will be a nop if this is
+not the case. The scheduler will not select plugins with the INFINITE_LOOP
+flag set as entries in a chain.
+
+A _yield in an entry will hand over control to the main thread context, allowing
+state changes and other actions to be performed. It will basically exit the
+_iterate() function. spending a long time in a loop will degrade app responsiveness
+because _iterate will take a long time.
+
+Calling yield, pulling, pushing can potentially never return because a state change
+might have happened, killing off execution of the plugin. pulling/pushing buffers
+will cause no leaks in this case because the core will free pending buffers in a
+state change to READY. The plugin must free allocated data/buffers itself in the state
+change function if the yield didn't retrun.
+
+
+
+
+
+
+
+