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