1,Bus
总线是一个简单的系统,负责将来自流线程的消息转发到应用程序自己的线程上下文中。总线的优势在于,应用程序不需要了解多线程就可以使用GStreamer,尽管GStreamer本身是高度多线程的。
每个管道默认都包含一个总线,因此应用程序不需要创建总线或任何其他内容。应用程序唯一需要做的是在总线上设置一个消息处理程序,这类似于对象的信号处理程序。当主循环运行时,总线将定期检查新消息,并在有任何消息可用时调用回调函数。
1.1,如何使用 bus
使用总线有两种方式:
-
要运行GLib/Gtk+主循环(或定期迭代默认的GLib主上下文),并将某种监视器附加到总线上。这样,GLib主循环将检查总线上的新消息,并在有消息时通知您。
在这种情况下,您通常会使用
gst_bus_add_watch()
或gst_bus_add_signal_watch()
。要使用总线,请使用
gst_bus_add_watch()
将消息处理程序附加到管道的总线。此处理程序将在管道向总线发出消息时被调用。在此处理程序中,检查信号类型(参见下一节),并据此采取相应的操作。处理程序的返回值应为TRUE以保持处理程序附加到总线,返回FALSE以将其删除。 -
可以使用
gst_bus_peek()
和/或gst_bus_poll()
自行检查总线上的消息。
#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;
}
了解处理程序将在主循环的线程上下文中被调用是很重要的。这意味着通过总线进行的管道与应用程序之间的交互是异步的,因此不适合一些实时用途,如音频轨道之间的交叉淡出、(理论上)无间隙播放或视频效果。所有这些都应该在管道上下文中完成,通过编写GStreamer插件来实现最为简单。然而,它对于其主要目的非常有用:将消息从管道传递给应用程序。这种方法的优势在于,GStreamer内部进行的所有线程操作对应用程序都是隐藏的,应用程序开发者根本不需要担心线程问题。
请注意,如果您使用的是默认的GLib主循环集成,您可以连接总线上的“message”信号,而不是附加监视器。这样您就不需要使用switch()函数处理所有可能的消息类型;只需以message::的形式连接到感兴趣的信号,其中是特定的消息类型(下一节将解释消息类型)。
上述代码片段也可以写成:
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);
[..]
如果您没有使用GLib主循环,则默认情况下异步消息信号将不可用。然而,您可以安装一个自定义的同步处理器,它唤醒自定义主循环并使用gst_bus_async_signal_func()来发射信号。(有关详细信息,请参见文档)
1.2,消息类型
GStreamer预定义了一些可以通过总线传递的消息类型。然而,这些消息是可扩展的。插件可以定义额外的消息,应用程序可以决定为这些消息提供特定代码或忽略它们。强烈建议所有应用程序至少处理错误消息,通过向用户提供视觉反馈。
所有消息都有一个消息源、类型和时间戳。消息源可以用来查看哪个元素发出了消息。对于某些消息,例如,只有顶级管道发出的消息对大多数应用程序来说可能很有趣(例如,用于状态更改通知)。下面是一个所有消息的列表以及它们的简短说明,以及如何解析特定于消息的内容。
-
错误、警告和信息通知:当需要向用户显示有关管道状态的消息时,元素会使用这些通知。错误消息是致命的,会终止数据传输。应该修复错误以恢复管道活动。警告虽然不致命,但仍然意味着存在问题。信息消息用于非问题通知。所有这些消息都包含一个GError,其中包含主要的错误类型和消息,以及可选的调试字符串。可以使用gst_message_parse_error()、_parse_warning() 和 _parse_info() 来提取它们。使用后应释放错误和调试字符串。
-
流结束通知:当流结束时发出此通知。管道的状态不会改变,但进一步的媒体处理将会停止。应用程序可以使用这个通知来跳到播放列表中的下一首歌曲。在流结束后,还可以在流中向后寻找。然后播放将自动继续。这个消息没有特定的参数。
-
标签:当在流中发现元数据时发出。对于管道来说,这可能会多次发出(例如,一次用于描述性元数据,如艺术家名称或歌曲标题,另一次用于流信息,如采样率和比特率)。应用程序应该在内部缓存元数据。应该使用gst_message_parse_tag()来解析标签列表,当不再需要时应该使用gst_tag_list_unref()来释放它。
-
状态更改:在成功的状态更改后发出。可以使用gst_message_parse_state_changed()来解析这次转换的旧状态和新状态。
-
缓冲:在网络流的缓存期间发出。可以通过从gst_message_get_structure()返回的结构中提取“buffer-percent”属性来手动提取进度(以百分比表示)。参见Buffering
-
元素消息:这些是特定于某些元素的特殊消息,通常代表附加功能。元素的文档应该详细说明特定元素可能发送哪些元素消息。例如,'qtdemux' QuickTime解复用器在某些情况下可能会在流包含重定向指令时发送'redirect'元素消息。
-
应用程序特定消息:通过获取消息结构(见上文)并阅读其字段,可以提取任何有关这些消息的信息。通常,这些消息可以安全地被忽略。
应用程序消息主要是为了在应用程序内部使用,以防应用程序需要将某些线程的信息传送到主线程。当应用程序使用元素信号时,这特别有用(因为这些信号将在流线程的上下文中发出)。