Gstreamer中,BUS(总线)是一个简单的系统,负责将消息从pipeline传递到应用程序。
默认情况下,每一个pipeline默认包含一个BUS,所以应用程序不需要再创建BUS。应用程序只需要在BUS上设置消息处理回调程序,当mainloop运行时,将定期检查bus是否有新消息,并在有消息可用时调用回调。
如何使用Bus?
使用gst_bus_add_watch ()
或 gst_bus_add_signal_watch ()
来监听BUS,并将消息处理程序附加到pipeline的BUS上,每当pipeline向BUS发出消息时,都将调用此处理程序。
请注意,如果你使用gst_bus_add_signal_watch()
,则可以连接总线上的message
信号,而不必switch()
处理所有可能的消息类型。只需以 message::
的形式连接到你需要处理的信号。
gst_bus_add_signal_watch
如下,使用gst_bus_add_signal_watch
,链接"message::error"和"message::eos":
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);
gst_object_unref(bus);
当然处理所有的message也没有问题:
GstBus *bus = gst_element_get_bus(pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect (G_OBJECT(bus), "message", G_CALLBACK (cb_message), user_data);
gst_object_unref(bus);
BUS watch
将自己引用@bus
,因此设置总线watch
后使用gst_object_unref()可以安全地unref
@bus
。
gst_bus_add_watch
使用gst_bus_add_watch
来监听BUS:
此函数用于在主循环中接收异步消息。每个BUS
只能有一个BUS watch
,必须在设置一个新的之前将其remove掉。
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
bus_watch_id_ = gst_bus_add_watch(bus, (GstBusFunc) GstBusCallback, this);
gst_object_unref(bus);
GST_DEBUG("add bus watch, id %d", bus_watch_id_);
这种方式最后退出的时候需要对bus_watch_id_进行释放:
g_source_remove(bus_watch_id_);
有g_source_remove这个代码后,从log中就可以看到:
GST_BUS gstbus.c:875:gst_bus_source_finalize:<bus2> finalize source 0xee459548
向总线发送message
如下,向BUS发送一个error message,可以测试BUS watch是否能正常工作:
{
const char *err_string = "test BUS error";
GError *error = g_error_new(GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED, "%s", err_string);
GstMessage *message = gst_message_new_error(GST_OBJECT_CAST(pipeline), error, err_string);
gst_element_post_message(GST_ELEMENT_CAST(pipeline), message);
g_error_free(error);
}
bus watch和mainloop
bus watch
和mainloop
必须在同一个线程,如果不是,很不幸,bus watch
是工作不起来的,并且mainloop
运行时,bus watch
才会工作。
有这样的例子:
创建pipeline在主线程中,然后让mainloop在另外一个线程,代码如下:
int Pipeline::CreatePipeline() {
// 创建pipeline
// ...
// 添加bus watch
GstBus *bus = gst_element_get_bus(pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect (G_OBJECT(bus), "message",
G_CALLBACK (Pipeline::GstBusCallback), user_data);
gst_object_unref(bus);
// 启动mainloop线程
thread_ = g_thread_new("pipeline_loop",
(GThreadFunc)Pipeline::MainLoop, this);
}
void Pipeline::MainLoop(void *user_data) {
g_main_loop_run(main_loop);
}
static gboolean
Pipeline::GstBusCallback(GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
这段代码实际运行的时候,发现是有问题的,GstBusCallback的回调是不会走到的,原因是bus watch的代码和main loop的代码不再同一个线程,放在mainloop线程就可以工作,如下:
int Pipeline::CreatePipeline() {
// 创建pipeline
// ...
// 启动mainloop线程
thread_ = g_thread_new("pipeline_loop",
(GThreadFunc)Pipeline::MainLoop, this);
}
void Pipeline::MainLoop(void *user_data) {
Pipeline* pipe = static_cast<Pipeline*>(user_data);
// 添加bus watch,放到main loop线程才可以
GstBus *bus = gst_element_get_bus(pipe->pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect (G_OBJECT(bus), "message",
G_CALLBACK (Pipeline::GstBusCallback), user_data);
gst_object_unref(bus);
g_main_loop_run(main_loop);
}
static gboolean
Pipeline::GstBusCallback(GstBus *bus,
GstMessage *msg,
gpointer data)
{
// ...
}