Ubuntu下GStreamer C程序Demux视频Pad链接失败求助
GStreamer MKV音视频解复用播放程序故障排查
问题现象
编译无错误,运行时出现以下报错并崩溃:
0:00:00.031117832 17158 0x616a13c34100 WARN basesrc gstbasesrc.c:3688:gst_base_src_start_complete: pad not activated yet
Received new pad 'video_0' from 'demux':
Entered the vid pad
(clock1:17158): GStreamer-CRITICAL **: 01:52:14.180: gst_pad_link_full: assertion 'GST_IS_PAD (sinkpad)' failed
** (clock1:17158): ERROR **: 01:52:14.181: Failed to link demux video pad to video queue pad. Exiting.
Trace/breakpoint trap (core dumped)
错误原因分析
- 全局Pad变量未初始化:
video_pad和audio_pad仅全局声明未赋值,调用gst_pad_link时传入空指针,触发GStreamer断言失败。 - 音视频Pad判断逻辑不可靠:用全局
temp变量按顺序判断音视频pad的方式,无法适配不同MKV文件的pad出现顺序,且未实际识别pad类型。 - 资源泄漏:调用
gst_element_get_static_pad获取pad后未调用gst_object_unref释放引用,会导致内存泄漏。 - 信号回调参数未利用:
pad-added回调的data参数未传入有效对象,代码依赖全局变量,耦合性高且易出错。
修复后的完整代码
#include <gst/gst.h> GstElement *pipeline, *source, *demux, *audio_queue, *audio_decode, *audio_convert, *video_queue, *video_decode, *video_convert, *video_overlay, *audio_sink, *video_sink; static void pad_added_callback(GstElement *src, GstPad *new_pad, gpointer data) { GstPad *sink_pad = NULL; GstCaps *new_pad_caps = NULL; GstStructure *new_pad_struct = NULL; const gchar *new_pad_type = NULL; g_print("Received new pad '%s' from '%s':\n", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(src)); // 获取新pad的caps信息 new_pad_caps = gst_pad_get_current_caps(new_pad); new_pad_struct = gst_caps_get_structure(new_pad_caps, 0); new_pad_type = gst_structure_get_name(new_pad_struct); // 判断pad类型并链接到对应队列 if (g_str_has_prefix(new_pad_type, "audio/x-raw")) { g_print("识别到音频Pad,链接到audio_queue\n"); sink_pad = gst_element_get_static_pad(audio_queue, "sink"); if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK) { g_error("音频Pad链接失败"); } gst_object_unref(sink_pad); } else if (g_str_has_prefix(new_pad_type, "video/x-raw")) { g_print("识别到视频Pad,链接到video_queue\n"); sink_pad = gst_element_get_static_pad(video_queue, "sink"); if (gst_pad_link(new_pad, sink_pad) != GST_PAD_LINK_OK) { g_error("视频Pad链接失败"); } gst_object_unref(sink_pad); } else { g_print("忽略非音视频Pad: %s\n", new_pad_type); } // 释放caps资源 if (new_pad_caps != NULL) { gst_caps_unref(new_pad_caps); } } int main(int argc, char *argv[]) { GstBus *bus; GstMessage *msg; // 初始化GStreamer gst_init(&argc, &argv); // 创建管道和元素 pipeline = gst_pipeline_new("pipeline"); source = gst_element_factory_make("filesrc", "source"); demux = gst_element_factory_make("matroskademux", "demux"); audio_queue = gst_element_factory_make("queue", "audio_queue"); audio_decode = gst_element_factory_make("decodebin", "audio_decode"); audio_convert = gst_element_factory_make("audioconvert", "audio_convert"); audio_sink = gst_element_factory_make("autoaudiosink", "audio_sink"); video_queue = gst_element_factory_make("queue", "video_queue"); video_decode = gst_element_factory_make("decodebin", "video_decode"); video_convert = gst_element_factory_make("videoconvert", "video_convert"); video_overlay = gst_element_factory_make("clockoverlay", "video_overlay"); video_sink = gst_element_factory_make("autovideosink", "video_sink"); // 检查元素创建是否成功 if (!pipeline || !source || !demux || !audio_queue || !audio_decode || !audio_convert || !audio_sink || !video_queue || !video_decode || !video_convert || !video_overlay || !video_sink) { g_error("元素创建失败,退出程序"); return -1; } // 设置文件路径 g_object_set(source, "location", "/home/lg/ml/sintel_video.mkv", NULL); // 将元素添加到管道 gst_bin_add_many(GST_BIN(pipeline), source, demux, audio_queue, audio_decode, audio_convert, audio_sink, video_queue, video_decode, video_convert, video_overlay, video_sink, NULL); // 链接固定元素 gst_element_link(source, demux); gst_element_link_many(audio_queue, audio_decode, audio_convert, audio_sink, NULL); gst_element_link_many(video_queue, video_decode, video_convert, video_overlay, video_sink, NULL); // 监听demux的pad-added信号 g_signal_connect(demux, "pad-added", G_CALLBACK(pad_added_callback), NULL); // 启动管道 gst_element_set_state(pipeline, GST_STATE_PLAYING); // 监听总线消息 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) { GError *err; gchar *debug_info; switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &debug_info); g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(msg->src), err->message); g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error(&err); g_free(debug_info); break; case GST_MESSAGE_EOS: g_print("End-Of-Stream reached.\n"); break; default: g_printerr("Unexpected message received.\n"); break; } gst_message_unref(msg); } // 释放资源 gst_object_unref(bus); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); return 0; }
关键修复点
- 移除未初始化的全局Pad变量:直接通过
gst_element_get_static_pad获取队列的sink pad,避免空指针问题。 - 基于Caps类型判断音视频Pad:用
g_str_has_prefix检查pad的caps类型,替代不可靠的顺序判断逻辑,适配不同MKV文件的pad顺序。 - 释放Pad引用:获取sink pad后调用
gst_object_unref释放,避免内存泄漏。 - 完善总线消息处理:添加错误消息解析,方便后续调试。
内容的提问来源于stack exchange,提问作者Muthulakshimi
相关产品推荐
相关产品推荐

