GStreamer——教程——基础教程2:GStreamer concepts

基本教程2:GStreamer概念

1,目标

之前的教程展示了如何自动构建管道。现在我们将手动构建一条pipeline:初始化每一个element并将它们连接起来。在此过程中,我们将学习:

  • 什么是GStreamer元素以及如何创建一个。

  • 如何将elements相互连接。

  • 如何自定义element的行为(属性)。

  • 如何监视bus的错误条件并从GStreamer messages 中提取信息。

2,自制 Hello World

将此代码复制到名为basic-tutorial-2.c文本文件中(或找到它 在您的GStreamer安装中)。

基础教程

#include <gst/gst.h>

#ifdef __APPLE__
#include <TargetConditionals.h>
#endif

int
tutorial_main (int argc, char *argv[])
{
  GstElement *pipeline, *source, *sink;
  GstBus *bus;
  GstMessage *msg;
  GstStateChangeReturn ret;

  /* Initialize GStreamer */
  gst_init (&argc, &argv);

  /* Create the elements */
  source = gst_element_factory_make ("videotestsrc", "source");
  sink = gst_element_factory_make ("autovideosink", "sink");

  /* Create the empty pipeline */
  pipeline = gst_pipeline_new ("test-pipeline");

  if (!pipeline || !source || !sink) {
    g_printerr ("Not all elements could be created.\n");
    return -1;
  }

  /* Build the pipeline */
  gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
  if (gst_element_link (source, sink) != TRUE) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
  }

  /* Modify the source's properties */
  g_object_set (source, "pattern", 0, NULL);

  /* Start playing */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (pipeline);
    return -1;
  }

  /* Wait until error or EOS */
  bus = gst_element_get_bus (pipeline);
  msg =
      gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
      GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

  /* Parse message */
  if (msg != NULL) {
    GError *err;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE (msg)) {
      case GST_MESSAGE_ERROR:
        gst_message_parse_error (msg, &err, &debug_info);
        g_printerr ("Error received from element %s: %s\n",
            GST_OBJECT_NAME (msg->src), err->message);
        g_printerr ("Debugging information: %s\n",
            debug_info ? debug_info : "none");
        g_clear_error (&err);
        g_free (debug_info);
        break;
      case GST_MESSAGE_EOS:
        g_print ("End-Of-Stream reached.\n");
        break;
      default:
        /* We should not reach here because we only asked for ERRORs and EOS */
        g_printerr ("Unexpected message received.\n");
        break;
    }
    gst_message_unref (msg);
  }

  /* Free resources */
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  return 0;
}

int
main (int argc, char *argv[])
{
#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
  return gst_macos_main ((GstMainFunc) tutorial_main, argc, argv, NULL);
#else
  return tutorial_main (argc, argv);
#endif
}

需要帮忙吗?

如果您需要帮助来编译此代码,请参阅为您的平台构建教程部分:LinuxMac OS XWindows,或在Linux上使用此特定命令:

gcc basic-tutorial-2.c -o basic-tutorial-2 `pkg-config --cflags --libs gstreamer-1.0`

如果您需要帮助来运行此代码,请参阅您平台的运行教程部分:LinuxMac OS X[2]或Windows

本教程打开一个窗口并显示一个测试模式,没有音频

所需库:gstreamer-1.0

3,工作流

这些 element 是GStreamer的基本构造单位。它们处理从source element(数据生产者)通过filter element流向sink element(数据消费者)的数据。

图1.示例管道

3.1,创建 element

我们将跳过GStreamer初始化,因为它与之前的教程相同:

  /* Create the elements */
  source = gst_element_factory_make ("videotestsrc", "source");
  sink = gst_element_factory_make ("autovideosink", "sink");

如本代码所示,如何使用gst_element_factory_make()新建一个element 。

第一个参数是要创建的element名,即插件名(基本教程14:方便的元素显示了一个 一些常见类型和基本教程10:GStreamer工具展示了如何 获取所有可用类型的列表)。

第二个参数是给这个特殊实例起的名称,在同一条pipeline中,必须是唯一的名称。如果你没有保留指针,给 element名可以方便你在以后检索它们(并且可以得到更有意义的调试输出)。但是,假如你传递NULL作为实例名,GStreamer也会自动为它初始化一个唯一的名称。

3.2,创建 pipeline

对于本教程,我们创建两个元素:videotestsrc autovideosink。中间没有filter element,所以整个pipeline看起来就如下图:

图2.本教程中构建的管道

Videotestsrc是一个按照制定pattern生成测试视频source element(它将生产数据),这个插件在测试和教程中很好用,但通常并不会出现在真实的应用中。

autovideosink是一个在窗口中播放它接收到的图像的sink element(它将消费数据),GStreamer包含有很多视频sink element,具体取决于操作系统,它们能够处理不同的图像格式,autovideosink将自动选择其中一个并实例话化,所以用户不需要担心平台兼容性问题。

  /* Create the empty pipeline */
  pipeline = gst_pipeline_new ("test-pipeline");

