Gstreamer应用开发实战指南

Posted Geek.Fan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gstreamer应用开发实战指南相关的知识,希望对你有一定的参考价值。

一、GStreamer中的元素

        对于应用程序编程人员来说,GStreamer 中最重要的对象是 GstElement 对象。元素是媒体管道的基本构建基块。我们使用的所有不同的高级组件都派生自 。实际上,每个解码器、编码器、解复用器、视频或音频输出都是GstElement。

什么是元素?

        对于应用程序员来说,元素最好可视化为黑匣子。一方面,你可能会放一些东西进去,元素用它做一些事情,另一边有其他东西出来。例如,对于解码器元素,您将输入编码的数据,该元素将输出解码的数据。

源元素:

        源元素生成供管道使用的数据,例如从磁盘或声卡读取数据。源元素的可视化显示了我们将如何可视化源元素。我们总是在元素的右侧绘制一个源板。

        源元素不接受数据,它们只生成数据。您可以在图中看到这一点,因为它只有一个源板(在右侧)。源板只能生成数据。

        过滤器、转换器、解复用器、复用器和编解码器:

        滤波器和类似滤波器的元件具有输入和输出焊盘。它们对在输入(接收器)焊盘上接收的数据进行操作,并将在其输出(源)焊盘上提供数据。此类元素的示例包括音量元素(过滤器),视频缩放器(转换器),Ogg解复用器或Vorbis解码器。

        类似滤波器的元件可以具有任意数量的源极或灌电流垫。例如,视频解复用器将具有一个沉降垫和多个 (1-N) 源板,容器格式中包含的每个基本流对应一个源板。另一方面,解码器只有一个源和汇垫板。

        过滤器元件的可视化显示了我们将如何可视化类似过滤器的元件。此特定元素有一个源焊盘和一个汇焊盘。接收输入数据的接收器垫被描绘在元件的左侧;源焊盘仍在右侧。

        具有多个输出焊盘的滤波器元件的可视化显示了另一个类似滤波器的元件,该元件具有多个输出(源)焊盘。 例如,一个此类元素的示例可以是用于包含音频和视频的 Ogg 流的 Ogg 解复用器。 一个源板将包含基本视频流,另一个将包含基本音频流。 多路复用器通常会在创建新焊盘时发出信号。 然后应用程序程序员可以在信号处理程序中处理新的基本流。

水槽元素:

        接收器元素是媒体管道中的端点。 他们接受数据但不产生任何东西。 磁盘写入、声卡播放和视频输出都将由 sink 元素实现。 接收器元素的可视化显示了接收器元素。

创建GstElement :

        创建元素的最简单方法是使用 gst_element_factory_make ()。此函数采用新创建元素的工厂名称和元素名称。例如,元素的名称是以后可用于在 bin 中查找元素的名称。该名称还将用于调试输出。可以使用NULL作为 name 参数传递以获取唯一的默认名称。

        当您不再需要该元素时,您需要使用gst_object_unref () 将其取消。这会将元素的引用计数减少 1。元素在创建时的引用计数为 1。当引用计数减少到 0 时,元素将被完全销毁。

        下面的示例 [1] 演示如何从名为 fakesrc 的元素工厂创建一个名为 source 的元素。它检查创建是否成功。检查后,它将取消还原元素。

#include <gst/gst.h>

int main (int   argc, char *argv[])

  GstElement *element;

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

  /* create element */
  element = gst_element_factory_make ("fakesrc", "source");
  if (!element) 
    g_print ("Failed to create element of type 'fakesrc'\\n");
    return -1;
  

  gst_object_unref (GST_OBJECT (element));

  return 0;

        gst_element_factory_make实际上是两个函数组合的简写。GstElement 对象是从工厂创建的。若要创建元素,必须使用唯一的工厂名称访问 GstElementFactory 对象。这是通过 gst_element_factory_find () 完成的。

        以下代码片段用于获取可用于创建 fakesrc 元素(假数据源)的工厂。函数gst_element_factory_create () 将使用元素工厂创建具有给定名称的元素。

#include <gst/gst.h>

int main (int   argc, char *argv[])

  GstElementFactory *factory;
  GstElement * element;

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

  /* create element, method #2 */
  factory = gst_element_factory_find ("fakesrc");
  if (!factory) 
    g_print ("Failed to find factory of type 'fakesrc'\\n");
    return -1;
  
  element = gst_element_factory_create (factory, "source");
  if (!element) 
    g_print ("Failed to create element, even though its factory exists!\\n");
    return -1;
  

  gst_object_unref (GST_OBJECT (element));
  gst_object_unref (GST_OBJECT (factory));

  return 0;

