mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-03 16:09:39 +00:00
243 lines
9.3 KiB
Markdown
243 lines
9.3 KiB
Markdown
|
---
|
||
|
title: Bus
|
||
|
...
|
||
|
|
||
|
# Bus
|
||
|
|
||
|
A bus is a simple system that takes care of forwarding messages from the
|
||
|
streaming threads to an application in its own thread context. The
|
||
|
advantage of a bus is that an application does not need to be
|
||
|
thread-aware in order to use GStreamer, even though GStreamer itself is
|
||
|
heavily threaded.
|
||
|
|
||
|
Every pipeline contains a bus by default, so applications do not need to
|
||
|
create a bus or anything. The only thing applications should do is set a
|
||
|
message handler on a bus, which is similar to a signal handler to an
|
||
|
object. When the mainloop is running, the bus will periodically be
|
||
|
checked for new messages, and the callback will be called when any
|
||
|
message is available.
|
||
|
|
||
|
# How to use a bus
|
||
|
|
||
|
There are two different ways to use a bus:
|
||
|
|
||
|
- Run a GLib/Gtk+ main loop (or iterate the default GLib main context
|
||
|
yourself regularly) and attach some kind of watch to the bus. This
|
||
|
way the GLib main loop will check the bus for new messages and
|
||
|
notify you whenever there are messages.
|
||
|
|
||
|
Typically you would use `gst_bus_add_watch ()` or
|
||
|
`gst_bus_add_signal_watch ()` in this case.
|
||
|
|
||
|
To use a bus, attach a message handler to the bus of a pipeline
|
||
|
using `gst_bus_add_watch ()`. This handler will be called whenever
|
||
|
the pipeline emits a message to the bus. In this handler, check the
|
||
|
signal type (see next section) and do something accordingly. The
|
||
|
return value of the handler should be TRUE to keep the handler
|
||
|
attached to the bus, return FALSE to remove it.
|
||
|
|
||
|
- Check for messages on the bus yourself. This can be done using
|
||
|
`gst_bus_peek ()` and/or `gst_bus_poll ()`.
|
||
|
|
||
|
<!-- end list -->
|
||
|
|
||
|
```
|
||
|
#include <gst/gst.h>
|
||
|
|
||
|
static GMainLoop *loop;
|
||
|
|
||
|
static gboolean
|
||
|
my_bus_callback (GstBus *bus,
|
||
|
GstMessage *message,
|
||
|
gpointer data)
|
||
|
{
|
||
|
g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
|
||
|
|
||
|
switch (GST_MESSAGE_TYPE (message)) {
|
||
|
case GST_MESSAGE_ERROR: {
|
||
|
GError *err;
|
||
|
gchar *debug;
|
||
|
|
||
|
gst_message_parse_error (message, &err, &debug);
|
||
|
g_print ("Error: %s\n", err->message);
|
||
|
g_error_free (err);
|
||
|
g_free (debug);
|
||
|
|
||
|
g_main_loop_quit (loop);
|
||
|
break;
|
||
|
}
|
||
|
case GST_MESSAGE_EOS:
|
||
|
/* end-of-stream */
|
||
|
g_main_loop_quit (loop);
|
||
|
break;
|
||
|
default:
|
||
|
/* unhandled message */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* we want to be notified again the next time there is a message
|
||
|
* on the bus, so returning TRUE (FALSE means we want to stop watching
|
||
|
* for messages on the bus and our callback should not be called again)
|
||
|
*/
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
gint
|
||
|
main (gint argc,
|
||
|
gchar *argv[])
|
||
|
{
|
||
|
GstElement *pipeline;
|
||
|
GstBus *bus;
|
||
|
guint bus_watch_id;
|
||
|
|
||
|
/* init */
|
||
|
gst_init (&argc, &argv);
|
||
|
|
||
|
/* create pipeline, add handler */
|
||
|
pipeline = gst_pipeline_new ("my_pipeline");
|
||
|
|
||
|
/* adds a watch for new message on our pipeline's message bus to
|
||
|
* the default GLib main context, which is the main context that our
|
||
|
* GLib main loop is attached to below
|
||
|
*/
|
||
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
|
||
|
bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
|
||
|
gst_object_unref (bus);
|
||
|
|
||
|
[..]
|
||
|
|
||
|
/* create a mainloop that runs/iterates the default GLib main context
|
||
|
* (context NULL), in other words: makes the context check if anything
|
||
|
* it watches for has happened. When a message has been posted on the
|
||
|
* bus, the default main context will automatically call our
|
||
|
* my_bus_callback() function to notify us of that message.
|
||
|
* The main loop will be run until someone calls g_main_loop_quit()
|
||
|
*/
|
||
|
loop = g_main_loop_new (NULL, FALSE);
|
||
|
g_main_loop_run (loop);
|
||
|
|
||
|
/* clean up */
|
||
|
gst_element_set_state (pipeline, GST_STATE_NULL);
|
||
|
gst_object_unref (pipeline);
|
||
|
g_source_remove (bus_watch_id);
|
||
|
g_main_loop_unref (loop);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
```
|
||
|
|
||
|
It is important to know that the handler will be called in the thread
|
||
|
context of the mainloop. This means that the interaction between the
|
||
|
pipeline and application over the bus is *asynchronous*, and thus not
|
||
|
suited for some real-time purposes, such as cross-fading between audio
|
||
|
tracks, doing (theoretically) gapless playback or video effects. All
|
||
|
such things should be done in the pipeline context, which is easiest by
|
||
|
writing a GStreamer plug-in. It is very useful for its primary purpose,
|
||
|
though: passing messages from pipeline to application. The advantage of
|
||
|
this approach is that all the threading that GStreamer does internally
|
||
|
is hidden from the application and the application developer does not
|
||
|
have to worry about thread issues at all.
|
||
|
|
||
|
Note that if you're using the default GLib mainloop integration, you
|
||
|
can, instead of attaching a watch, connect to the “message” signal on
|
||
|
the bus. This way you don't have to `switch()` on all possible message
|
||
|
types; just connect to the interesting signals in form of
|
||
|
“message::\<type\>”, where \<type\> is a specific message type (see
|
||
|
the next section for an explanation of message types).
|
||
|
|
||
|
The above snippet could then also be written as:
|
||
|
|
||
|
```
|
||
|
GstBus *bus;
|
||
|
|
||
|
[..]
|
||
|
|
||
|
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline);
|
||
|
gst_bus_add_signal_watch (bus);
|
||
|
g_signal_connect (bus, "message::error", G_CALLBACK (cb_message_error), NULL);
|
||
|
g_signal_connect (bus, "message::eos", G_CALLBACK (cb_message_eos), NULL);
|
||
|
|
||
|
[..]
|
||
|
|
||
|
```
|
||
|
|
||
|
If you aren't using GLib mainloop, the asynchronous message signals
|
||
|
won't be available by default. You can however install a custom sync
|
||
|
handler that wakes up the custom mainloop and that uses
|
||
|
`gst_bus_async_signal_func ()` to emit the signals. (see also
|
||
|
[documentation](http://gstreamer.freedesktop.org/data/doc/gstreamer/stable/gstreamer/html/GstBus.html)
|
||
|
for details)
|
||
|
|
||
|
# Message types
|
||
|
|
||
|
GStreamer has a few pre-defined message types that can be passed over
|
||
|
the bus. The messages are extensible, however. Plug-ins can define
|
||
|
additional messages, and applications can decide to either have specific
|
||
|
code for those or ignore them. All applications are strongly recommended
|
||
|
to at least handle error messages by providing visual feedback to the
|
||
|
user.
|
||
|
|
||
|
All messages have a message source, type and timestamp. The message
|
||
|
source can be used to see which element emitted the message. For some
|
||
|
messages, for example, only the ones emitted by the top-level pipeline
|
||
|
will be interesting to most applications (e.g. for state-change
|
||
|
notifications). Below is a list of all messages and a short explanation
|
||
|
of what they do and how to parse message-specific content.
|
||
|
|
||
|
- Error, warning and information notifications: those are used by
|
||
|
elements if a message should be shown to the user about the state of
|
||
|
the pipeline. Error messages are fatal and terminate the
|
||
|
data-passing. The error should be repaired to resume pipeline
|
||
|
activity. Warnings are not fatal, but imply a problem nevertheless.
|
||
|
Information messages are for non-problem notifications. All those
|
||
|
messages contain a `GError` with the main error type and message,
|
||
|
and optionally a debug string. Both can be extracted using
|
||
|
`gst_message_parse_error
|
||
|
()`, `_parse_warning ()` and `_parse_info ()`. Both error and debug
|
||
|
strings should be freed after use.
|
||
|
|
||
|
- End-of-stream notification: this is emitted when the stream has
|
||
|
ended. The state of the pipeline will not change, but further media
|
||
|
handling will stall. Applications can use this to skip to the next
|
||
|
song in their playlist. After end-of-stream, it is also possible to
|
||
|
seek back in the stream. Playback will then continue automatically.
|
||
|
This message has no specific arguments.
|
||
|
|
||
|
- Tags: emitted when metadata was found in the stream. This can be
|
||
|
emitted multiple times for a pipeline (e.g. once for descriptive
|
||
|
metadata such as artist name or song title, and another one for
|
||
|
stream-information, such as samplerate and bitrate). Applications
|
||
|
should cache metadata internally. `gst_message_parse_tag
|
||
|
()` should be used to parse the taglist, which should be
|
||
|
`gst_tag_list_unref ()`'ed when no longer needed.
|
||
|
|
||
|
- State-changes: emitted after a successful state change.
|
||
|
`gst_message_parse_state_changed ()` can be used to parse the old
|
||
|
and new state of this transition.
|
||
|
|
||
|
- Buffering: emitted during caching of network-streams. One can
|
||
|
manually extract the progress (in percent) from the message by
|
||
|
extracting the “buffer-percent” property from the structure returned
|
||
|
by `gst_message_get_structure
|
||
|
()`. See also [Buffering](manual-buffering.md).
|
||
|
|
||
|
- Element messages: these are special messages that are unique to
|
||
|
certain elements and usually represent additional features. The
|
||
|
element's documentation should mention in detail which element
|
||
|
messages a particular element may send. As an example, the 'qtdemux'
|
||
|
QuickTime demuxer element may send a 'redirect' element message on
|
||
|
certain occasions if the stream contains a redirect instruction.
|
||
|
|
||
|
- Application-specific messages: any information on those can be
|
||
|
extracted by getting the message structure (see above) and reading
|
||
|
its fields. Usually these messages can safely be ignored.
|
||
|
|
||
|
Application messages are primarily meant for internal use in
|
||
|
applications in case the application needs to marshal information
|
||
|
from some thread into the main thread. This is particularly useful
|
||
|
when the application is making use of element signals (as those
|
||
|
signals will be emitted in the context of the streaming thread).
|
||
|
|