gst_pipeline_new()创建 pipeline,GStreamer中的所有元素在使用之前通常必须包含在一条pipeline 中,pipeline将负责一些时钟和消息功能。

  /* Build the pipeline */
  gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
  if (gst_element_link (source, sink) != TRUE) {
    g_printerr ("Elements could not be linked.\n");
    gst_object_unref (pipeline);
    return -1;
  }

一条pipeline也是一个特殊的 bin,它是用于 包含其他elements。因此,适用于bin的所有方法也适用于pipeline。

在我们的例子中,我们调用gst_bin_add_many()来将elements添加到pipeline中(注意映射)。此函数接受一个要被添加到pipeline中的element列表,因为不确定列表长度所以需要以NULL结尾。添加单个element可以使gst_bin_add()。

然而,这些元素还没有相互联系。为此, 我们需要使用gst_element_link()。它的第一个参数是source, 第二个是destination。顺序很重要,因为链接必须按照数据流建立(即,从source elemnt到sink element)。请记住,只有 element 驻留在同一个bin中可以链接在一起,所以记得在之前将它们添加到pipeline中试图链接它们!

3.3,属性

GStreamer元素都是一种特殊的GObject,它是提供属性设施的实体。

大多数GStreamer元素都具有可自定义的属性:可以修改的命名属性以更改元素的行为(可写属性)或查询以了解元素的内部状态(可读属性)。

属性从g_object_get()中读取并写入用g_object_set()。

g_object_set()可以接受一个以NULL结束的属性名-属性值键值对列表,所以可以一次性设置多个属性。

这就是为什么属性处理方法具有g_前缀的原因。

回到上面的例子中,

  /* Modify the source's properties */
  g_object_set (source, "pattern", 0, NULL);

上面的代码行改变了videotestsrc的“pattern”属性, 它控制元素输出的测试视频类型。尝试不同的 值!

element 公开的所有属性的名称和可能值可以使用基本教程10:GStreamer工具或该元素的文档中描述的gst-inspect-1.0工具找到 (这里指的是videotestsrc)。

3.4,Error 监听

至此,我们已经构建和设置了整个管道,教程的其余部分与上一个非常相似,但我们将添加更多错误检查:

  /* Start playing */
  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
  if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (pipeline);
    return -1;
  }

我们调用gst_element_set_state(),但是这次将检查状态改变的返回值。假如状态修改失败,将返回一个error值并进行相关退出处理,还有更多详细信息在基础教程3:动态管道中给出。

  /* Wait until error or EOS */
  bus = gst_element_get_bus (pipeline);
  msg =
      gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
      GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

  /* Parse message */
  if (msg != NULL) {
    GError *err;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE (msg)) {
      case GST_MESSAGE_ERROR:
        gst_message_parse_error (msg, &err, &debug_info);
        g_printerr ("Error received from element %s: %s\n",
            GST_OBJECT_NAME (msg->src), err->message);
        g_printerr ("Debugging information: %s\n",
            debug_info ? debug_info : "none");
        g_clear_error (&err);
        g_free (debug_info);
        break;
      case GST_MESSAGE_EOS:
        g_print ("End-Of-Stream reached.\n");
        break;
      default:
        /* We should not reach here because we only asked for ERRORs and EOS */
        g_printerr ("Unexpected message received.\n");
        break;
    }
    gst_message_unref (msg);
  }

gst_bus_timed_pop_filtered() 等待执行结束并返回带有我们之前忽略的GstMessage。我们要求gst_bus_timed_pop_filtered() 返回时GStreamer 遇到错误条件或EOS,所以我们需要检查发生了哪一个,并在屏幕上打印一条消息(您的应用程序将可能想采取更复杂的行动)。

GstMessage是一个非常通用的结构,它可以传递几乎任何类型的信息。幸运的是,GStreamer提供了一系列消息的解析函数。

在这种情况下,一旦我们知道消息包含错误(通过使用 GST_MESSAGE_TYPE() 宏),我们可以使用 gst_message_parse_error() 返回GLib的GError结构和对调试有用的字符串。检查代码以了解如何这些被使用并在之后释放。

3.5,GStreamer bus

在这一点上,值得更正式地介绍一下GStreamer bus 。GStreamer bus它是负责将element生成的GstMessages 按顺序交付给应用程序和应用程序线程(这点很重要,因此GStreamer实际是在其他的线程中处理媒体流)的对象。

消息可以通过 gst_bus_timed_pop_filtered()及其相关函数同步地从总线中提取,或者通过信号异步地提取(如在下一个教程中所示)。你的应用程序应该始终关注总线,以便被通知错误和其他与播放相关的问题。

其余的代码是清理序列,与基础教程1: Hello world!中的相同。

4,练习

如果您想练习,请尝试此练习:尝试在这条example pipeline的source和sink之间添加视频filter element,例如vertigotv,你需要创建它,将它加入pipeline,并将它和pipeline中的其他元素连接起来。

根据您的平台和可用插件,您可能会得到一个 “negotiation”错误,因为sink element 正在生产什么(更多关于基本教程6:媒体格式和Pad功能的协商)。在这种情况下你需要在filter 之后添加videoconvert(即构建一个4个元素的管道。更多关于 videoconvert在基本教程14:Handy elements)。

5,总结

本教程展示了:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值