使用元素作为 GObject:

        一个 GstElement 可以有几个使用标准 GObject 属性实现的属性。 因此支持查询、设置和获取属性值和 GParamSpecs 的常用 GObject 方法。

        每个 GstElement 从其父 GstObject 继承至少一个属性:“名称”属性。 这是我们为函数 gst_element_factory_make () 或 gst_element_factory_create () 提供的名称。 我们可以使用函数 gst_object_set_name 和 gst_object_get_name 获取和设置此属性,或者使用 GObject 属性机制,如下所示。

#include <gst/gst.h>

int main (int   argc, char *argv[])

  GstElement *element;
  gchar *name;

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

  /* create element */
  element = gst_element_factory_make ("fakesrc", "source");

  /* get name */
  g_object_get (G_OBJECT (element), "name", &name, NULL);
  g_print ("The name of the element is '%s'.\\n", name);
  g_free (name);

  gst_object_unref (GST_OBJECT (element));

  return 0;

        大多数插件提供附加属性以提供有关其配置或配置元素的更多信息。 gst-inspect 是查询特定元素属性的有用工具,它还将使用属性自省来简要说明属性的功能以及它支持的参数类型和范围。 有关 gst-inspect 的详细信息,请参阅附录中的 gst-inspect。

        有关 GObject 属性的更多信息,我们建议您阅读 GObject 手册和 Glib 对象系统介绍。

        GstElement 还提供了各种可用作灵活回调机制的 GObject 信号。 在这里,您也可以使用 gst-inspect 查看特定元素支持哪些信号。 总之,信号和属性是元素和应用程序交互的最基本方式。

更多关于元素工厂:

        在上一节中,我们已经简要介绍了 GstElementFactory 对象作为创建元素实例的一种方式。 然而,元素工厂远不止这些。 元素工厂是从 GStreamer 注册表中检索到的基本类型,它们描述了 GStreamer 可以创建的所有插件和元素。 这意味着元素工厂对于自动元素实例化非常有用,例如 autopluggers 所做的事情,以及创建可用元素的列表。

使用工厂获取有关元素的信息:

        gst-inspect 之类的工具将提供有关元素的一些通用信息,例如编写插件的人、描述性名称(和短名称)、等级和类别。 类别可用于获取可以使用此元素工厂创建的元素的类型。 类别的示例包括 Codec/Decoder/Video(视频解码器)、Codec/Encoder/Video(视频编码器)、Source/Video(视频生成器)、Sink/Video(视频输出),所有这些都存在于音频中 , 当然。 然后,还有 Codec/Demuxer 和 Codec/Muxer 等等。 gst-inspect 将给出所有工厂的列表,而 gst-inspect <factory-name> 将列出所有上述信息,以及更多信息。

#include <gst/gst.h>

int  main (int   argc, char *argv[])

  GstElementFactory *factory;

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

  /* get factory */
  factory = gst_element_factory_find ("fakesrc");
  if (!factory) 
    g_print ("You don't have the 'fakesrc' element installed!\\n");
    return -1;
  

  /* display information */
  g_print ("The '%s' element is a member of the category %s.\\n"
           "Description: %s\\n",
           gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
           gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS),
           gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_DESCRIPTION));

  gst_object_unref (GST_OBJECT (factory));

  return 0;

        我们可以使用 gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY) 来获取 GStreamer 知道的所有元素工厂的列表。

        找出一个元素可以包含哪些焊盘:

        元素工厂最强大的功能可能是它们包含元素可以生成的 pad 的完整描述,以及这些 pad 的功能(用外行的话来说:哪些类型的媒体可以在这些 pad 上流式传输),而实际上不必 将这些插件加载到内存中。 这可用于为编码器提供编解码器选择列表,也可用于媒体播放器的自动插入目的。 当前所有基于 GStreamer 的媒体播放器和自动插入器都以这种方式工作。 在下一章了解 GstPad 和 GstCaps 时,我们将仔细研究这些特性: 焊盘和功能。

链接元素:

        通过将源元素与零个或多个类似过滤器的元素以及最后一个接收器元素链接,您可以设置媒体管道。 数据将流经元素。 这是 GStreamer 中媒体处理的基本概念。

         通过链接这三个元素,我们创建了一个非常简单的元素链。 这样做的效果是源元素的输出将用作类似过滤器的元素的输入。 类似过滤器的元素将对数据进行处理并将结果发送到最终的接收器元素。

        将上图想象成一个简单的 Ogg/Vorbis 音频解码器。 源是从磁盘读取文件的磁盘源。 第二个元素是 Ogg/Vorbis 音频解码器。 sink 元素是你的声卡,播放解码的音频数据。 我们将在本手册后面使用这个简单的图表来构建一个 Ogg/Vorbis 播放器。

        在代码中,上图是这样写的:

