gstreamer教程(5)——构建应用之element的使用
Element 元素:
对于应用程序程序员来说, GstElement
对象是GStreamer 中最重要的对象。element (元素)是媒体Pipeline的基本构建块。您使用的所有不同的高级组件都派生自 GstElement
。每个解码器、编码器、解复用器、视频或音频输出事实上都是一个 GstElement。
什么是元素:
对于应用程序程序员来说,element (元素)最好可视化为黑盒。在一端,你可能会放一些东西进去,元素对它做一些事情,又从另一端出来。例如,对于 decoder element(解码器元素),您放进去编码后的数据,该元素将输出解码后的数据。在下一章(请参阅 Pad和能力)中,您将了解有关element (元素)中的数据输入和输出的更多信息,以及如何在应用程序中进行设置。
Source element 源元素:
Source element(源元素)生成Pipeline使用的数据,例如从磁盘或声卡读取数据。Source element(源元素)显示了我们将如何可视化源元素。我们总是在 Element 的右侧绘制一个 source pad。
Source element(源元素)不接受数据,它们只生成数据。您可以在图中看到这一点,因为它只有一个 source pad (在右侧)。 source pad 只能生成数据。
Filters, convertors, demuxers, muxers and codecs 过滤器、转换器、解复用器、多路复用器和编解码器:
过滤器和类过滤的元素同时具有输入和输出Pad。它们对在 input (sink) pad 上接输入的数据进行操作,并将在其 output (source) pad 上输出数据。此类元素的示例包括音量元素(过滤)、视频缩放器(转换器)、Ogg 解复用器或 Vorbis 解码器。
类过滤的元件可以有任意数量的 source 或 sink pad。例如,视频解复用器将有一个 sink pad 和几个 (1-N) source pad,一个用于容器格式中包含的每个基本流。然而,解码器只有一个 source 和多个 sink pad。
过滤器元素显示了我们将如何可视化类过滤器的元素。这个特定的元件有一个 source pad 和一个 sink pad。接收输入数据的 sink pad 描绘在元素的左侧;source Pad 仍然位于右侧。
具有多个输出pad的过滤器元件显示另一个类过滤器的元件,该元件具有多个输出(source)pad。例如,下例是一个包含音频和视频的 Ogg 流的 Ogg 解复用器元素。一个source pad 将包含基本视频流,另一个source pad 将包含基本音频流。Demuxer 通常会在创建新 pad 时触发信号。然后,应用程序程序员可以在 signal 处理程序中处理新的基本流。
Sink element元素:
sink element是媒体pipeline中的终点。它们接受数据但不产生任何东西。磁盘写入、声卡播放和视频输出都将由 sink element实现。sink element的可视化如下。
创建 GstElement:
创建element 的最简单方法是使用 gst_element_factory_make(factory_name,element_name)
。此函数接收用于创建element的factory名称和element名称。例如,element名称是你以后可以在 bin 中查找element的名称。该名称也将用于调试输出。您可以将 NULL
作为 element name 参数传递,以获得唯一的默认名称。
当你不再需要该element时,你需要使用 gst_object_unref()
取消引用它。这会将element的引用计数减少 1。element在创建引用计数为1。当引用计数减少到 0 时,element将被完全销毁。
下面的示例 basic-example-3.c 显示了如何从名为 fakesrc 的元素工厂创建名为 source 的element。它会检查创建是否成功。检查后,它会取消引用元素。
#include <stdio.h> #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; }
编译文件:
gcc basic-example-3.c -o basic-example-3 `pkg-config --cflags --libs gstreamer-1.0`
运行结果:无打印
gst_element_factory_make
实际上是两个函数组合的简写。GstElement
对象是从工厂创建的。要创建元素,您必须使用唯一的工厂名称访问 GstElementFactory
对象。这是通过 gst_element_factory_find()
完成的。
以下代码 basic-example-4.c 用于获取可用于创建 fakesrc element(一个假的数据源)的工厂。函数 gst_element_factory_create()
将使用元素工厂创建具有给定名称的element。
#include <stdio.h> #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; }
编译文件:
gcc basic-example-4.c -o basic-example-4 `pkg-config --cflags --libs gstreamer-1.0`
运行结果:无
将元素当做GObject使用:
GstElement
作为标准的 Gobject使用时可以具有很多属性。因此,像常用的 GObject
方法:查询、设置和获取属性值以及 GParamSpecs
都是支持的。
每个 GstElement
都从其父 GstObject
继承至少一个属性:“name”属性。这是您为函数 gst_element_factory_make() 或
gst_element_factory_create()
提供的名称。您可以使用函数 gst_object_set_name
和 gst_object_get_name
获取和设置此属性,也可以使用 GObject
属性机制,如下所示。
basic-example-5.c
#include <stdio.h> #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; }
编译运行:略
运行结果:
/opt/gstreamer# ./basic-example-5 The name of the element is 'source'.
大多数插件都提供了额外的属性,以提供有关其配置的更多信息或配置 element元素。gst-inspect
是一个查询特定 element 元素属性很有用的工具,它还将使用属性自省来简要说明属性的功能以及它支持的参数类型和范围。有关 gst-inspect
的详细信息,请参阅附录中的 gst-inspect。
有关 GObject
属性的更多信息,我们建议您阅读 GObject 手册和 Glib Object 系统简介。
GstElement
还提供了各种 GObject
信号,这些信号可用作灵活的回调机制。在这里,您也可以使用 gst-inspect
来查看特定元素支持哪些信号。信号和属性一起是元素和应用程序交互的最基本方式。
更多关于 element 工厂:
在上一节中,我们简要介绍了 GstElementFactory
对象作为创建 element 元素实例的一种方式。然而,element 元素工厂远不止于此。element 元素工厂是从 GStreamer 注册表中检索的基本类型,它们描述了所有 GStreamer 可以创建的插件和 element 元素。这意味着 element 元素工厂对于自动 element 元素实例化(例如自动插件的作用)以及创建可用 element 元素列表非常有用。
使用工厂获取有关 element 元素的信息:
gst-inspect
等工具将提供有关 element 元素的一些通用信息,例如编写插件的人、描述性名称(和简称)、排名和种类。种类可用于获取可使用此 element 元素工厂创建的元素的类型。种类的例子包括 Codec/Decoder/Video
(视频解码器)、Codec/Encoder/Video
(视频编码器)、Source/Video
(视频生成器)、Sink/Video
(视频输出),当然,所有这些都存在于音频中。然后,还有 Codec/Demuxer
和 Codec/Muxer
等等。gst-inspect
将给出所有工厂的列表,而 gst-inspect <factory-name>
将列出上述所有信息,以及更多信息。
basic-example-6.c
#include <stdio.h> #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; }
编译运行:略
运行结果:
/opt/gstreamer# ./basic-example-6 The 'fakesrc' element is a member of the category Source. Description: Push empty (no data) buffers around
你可以用来 gst_registry_pool_feature_list(GST_TYPE_ELEMENT_FACTORY)
获取 GStreamer 知道的所有 element 元素工厂的列表。
找出元素可以包含哪些Pad:
也许 element 工厂最强大的功能是它们包含了 element 可以生成的 pad 的完整描述,以及这些 pad 的功能(通俗地说:哪些类型的媒体可以在这些 pad上流动),而无需实际将这些插件加载到内存中。这可用于为编码器提供编解码器选择列表,也可以用于媒体播放器的自动插入目的。所有当前基于 GStreamer 的媒体播放器和自动插件都以这种方式工作的。在下一章中,当我们了解 GstPad
和 GstCap
时,我们将仔细研究这些功能:Pad和能力集
链接 Element 元素:
通过将 source element 元素与零个或多个 filte-like 类似过滤器的 element 元素链接,最后链接一个 sink element 元素,然后设置一个媒体 pipeline 管道。数据就会流经这些 element 元素。这是 GStreamer 中媒体处理的基本概念。
通过链接这三个 element 元素,我们创建了一个非常简单的 element 元素链。这样做的效果是,source element 元素的输出将用作 filter-like 类过滤器 element 元素的输入。filter-like 类过滤器 element 元素将对数据执行一些处理,并将结果发送到最终的 sink element 元素。
将上图想象成一个简单的 Ogg/Vorbis 音频解码器。source element 元素是从硬盘读取文件的磁盘 source 。第二个 element 是 Ogg/Vorbis 音频解码器。sink element 元素是声卡用于播放解码后的音频数据。在本手册的后面,我们将使用这个简单的图表来构建一个 Ogg/Vorbis 播放器。
basic-example-7.c
#include <stdio.h> #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!"); } [..] }
该示例并不是完整代码,不能运行,主要是理解pipeline的创建,element的创建和添加,还有熟悉elements之间的link的调用。
对于更具体的行为,还有函数 gst_element_link()
和 gst_element_link_pads()
。您还可以获取单个pad的引用,并使用各种 gst_pad_link_*()
函数将它们链接起来。有关更多详细信息,请参阅 API 参考。
重要提示:在链接 element 元素之前,您必须将元素都添加到 bin 或 pipeline,因为向 bin 中添加 element 元素会导致已经链接过的连接断开,如果先链接再添加,那此前的链接也会失效。此外,您不能链接不同 bin 或 pipeline 中的元素;如果你想链接不同层级的 element 元素或 pad,则需要使用 ghost pad(稍后会详细介绍 Ghost Pad)。
Element States 元素状态:
element 元素创建后,实际上不会执行任何操作。你需要改变 element 元素的状态来让它做一些事情。GStreamer 有四种元素状态,每种状态都有非常具体的含义。这四个状态是:
GST_STATE_NULL
:这是默认状态。在此状态下未分配任何资源,因此,转换到该状态将释放所有资源。当 element 元素的引用计数达到 0 并被释放时,该 element 元素必须处于此状态。GST_STATE_READY
:在 READY 状态下,element 元素已经分配了它的所有全局资源,即可以保存在流中的资源。您可以考虑打开设备、分配缓冲区等。但是,流在此状态下是未打开的,因此流位置自动为零。如果之前打开了流,则应在此状态下关闭该流,并且应重置位置、属性等。GST_STATE_PAUSED
:在此状态下,element 元素已打开流,但未主动处理它。一旦状态更改为 PAUSED,element 就允许修改流的位置、读取和处理数据等,以便为播放做准备,但不允许播放那些会让时钟运行的内容。总之,PAUSED 与 PLAYING 只是没有运行时钟,其他的都一样。
进入 PAUSED
状态的元素应尽快准备好切换到 PLAYING
状态。例如,视频或音频输出将等待数据到达并排列数据,以便它们可以在状态更改后立即播放数据。此外,视频 sink 已经可以播放第一帧(因为这还不会影响时钟)。自链接的插头可以使用相同状态变化来将 pipeline 耦合在一起。但是,大多数其他元素(如编解码器或筛选器)不需要在此状态下显式执行任何操作。
GST_STATE_PLAYING
:在PLAYING
状态下,元素的作用与PAUSED
状态完全相同,只是时钟开始运行。
您可以使用函数 gst_element_set_state()
更改元素的状态。如果你将 element 元素设置为另一个状态,GStreamer 将在内部遍历所有的中间状态。因此,如果您直接将 element 元素从 NULL
设置为 PLAYING,GStreamer 将在内部将 element 元素依次设置为 READY 和 PAUSED
。
当状态变为 GST_STATE_PLAYING
时,管道将自动处理数据。它们不需要任何形式的指令。在内部,GStreamer 将启动承接此任务的所有线程。GStreamer 还将通过使用 GstBus
将消息从 pipeline 管道的线程切换到应用程序自己的线程。有关详细信息,请参阅 Bus。
当你将 bin 或 pipeline 设置为某个目标状态时,它通常会自动将状态更改传播到 bin 或 pipeline 中的所有元素,因此通常只需要设置顶级 pipeline 管道的状态即可启动或关闭。但是,当 element 元素动态添加到已经运行的 pipeline 管道时,会有类似“pad-added”信号回调,您需要使用以下命令 gst_element_set_state()
或 gst_element_sync_state_with_parent()
将其设置为所需的目标状态。