GStreamer笔记 -- 2.GStreamer concepts

Goal

在上一个教程,我们已经知道了怎么自动创建一个pipline。现在我们将要手动实例化一些元素,并且把它们连接到一起,形成一个pipeline,我们将要学到如下

  • 什么是gstream 的元素并且怎么创建一个元素
  • 怎么将创建的元素连接起来
  • 怎么定制元素的属性
  • 怎么监视总线(bus)的错误信息,并提取出gstream messages

Manual Hello World

basic-tutorial-2.c

#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 */
  //创建一个元素,第一个参数是gstream中允许的插件,第二个参数是我们给他取得别名,如果为null,则自动生成一个别名
  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
  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;
}

编译

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

**`pkg-config --cflags --libs gstreamer-1.0`**为自动推到 gstreamer-1.0的依赖库和依赖头文件,就不需要我们添加-L -I参数了

Walkthrough

上面的代码我们创建了两个元素,并将它们连接成一个管道,那他们是什么样子的呢,如下图
在这里插入图片描述
中间的filter元素我们没有创建,这里做个展示,数据从左流向右侧,从source产生,到sink消费,中间流经filter

创建元素

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

这里,我们用 gst_element_factory_make 创建了两个元素(elements),第一个参数是gstream的允许的插件,第二个参数是我们取的插件别名,你可以设置为null,如果这样,他会自动创建一个别名

videotestsrc 是一个源元素(生产数据),这个插件产生一个测试视频图案,这个插件主要在调试和教程中使用,在应用中没有用
autovideosink 是一个消费元素(消费数据),他将接收到的图片信息显示到窗口。这里存在多个视频消费元素,依赖于系统,各个元素拥有不同的能力。autovideosink 会实例化一个最好的,因此你不用担心具体细节

关于更多插件:你可以在终端执行

gst-inspect-1.0 #不跟参数,列举所有可以使用的插件
gst-inspect-1.0 [要查看的插件] # 后面跟要查看的插件名称,列举该插件的详细信息

创建管道

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

所有元素需要包含在一个管道中,因为管道负责同步时钟和消息传递。我们使用gst_pipeline_new 来创建一个管道

/* 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),他是一个包含其他元素的元素。我们可以用操作bin的方法来操作pipeline,因此我们用gst_bin_add_many将元素添加到管道中,使用NULL结尾。单独添加一个元素使用gst_bin_add()
我们已经将元素添加到管道中了,但是他们还不能工作,我们还得使用gst_element_link 将元素连接起来。这样才能形成数据流。但要注意的是在连接前,你要确保已经添加到管道中

设置属性

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

gstream的元素有很多属性,我们可以设置这些属性,
g_object_get() 获取属性,g_object_set() 设置属性

Error checking

到这里,我们已经建立了一个完整的管道,接下来我们将启动这个管道

/* 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);
}

gst_bus_timed_pop_filtered() 等待管道结束和返回一个GstMessage 消息。我们调用这个函数,当这个管道遇到一个错误或者结束符(EOS)就会返回
GstMessage 是一个很有用的结构体,他向我们展示了各种各样的信息,当然,gstream提供了一些类的函数来解析这些消息,gst_message_parse_error()即使来解析错误的

The GStreamer bus

到这里,有必要正式介绍一下gstream的 bus。bus负责将各个元素产生的应用消息传递给上层应用和应用线程。值得注意的是,很多时候,流处理和上层应用是在不同的线程中完成的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值