#include <gst/gst.h>

int  main (int   argc,  char *argv[])

  GstElement *pipeline;
  GstElement *source, *filter, *sink;

  /* init */
  gst_init (&argc, &argv);

  /* create pipeline */
  pipeline = gst_pipeline_new ("my-pipeline");

  /* create elements */
  source = gst_element_factory_make ("fakesrc", "source");
  filter = gst_element_factory_make ("identity", "filter");
  sink = gst_element_factory_make ("fakesink", "sink");

  /* must add elements to pipeline before linking them */
  gst_bin_add_many (GST_BIN (pipeline), source, filter, sink, NULL);

  /* link */
  if (!gst_element_link_many (source, filter, sink, NULL)) 
    g_warning ("Failed to link elements!");
  

[..]


        对于更具体的行为,还有函数 gst_element_link () 和 gst_element_link_pads ()。 我们还可以获得对单个焊盘的引用并使用各种 gst_pad_link_* () 函数链接这些焊盘。 有关更多详细信息,请参阅 API 参考。

重要提示:

        我们必须先将元素添加到 bin 或管道,然后才能链接它们,因为将元素添加到 bin 会断开任何现有的链接。 此外,我们不能直接链接不在同一个 bin 或管道中的元素; 如果我们想链接不同层次级别的元素或焊盘,我们将需要使用幻影焊盘(稍后将详细介绍幻影焊盘)。

元素状态:

        创建后,元素实际上还不会执行任何操作。 您需要更改元素状态以使其执行某些操作。 GStreamer 知道4四种元素状态,每种状态都有非常具体的含义。 这4个状态是:

        GST_STATE_NULL:这是默认状态。 在此状态下没有分配任何资源,因此,转换到该状态将释放所有资源。 当元素的引用计数达到 0 并被释放时,元素必须处于此状态。

        GST_STATE_READY:处于就绪状态,一个元素已经分配了它所有的全局资源,即可以保留在流中的资源。 你可以考虑打开设备、分配缓冲区等等。 但是,在这种状态下,流并未打开,因此流位置自动为零。 如果一个流之前打开过,它应该在这个状态下关闭,并且位置、属性等应该被重置。

        GST_STATE_PAUSED:在这种状态下,一个元素已经打开了流,但没有主动处理它。 允许元素修改流的位置,读取和处理数据等,以便在状态更改为 PAUSED 时立即准备播放,但不允许播放会使时钟运行的数据。 总之,PAUSED 与 PLAYING 相同,但没有运行时钟。

进入 PAUSED 状态的元素应该为尽快进入 PLAYING 状态做好准备。 例如,视频或音频输出将等待数据到达并将其排队,以便在状态更改后立即播放。 此外,视频接收器已经可以播放第一帧(因为这还不影响时钟)。 Autopluggers 可以使用相同的状态转换来将管道连接在一起。 然而,大多数其他元素,例如编解码器或过滤器,不需要在此状态下显式执行任何操作。

        GST_STATE_PLAYING:在 PLAYING 状态下,元素的行为与 PAUSED 状态完全相同,只是时钟现在运行。

        我们可以使用函数 gst_element_set_state () 更改元素的状态。 如果将一个元素设置为另一个状态,GStreamer 将在内部遍历所有中间状态。 因此,如果我们将一个元素从 NULL 设置为 PLAYING,GStreamer 将在内部将该元素设置为 READY 和 PAUSED。

       当移动到 GST_STATE_PLAYING 时,管道将自动处理数据。 它们不需要以任何形式迭代。 在内部,GStreamer 将为它们启动执行此任务的线程。 GStreamer 还将通过使用 GstBus 将消息从管道的线程切换到应用程序自己的线程。 有关详细信息,请参阅总线。

        当您将 bin 或 pipeline 设置为某个目标状态时,它通常会自动将状态更改传播到 bin 或 pipeline 中的所有元素,因此通常只需设置顶级管道的状态即可启动管道 或将其关闭。 但是,当将元素动态添加到已经运行的管道时,例如 在“pad-added”信号回调中,您需要自己使用 gst_element_set_state () 或 gst_element_sync_state_with_parent () 将其设置为所需的目标状态。

        此示例的代码自动从文档中提取并构建在 GStreamer tarball 中的 tests/examples/manual 下。

以上是关于Gstreamer应用开发实战指南的主要内容,如果未能解决你的问题,请参考以下文章

Gstreamer应用开发实战指南

如何从 gstreamer 中的源请求更多缓冲区?

使用 gstreamer 和 ffmpeg 进行 H.264 解码

Sailfish OS下的gstreamer没有输出声音

从 GStreamer 实时接收 Numpy 数组

使用 Gstreamer 接收音频流导致原因未协商错误