mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-04 23:46:43 +00:00
dc64f3e6cf
https://gitlab.freedesktop.org/gstreamer/gst-docs/-/merge_requests/50 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4690>
352 lines
14 KiB
Markdown
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.
|