GStreamer应用程序——Bus

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'元素消息。

  • 应用程序特定消息:通过获取消息结构(见上文)并阅读其字段,可以提取任何有关这些消息的信息。通常,这些消息可以安全地被忽略。

    应用程序消息主要是为了在应用程序内部使用,以防应用程序需要将某些线程的信息传送到主线程。当应用程序使用元素信号时,这特别有用(因为这些信号将在流线程的上下文中发出)。

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gstreamer应用程序开发中,要调用插件接口,可以按照以下步骤进行: 1. 创建GStreamer的pipeline:创建一个GstPipeline对象,作为音视频流的处理管道。 2. 加载插件:使用gst_element_factory_make()函数来加载所需的插件。该函数接受插件的类型和插件名称作为参数,并返回一个对应的GstElement对象。 3. 连接元素:使用gst_element_link()函数将不同的GstElement对象连接起来,形成数据流的处理链。通过将源元素和目标元素传递给该函数,可以将它们连接起来。 4. 配置插件属性:对需要的插件进行属性设置。可以使用gst_element_set_property()函数为插件设置属性值,也可以使用gst_element_get_property()函数获取属性的当前值。 5. 监听事件:为需要监听特定事件的插件添加相应的事件处理器。可以通过使用gst_element_add_event_probe()函数来添加事件探针,该函数将在触发特定事件时调用相应的回调函数。 6. 启动流媒体流:使用gst_element_set_state()函数将pipeline设置为播放状态,开始处理音视频数据流。 7. 处理数据:处理从插件接收到的数据。可以通过连接插件的src pad和sink pad来获取输入和输出数据,并在处理数据时使用对应的回调函数。 8. 监听信号:为需要监听信号的插件添加相应的信号处理函数。使用g_signal_connect()函数将信号与回调函数连接起来,在触发信号时执行相应的操作。 9. 控制流媒体流:使用gst_element_set_state()函数将pipeline设置为停止状态,结束数据的处理。 总之,调用插件接口的关键是正确配置和连接GstElement对象,以及使用适当的函数设置和获取属性值、添加事件探针和信号处理函数。以上步骤可以帮助开发者在gstreamer应用程序中调用插件接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值