Gstreamer BUS处理message

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 watchmainloop必须在同一个线程,如果不是,很不幸,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)
{
    // ...
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值