mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
350 lines
14 KiB
Markdown
350 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:
|
||
|
|
||
|
```
|
||
|
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
|
||
|
element 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
|
||
|
informs 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 call 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 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.
|
||
|
|
||
|
- 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 the
|
||
|
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](pwg-negotiation.md) for more information
|
||
|
about negotiation.
|
||
|
|
||
|
## 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 it 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)](pwg-advanced-tagging.md). 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.
|
||
|
|
||
|
## 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)](pwg-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.
|
||
|
|