blob: 2f3a337b38bf7d4f167987c5a88abdd18d29d100 [file] [log] [blame]
This document tries to describe a possible implementation of an event
system for GStreamer that is able to handle all known problems and works
better than the current (0.3.1) system which evolved over time.
The event system is designed to be a mechanism for communication between
elements. They are used to get information to the right point when this
point cannot be known in advance.
Events can be generated by either an element or the application and are
processed by elements.
Event Handling
Events may be inserted into a pipeline in the PAUSED or PLAYING state. Some
events may travel during the PAUSED state, others may only travel when PLAYING.
The insertion of events during the NULL or READY state should be supported if
at all possible. Events may not be processed in those states though.
After an event is inserted into the pipeline, no assumption may be made on how
the event will be processed. It is eg wrong to assume that an event that is
inserted at the beginning of the pipeline may come out at the end.
There are 3 different directions an event can be processed.
* downstream events
Downstream events are inserted on source pads and travel along the pipeline.
They are handled like buffers and processed in order. If event x is inserted
into a pipeline after buffer y, they are guaranteed to travel in that order.
Downstream events therefore only travel when the pipeline is PLAYING.
Downstream events must be handled by the routines that handle buffers, too.
An example downstream event is the event signalling that the stream has ended.
Please keep in mind that downstream events take the same way as buffers. So a
ghost pad will never receive these events.
* upstream events
Upstream events are inserted on sink pads and travel backwards through the
pipeline. They travel as fast as possible. Source pads must have a handler
function in place to process events. A default handler is implemented.
An example upstream event is an event that seeks inside the stream.
Please keep in mind that upstream events take the same way as buffers in reverse
direction. This means that ghost pads will never receive them.
* vertical events
Vertical events travel from elements to their parents. They are targetted at
the application. Vertical events should be used for information that an
application cannot receive in an easy way by using callbacks or properties.
Vertical events are send to the application by the pipeline that collects those
events and supplies a callback for the application. Vertical events are also only
happening when the pipeline is in PAUSED or PLAZING state.
An example vertical event is the error event informing the application about
unexpected behaviour.
The GstEvent object
struct _GstEvent {
GstData data;
GstEventType type;
guint64 timestamp;
GstObject *src;
union {
} event_data;
data: The parent object.
type: The type of the event. GStreamer aims to keep the number of different
plugin types as small as possible.
timestamp: The time when the event was created. This property is used to identify
duplicated events. If the application inserts an event, the timestamp
is set by the element receiving the event from the application.
src: The element that created the event. If an application inserts an event,
the element that received the event from the application sets itself as
the source.
event_data: data specific to the event type.
The different event types
The following names in brackets correspong to the event's type property.
direction(s): downstream
event_data: struct {
GstDiscontType type;
} discontinuous;
This event is used to indicate that the current stream does not continue. Possible
indications are a new stream (type = GST_DISCONT_NEW), the happening of a seek
(type = GST_DISCONT_SEEK) or the end of the stream when no more data is available.
direction(s): upstream
event_data: struct {
GstSeekType type;
gint64 offset;
gboolean flush;
} seek;
This event is used if a seek is needed. Uses include applications or the avi demuxer
element requesting the end of the stream first. The seek can happen absolute (SET),
relative to the current position (CUR) or relative to the end (END). It is possible
to seek by frames (FRAME), time in microseconds (TIME) or bytes (BYTE). This is
indicated by the type field, which takes the values
GST_SEEK_FRAME/TIME/BYTEOFFSET_SET/CUR/END. The offset field indicates how many units
should be seeked. Negative values indicate seeking backwards from the indicated position.
The flush field indicates if buffered data shuold be flushed or discarded.
direction(s): upstream
event_data: none
This event indicates that all buffered data should be flushed out immediately.
direction(s): downstream, vertical
event_data: struct {
GstProps *props;
} info;
The Info event is used to transport meta information like bitrate, author, title,
interpret or stream length. Most info events will be emitted vertical and downstream
at the same time. Vertical emission ensures that an application knows about those
properties and downstream emission ensures that elements can compute own information
from these infos. (eg converting stream length in bytes to song length in
Props consist of key / value pairs, where the key is a string identifier and the value
is a GstPropEntry. Many key strings are predefined to allow consistency between elements.
Elements should try to suppy any information they can as soon as possible.
direction(s): upstream
void (*GstHasInfoCallback) (gchar *name, GstPropsEntry *info, gpointer data);
event_data: struct {
GList *info;
GstHasInfoCallback callback;
gpointer data;
} has_info;
The has_info event might be inserted by an application to find out if a pipeline can supply
the specified infos. the info list contains all information that the application is
interested in. If an element can supply information it calls the supplied callback with the
name of the information it can supply, the information if it is already available or NULL and
the data. If this event is destroyed, it will call the callback with name = NULL to indicate
that no more data will be received.
This event will for example be used by playlists when they generate information.
direction(s): vertical
event_data: struct {
gchar *message
} error;
An error event is emitted, whenever a recoverable error occurs that the application
should know about. The usage should be similar to GLibs GError. An example would be
"connection closed" for a host to host plugin.
Reference Counting
References to events are handled similar to buffers. An element receives an event with
a single reference. If it forwards the event, this reference is lost.
Events own a reference to the element that created them. They take care of all of all
data inside them too (strings, props). So elements and applications that want to keep
this informations need to copy or add a reference them.
Changing Events
It is not allowed to change any data inside an event. Changing events can only be
accomplished by removing the reference to them and not forwarding the event and then
creating a new one.
Default Behaviour
* downstream events
These are not handled by default, because they must be handled by the chain handler
of the sink pad. There is however a function called gst_pad_event_default(GstPad *,
GstData *) that will take care of events if your code doesn't want to handle them.
But your code must be aware that not everything that your chain function receives
is a buffer. It could be an event.
* upstream events
Upstream events are handled by a default handler function that is inserted on sink
pads when they are created. This function simply forwards the event to all connected
sink pads of the element. You are free to change this handler.
* vertical events
Vertical events can not be received by elements. Bins have a default handler function
that simply forwards the event to their parent. Pipelines offer callbacks for events.
You may change this handler for your custom bins.
Use Cases
Following are some simple use cases describing how events are generated. The pipeline
decriptions use gst-launch syntax. "..." indicates that something follows there but is
not important for the example.
* filesrc ! fakesink
- When starting the pipeline, filesrc will emit a DISCONTINUOUS event of type NEW
indicating a new stream.
- Following that event will be an INFO event containing the length of the file/stream
in bytes.
- After the file was played, the filesrc emits a "DISCONTINUOUS" of type EOS.
* filesrc ! mad ! ...
- When starting, filesrc emits a DISCONTINUOUS event followed by an INFO event (see above).
The mad plugin remembers the length of the file and removes the INFO element as it
is no longer of use. The DISCONTINUOUS event has passed mad after making sure, that all
buffers are cleared.
- Mad will emit a SEEK event to BYTEOFFSET_END; offset = -sizeof(ID3_info) to read out the ID3
- Filesrc emits a DISCONTINUOUS event of type SEEK to indicate that it seeked to the end.
This event will not be passed on by mad.
- after receiving the ID 3 information, mad will issue an INFO event containing all data
it extracted. This event will probably only be passed vertical as ID3 information is of
no use to other elements.
- mad then ISSUES a SEEK event of type BYTEOFFSET_SET; offset = 0 to make the filesrc start
playing the file.
- The filesrc will reset its offset and issue a DISCONTINUOUS event of type SEEK. This event
will not be forwarded by mad.
- When playing starts, mad is able to compute bitrate and other information including playing
time with the help of the previous length information supplied by the filesrc. It will then
issue another INFO event with that informations. This one will be send downstream and vertical.
* ... ! avimux ! filesink
This example is showing a more exotic way of using events. The reader should be aware that AVI
files have a limited filesize. Only 4 GB are allowed. We now show what happens when the avimux
encoder hits that limit.
- When the internal counter of avimux shows that it is approaching the filesize limit, the
avimux element pushes a buffer containig the footer to the filesink.
- After that it issues a DISCONTINUOUS event of the type DISCONT_NEW indicating a new stream.
The filesink will close the file and reopen a new one.
- The avimux plugin resets its internal size counter and restarts sending data to the new file.
* filesrc ! gunzip ! mikmod ! osssink
(please note that this example is purely theoretical. It should just show ideas)
During playback, an application is interested in "interpret", "title", "length_time",
"length_size" and "URI" of the current stream.
- The application creates a HAS_INFO event and inserts it at the end of the pipeline into the
- The osssink cannot supply any info so it forwards the event to the mikmod element.
- The mikmod element can supply "title" and "length_time". It calls the supplied callback twice
and gives these two options. It forwards the event to the gunzip element.
- The gunzip element has already decoded the whole data so it knows the size of the stream. It
calls the callback for "length_size" and forwards the event.
- The filesrc supplies the "URI" and the "length_size" for a second time. It is now up to the
application's callback function to handle this second occurence of "length_size" information.
The filesrc does not forward the event and dereferences it.
- During disposal of the event, the callback function is called again with name=NULL. The
application now knows that no "title" can be supplied.
Open Questions
Open questions are issues that should probably be solved by events but can not be solved
* A filesink needs to be able to inform elements of a restricted file size. Simply closing
the file and opening a new one might not work because elements might need to supply a
footer. (eg avimux)
Issues / changes (to be deleted in final version)
? Are the event directions distinct? Or is it possible that some type of event
can travel eg upstream _and_ vertical?
? How are upstream/vertical events supposed to be handled if they occur when
the element is READY or NULL? Buffer the event? How many events should be
buffered? Maybe a READY element is attached to a PLAYING/PAUSED one and
constantly receiving events, no?
! The EOS event was merged with the DISCONTINUOUS event.
? Does the DISCONTINUOUS event need a "flush" option?
? Should chain funcs be changed to expect GstData instead of GstBuffer?
It's a little bit misleading if events can arrive there.
! added information about timestamp.
? Should timestamps of "follow up" events (eg conversion of seek) keep the
? src = NULL, when app inserts event?
? How do elements handle events they cannot use? (eg filesrc getting timebased
seek request)
? Somebody fix the GST_EVENT_FLUSH part.
? GValue or GstProps for INFO events? First requires to open up the props headers
and writing some API to ease the retrieval of the elements, the second requires
a rewrite of GST_EVENT_INFO.
? GQuark/GValue possible in INFO events?
! Merged INFO and PROPS event. They are nearly the same. Added documentation.
? Need to work out the ERROR event.
! changed prototype for gst_pad_event_default to accept buffers so the function checks
if it is an event and not every chain handler has to.
! added HAS_INFO event. An alternative to the callback function could be another vertical
? Should HAS_INFO callback supply the element calling the function?
? Use case one: start with discont event?
? Do we need a state change event?
? Should we make elements supply information as soon as possible or only upon HAS_INFO
? should the second example be done with region requesting instead of events?
? "location" or "URI"?
? What about suggesting buffer sizes?
? What about QoS?