You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

错误原因分析

  1. 全局Pad变量未初始化:video_pad和audio_pad仅全局声明未赋值,调用gst_pad_link时传入空指针,触发GStreamer断言失败。
  2. 音视频Pad判断逻辑不可靠:用全局temp变量按顺序判断音视频pad的方式,无法适配不同MKV文件的pad出现顺序,且未实际识别pad类型。
  3. 资源泄漏:调用gst_element_get_static_pad获取pad后未调用gst_object_unref释放引用,会导致内存泄漏。
  4. 信号回调参数未利用: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:20:59