06.Pad Capabilities(能力协商)
2026/1/19大约 4 分钟padcapabilities
GStreamer学习笔记:06.Pad Capabilities(能力协商)
本示例尝试理清 GStreamer 中 Pad Capabilities(Capabilities,简称 Caps)的相关概念,这是 Element 之间能否成功连接的关键。
核心概念
1. 概念梳理
Element 元素
- GStreamer 的基本构成单位
- source 元素:生产数据
- filter 元素:处理数据
- sink 元素:消费数据
- 元素可以两两连接:
{source 元素} -> {sink 元素}{source 元素} -> {filter 元素} -> {sink 元素}
Pad 插槽
- 元素通过 Pad 连接
- 连接顺序只能是:
[src 插槽] -> [sink 插槽]{source 元素[src 插槽]} -> {[sink 插槽]filter 元素[src 插槽]} -> {[src 插槽]sink 元素}
- 各类型元素的 Pad:
- source 元素:有 src 插槽
- filter 元素:有 sink 插槽、src 插槽
- sink 元素:有 sink 插槽
Pad Templates 插槽模板
- templates 用于生成一个 pad
- 描述 pad 类型:
- SRC template:src 生产数据的 pad
- SINK template:sink 消费数据的 pad
- 描述能力的可获得性:
- Availability: Always 总是
- Availability: Sometimes 有时
- Availability: On request 当请求时
- Capabilities 描述了一个 pad 的所有能力
- 连接两个 Element 元素必须保证两个 pad 的 caps 能力有交集
- 例如:解码器输出 YUV 格式,播放器接收 YUV 格式
- Caps 的属性是一个范围:如
rate: [ 1, 2147483647 ],layout: { (string)interleaved, (string)non-interleaved } - 当两个 element 的 pad 协商完成建立连接后,Caps 的属性是一个具体的值:
- 如:
rate: 48000,layout: interleaved
- 如:
- 连接两个 Element 元素必须保证两个 pad 的 caps 能力有交集
2. Capabilities 示例
支持两种(S16LE、U8)音频格式的能力
audio/x-raw
format: S16LE
rate: [ 1, 2147483647 ]
channels: [ 1, 2 ]
audio/x-raw
format: U8
rate: [ 1, 2147483647 ]
channels: [ 1, 2 ]支持任何能力
ANY没有任何能力
EMPTY3. 打印 Capabilities
打印一个 caps 的域
static gboolean print_field(GQuark field_id, const GValue *value, gpointer user_data)
{
gchar *prefix = (gchar *)user_data;
const gchar *name = g_quark_to_string(field_id); // 获取字段名
gchar *svalue = gst_value_serialize(value); // 获取字段值
g_print("%s %15s: %s\n", prefix, name, svalue);
g_free(svalue);
return TRUE;
}打印 Caps
static void print_caps(const GstCaps *caps, const gchar *pfx)
{
guint i;
g_return_if_fail(caps != NULL);
if (gst_caps_is_any(caps)) // 支持任何能力
{
g_print("%sANY\n", pfx);
return;
}
if (gst_caps_is_empty(caps)) // 没有任何能力
{
g_print("%sEMPTY\n", pfx);
return;
}
for (i = 0; i < gst_caps_get_size(caps); i++) // 遍历所有 caps
{
GstStructure *cap = gst_caps_get_structure(caps, i);
g_print("%s%s\n", pfx, gst_structure_get_name(cap));
// 打印输出这个 cap 能力所有属性
gst_structure_foreach(cap, print_field, (gpointer)pfx);
}
}打印 Pad Template
static void print_pad_templates_information(GstElementFactory *factory)
{
const GList *temps;
GstStaticPadTemplate *temp;
g_print("Pad Templates for %s:\n", gst_element_factory_get_longname(factory));
if (!gst_element_factory_get_num_pad_templates(factory))
{
g_print(" none\n");
return;
}
temps = gst_element_factory_get_static_pad_templates(factory);
while (temps)
{
temp = temps->data;
temps = g_list_next(temps);
// 输出 pad_template 方向:src/sink
if (temp->direction == GST_PAD_SRC)
g_print(" SRC template: '%s'\n", temp->name_template);
else if (temp->direction == GST_PAD_SINK)
g_print(" SINK template: '%s'\n", temp->name_template);
else
g_print(" UNKNOWN!!! template: '%s'\n", temp->name_template);
// 输出 pad_template 存在方式
g_print(" Availability: %s\n",
temp->presence == GST_PAD_ALWAYS ? "Always"
: temp->presence == GST_PAD_SOMETIMES ? "Sometimes"
: temp->presence == GST_PAD_REQUEST ? "On request"
: "UNKNOWN!!!"
);
// 输出 pad 静态能力
if (temp->static_caps.string)
{
GstCaps *caps;
g_print(" Capabilities:\n");
caps = gst_static_caps_get(&temp->static_caps);
print_caps(caps, " ");
gst_caps_unref(caps);
}
g_print("\n");
}
}打印当前 Pad 的 Capabilities
static void print_pad_capabilities(GstElement *element, gchar *pad_name)
{
GstPad *pad = NULL;
GstCaps *caps = NULL;
// 获取一个元素的静态 pad
pad = gst_element_get_static_pad(element, pad_name);
if (!pad)
{
g_printerr("Could not retrieve pad '%s'\n", pad_name);
return;
}
// 获取 pad 当前的 caps 能力
caps = gst_pad_get_current_caps(pad);
if (!caps)
caps = gst_pad_query_caps(pad, NULL);
g_print("Caps for the %s pad:\n", pad_name);
print_caps(caps, " ");
gst_caps_unref(caps);
gst_object_unref(pad);
}4. Capabilities 协商过程
在 NULL 状态下
In NULL state:
Caps for the sink pad:
ANY状态变为 PLAYING 后
Pipeline state changed from NULL to READY:
Caps for the sink pad:
audio/x-raw
format: F32LE
layout: interleaved
rate: 48000
channels: 2
channel-mask: 0x0000000000000003注意:Caps 的属性从范围(如 rate: [ 1, 2147483647 ])变成了具体值(如 rate: 48000)
5. 使用 Element Factory
source_factory = gst_element_factory_find("audiotestsrc");
sink_factory = gst_element_factory_find("autoaudiosink");
// 实例化元素
source = gst_element_factory_create(source_factory, "source");
sink = gst_element_factory_create(sink_factory, "sink");关键代码示例
打印 source_factory 的 Pad Templates
Pad Templates for Audio test source:
SRC template: 'src'
Availability: Always
Capabilities:
audio/x-raw
format: { (string)S16LE, (string)S16BE, (string)U16LE, ... }
layout: { (string)interleaved, (string)non-interleaved }
rate: [ 1, 2147483647 ]
channels: [ 1, 2147483647 ]打印 sink_factory 的 Pad Templates
Pad Templates for Auto audio sink:
SINK template: 'sink'
Availability: Always
Capabilities:
ANY完整代码
(代码较长,完整实现请参考 06.pad capabilities/main.c 文件)
编译和运行
gcc main.c -o main.out $(pkg-config --cflags --libs gstreamer-1.0)
./main.out总结
本示例介绍了 GStreamer 的核心概念:
- Element:基本构成单位
- Pad:元素之间的连接点
- Pad Templates:Pad 的模板定义
- Capabilities:描述 Pad 支持的所有能力
- 能力协商:两个 Pad 连接时的能力匹配过程
理解 Capabilities 是掌握 GStreamer 的关键,它决定了:
- Element 是否可以连接
- 连接后使用什么样的媒体格式
- Pipeline 是否能正常工作
Capabilities 协商是 GStreamer 动态性和灵活性的基础。