"pad-added" 事件详解
"pad-added"
是 GStreamer 中一个非常重要的信号,当元素动态创建一个新的 pad(连接点)时会发出此信号。
基本概念:
-
Pad:GStreamer 中元素之间的连接点,数据通过 pad 流动
-
动态 Pad:某些元素(如 rtspsrc、decodebin)在运行时才会创建 pad,而不是在初始化时就存在
-
典型应用场景:RTSP 源、解码器等元素经常使用动态 pad
为什么需要处理 "pad-added":
-
对于像
rtspsrc
这样的源元素,你无法预先知道它会提供多少个流(视频、音频等) -
对于像
decodebin
这样的解码元素,你无法预先知道输入媒体的类型 -
必须在 pad 可用时才能建立元素间的连接
典型回调函数签名:
void callback(GstElement *src, GstPad *new_pad, gpointer user_data);
rtspsrc 的常见信号
除了 "pad-added",rtspsrc 还提供以下重要信号:
1. 连接相关信号
-
"error":发生错误时触发
void callback(GstElement *src, guint error_code, gchar *error_msg, gpointer user_data);
-
"warning":发生警告时触发
void callback(GstElement *src, guint warning_code, gchar *warning_msg, gpointer user_data);
-
"state-changed":元素状态改变时触发
void callback(GstElement *src, GstState old_state, GstState new_state, GstState pending_state, gpointer user_data);
2. 流管理信号
-
"new-stream":检测到新流时触发
void callback(GstElement *src, GstPad *pad, gpointer user_data);
-
"select-stream":允许应用程序选择特定流
gboolean callback(GstElement *src, guint stream_id, GstCaps *caps, gpointer user_data);
-
"pad-removed":当 pad 被移除时触发
void callback(GstElement *src, GstPad *pad, gpointer user_data);
3. 媒体处理信号
-
"eos":流结束时触发(End Of Stream)
void callback(GstElement *src, gpointer user_data);
-
"enough-streams":当收集到足够多流时触发
void callback(GstElement *src, gpointer user_data);
其他常用 GStreamer 元素的信号
decodebin 信号
-
"pad-added":当解码器创建新 pad 时
-
"autoplug-continue":决定是否继续自动插件
-
"autoplug-select":选择自动插件类型
-
"drained":元素已排空
appsrc 信号
-
"need-data":需要新数据时触发
-
"enough-data":有足够数据时触发
-
"seek-data":请求定位时触发
videosink 信号
-
"preroll-handoff":第一帧显示前触发
-
"handoff":每帧显示时触发
完整示例:处理多个 rtspsrc 信号
#include <gst/gst.h> // pad-added 回调 static void on_pad_added(GstElement *src, GstPad *new_pad, gpointer data) { GstElement *pipeline = (GstElement *)data; GstElement *queue = gst_bin_get_by_name(GST_BIN(pipeline), "queue"); GstPad *sink_pad = gst_element_get_static_pad(queue, "sink"); if (gst_pad_is_linked(sink_pad)) { gst_object_unref(sink_pad); return; } GstPadLinkReturn ret = gst_pad_link(new_pad, sink_pad); if (GST_PAD_LINK_FAILED(ret)) { g_printerr("Pad link failed.\n"); } gst_object_unref(sink_pad); } // 错误处理回调 static void on_error(GstElement *src, guint error_code, gchar *error_msg, gpointer user_data) { g_printerr("RTSP Error %d: %s\n", error_code, error_msg); // 可以在这里实现重连逻辑 } // 新流回调 static void on_new_stream(GstElement *src, GstPad *pad, gpointer user_data) { g_print("New stream detected on pad %s\n", GST_PAD_NAME(pad)); } // EOS回调 static void on_eos(GstElement *src, gpointer user_data) { g_print("End of stream reached\n"); // 可以在这里实现流重启逻辑 } int main(int argc, char *argv[]) { gst_init(&argc, &argv); GstElement *pipeline = gst_pipeline_new("rtsp-pipeline"); GstElement *rtspsrc = gst_element_factory_make("rtspsrc", "source"); GstElement *queue = gst_element_factory_make("queue", "queue"); // ... 其他元素创建 // 设置RTSP URL g_object_set(rtspsrc, "location", "rtsp://example.com/stream", NULL); // 添加元素到管道 gst_bin_add_many(GST_BIN(pipeline), rtspsrc, queue, /* 其他元素 */, NULL); // 连接信号 g_signal_connect(rtspsrc, "pad-added", G_CALLBACK(on_pad_added), pipeline); g_signal_connect(rtspsrc, "error", G_CALLBACK(on_error), NULL); g_signal_connect(rtspsrc, "new-stream", G_CALLBACK(on_new_stream), NULL); g_signal_connect(rtspsrc, "eos", G_CALLBACK(on_eos), NULL); // 启动管道并运行主循环... return 0; }
信号处理的最佳实践
-
保持回调简洁:不要在回调中执行耗时操作
-
线程安全:GStreamer 信号可能来自不同的线程
-
错误处理:始终处理错误信号
-
资源管理:正确管理 pad 和元素的引用计数
-
状态检查:在回调中检查管道/元素状态
理解这些信号及其用途对于构建健壮的 GStreamer 应用程序至关重要,特别是在处理网络流媒体时。