mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 00:06:36 +00:00
626cbdc8b2
Original commit message from CVS: cleanup of unused and forgoten sections fixed links from the manual and the pwg to the API docs added more notes to README
418 lines
18 KiB
XML
418 lines
18 KiB
XML
<chapter id="chapter-advanced-events">
|
|
<title>Events: Seeking, Navigation and More</title>
|
|
<para>
|
|
There are many different event types but only 2 ways they can travel across
|
|
the pipeline: downstream or upstream. It is very important to understand
|
|
how both of those methods work because if one element in the pipeline is not
|
|
handling them correctly the whole event system of the pipeline is broken.
|
|
We will try to explain here how these methods work and how elements are
|
|
supposed to implement them.
|
|
</para>
|
|
<sect1 id="section-events-downstream" xreflabel="Downstream events">
|
|
<title>Downstream events</title>
|
|
<para>
|
|
Downstream events are received through the sink pad's dataflow. Depending
|
|
if your element is loop or chain based you will receive events in your
|
|
loop/chain function as a GstData with <function>gst_pad_pull</function>
|
|
or directly in the function call arguments. So when receiving dataflow
|
|
from the sink pad you have to check first if this data chunk is an event.
|
|
If that's the case you check what kind of event it is to react on relevant
|
|
ones and then forward others downstream using
|
|
<function>gst_pad_event_default</function>. Here is an example for both
|
|
loop and chain based elements.
|
|
</para>
|
|
<programlisting>
|
|
/* Chain based element */
|
|
static void
|
|
gst_my_filter_chain (GstPad *pad,
|
|
GstData *data)
|
|
{
|
|
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
|
...
|
|
if (GST_IS_EVENT (data)) {
|
|
GstEvent *event = GST_EVENT (data);
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_EOS:
|
|
/* end-of-stream, we should close down all stream leftovers here */
|
|
gst_my_filter_stop_processing (filter);
|
|
/* fall-through to default event handling */
|
|
default:
|
|
gst_pad_event_default (pad, event);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
...
|
|
}
|
|
|
|
/* Loop based element */
|
|
static void
|
|
gst_my_filter_loop (GstElement *element)
|
|
{
|
|
GstMyFilter *filter = GST_MY_FILTER (element);
|
|
GstData *data = NULL;
|
|
|
|
data = gst_pad_pull (filter->sinkpad);
|
|
|
|
if (GST_IS_EVENT (data)) {
|
|
GstEvent *event = GST_EVENT (data);
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_EOS:
|
|
/* end-of-stream, we should close down all stream leftovers here */
|
|
gst_my_filter_stop_processing (filter);
|
|
/* fall-through to default event handling */
|
|
default:
|
|
gst_pad_event_default (filter->sinkpad, event);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
...
|
|
}
|
|
</programlisting>
|
|
</sect1>
|
|
<sect1 id="section-events-upstream" xreflabel="Upstream events">
|
|
<title>Upstream events</title>
|
|
<para>
|
|
Upstream events are generated by an element somewhere in the pipeline and
|
|
sent using the <function>gst_pad_send_event</function> function. This
|
|
function simply realizes the pad and call the default event handler of that
|
|
pad. The default event handler of pads is <function>gst_pad_event_default</function>
|
|
, it basically sends the event to the peer pad. So upstream events always
|
|
arrive on the src pad of your element and are handled by the default event
|
|
handler except if you override that handler to handle it yourself. There
|
|
are some specific cases where you have to do that :
|
|
</para>
|
|
<itemizedlist mark="opencircle">
|
|
<listitem>
|
|
<para>
|
|
If you have multiple sink pads in your element. In that case you will
|
|
have to decide which one of the sink pads you will send the event to.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If you need to handle that event locally. For example a navigation
|
|
event that you will want to convert before sending it upstream.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
The processing you will do in that event handler does not really matter
|
|
but there are important rules you have to absolutely respect because
|
|
one broken element event handler is breaking the whole pipeline event
|
|
handling. Here they are :
|
|
</para>
|
|
<itemizedlist mark="opencircle">
|
|
<listitem>
|
|
<para>
|
|
Always forward events you won't handle upstream using the default
|
|
<function>gst_pad_event_default</function> method.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
If you are generating some new event based on the one you received
|
|
don't forget to gst_event_unref the event you received.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Event handler function are supposed to return TRUE or FALSE indicating
|
|
if the event has been handled or not. Never simply return TRUE/FALSE
|
|
in that handler except if you really know that you have handled that
|
|
event.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
Here is an example of correct upstream event handling for a plugin
|
|
that wants to modify navigation events.
|
|
</para>
|
|
<programlisting>
|
|
static gboolean
|
|
gst_my_filter_handle_src_event (GstPad *pad,
|
|
GstEvent *event)
|
|
{
|
|
GstMyFilter *filter = GST_MY_FILTER (gst_pad_get_parent (pad));
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_NAVIGATION:
|
|
GstEvent *new_event = gst_event_new (GST_EVENT_NAVIGATION);;
|
|
/* Create a new event based on received one and then send it */
|
|
...
|
|
gst_event_unref (event);
|
|
return gst_pad_event_default (pad, new_event);
|
|
default:
|
|
/* Falling back to default event handling for that pad */
|
|
return gst_pad_event_default (pad, event);
|
|
}
|
|
}
|
|
</programlisting>
|
|
</sect1>
|
|
|
|
<sect1 id="section-events-definitions" xreflabel="All Events Together">
|
|
<title>All Events Together</title>
|
|
<para>
|
|
In this chapter follows a list of all defined events that are currently
|
|
being used, plus how they should be used/interpreted. Events are stored
|
|
in a <ulink type="http"
|
|
url="../../gstreamer/html/gstreamer-GstEvent.html"><classname>GstEvent
|
|
</classname></ulink> structure, which is simply a big C union with the
|
|
types for each event in it. For the next development cycle, we intend to
|
|
switch events over to <ulink type="http"
|
|
url="../../gstreamer/html/gstreamer-GstStructure.html"><classname>GstStructure
|
|
</classname></ulink>,
|
|
but you don't need to worry about that too much for now.
|
|
</para>
|
|
<para>
|
|
In this chapter, we will discuss the following events:
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem><para><xref linkend="section-events-eos"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-flush"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-discont"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-seek"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-filler"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-interrupt"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-nav"/></para></listitem>
|
|
<listitem><para><xref linkend="section-events-tag"/></para></listitem>
|
|
</itemizedlist>
|
|
|
|
<sect2 id="section-events-eos" xreflabel="End of Stream (EOS)">
|
|
<title>End of Stream (EOS)</title>
|
|
<para>
|
|
End-of-stream events are sent if the stream that an element sends out
|
|
is finished. An element receiving this event (from upstream, so it
|
|
receives it on its sinkpad) will generally forward the event further
|
|
downstream and set itself to EOS (<function>gst_element_set_eos ()</function>).
|
|
<function>gst_pad_event_default ()</function> takes care of all this,
|
|
so most elements do not need to support this event. Exceptions are
|
|
elements that explicitly need to close a resource down on EOS, and
|
|
N-to-1 elements. Note that the stream itself is <emphasis>not</emphasis>
|
|
a resource that should be closed down on EOS! Applications might seek
|
|
back to a point before EOS and set the pipeline to PLAYING again.
|
|
N-to-1 elements have been discussed previously in
|
|
<xref linkend="section-loopfn-multiinput"/>.
|
|
</para>
|
|
<para>
|
|
The EOS event (<symbol>GST_EVENT_EOS</symbol>) has no properties,
|
|
and that makes it one of the simplest events in &GStreamer;. It is
|
|
created using <function>gst_event_new (GST_EVENT_EOS);</function>.
|
|
</para>
|
|
<para>
|
|
Some elements support the EOS event upstream, too. This signals the
|
|
element to go into EOS as soon as possible and signal the EOS event
|
|
forward downstream. This is useful for elements that have no concept
|
|
of end-of-stream themselves. Examples are TV card sources, audio card
|
|
sources, etc. This is not (yet) part of the official specifications of
|
|
this event, though.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-flush" xreflabel="Flush">
|
|
<title>Flush</title>
|
|
<para>
|
|
The flush event is being sent downstream if all buffers and caches
|
|
in the pipeline should be emptied. <quote>Queue</quote> elements will
|
|
empty their internal list of buffers when they receive this event, for
|
|
example. File sink elements (e.g. <quote>filesink</quote>) will flush
|
|
the kernel-to-disk cache (<function>fdatasync ()</function> or
|
|
<function>fflush ()</function>) when they receive this event. Normally,
|
|
elements receiving this event will simply just forward it, since most
|
|
filter or filter-like elements don't have an internal cache of data.
|
|
<function>gst_pad_event_default ()</function> does just that, so for
|
|
most elements, it is enough to forward the event using the default
|
|
event handler.
|
|
</para>
|
|
<para>
|
|
The flush event is created with <function>gst_event_new (GST_EVENT_FLUSH);</function>.
|
|
Like the EOS event, it has no properties.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-discont" xreflabel="Stream Discontinuity">
|
|
<title>Stream Discontinuity</title>
|
|
<para>
|
|
A discontinuity event is sent downstream to indicate a discontinuity in
|
|
the data stream. This can happen because the application used the seek
|
|
event to seek to a different position in the stream, but it can also be
|
|
because a real-time network source temporarily lost the connection.
|
|
After the connection is restored, the data stream will continue, but
|
|
not at the same point where it got lost. Therefore, a discontinuity
|
|
event is being sent downstream, too.
|
|
</para>
|
|
<para>
|
|
Depending on the element type, the event can simply be forwarded using
|
|
<function>gst_pad_event_default ()</function>, or it should be parsed
|
|
and a modified event should be sent on. The last is true for demuxers,
|
|
which generally have a byte-to-time conversion concept. Their input
|
|
is usually byte-based, so the incoming event will have an offset in
|
|
byte units (<symbol>GST_FORMAT_BYTES</symbol>), too. Elements
|
|
downstream, however, expect discontinuity events in time units, so that
|
|
it can be used to update the pipeline clock. Therefore, demuxers and
|
|
similar elements should not forward the event, but parse it, free it
|
|
and send a new discontinuity event (in time units,
|
|
<symbol>GST_FORMAT_TIME</symbol>) further downstream.
|
|
</para>
|
|
<para>
|
|
The discontinuity event is created using the function
|
|
<function>gst_event_new_discontinuous ()</function>. It should set a
|
|
boolean value which indicates if the discontinuity event is sent
|
|
because of a new media type (this can happen if - during iteration -
|
|
a new location was set on a network source or on a file source).
|
|
then, it should give a list of formats and offsets in that format. The
|
|
list should be terminated by 0 as format.
|
|
</para>
|
|
<programlisting>
|
|
static void
|
|
my_filter_some_function (GstMyFilter *filter)
|
|
{
|
|
GstEvent *event;
|
|
[..]
|
|
event = gst_event_new_discontinuous (FALSE,
|
|
GST_FORMAT_BYTES, 0,
|
|
GST_FORMAT_TIME, 0,
|
|
0);
|
|
gst_pad_push (filter->srcpad, GST_DATA (event));
|
|
[..]
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
Elements parsing this event can use macros and functions to access the
|
|
various properties. <function>GST_EVENT_DISCONT_NEW_MEDIA (event)</function>
|
|
checks the new-media boolean value.
|
|
<function>gst_event_discont_get_value (event, format, &value)</function>
|
|
gets the offset of the new stream position in the specified format. If
|
|
that format was not specified when creating the event, the function
|
|
returns FALSE.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-seek" xreflabel="Seek Request">
|
|
<title>Seek Request</title>
|
|
<para>
|
|
Seek events are meant to request a new stream position to elements.
|
|
This new position can be set in several formats (time, bytes or
|
|
<quote>units</quote> [a term indicating frames for video, samples for
|
|
audio, etc.]). Seeking can be done with respect to the end-of-file,
|
|
start-of-file or current position, and can happen in both upstream and
|
|
downstream direction. Elements receiving seek events should, depending
|
|
on the element type, either forward it (filters, decoders), change the
|
|
format in which the event is given and forward it (demuxers), handle
|
|
the event by changing the file pointer in their internal stream
|
|
resource (file sources) or something else.
|
|
</para>
|
|
<para>
|
|
Seek events are, like discontinuity events, built up using positions in
|
|
specified formats (time, bytes, units). They are created using the
|
|
function <function>gst_event_new_seek ()</function>, where the first
|
|
argument is the seek type (indicating with respect to which position
|
|
[current, end, start] the seek should be applied, and the format in
|
|
which the new position is given (time, bytes, units), and an offset
|
|
which is the requested position in the specified format.
|
|
</para>
|
|
<programlisting>
|
|
static void
|
|
my_filter_some_function (GstMyFilter *filter)
|
|
{
|
|
GstEvent *event;
|
|
[..]
|
|
/* seek to the start of a resource */
|
|
event = gst_event_new_seek (GST_SEEK_SET | GST_FORMAT_BYTES, 0);
|
|
gst_pad_push (filter->srcpad, GST_DATA (event));
|
|
[..]
|
|
}
|
|
</programlisting>
|
|
<para>
|
|
Elements parsing this event can use macros and functions to access the
|
|
properties. The seek type can be retrieved using
|
|
<function>GST_EVENT_SEEK_TYPE (event)</function>. This seek type
|
|
contains both the indicator of with respect to what position the seek
|
|
should be applied, and the format in which the seek event is given.
|
|
To get either one of these properties separately, use
|
|
<function>GST_EVENT_SEEK_FORMAT (event)</function> or
|
|
<function>GST_EVENT_SEEK_METHOD (event)</function>. The requested
|
|
position is available through <function>GST_EVENT_SEEK_OFFSET (event)</function>,
|
|
and is given in the specified format.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-filler" xreflabel="Stream Filler">
|
|
<title>Stream Filler</title>
|
|
<para>
|
|
The filler event is, as the name says, a <quote>filler</quote> of the
|
|
stream which has no special meaning associated with itself. It is used
|
|
to provide data to downstream elements and should be interpreted as a
|
|
way of assuring that the normal data flow will continue further
|
|
downstream. The event is especially intended for real-time MIDI source
|
|
elements, which only generate data when something <emphasis>changes</emphasis>.
|
|
MIDI decoders will therefore stall if nothing changes for several
|
|
seconds, and therefore playback will stop. The filler event is sent
|
|
downstream to assure the MIDI decoder that nothing changed, so that the
|
|
normal decoding process will continue and playback will, too. Unless
|
|
you intend to work with MIDI or other control-language-based data
|
|
types, you don't need this event. You can mostly simply forward it
|
|
with <function>gst_pad_event_default ()</function>.
|
|
</para>
|
|
<para>
|
|
The stream filler is created using <function>gst_event_new (GST_EVENT_FILLER);</function>.
|
|
It has no properties.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-interrupt" xreflabel="Interruption">
|
|
<title>Interruption</title>
|
|
<para>
|
|
The interrupt event is generated by queue elements and sent downstream
|
|
if a timeout occurs on the stream. The scheduler will use this event to
|
|
get back in its own main loop and schedule other elements. This
|
|
prevents deadlocks or a stream stall if no data is generated over a
|
|
part of the pipeline for a considerable amount of time. The scheduler
|
|
will process this event internally, so any normal elements do not need
|
|
to generate or handle this event at all.
|
|
</para>
|
|
<para>
|
|
The difference between the filler event and the interrupt event is that
|
|
the filler event is a real part of a pipeline, so it will reach fellow
|
|
elements, which can use it to "do nothing else than what I used to do".
|
|
The interrupt event never reaches fellow elements.
|
|
</para>
|
|
<para>
|
|
The interrupt event (<function>gst_event_new (GST_EVENT_INTERRUPT);</function>)
|
|
has no properties.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-nav" xreflabel="Navigation">
|
|
<title>Navigation</title>
|
|
<para>
|
|
WRITEME
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2 id="section-events-tag" xreflabel="Tag (metadata)">
|
|
<title>Tag (metadata)</title>
|
|
<para>
|
|
Tagging events are being sent downstream to indicate the tags as parsed
|
|
from the stream data. This is currently used to preserve tags during
|
|
stream transcoding from one format to the other. Tags are discussed
|
|
extensively in <xref linkend="chapter-advanced-tagging"/>. Most
|
|
elements will simply forward the event by calling
|
|
<function>gst_pad_event_default ()</function>.
|
|
</para>
|
|
<para>
|
|
The tag event is created using the function
|
|
<function>gst_event_new_tag ()</function>. It requires a filled
|
|
taglist as argument.
|
|
</para>
|
|
<para>
|
|
Elements parsing this event can use the function
|
|
<function>gst_event_tag_get_list (event)</function> to acquire the
|
|
taglist that was parsed.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|