背景
开发记录一用 playbin 一行搞定,但它是"黑盒"。记录二手工逐个创建元件并链接,真正理解 GStreamer 的四个核心对象:
- Element(元件)
- Pad(衬垫)
- Bin(箱柜)
- Pipeline(管道)
- Caps(能力协商)
四个核心对象
| 概念 | 定义 | 类比 |
|---|---|---|
| Element | 管道中的一个功能单元。按数据流方向分 source、filter、sink | 工厂里的机器 |
| Pad | 元件的输入/输出端口。sink pad 接收,src pad 产出 | 机器的进料口/出料口 |
| Bin | 装载元件的容器,对外行为像一个元件 | 车间 |
| Pipeline | 一种特殊的 Bin,代表完整可运行的数据流,负责时钟与消息总线 | 整条生产线 |
图示:
┌──────────────────── Pipeline (Bin) ────────────────────┐
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ videotestsrc │ │autovideosink │ │
│ │ │ │ │ │
│ │ src pad│──── link ───▶│sink pad │ │
│ └──────────────┘ └──────────────┘ │
│ source sink │
└────────────────────────────────────────────────────────┘
链接的本质 = pad 与 pad 相连。
手工建管道的 API 流程
1. gst_element_factory_make("类型名", "实例名") 创建元件
2. gst_pipeline_new("名字") 创建空管道
3. gst_bin_add_many(GST_BIN(pipeline), e1, e2, ..., NULL) 加元件
4. gst_element_link(e1, e2) 或 gst_element_link_many(...) 链接
5. g_object_set(element, "属性", 值, NULL) 设属性
6. gst_element_set_state(pipeline, GST_STATE_PLAYING) 播放
7. 等待消息 → 收尾
完整代码
#include <gst/gst.h>
int main (int argc, char *argv[]) {
GstElement *pipeline, *source, *sink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
gst_init (&argc, &argv);
/* 1. 创建元件 */
source = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
pipeline = gst_pipeline_new ("test-pipeline");
if (!pipeline || !source || !sink) {
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* 2. 加入管道 */
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
/* 3. 链接(内部即 pad 与 pad 相连) */
if (gst_element_link (source, sink) != TRUE) {
g_printerr ("Elements could not be linked.\n");
gst_object_unref (pipeline);
return -1;
}
/* 4. 设置属性:测试图案类型 */
g_object_set (source, "pattern", 0, NULL);
/* 5. 播放 */
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr ("Unable to set the pipeline to the playing state.\n");
gst_object_unref (pipeline);
return -1;
}
/* 6. 等待 ERROR 或 EOS */
bus = gst_element_get_bus (pipeline);
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
if (msg != NULL) gst_message_unref (msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
逐段解析
1. 创建元件
source = gst_element_factory_make ("videotestsrc", "source");
sink = gst_element_factory_make ("autovideosink", "sink");
pipeline = gst_pipeline_new ("test-pipeline");
| 函数 | 作用 |
|---|---|
gst_element_factory_make(类型, 名字) | 创建元件 |
gst_pipeline_new(名字) | 创建管道 |
常用元件:
| 元件 | 作用 |
|---|---|
videotestsrc | 测试视频源(彩条) |
audiotestsrc | 测试音频源(正弦波) |
filesrc | 文件源 |
autovideosink | 自动视频输出 |
autoaudiosink | 自动音频输出 |
videoconvert | 视频格式转换 |
元件名写错,编译不报错,运行时返回 NULL。
2. 加入管道
gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
GstBin是容器基类,GstPipeline继承自它GST_BIN(pipeline)是类型转换宏NULL是可变参数结束标志
为什么必须加入管道? 管道负责元件的生命周期、状态、时钟同步。
3. 链接
if (gst_element_link (source, sink) != TRUE) { ... }
gst_element_link 自动找 source 的 src pad 和 sink 的 sink pad 并连接。
等价于:
gst_element_link_pads(source, "src", sink, "sink");
4. 设置属性
g_object_set (source, "pattern", 0, NULL);
videotestsrc 的 pattern 属性:
| 值 | 图案 |
|---|---|
| 0 | SMPTE 彩条 |
| 1 | 雪花 |
| 2 | 纯色 |
| 3 | 棋盘 |
g_object_set 是可变参数函数,最后必须传 NULL。
5. 播放
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) { ... }
返回值:
| 返回值 | 含义 |
|---|---|
GST_STATE_CHANGE_SUCCESS | 成功 |
GST_STATE_CHANGE_ASYNC | 异步,稍后完成 |
GST_STATE_CHANGE_FAILURE | 失败 |
异步返回 ASYNC 不算失败。
6. 等待消息
和开发记录(一)一样,从总线阻塞等待 ERROR 或 EOS。
7. 释放资源
和开发记录(一)一样,注意先停止管道,再释放管道。
为什么需要转换元件(videoconvert / audioconvert)
官方原话:
conversion elements 是必要的,用来保证管道可以链接。因为 sink 的 Caps 取决于硬件,你在设计时并不知道它是否与上游产生的 Caps 匹配。如果 Caps 匹配,这些元件会工作在 'pass-through' 模式,不修改信号,对性能影响可忽略。
经验法则:
只要你在用
autovideosink/autoaudiosink这类"Caps 设计时不确定的"元件,或解码用户提供的内容,就始终插一个videoconvert/audioconvert。
Caps 匹配时,转换元件是 pass-through,几乎零开销。
编译与运行
gcc 2-manual_pipeline.c -o 2-manual_pipeline $(pkg-config --cflags --libs gstreamer-1.0)
./2-manual_pipeline
等价命令行(加 -v 可看到协商出的 Caps):
gst-launch-1.0 videotestsrc pattern=0 ! autovideosink
本课小结
| 点 | 内容 |
|---|---|
| 核心对象 | Element 是功能单元;Pad 是其端口;链接 = pad 相连;Bin 是容器;Pipeline 是可运行的完整 Bin |
| 手工建管道五步 | factory_make → pipeline_new → bin_add_many → element_link → set_state |
| 转换元件 | Caps 不确定时就插 videoconvert / audioconvert;匹配时是 pass-through,几乎零开销 |