Pad 是 GStreamer 中元素之间数据流动的连接点,理解 Pad 的工作原理对于构建复杂管道至关重要。以下是 Pad 的全面解析:
1. Pad 基本概念
1.1 Pad 的类型
类型 | 方向 | 说明 |
---|---|---|
Src Pad | 输出 (→) | 元素的数据出口 |
Sink Pad | 输入 (←) | 元素的数据入口 |
Always Pad | 固定 | 元素创建时即存在 |
Sometimes Pad | 动态 | 运行时才创建(如 demuxer 的流输出) |
Request Pad | 按需 | 需显式请求创建(如 tee 的分支) |
1.2 Pad 的能力(Capabilities)
Pad 通过 Caps (Capabilities) 描述支持的数据格式:
bash
# 示例 Caps 描述
video/x-raw, format=RGB, width=640, height=480, framerate=30/1
audio/x-raw, format=S16LE, rate=44100, channels=2
2. Pad 操作实战
2.1 获取 Pad 的三种方式
(1) 静态获取
// 获取元素的静态Pad
GstPad *sink_pad = gst_element_get_static_pad(decoder, "sink");
(2) 动态Pad连接(信号方式)
// 处理demuxer的动态Pad
static void on_pad_added(GstElement *src, GstPad *new_pad, gpointer user_data) {
GstPadLinkReturn ret;
GstPad *sink_pad = gst_element_get_static_pad(decoder, "sink");
// 检查Pad兼容性
GstCaps *new_pad_caps = gst_pad_get_current_caps(new_pad);
GstStructure *new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
const gchar *new_pad_type = gst_structure_get_name(new_pad_struct);
if (g_str_has_prefix(new_pad_type, "video/x-h264")) {
ret = gst_pad_link(new_pad, sink_pad);
if (GST_PAD_LINK_FAILED(ret)) {
g_print("Pad链接失败\n");
}
}
gst_object_unref(sink_pad);
}
// 连接信号
g_signal_connect(demux, "pad-added", G_CALLBACK(on_pad_added), NULL);
(3) 请求Pad(用于tee/muxer等)
GstPad *tee_src_pad = gst_element_get_request_pad(tee, "src_%u");
gst_pad_link(tee_src_pad, encoder_sink_pad);
2.2 Pad 能力协商流程

2.3 手动能力设置(高级)
// 强制设置特定格式
GstCaps *caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "I420",
"width", G_TYPE_INT, 640,
"height", G_TYPE_INT, 480,
"framerate", GST_TYPE_FRACTION, 30, 1,
NULL);
// 在Pad之间插入capsfilter
GstElement *filter = gst_element_factory_make("capsfilter", "filter");
g_object_set(filter, "caps", caps, NULL);
gst_bin_add(GST_BIN(pipeline), filter);
gst_element_link_many(decoder, filter, converter, NULL);
3. 高级 Pad 操作
3.1 Ghost Pad(幽灵Pad)
// 创建bin并对外暴露Pad
GstElement *bin = gst_bin_new("my-bin");
GstElement *convert = gst_element_factory_make("videoconvert", "convert");
GstElement *sink = gst_element_factory_make("autovideosink", "sink");
gst_bin_add_many(GST_BIN(bin), convert, sink, NULL);
gst_element_link(convert, sink);
// 创建Ghost Pad
GstPad *pad = gst_element_get_static_pad(convert, "sink");
GstPad *ghost_pad = gst_ghost_pad_new("sink", pad);
gst_element_add_pad(bin, ghost_pad);
gst_object_unref(pad);
3.2 Pad 探针(Probe)
// 添加缓冲探针
static GstPadProbeReturn buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
if (buffer) {
g_print("收到缓冲区,大小: %" G_GSIZE_FORMAT "\n",
gst_buffer_get_size(buffer));
}
return GST_PAD_PROBE_OK;
}
GstPad *sinkpad = gst_element_get_static_pad(convert, "sink");
gst_pad_add_probe(sinkpad, GST_PAD_PROBE_TYPE_BUFFER, buffer_probe, NULL, NULL);
gst_object_unref(sinkpad);
4. 常见问题解决方案
4.1 Pad 连接失败
-
检查Caps兼容性:
bash
GST_DEBUG=2 gst-launch-1.0 ... # 查看详细的Caps协商过程
-
插入格式转换:
bash
... ! videoconvert ! video/x-raw,format=NV12 ! ...
4.2 动态Pad未触发
-
确保元素状态为 READY 或 PAUSED
-
检查信号连接是否正确:
g_signal_connect(element, "pad-added", G_CALLBACK(callback), NULL);
4.3 内存泄漏排查
// 检查Pad引用计数
g_print("Pad引用计数: %d\n", GST_OBJECT_REFCOUNT_VALUE(pad));
// 正确释放Pad
gst_object_unref(pad);
5. 性能优化技巧
-
减少Pad探针开销:
// 仅在需要时保持探针 gulong probe_id = gst_pad_add_probe(pad, ...); gst_pad_remove_probe(pad, probe_id);
-
批量处理数据:
// 设置聚合器参数 g_object_set(aggregator, "latency", 50 * GST_MSECOND, "max-size-time", 100 * GST_MSECOND, NULL);
-
零拷贝优化:
bash
# 使用DMA-BUF格式 video/x-raw,format=DMABUF ! ...