4. 管道搭建基础语法
好,咱们进入第四讲。前面几章我们把GStreamer的框架搭起来了,也跑通了几个简单的管道。但说实话,那时候的管道就像个黑盒子——你知道它能把音频从A送到B,但中间到底发生了什么,你并不清楚。
这一章,我们就来拆开这个黑盒子。聊聊Element的分类,以及怎么用gst-inspect这个神器,把每个元件扒个底朝天。
4.1 Element的三大分类:源、过滤器、汇
GStreamer里的Element,说白了就三种角色。我刚开始学的时候,觉得这分类太简单了,后来才发现,理解透这三种角色,是搭复杂管道的基础。
| 分类 | 英文名 | 作用 | 典型例子 |
|---|---|---|---|
| 源元件 | Source Element | 产生数据,只有源垫(Src Pad) | filesrc, audiotestsrc, v4l2src |
| 过滤器元件 | Filter Element | 处理数据,既有源垫又有汇垫 | videoconvert, volume, capsfilter |
| 汇元件 | Sink Element | 消费数据,只有汇垫(Sink Pad) | autoaudiosink, filesink, fakesink |
你想想看,一个管道就是「源 → 过滤器 → 汇」这样的链条。源只管往外吐数据,过滤器在中间做各种变换,汇则负责把数据输出到设备或文件。就这么简单。
核心概念:一个Element可以有多个Pad,但源元件只有Src Pad,汇元件只有Sink Pad。过滤器元件两者都有。这是判断元件类型的最直接方法。
4.2 用gst-inspect查看Element的属性和Pad
好,理论说完了,咱们来点实战。怎么知道一个元件有哪些属性?有哪些Pad?能接什么格式的数据?
答案就是gst-inspect-1.0。这个工具,我几乎每天都要用。它就像元件的「身份证」加「说明书」。
4.2.1 基本用法
打开终端,输入:
gst-inspect-1.0 videotestsrc
你会看到一大段输出。别慌,我带你逐段看。
第一段是基本信息:
Factory Details:
Rank: none (0)
Long-name: Video test source
Klass: Source/Video
Description: Creates a test video stream
Author: David A. Schleef <ds@schleef.org>
注意看Klass字段,它告诉你这个元件属于Source/Video类。嗯,源元件,没错。
接下来是Pad模板:
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
video/x-raw
format: { I420, YV12, YUY2, ... }
width: [ 1, 2147483647 ]
height: [ 1, 2147483647 ]
framerate: [ 0/1, 2147483647/1 ]
video/x-raw(meta:video/x-raw-meta)
...
这里信息量很大。它告诉你这个源垫支持哪些格式、分辨率范围、帧率范围。说白了,就是「我能吐出什么样的数据」。
我的小技巧:当你看到Availability: Always,表示这个Pad是固定存在的。如果是Sometimes,那它可能在某些条件下才出现,比如oggdemux的解复用器,数据解析完才知道有几个输出流。
再往下翻,是元件属性:
Element Properties:
name : The name of the object
flags: readable, writable
String. Default: "videotestsrc0"
num-buffers : Number of buffers to output before sending EOS
flags: readable, writable
Unsigned Integer. Default: -1, Min: -1, Max: 2147483647
pattern : Test pattern to generate
flags: readable, writable
Enum "GstVideoTestSrcPattern" Default: 0, "smpte"
(0): smpte - SMPTE 100% color bars
(1): snow - Random (television snow)
(2): black - 100% Black
...
看到了吗?pattern属性可以设置不同的测试图案。默认是smpte彩条,你也可以改成snow雪花或者black纯黑。
4.2.2 快速查看特定信息
有时候你不想看全部输出,只想查某个属性或Pad。可以用grep过滤:
# 只看属性
gst-inspect-1.0 videotestsrc | grep -A 5 "Element Properties"
# 只看Pad模板
gst-inspect-1.0 videotestsrc | grep -A 20 "Pad Templates"
我个人习惯把常用元件的输出保存成文件,方便查阅:
gst-inspect-1.0 videotestsrc > videotestsrc_info.txt
4.3 动手修改属性
光看不动,那是纸上谈兵。咱们来改改属性,看看效果。
4.3.1 通过命令行修改
最简单的办法,就是在gst-launch-1.0里直接设置:
gst-launch-1.0 videotestsrc pattern=2 ! autovideosink
这条命令把pattern设为2,也就是纯黑画面。你运行一下,窗口里应该是一片黑。
再试试雪花效果:
gst-launch-1.0 videotestsrc pattern=1 ! autovideosink
嗯,满屏的雪花,是不是有点老电视的感觉?
注意:属性值可以是数字,也可以是字符串。具体用哪种,看gst-inspect输出的类型。如果是Enum类型,你可以用数字索引,也可以用字符串名称。比如pattern=1和pattern=snow效果一样。
4.3.2 通过代码修改
在C代码里,修改属性用g_object_set:
#include <gst/gst.h>
int main(int argc, char *argv[]) {
GstElement *pipeline, *source;
gst_init(&argc, &argv);
pipeline = gst_pipeline_new("test-pipeline");
source = gst_element_factory_make("videotestsrc", "source");
// 修改属性:设置图案为雪花,输出10帧后结束
g_object_set(source, "pattern", 1, "num-buffers", 10, NULL);
gst_bin_add(GST_BIN(pipeline), source);
// ... 连接其他元件并启动
return 0;
}
这里要注意,g_object_set的参数是可变参数列表,以NULL结尾。属性名和值成对出现。
4.3.3 运行时动态修改
管道跑起来之后,能不能改属性?当然可以。用gst-launch-1.0的--eos-on-signal参数,或者通过总线消息机制。
更常用的方式是用gst-launch-1.0的交互模式:
gst-launch-1.0 -v videotestsrc ! autovideosink
加上-v参数后,你会看到管道状态变化的信息。但真正动态修改,我建议用Python或者写个小程序,监听键盘事件来切换属性。
我曾经在一个项目中需要实时切换视频源的分辨率。一开始我重建了整个管道,后来发现直接用g_object_set修改videoscale的width和height属性,配合capsfilter,就能无缝切换。省了不少事。
4.4 知识体系图
下面这张图,帮你把本章的核心逻辑串起来:
4.5 实战:用gst-inspect排查问题
最后,分享一个我实际遇到的案例。
有一次,我需要把摄像头采集的MJPEG流解码并显示。我搭了这么个管道:
gst-launch-1.0 v4l2src ! jpegdec ! autovideosink
结果报错了,说Pad不兼容。我第一反应就是查v4l2src的输出格式:
gst-inspect-1.0 v4l2src | grep -A 30 "SRC template"
输出显示,v4l2src的源垫支持video/x-raw和image/jpeg两种格式。但默认情况下,它可能输出video/x-raw,而jpegdec需要image/jpeg输入。
解决办法是在中间加一个capsfilter,强制指定格式:
gst-launch-1.0 v4l2src ! video/x-raw,format=YUY2 ! videoconvert ! autovideosink
或者直接用jpegdec能识别的格式:
gst-launch-1.0 v4l2src ! image/jpeg ! jpegdec ! videoconvert ! autovideosink
避坑指南:我曾经花了一下午调试一个管道,怎么都连不上。最后发现是capsfilter里写错了属性名——把format写成了fmt。记住,属性名必须和gst-inspect输出的一模一样,大小写敏感。
嗯,这一章的内容就到这。记住,gst-inspect是你调试GStreamer管道的左膀右臂。遇到问题,先查它,准没错。