4. Pad与Caps协商机制
GStreamer 里的 Element(元素),说白了就是管线里的积木块。你搭一条管线,本质上就是把各种 Element 串起来。我刚开始接触 GStreamer 时,总觉得这东西很玄乎,后来发现它其实就三种角色:Source(源头)、Filter(过滤器)、Sink(接收器)。
嗯,咱们今天就把它彻底讲透。
4.1 三种核心类型
每个 Element 在管线里都有自己的「岗位」。我习惯用一句话来记:Source 只管往外吐数据,Sink 只管往里收数据,Filter 夹在中间做处理。
| 类型 | 角色 | 典型例子 | Pad 特点 |
|---|---|---|---|
| Source | 数据生产者 | filesrc、audiotestsrc、v4l2src |
只有 src pad(输出) |
| Filter | 数据处理者 | videoconvert、capsfilter、volume |
既有 sink pad(输入),也有 src pad(输出) |
| Sink | 数据消费者 | autovideosink、filesink、alsasink |
只有 sink pad(输入) |
关键认知:Source 和 Sink 是管线的「边界」。Filter 是管线的「内脏」。你想想看,没有 Source 数据从哪来?没有 Sink 数据去哪了?Filter 再多,也得靠两头撑着。
我在项目中遇到过一个问题:有人把 filesrc 当 Filter 用,试图在它后面接两个 Sink。结果呢?管线直接报错。因为 Source 只有一个 src pad,它没法同时把数据分给两个下游。这就是不理解 Element 类型的后果。
4.2 用 gst-inspect 查看 Element
光知道类型还不够。实际开发中,你拿到一个 Element,得知道它有哪些属性可以调,有哪些 Pad 可以连。这时候 gst-inspect 就是你的「照妖镜」。
4.2.1 基本用法
# 查看某个 Element 的详细信息
gst-inspect-1.0 filesrc
# 列出所有已安装的 Element
gst-inspect-1.0 | grep src
我个人习惯先跑 gst-inspect-1.0 filesrc,然后直接看输出里的几个关键段落。输出内容很多,但咱们只抓重点。
4.2.2 输出结构解读
拿 filesrc 举例,输出大概长这样(我简化了):
Factory Details:
Rank: none (0)
Long-name: File Source
Class: Source/File
...
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
video/mpeg
audio/mpeg
...
Element Properties:
name : The name of the object
location : Location of the file to read
blocksize : Size of blocks to read (default: 4096)
...
咱们拆开来看:
- Factory Details:告诉你这个 Element 叫什么、属于哪一类。比如
Class: Source/File,一眼就知道它是 Source 类型。 - Pad Templates:这是最核心的部分。它列出了这个 Element 有哪些 Pad,每个 Pad 支持什么格式(Capabilities)。
filesrc只有一个srcPad,而且Availability: Always,意思是这个 Pad 一直存在。 - Element Properties:属性列表。每个属性都有名字、类型、默认值、描述。比如
location就是你要读取的文件路径。
小技巧:如果你想知道某个属性支持哪些值,可以用 gst-inspect-1.0 元素名 属性名。比如 gst-inspect-1.0 x264enc bitrate,它会单独显示这个属性的详细约束。
4.2.3 查看 Pad 的 Capabilities
Pad 的 Capabilities 决定了这个 Element 能处理什么格式的数据。我曾经调试一个视频管线,画面一直出不来,最后发现是 videoconvert 的 src pad 输出的格式跟下游 Sink 不匹配。
用 gst-inspect 可以清楚看到:
gst-inspect-1.0 videoconvert
Pad Templates:
SINK template: 'sink'
Availability: Always
Capabilities:
video/x-raw
format: { I420, YV12, NV12, NV21, ... }
width: [ 1, 2147483647 ]
height: [ 1, 2147483647 ]
SRC template: 'src'
Availability: Always
Capabilities:
video/x-raw
format: { I420, YV12, NV12, NV21, ... }
width: [ 1, 2147483647 ]
height: [ 1, 2147483647 ]
看到 format: { I420, YV12, ... } 了吗?这就是它支持的像素格式列表。如果你的 Source 输出的是 RGB,而 videoconvert 的 sink pad 不支持,那管线就会协商失败。
4.3 属性操作实战
光看不行,还得会改。属性操作有两种方式:
- 命令行:用
gst-launch-1.0的属性名=值语法。 - 代码中:用
g_object_set()或 GStreamer 的gst_element_set_property()。
4.3.1 命令行示例
# 设置 filesrc 的 location 属性
gst-launch-1.0 filesrc location=/path/to/video.mp4 ! decodebin ! autovideosink
# 设置 volume 的 volume 属性(0.0 ~ 1.0)
gst-launch-1.0 audiotestsrc ! volume volume=0.5 ! autoaudiosink
这里要注意:属性名是大小写敏感的。我曾经手滑把 location 写成 Location,结果管线直接罢工。嗯,这种低级错误犯过一次就记住了。
4.3.2 代码中操作
// C 语言示例
GstElement *volume = gst_element_factory_make("volume", "my_volume");
g_object_set(volume, "volume", 0.5, NULL);
// 或者用 GStreamer 专用 API
gst_element_set_property(volume, "volume", 0.5);
避坑指南:我曾经在 Python 绑定里用 set_property("volume", 0.5),结果发现音量没变。查了半天,原来是属性类型是 double,而我传了整数 0。GStreamer 不会帮你做隐式类型转换,传错类型它就直接忽略。所以,一定要用 gst-inspect 确认属性类型。
4.4 知识体系图
下面这张图总结了 Element 的类型、Pad 和属性的关系。我建议你把它存下来,以后遇到 Element 相关的问题,先看这张图定位。
4.5 实战:用 gst-inspect 诊断问题
最后分享一个真实案例。有一次我在调试 RTSP 推流,画面一直黑屏。我怀疑是编码器参数不对,于是:
- 先用
gst-inspect-1.0 x264enc查看所有属性。 - 发现
bitrate属性的范围是[0, 100000],单位是 kbps。 - 又看了
key-int-max属性,默认值是250。 - 最后发现是
pass属性设成了qual(质量模式),而接收端只支持cbr(恒定码率)。
改完 pass=cbr,画面就出来了。你看,gst-inspect 就是你的调试利器。遇到问题别瞎猜,先 inspect 一下。
我的习惯:每次引入一个新的 Element,第一件事就是跑 gst-inspect-1.0 元素名 | grep -i "property\|pad\|cap",快速定位关键信息。省时省力。