Cothreads
Cothreads are user-space threads that greatly reduce context switching overhead introduced by
regular kernel threads. Cothreads are also used to handle the more complex elements. They differ
from other user-space threading libraries in that they are scheduled explictly by GStreamer.
A cothread is created by a GstBin
whenever an element is found
inside the bin that has one or more of the following properties:
The element is loop-based instead of chain-based
The element has multiple input pads
The element has the MULTI_IN flag set
The GstBin
will create a cothread context for all the elements
in the bin so that the elements will interact in cooperative
multithreading.
Before proceding to the concept of loop-based elements we will first
explain the chain-based elements.
Chain-based elements
Chain based elements receive a buffer of data and are supposed
to handle the data and perform a gst_pad_push.
The basic main function of a chain-based element is like:
static void
chain_function (GstPad *pad, GstBuffer *buffer)
{
GstBuffer *outbuffer;
....
// process the buffer, create a new outbuffer
...
gst_pad_push (srcpad, outbuffer);
}
Chain based function are mainly used for elements that have a one to one
relation between their input and output behaviour. An example of such an
element can be a simple video blur filter. The filter takes a buffer in, performs
the blur operation on it and sends out the resulting buffer.
Another element, for example, is a volume filter. The filter takes audio samples as
input, performs the volume effect and sends out the resulting buffer.
Loop-based elements
As opposed to chain-based elements, loop-based elements enter an
infinite loop that looks like this:
GstBuffer *buffer, *outbuffer;
while (1) {
buffer = gst_pad_pull (sinkpad);
...
// process buffer, create outbuffer
while (!done) {
....
// optionally request another buffer
buffer = gst_pad_pull (sinkpad);
....
}
...
gst_pad_push (srcpad, outbuffer);
}
The loop-based elements request a buffer whenever they need one.
When the request for a buffer cannot be immediately satisfied, the control
will be given to the source element of the loop-based element until it
performs a push on its source pad. At that time the control is handed
back to the loop-based element, etc... The execution trace can get
fairly complex using cothreads when there are multiple input/output
pads for the loop-based element. Cothread switches are performed within
the call to gst_pad_pull and gst_pad_push; from the perspective of
the loop-based element, it just "appears" that gst_pad_push (or _pull)
might take a long time to return.
Loop based elements are mainly used for the more complex elements
that need a specific amount of data before they can start to produce
output. An example of such an element is the MPEG video decoder. The
element will pull a buffer, perform some decoding on it and optionally
request more buffers to decode, and when a complete video frame has
been decoded, a buffer is sent out. For example, any plugin using the
bytestream library will need to be loop-based.
There is no problem in putting cothreaded elements into a GstThread
to
create even more complex pipelines with both user and kernel space threads.