本节摘要:Caps(能力集)是 GStreamer 描述媒体格式的语言:一个媒体类型加一组字段,字段可取固定值、范围或枚举。它在管线里有三种身份——衬垫模板(出厂规格)、能力过滤器(人工约束)、协商结果(定格格式)。本节讲透语法与三种身份的转换,为下一节的协商机制备好词汇表。承接首航命令里打印的那行输出,通往全册所有涉及格式的讨论。
首航的详细输出里有这样一行:媒体类型是裸视频,排布 I420,宽 320 高 240,帧率每秒 30 帧,像素纵横比 1 比 1。把它拆开:斜杠前的部分是媒体类型(裸视频、编码视频、原始音频、容器流),冒号后是一组键值字段。字段取值有三种形态:固定值(宽 320)、范围(帧率从 1 到 60)、枚举(档位取基线、主流、高规格三者之一)。这套语法是管线的世界语——模板声明用它、过滤器约束用它、协商定格用它、日志打印也是它。

"任意"与"空集"这两个特殊值值得单独记。任意出现在解码装配器的源垫模板里——读完文件头之前,它不知道会吐什么,模板干脆宣称来者不拒;空集则出现在解封装器的动态衬垫上,意思是"我确实有一个垫,但能力未知,等我通报"。日志里看到这两个词,就知道管线正在等下一步信息,而不是出了故障。
上一节的表达式里其实已经用过过滤器语法,只是没点名。感叹号之间插入一段能力集,就是给这一段管道人工约束。
# 约束测试源的输出:宽高定格 六百四十乘三百六十 gst-launch-1.0 videotestsrc ! \ video/x-raw,width=640,height=360 ! autovideosink # 约束帧率范围与排布:多个字段逗号相连 gst-launch-1.0 v4l2src ! \ video/x-raw,format=YUY2,width=1280,height=720,framerate=30/1 ! \ videoconvert ! autovideosink
过滤器的价值在收紧协商空间。摄像头能输出十几种格式组合,不约束时协商结果随驱动心情而定;把宽高与帧率钉死,管线行为才可复现。反过来的代价也要清楚:约束写得越死,可用元件越少——约束了一个冷门排布,可能整条管线协商失败。写过滤器的分寸是只钉影响业务的字段(分辨率、帧率、档位),排布这类实现细节交给转换元件。
三种身份在工具与代码里各有一套查询动作,整理成速查表。
| 身份 | 哪里看 | 典型形态 | 用途 |
|---|---|---|---|
| 衬垫模板 | 目录查询命令 | 范围与枚举 | 选元件前验接口 |
| 能力过滤器 | 表达式与代码 | 部分固定 | 收紧协商空间 |
| 协商结果 | 详细模式与日志 | 全固定 | 验证实际行为 |
代码里查询协商结果也是常事,比如渲染前确认真实的宽高。
// 取源垫当前能力集 未定格时可能为空指针 GstPad *pad = gst_element_get_static_pad(conv, "src"); GstCaps *caps = gst_pad_get_current_caps(pad); if (caps && gst_caps_is_fixed(caps)) { GstStructure *s = gst_caps_get_structure(caps, 0); gint width = 0, height = 0; gst_structure_get_int(s, "width", &width); gst_structure_get_int(s, "height", &height); g_print("当前协商定格为 宽 %d 高 %d\n", width, height); } gst_caps_unref(caps); gst_object_unref(pad);
⚠️ 常见坑:把模板当结果。目录里查到的宽高范围只是"可能",程序里真拿宽高去分配缓冲前,必须用当前能力集接口确认已定格且为固定形态,否则拿到的是空指针或未固定结构。
能力集不只是描述语言,还是可运算的对象:两个能力集可以求交集(协商的核心动作)、可以判断是否固定、可以从范围里挑一个值(收敛动作)。下一节把这些运算放进协商流程里演一遍——谁先出牌、谁提建议、谁拍板定格,全流程配上真实日志。
| 媒体类型 | 含义 | 典型字段 | 常在哪里见到 |
|---|---|---|---|
| 裸视频 | 未压缩帧 | 排布 宽高 帧率 | 解码器之后 |
| 编码视频 | 压缩码流 | 档位 级别 | 解码器之前 封装器内部 |
| 裸音频 | 未压缩采样 | 采样格式 采样率 声道 | 音频解码之后 |
| 编码音频 | 压缩音频流 | 档位 比特率 | 音频解码之前 |
| 容器流 | 封装格式 | 流结构 | 解封装器前后 |
| 传输负载 | 网络封装包 | 载荷类型 时钟速率 | 推拉流的网络段 |
| 应用数据 | 自定义数据 | 视实现而定 | 自定义元件之间 |
速查表的用法是先认类型再看字段:拿到一行协商日志,先读媒体类型定位自己在数据流的哪一段(压缩侧还是裸数据侧),再看字段判断规格。配合第三章 3.1 节的详细模式,任何管线的实际走线都能这样逐段读懂。
能力集是可运算对象,三个高频运算对应三个日常问题。问:这两边能不能接——求交集,交集非空即能接(协商第一步的机器判据);问:这条能力集是不是已经定了——固定性判断,全字段定值才是真·结果,含范围就还没谈完(3.2 节"模板不是结果"的机器版);问:从范围里挑哪个值——收敛运算,按规则从多种可能里选一个(高值优先、靠近默认)。三问在程序里的入口都是衬垫或能力集对象上的现成接口,返回值即答案。
这三个运算是第三章与第八章的桥:协商失败的判据是"交集为空",协商完成的判据是"已固定",跳转后的重协商是"再走一遍收敛"。把三问答熟,第八章排错实录里的每一步日志你都能预判它接下来打印什么。
词汇表备齐,下一节进入协商现场:三步流程、两个方向、三类失败。