gstreamer/subprojects/gst-docs/markdown/plugin-development/advanced/events.md

352 lines
14 KiB
Markdown

---
title: 'Events: Seeking, Navigation and More'
...
# Events: Seeking, Navigation and More
There are many different event types but only two ways they can travel
in the pipeline: downstream or upstream. It is very important to
understand how both of these 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.
## Downstream events
Downstream events are received through the sink pad's event handler, as
set using `gst_pad_set_event_function ()` when the pad was created.
Downstream events can travel in two ways: they can be in-band
(serialised with the buffer flow) or out-of-band (travelling through the
pipeline instantly, possibly not in the same thread as the streaming
thread that is processing the buffers, skipping ahead of buffers being
processed or queued in the pipeline). The most common downstream events
(SEGMENT, CAPS, TAG, EOS) are all serialised with the buffer flow.
Here is a typical event function:
``` c
static gboolean
gst_my_filter_sink_event (GstPad *pad, GstObject * parent, GstEvent * event)
{
GstMyFilter *filter;
gboolean ret;
filter = GST_MY_FILTER (parent);
...
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEGMENT:
/* maybe save and/or update the current segment (e.g. for output
* clipping) or convert the event into one in a different format
* (e.g. BYTES to TIME) or drop it and set a flag to send a segment
* event in a different format later */
ret = gst_pad_push_event (filter->src_pad, event);
break;
case GST_EVENT_EOS:
/* end-of-stream, we should close down all stream leftovers here */
gst_my_filter_stop_processing (filter);
ret = gst_pad_push_event (filter->src_pad, event);
break;
case GST_EVENT_FLUSH_STOP:
gst_my_filter_clear_temporary_buffers (filter);
ret = gst_pad_push_event (filter->src_pad, event);
break;
default:
ret = gst_pad_event_default (pad, parent, event);
break;
}
...
return ret;
}
```
If your element is chain-based, you will almost always have to implement
a sink event function, since that is how you are notified about
segments, caps and the end of the stream.
If your element is exclusively loop-based, you may or may not want a
sink event function (since the element is driving the pipeline it will
know the length of the stream in advance or be notified by the flow
return value of `gst_pad_pull_range()`. In some cases even loop-based
elements may receive events from upstream though (for example audio
decoders with an id3demux or apedemux element in front of them, or
demuxers that are being fed input from sources that send additional
information about the stream in custom events, as DVD sources do).
## Upstream events
Upstream events are generated by an element somewhere downstream in the
pipeline (example: a video sink may generate navigation events that
inform upstream elements about the current position of the mouse
pointer). This may also happen indirectly on request of the application,
for example when the application executes a seek on a pipeline this seek
request will be passed on to a sink element which will then in turn
generate an upstream seek event.
The most common upstream events are seek events, Quality-of-Service
(QoS) and reconfigure events.
An upstream event can be sent using the `gst_pad_send_event` function.
This function simply calls the default event handler of that pad. The
default event handler of pads is `gst_pad_event_default`, and it
basically sends the event to the peer of the internally linked 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:
- 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 (if not all of them).
- If you need to handle that event locally. For example a navigation
event that you will want to convert before sending it upstream, or a
QoS event that you want to handle.
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:
- Always handle events you won't handle using the default
`gst_pad_event_default` method. This method will depending on the
event, forward the event or drop it.
- If you are generating some new event based on the one you received
don't forget to gst\_event\_unref the event you received.
- Event handler functions 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.
- Remember that the event handler might be called from a different
thread than the streaming thread, so make sure you use appropriate
locking everywhere.
## All Events Together
In this chapter follows a list of all defined events that are currently
being used, plus how they should be used/interpreted. You can check
what type a certain event is using the GST\_EVENT\_TYPE macro (or if you
need a string for debugging purposes you can use
GST\_EVENT\_TYPE\_NAME).
In this chapter, we will discuss the following events:
- [Stream Start](#stream-start)
- [Caps](#caps)
- [Segment](#segment)
- [Tag (metadata)](#tag-metadata)
- [End of Stream (EOS)](#end-of-stream-eos)
- [Table Of Contents](#table-of-contents)
- [Gap](#gap)
- [Flush Start](#flush-start)
- [Flush Stop](#flush-stop)
- [Quality Of Service (QOS)](#quality-of-service-qos)
- [Seek Request](#seek-request)
- [Navigation](#navigation)
For more comprehensive information about events and how they should be
used correctly in various circumstances please consult the GStreamer
design documentation. This section only gives a general overview.
### Stream Start
WRITEME
### Caps
The CAPS event contains the format description of the following buffers.
See [Caps negotiation][caps-negotiation] for more information
about negotiation.
[caps-negotiation]: plugin-development/advanced/negotiation.md
### Segment
A segment event is sent downstream to announce the range of valid
timestamps in the stream and how they should be transformed into
running-time and stream-time. A segment event must always be sent before
the first buffer of data and after a flush (see above).
The first segment event is created by the element driving the pipeline,
like a source operating in push-mode or a demuxer/decoder operating
pull-based. This segment event then travels down the pipeline and may be
transformed on the way (a decoder, for example, might receive a segment
event in BYTES format and might transform this into a segment event in
TIMES format based on the average bitrate).
Depending on the element type, the event can simply be forwarded using
`gst_pad_event_default ()`, 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
(`GST_FORMAT_BYTES`), too. Elements downstream, however, expect segment
events in time units, so that they can be used to synchronize against the
pipeline clock. Therefore, demuxers and similar elements should not
forward the event, but parse it, free it and send a segment event (in
time units, `GST_FORMAT_TIME`) further downstream.
The segment event is created using the function `gst_event_new_segment
()`. See the API reference and design document for details about its
parameters.
Elements parsing this event can use gst\_event\_parse\_segment() to
extract the event details. Elements may find the GstSegment API useful
to keep track of the current segment (if they want to use it for output
clipping, for example).
### Tag (metadata)
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 [Tagging (Metadata and Streaminfo)][metadata]. Most elements
will simply forward the event by calling `gst_pad_event_default ()`.
The tag event is created using the function `gst_event_new_tag ()`, but
more often elements will send a tag event downstream that will be
converted into a message on the bus by sink elements. All of these
functions require a filled-in taglist as argument, which they will take
ownership of.
Elements parsing this event can use the function `gst_event_parse_tag ()` to
acquire the taglist that the event contains.
[metadata]: plugin-development/advanced/tagging.md
### End of Stream (EOS)
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 just process any buffered data (if
there is any) and then forward the event further downstream. The
`gst_pad_event_default ()` 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 *not* a resource that should be closed down on EOS\!
Applications might seek back to a point before EOS and continue playing
again.
The EOS event has no properties, which makes it one of the simplest
events in GStreamer. It is created using the `gst_event_new_eos()`
function.
It is important to note that *only elements driving the pipeline should
ever send an EOS event*. If your element is chain-based, it is not
driving the pipeline. Chain-based elements should just return
GST\_FLOW\_EOS from their chain function at the end of the stream (or
the configured segment), the upstream element that is driving the
pipeline will then take care of sending the EOS event (or alternatively
post a SEGMENT\_DONE message on the bus depending on the mode of
operation). If you are implementing your own source element, you also do
not need to ever manually send an EOS event, you should also just return
GST\_FLOW\_EOS in your create or fill function (assuming your element
derives from GstBaseSrc or GstPushSrc).
### Table Of Contents
WRITEME
### Gap
WRITEME
### Flush Start
The flush start event is sent downstream (in push mode) or upstream (in
pull mode) if all buffers and caches in the pipeline should be emptied.
“Queue” elements will empty their internal list of buffers when they
receive this event, for example. File sink elements (e.g. “filesink”)
will flush the kernel-to-disk cache (`fdatasync ()` or `fflush ()`) 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. `gst_pad_event_default ()` does just
that, so for most elements, it is enough to forward the event using the
default event handler.
As a side-effect of flushing all data from the pipeline, this event
unblocks the streaming thread by making all pads reject data until they
receive a [Flush Stop](#flush-stop) signal (elements trying to push data
will get a FLUSHING flow return and stop processing data).
The flush-start event is created with the `gst_event_new_flush_start
()`. Like the EOS event, it has no properties. This event is usually
only created by elements driving the pipeline, like source elements
operating in push-mode or pull-range based demuxers/decoders.
### Flush Stop
The flush-stop event is sent by an element driving the pipeline after a
flush-start and tells pads and elements downstream that they should
accept events and buffers again (there will be at least a SEGMENT event
before any buffers first though).
If your element keeps temporary caches of stream data, it should clear
them when it receives a FLUSH-STOP event (and also whenever its chain
function receives a buffer with the DISCONT flag set).
The flush-stop event is created with `gst_event_new_flush_stop ()`. It
has one parameter that controls if the running-time of the pipeline
should be reset to 0 or not. Normally after a flushing seek, the
running\_time is set back to 0.
### Quality Of Service (QOS)
The QOS event contains a report about the current real-time performance
of the stream. See more info in [Quality Of Service (QoS)][qos].
[qos]: plugin-development/advanced/qos.md
### Seek Request
Seek events are meant to request a new stream position to elements. This
new position can be set in several formats (time, bytes or “default
units” \[a term indicating frames for video, channel-independent samples
for audio, etc.\]). Seeking can be done with respect to the end-of-file
or start-of-file, and usually happens in upstream direction (downstream
seeking is done by sending a SEGMENT event with the appropriate offsets
for elements that support that, like filesink).
Elements receiving seek events should, depending on the element type,
either just forward it upstream (filters, decoders), change the format
in which the event is given and then forward it (demuxers), or handle
the event by changing the file pointer in their internal stream resource
(file sources, demuxers/decoders driving the pipeline in pull-mode) or
something else.
Seek events are built up using positions in specified formats (time,
bytes, units). They are created using the function `gst_event_new_seek
()`. Note that many plugins do not support seeking from the end of the
stream. An element not driving the pipeline and forwarding a seek
request should not assume that the seek succeeded or actually happened,
it should operate based on the SEGMENT events it receives.
Elements parsing this event can do this using `gst_event_parse_seek()`.
### Navigation
Navigation events are sent upstream by video sinks to inform upstream
elements of where the mouse pointer is, if and where mouse pointer
clicks have happened, or if keys have been pressed or released.
All this information is contained in the event structure which can be
obtained with `gst_event_get_structure ()`.
Check out the navigationtest element in gst-plugins-good for an idea how
to extract navigation information from this event.