mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-16 21:36:35 +00:00
328 lines
14 KiB
Text
328 lines
14 KiB
Text
|
EVENTS RFC
|
||
|
==========
|
||
|
|
||
|
|
||
|
Scope
|
||
|
-----
|
||
|
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.
|
||
|
|
||
|
|
||
|
Definition
|
||
|
----------
|
||
|
|
||
|
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.
|
||
|
|
||
|
GST_EVENT_DISCONTINUOUS
|
||
|
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.
|
||
|
(type = GST_DISCONT_EOS)
|
||
|
|
||
|
GST_EVENT_SEEK
|
||
|
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.
|
||
|
|
||
|
GST_EVENT_FLUSH
|
||
|
direction(s): upstream
|
||
|
event_data: none
|
||
|
This event indicates that all buffered data should be flushed out immediately.
|
||
|
|
||
|
GST_EVENT_INFO
|
||
|
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
|
||
|
microseconds).
|
||
|
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.
|
||
|
|
||
|
GST_EVENT_HAS_INFO
|
||
|
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.
|
||
|
|
||
|
GST_EVENT_ERROR
|
||
|
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
|
||
|
information.
|
||
|
- 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 ! disksink
|
||
|
|
||
|
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 disksink.
|
||
|
- After that it issues a DISCONTINUOUS event of the type DISCONT_NEW indicating a new stream.
|
||
|
The disksink 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 appplication creates a HAS_INFO event and inserts it at the end of the pipeline into the
|
||
|
osssink.
|
||
|
- 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
|
||
|
currently.
|
||
|
|
||
|
* A disksink 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
|
||
|
timestamp?
|
||
|
? 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
|
||
|
event.
|
||
|
? 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
|
||
|
request?
|
||
|
? should the second example be done with region requesting instead of events?
|
||
|
? "location" or "URI"?
|
||
|
? What about suggesting buffer sizes?
|
||
|
? What about QoS?
|