Pads 和 capabilities(功能)
正如我们在元素中看到的,pads是元素与外部世界的接口。来自一个的数据流元素的源pad到另一个元素的接收pad。特定类型的元素可以处理的媒体将被pad暴露能力。我们将在本章后面更多地讨论功能 (参见pad的功能)。
Pads
pad类型由两个属性定义:方向和可用性。正如我们之前提到的,GStreamer定义了两个pad方向:源pad和接收pad。这个术语是从元素内部的角度定义的:元素在其接收pad上接收数据,并在其源pad上生成数据。示意性地,接收pad绘制在元素的左侧,而源pad绘制在元素的右侧。在这样的图表中,数据从左到右流动。[1]
与pad可用性相比,pad方向非常简单。pad可以具有三种可用性中的任何一种:始终、有时和应请求。这三种类型的含义与它所说的完全相同:pad始终存在,有时pad仅在某些情况下存在(并且可以随机消失),应请求pads仅在应用程序明确请求时出现。
动态(或有时)pads
创建元素时,某些元素可能没有所有的pad。例如,这可能发生在Ogg解复用器元素上。当元素在Ogg流中检测到这样的流时,该元素将读取Ogg流并为每个包含的基本流(Vorbis、theora)创建动态pad。同样,当流结束时,它将删除pad。例如,这个原则对于解复用器元素非常有用。
运行gst-inspect-1.0 oggdemux
将显示元素只有一个 pad:一个叫做“sink”的sink pad。其他pad是“休眠的”。你可以看到 这在pad模板中,因为有一个“可用性:有时” 属性。根据您播放的Ogg文件类型,pads 将 创建。我们会看到这是非常重要的,当你要去 创建动态管道。您可以将信号处理程序附加到元素 通知您元素何时从其之一创建了一个新pad “有时”pad模板。以下代码是一个示例如何做到这一点:
#include <gst/gst.h>
static void
cb_new_pad (GstElement *element,
GstPad *pad,
gpointer data)
{
gchar *name;
name = gst_pad_get_name (pad);
g_print ("A new pad %s was created\n", name);
g_free (name);
/* here, you would setup a new pad link for the newly created pad */
[..]
}
int
main (int argc,
char *argv[])
{
GstElement *pipeline, *source, *demux;
GMainLoop *loop;
/* init */
gst_init (&argc, &argv);
/* create elements */
pipeline = gst_pipeline_new ("my_pipeline");
source = gst_element_factory_make ("filesrc", "source");
g_object_set (source, "location", argv[1], NULL);
demux = gst_element_factory_make ("oggdemux", "demuxer");
/* you would normally check that the elements were created properly */
/* put together a pipeline */
gst_bin_add_many (GST_BIN (pipeline), source, demux, NULL);
gst_element_link_pads (source, "src", demux, "sink");
/* listen for newly created pads */
g_signal_connect (demux, "pad-added", G_CALLBACK (cb_new_pad), NULL);
/* start the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
[..]
}
仅从管道中添加元素并不少见 “填充添加”回调。如果您这样做,请不要忘记设置 使用管道的目标状态新添加的元素 gst_element_set_state ()
或gst_element_sync_state_with_parent ()
。
请求pads
一个元素也可以有请求pads。这些pads不是自动创建的,而是根据需要创建的。这对多路复用器、聚合器和三通元素非常有用。聚合器是将几个输入流的内容合并成一个输出流的元素。三通元素正好相反:它们是具有一个输入流的元素,并将此流复制到它们的每个输出pad上,这些输出pad是根据请求创建的。每当应用程序需要流的另一个副本时,它可以简单地从三通元素请求一个新的输出pad。
以下代码显示了如何从“tee”元素请求新的输出pad:
static void
some_function (GstElement * tee)
{
GstPad *pad;
gchar *name;
pad = gst_element_request_pad_simple (tee, "src%d");
name = gst_pad_get_name (pad);
g_print ("A new pad %s was created\n", name);
g_free (name);
/* here, you would link the pad */
/* [..] */
/* and, after doing that, free our reference */
gst_object_unref (GST_OBJECT (pad));
}
使用gst_element_request_pad_simple ()
方法可以得到一个pad 来自基于pad模板名称的元素。它也是 可以请求与另一个pad模板兼容的pad。 如果您想将元素链接到多路复用器,这将非常有用 元素,您需要请求一个兼容的pad。方法 gst_element_get_compatible_pad ()
可用于请求兼容的 pad,如下一个示例所示。它将从来自任何输入的Ogg多路复用器。
static void
link_to_multiplexer (GstPad * tolink_pad, GstElement * mux)
{
GstPad *pad;
gchar *srcname, *sinkname;
srcname = gst_pad_get_name (tolink_pad);
pad = gst_element_get_compatible_pad (mux, tolink_pad, NULL);
gst_pad_link (tolink_pad, pad);
sinkname = gst_pad_get_name (pad);
gst_object_unref (GST_OBJECT (pad));
g_print ("A new pad %s was created and linked to %s\n", sinkname, srcname);
g_free (sinkname);
g_free (srcname);
}
pad的功能
因为pad在如何查看元素方面起着非常重要的作用通过外部世界,实现了一种机制来描述数据 可以通过使用功能流过或当前流过pad。 在这里,我们将简要描述什么是能力以及如何使用他们,足以理解这个概念。为了深入查看功能和中定义的所有功能的列表 GStreamer,请参阅插件编写器指南
功能附加到pad模板和pad。对于pad模板,它将描述可以流过从该模板创建的pad的媒体类型。对于pad,它可以是可能的上限列表(通常是pad模板功能的副本),在这种情况下,pad尚未协商,或者是当前流过该pad的媒体类型,在这种情况下,pad已经协商过了。
分析能力
pad的功能在GstCaps
对象中描述 GstCaps 将包含一个或多个 GstStructure 这将描述一种媒体类型。协商pad将有 只包含一个结构的能力集 结构将只包含固定值。这些约束不是对于未协商的pads或pad模板为真。
例如,下面是“Vorbisdec”功能的转储元素,您将通过运行gst-inspect vorbisdec
。你会的看两个pad:一个源pad和一个sink pad。这两个pad总是可用,并且两者都具有附加功能。sink pad将接受Vorbis编码的音频数据,具有媒体类型 “音频/x-Vorbis”。源 pad将用于发送原始(解码) 音频样本到下一个元素,具有原始音频媒体类型(在此案例,“音频/x-原始”)。源pad还将包含以下属性 音频采样率和通道数量,加上更多您暂时不需要担心。
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
audio/x-raw
format: F32LE
rate: [ 1, 2147483647 ]
channels: [ 1, 256 ]
SINK template: 'sink'
Availability: Always
Capabilities:
audio/x-vorbis
属性和值
属性用于描述功能的额外信息。属性由键(字符串)和值组成。可以使用不同的可能值类型:
-
基本类型,这几乎可以是任何
GType
注册 Glib。这些属性指示特定的非动态值 这个属性。示例包括:-
整数值(
G_TYPE_INT
):该属性具有以下精确值 值。 -
布尔值(
G_TYPE_BOOLEAN
):属性TRUE
或者FALSE
。 -
浮点值(
G_TYPE_FLOAT
):该属性具有以下精确值 浮点值。 -
字符串值(
G_TYPE_STRING
):属性包含UTF-8 字符串。 -
分数值(
GST_TYPE_FRACTION
):包含一个分数 由整数分子和分母表示。
-
-
范围类型是由GStreamer注册的
GType
,用于指示范围可能的值。它们用于指示允许的音频采样值或支持的视频大小。中定义的两种类型 GStreamer是:-
整数范围值(
GST_TYPE_INT_RANGE
):属性表示可能的整数范围,有一个下限和一个上限 边界。例如,“Vorbisdec”元素有一个速率 可以在8000到50000之间的属性。 -
浮点范围值(
GST_TYPE_FLOAT_RANGE
):属性表示一系列可能的浮点值,具有较低的 和一个上边界。 -
分数范围值(
GST_TYPE_FRACTION_RANGE
):属性表示一系列可能的分数值,其中包含 上边界。
-
-
列表值(
GST_TYPE_LIST
):属性可以从 此列表中给出的基本值列表。示例:表示支持44100 Hz采样率和48000 Hz采样率的上限将使用整数值列表,其中一个值为44100,一个值为48000。
-
数组值(
GST_TYPE_ARRAY
):属性是一个数组值。数组中的每个值本身也是一个完整值。所有 数组中的值应该是相同的基本类型。这 意味着数组可以包含整数、列表的任意组合 整数,整数范围在一起,浮点数或 字符串,但它不能同时包含浮点数和整数 时间。示例:对于涉及两个以上通道的音频 需要指定通道布局(对于一个和两个通道 音频通道布局是隐式的,除非在 大写)。所以通道布局将是一个整数枚举数组 每个枚举值代表扬声器位置的值。 与
GST_TYPE_LIST
不同,数组中的值将被解释 作为一个整体。
capabilities(功能)是用来做什么的
功能(简称:caps)描述在两个pads之间流式传输的数据类型,或者一个pad(模板)支持的数据类型。这使得它们对于各种目的非常有用:
-
自动插拔:根据其功能自动查找链接到pad的元素。所有自动插拔器都使用此方法。
-
兼容性检测:当两个pad链接时,GStreamer可以验证两个pad是否在谈论相同的媒体类型。链接两个pad并检查它们是否兼容的过程称为“大写协商”。
-
元数据:通过从pad读取功能,应用程序可以提供有关在pad上流式传输的媒体类型的信息,即有关当前正在播放的流的信息。
-
过滤:应用程序可以使用功能来限制可能的 可以在两个pad之间流式传输到特定子集的媒体类型 他们支持的流类型。例如,应用程序可以使用 “过滤大写”以设置特定(固定或非固定)视频大小 应该在两个pad之间流动。您将看到一个示例过滤大写在本手册后面的手动向管道添加或删除数据中。 您可以通过将caps filter元素插入到 您的管道并设置其“大写”属性。大写过滤器是通常放置在audio转换器等转换器元素之后, 音频采样、视频转换或视频缩放以强制这些转换器 在某个点将数据转换为特定的输出格式 流。
对元数据使用功能
一个pad可以附加一组(即一个或多个)功能。 能力(GstCaps
)表示为一个或多个 GstStructure
GstStructure
都是一个字段数组,其中 每个字段由一个字段名称字符串(例如“宽度”)和一个类型化的值(例如G_TYPE_INT
或GST_TYPE_INT_RANGE
)。
请注意,有一个明显的差异之间的垫可能的能力(即通常你发现的垫模板的上限,因为他们显示在gst-inspect),允许的上限的pad(可以是相同的pad的模板上限或其子集,取决于对等pad的可能上限)和最后协商的上限(这些描述流或缓冲区的确切格式,只包含一个结构,没有可变位,如范围或列表,即它们是固定的上限)。
您可以通过查询获取一组功能中的属性值 一种结构的单个属性。您可以从 使用gst_caps_get_structure ()
和结构数量的大写 GstCaps
使用gst_caps_get_size ()
。
当Caps仅包含一个结构时,Caps称为简单caps;当它们只包含一个结构且没有可变字段类型(如范围或可能值列表)时,将称为固定caps。另外两种特殊类型的caps是ANY caps和empty caps。
以下是如何从一组固定视频caps中提取宽度和高度的示例:
static void
read_video_props (GstCaps *caps)
{
gint width, height;
const GstStructure *str;
g_return_if_fail (gst_caps_is_fixed (caps));
str = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (str, "width", &width) ||
!gst_structure_get_int (str, "height", &height)) {
g_print ("No width/height available\n");
return;
}
g_print ("The video size of this set of capabilities is %dx%d\n",
width, height);
}
创建过滤功能
虽然功能主要用于插件内部来描述媒体 Pad的类型,应用程序程序员通常也必须拥有对功能的基本了解,以便与插件,尤其是在使用过滤caps时。当你使用过滤 caps或固定caps,您将限制在两个pads之间流动的媒体类型为其支持的媒体类型的子集。你使用管道中的capsfilter
元素执行此操作 您还需要创建自己的GstCaps
。最简单的方法这是通过使用方便函数gst_caps_new_simple ()
:
static gboolean
link_elements_with_filter (GstElement *element1, GstElement *element2)
{
gboolean link_ok;
GstCaps *caps;
caps = gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "I420",
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 288,
"framerate", GST_TYPE_FRACTION, 25, 1,
NULL);
link_ok = gst_element_link_filtered (element1, element2, caps);
gst_caps_unref (caps);
if (!link_ok) {
g_warning ("Failed to link element1 and element2!");
}
return link_ok;
}
这将强制两个元素之间的数据流采用特定的视频格式、宽度、高度和帧率(或者,如果无法在涉及的元素上下文中实现这一点,链接将失败)。请记住,当您使用gst_element_link_filtered ()
时,它会自动创建一个 capsfilter
元素,并将其插入到您的bin或管道中 在您要连接的两个元素之间(如果您曾经想断开这些元素,因为那样你就必须 改为从capsfilter断开两个元素)。
在某些情况下,您会希望创建一组更精细的 过滤两个pads之间链接的功能。然后,这个功能是太简单了,你会想使用方法gst_caps_new_full ()
:
static gboolean
link_elements_with_filter (GstElement *element1, GstElement *element2)
{
gboolean link_ok;
GstCaps *caps;
caps = gst_caps_new_full (
gst_structure_new ("video/x-raw",
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 288,
"framerate", GST_TYPE_FRACTION, 25, 1,
NULL),
gst_structure_new ("video/x-bayer",
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 288,
"framerate", GST_TYPE_FRACTION, 25, 1,
NULL),
NULL);
link_ok = gst_element_link_filtered (element1, element2, caps);
gst_caps_unref (caps);
if (!link_ok) {
g_warning ("Failed to link element1 and element2!");
}
return link_ok;
}
请参阅API参考以获取完整的API GstStructure 和 GstCaps。
Ghost Pads
你可以看到从可视化的Gstbin元素没有Ghost Pads如何没有自己的Pads。这就是“Ghost Pads”发挥作用的地方。
Ghost Pads是来自bin中某些元素的pad,也可以直接从bin访问。将其与UNIX文件系统中的符号链接进行比较。在bin上使用Ghost Pads,bin也有一个pad,并且可以透明地用作代码其他部分的元素。
带有Ghost Pads的GstBin元素的可视化是Ghost Pads的一个表示。元素一的接收pad现在也是bin的一个pad。由于Ghost Pads在外观和功能上与其他pad无异,它们可以像普通pad一样被添加到任何类型的元素中,而不仅仅是GstBin。
创建Ghost Pads使用的是gst_ghost_pad_new()函数。
#include <gst/gst.h>
int
main (int argc,
char *argv[])
{
GstElement *bin, *sink;
GstPad *pad;
/* init */
gst_init (&argc, &argv);
/* create element, add to bin */
sink = gst_element_factory_make ("fakesink", "sink");
bin = gst_bin_new ("mybin");
gst_bin_add (GST_BIN (bin), sink);
/* add ghostpad */
pad = gst_element_get_static_pad (sink, "sink");
gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
gst_object_unref (GST_OBJECT (pad));
[..]
}
在上面的例子中,bin现在还有一个pad:给定元素的称为“接收器”的pad。从这里开始,bin可以用作接收器元素的替代品。例如,您可以将另一个元素链接到bin。
- 实际上,数据从元素的源pad流向上游(图中此元素左侧)的接收pad并无不可。然而,数据总是会从一个元素的源pad流向另一个元素的接收pad。