GStreamer学习笔记(三)——基础教程2:GStreamer概念

原文:Basic tutorial 2: GStreamer concepts

目标

前一个教程展示了怎么自动构建一个pipeline。现在我们通过实例化每一个element,然后把他们链接到一起来手动创建一个pipeline。这个过程中,我们会学到:

  • 什么是element,怎么创建一个element
  • 怎么连接elements
  • 怎么定制一个element的行为
  • 如何观察总线(bus)的错误情况,并从消息(message)中解析信息

手动的“Hello World”

#include <gst/gst.h>

int
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;
}

说明

element是GStreamer中的基础构建块。他们处理从source element(数据生成者)流向sink element(数据消费者)的数据流,中间经过filter element。

Element创建

我们跳过GStreamer的初始化,因为和前一个教程一致。

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

如代码所示,新的element可以使用gst_element_factory_make()创建。第一个参数是创建的element类型(基础教程14展示了一些通用类型,基础教程10展示了如何过去可用的类型列表)。第二个参数是我们给这个实例起的名字。如果没有保留指针,对element命名会很有用(而且对调试输出也很有意义)。如果名字传递一个NULL,GStreamer也会提供一个特定的名字。

该示例创建了两个element:videotestsrc和autovideosink。没有filter element。因此,pipeline如下图所示:

 videotestsrc是一个source element(数据生产者),它创建了一个测试的视频模式。这个element调试有用,但不会用在实际应用中。

autovideosink是一个sink element(数据消费者),它在窗口上显示收到的图像。根据操作系统的不同,存在一些不同能力的视频sink。autovideosink自动选择和实例化最佳的sink,你不需要关注细节,并且你的代码是独立于平台的。

Pipeline创建

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

所有的element使用前都必须加到一个pipeline中,它负责时钟和消息传递功能。gst_pipeline_new()可以创建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;
}

bin是一种特殊的element,它包含其他的element,pipeline是一种特殊的bin。因此bin的所有方法也可以用在pipeline上。

在本例中,我们调用gst_bin_add_many()把element添加到pipeline中(注意转换,GST_BIN(pipeline))。这个方法接收待添加的element,以NULL结束。单个element可以使用gst_bin_add()添加。

但是这些elements还没有彼此链接。我们需要调用gst_element_link()。它的第一个参数是源,第二个参数是目的。顺序很重要,因此链接必须根据数据流建立(从source element流向sink element)。记住只有一个bin中的element才能链接到一起,所以链接前记得把element添加到pipeline中。

Properties

GStreamer中的element都是一种GObject,它提供了property功能。

绝大多数element拥有可定制化的property:通过改变已命名的属性改变element的行为(可写property)或者查询element内部的状态(可读property)。

property的读写通过g_object_get()和g_object_set()。

g_object_set()接受一个以NULL结尾的属性名、属性值成对的列表。依次可改变多个property。

这就是为什么property处理方法都包含g_前缀。

回到上面的例子中:

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

上面这行代码修改了videotestsrc的“pattern”属性。它控制了输出的类型。尝试不同的值试试。

一个element暴露出的所有属性的name和value可以通过gst-inspect-1.0 tool查询(基础教程10描述)或者在这个element的文档中。

错误检查

到这里,我们已经构建了整个pipeline,本例的剩余部门和上一个类似,但是我们加了更多错误检测:

/* 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()但是这次检查了它的返回值错误情况。改变状态是一个复杂的过程,基础教程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()会在发生错误或者EOS的情况下返回,因此我们需要检查是哪一个情况,然后在屏幕上打印相应的信息(你的应用可能会承载更多的操作)。

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

在本例中,一旦我们知道消息包含错误(通过使用GST_MESSAGE_TYPE()宏),我们就可以使用gst_message_parse_error(),它返回一个GLib GError错误结构和一个用于调试的字符串。检查代码,看看这些是如何使用和释放的。

GStreamer总线

现在,有必要更正式地介绍一下GStreamer总线。它是负责将element生成的GstMessages按顺序传递给应用程序并传递给应用程序线程的对象。最后一点很重要,因为实际的媒体流是在应用程序以外的另一个线程中完成的。

可以使用gst_bus_timed_pop_filtered()方法同步地从总线提取消息,也可以使用信号异步地从总线提取消息(将在下一个教程中展示)。您的应用程序应该始终关注总线,以便收到错误和其他播放相关问题的通知。

剩下的代码是清理流程,与基础教程1中相同。

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最佳打工人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值