前言

本系列文章将纪录学习 GStreamer 的过程。

为什么想学习 GStreamer,有这么几个原因:

  1. 多媒体处理是一个复杂的任务,GStreamer 的管道架构可以将复杂的任务以「图」的形式模块化的进行处理,它足够灵活。学习 GStreamer 这种架构思想,可以帮助我扩展视野,面对复杂任务如何给出一套灵活可靠的框架。
  2. 掌握 GStreamer 对求职有所帮助,如果你对 GStreamer 很熟悉,很多音视频岗位是可以加分的。
  3. 我想造一个视频编辑框架的轮子,无论是基于 GStreamer 来实现,还是参考 GStreamer 的框架,我都得对 GStreamer 非常熟悉。

我对 FFMpeg 比较熟悉,对于 GStreamer 属于纯纯新手,因此本系列文章面向的观众也是像我一样想要学习 GStreamer 的小白,内容上不会太过深入,属于是想到啥写啥,遇到啥写啥,将学习中查找的资料、遇到的问题、解决的方式、个人的理解通通都写上。

当前目标:

  1. 将 Basic Tutorial 中教程全部过一遍。
  2. 封装一个自己的插件

一、源码环境搭建

在源码环境下进行断点调试,可以一窥 GStreamer 的实现逻辑。
如何搭建源码调试环境请参考 GStreamer 源码编译,在 Clion 下搭建调试环境

接下来说明如何在源码环境下运行 Tutorial。

  1. 新建文件夹。在 gstreamer/subprojects 下,找一个文件夹,例如我用的是 gst-examples。在 gst-examples 下面新建一个 my_examples 文件夹
    在这里插入图片描述
  2. 修改 gst-examples 的 meson.build,添加 subdir('my_examples') 即可
    在这里插入图片描述
  3. 添加 tutorial 运行文件。从 gstreamer/subprojects/gst-docs/examples/tutorials 下,拷贝 basic-tutorial-* 等这些教程运行文件到 my_examples 下
  4. 更新 my_examples/meson.build 文件,如下
executable('basic-tutorial-1',
           ['basic-tutorial-1.c'],
           dependencies : [gst_dep, m_dep])

在这里插入图片描述
至此,教程运行文件添加完毕,我们可以在 CLion 上快乐地源码调试运行这些教程了。

我把对应的代码上传到了 github 上,你可以参考这里 my_examples

二、Basic Tutorial 1 Hello world

教程链接:https://gstreamer.freedesktop.org/documentation/tutorials/basic/hello-world.html?gi-language=c

代码咋一看挺多挺唬人的,但其实真正在工作的就 4 行,其他的都是初始化、清理等。下面对重要代码做下说明

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

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

  /* Build the pipeline */
  pipeline =
      gst_parse_launch
      ("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm",
      NULL);

  /* Start playing */
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

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

  /* See next tutorial for proper error message handling/parsing */
  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
    g_printerr ("An error occurred! Re-run with the GST_DEBUG=*:WARN "
        "environment variable set for more details.\n");
  }

  /* Free resources */
  /...
  return 0;
}

这些代码行是一个使用GStreamer的基本程序,它主要用来播放网络上的流媒体内容。以下是这些代码的各个步骤的总结:

  1. 初始化GStreamer

    gst_init (&argc, &argv);
    

    这是所有GStreamer应用程序的第一个命令。这个函数完成了内部结构的初始化,检查插件的可用性,和执行为GStreamer预设的命令行选项。如果你的应用程序总是把argc和argv参数传递给gst_init,你的应用程序将自动受益于GStreamer的标准命令行选项。

  2. 构建管道

    pipeline = gst_parse_launch("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
    

    gst_parse_launch()函数把一个文本表达的pipeline转变为一个实际的pipeline,这个函数十分方便。你需要构建的pipeline是由一个叫做playbin的元素组成,playbin是一个特殊的元素,它可以作为一个源和一个sink,它是一个完整的pipeline。在这个例子中,我们只给playbin传递了一个参数,这个参数是我们想要播放的媒体的URI。试试改变它吧!不论它是一个http://或者file://的URI,playbin都会透明的实例化一个适当的GStreamer源。

  3. 开始播放

    gst_element_set_state (pipeline, GST_STATE_PLAYING);
    

    这行代码展示了另一个有趣的概念:状态。每一个GStreamer元素都有一个关联的状态,你可以大致理解为你的DVD播放器上的播放/暂停按钮。播放将不会开始,除非你把管道设置为播放状态。在这行代码中,gst_element_set_state()将管道设置为播放状态,从而启动播放。

  4. 等待错误或EOS

    bus = gst_element_get_bus (pipeline);
    msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
    

    这些代码行将会一直等待,直到出现一个错误或者找到流的结束。gst_element_get_bus()获取管道的总线,而gst_bus_timed_pop_filtered()则会阻塞,直到你通过这个总线接收到一个错误或者EOS(流结束)。

三、开启更多日志

在运行 Gstreamer 程序时开启更多日志可以帮助我们排查错误。

#NameDescription
0none不输出任何信息
1ERROR打印致命错误信息,正确的错误处理可以使得程序还能正常运行
2WARNING打印警告信息,程序可能出现预期外的现象
3FIXME打印“fixme”信息,通常意味着程序触发了一个已知不完整的代码路径,程序大多数情况下可能工作正常,但在特定情况下可能会引发问题
4INFO打印消息类信息,通常用于报告系统中只发生一次的事件,或者是重要且罕见的事件
5DEBUG打印所有的调试信息,包括参数更改,加载,卸载等事件发生
6LOG打印所有日志消息,包含大量重复发生的事件信息
7TRACE打印所有跟踪信息,包括每次修改GstMiniObject(如GstBuffer或GstEvent)的引 用计数等信息
9MEMDUMP记录所有内存转储消息。这是最繁重的日志记录,可能包括转储内存块的内容

在运行时,通过设置环境变量 GST_DEBUG 即可。例如 export GST_DEBUG=2 意味着打印 WARNING 和 ERROR 信息

参考

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