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

如何用GStreamer的C代码显式调用rtspsrc读取RTSP流?代码问题求助

使用GStreamer C代码显式调用rtspsrc读取RTSP流的问题解决与示例

你的代码核心问题

你编写的代码中rtspsrc元素未被添加到pipeline中,这是pad_added_handler从未触发的根本原因。gst_bin_add_many仅添加了解码、显示环节的元素,却遗漏了作为输入源的rtspsrc——未加入管道的元素不会被激活,自然不会创建动态Pad并发送pad-added信号。

另外还有一处逻辑瑕疵:你的Pad处理函数仅判断了audio/x-raw类型,但RTSP流输出的是RTP封装的H.265流,实际类型为application/x-rtp,需要调整判断逻辑以精准匹配目标流。

修正后的完整代码

#include <gst/gst.h>

static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *rtph265depay);

int main(int argc, char *argv[]) {
    GstBus *bus;
    GstMessage *msg;
    GstStateChangeReturn ret;
    gboolean terminate = FALSE;

    /* Initialize GStreamer */
    gst_init (&argc, &argv);

    GstElement *pipeline = gst_pipeline_new ("rtsp-pipeline");
    if (!pipeline) {
        g_printerr ("Pipeline could not be created. Exiting.\n");
        return -1;
    }

    // input
    GstElement *rtspsrc = gst_element_factory_make("rtspsrc", "rtspsrc");
    g_object_set (G_OBJECT (rtspsrc), "location", "rtsp://192.168.1.88:554/11", "latency", 10, NULL);

    // decoding
    GstElement *rtph265depay = gst_element_factory_make("rtph265depay", "rtph265depay");
    GstElement *h265parse = gst_element_factory_make("h265parse", "h265parse");
    GstElement *avdec_h265 = gst_element_factory_make("avdec_h265", "avdec_h265");

    // display
    GstElement *videoconvert = gst_element_factory_make("videoconvert", "videoconvert_screen");
    GstElement *sink = gst_element_factory_make("autovideosink", "nvvideo_renderer");

    // 修正:将rtspsrc添加到pipeline
    gst_bin_add_many(GST_BIN(pipeline), rtspsrc, rtph265depay, h265parse, avdec_h265, videoconvert, sink, NULL);
    if (!gst_element_link_many(rtph265depay, h265parse, avdec_h265, videoconvert, sink, NULL)) {
        g_printerr("Elements could not be linked. Exiting.\n");
        return -1;
    }

    // 注册Pad创建回调
    g_signal_connect (rtspsrc, "pad-added", G_CALLBACK (pad_added_handler), rtph265depay);


    /* 启动管道 */
    ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr ("Unable to set the pipeline to the playing state.\n");
        gst_object_unref (pipeline);
        return -1;
    }

    /* 监听总线消息 */
    bus = gst_element_get_bus (pipeline);
    do {
        msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
            GST_MESSAGE_STATE_CHANGED | 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);
                terminate = TRUE;
                break;
            case GST_MESSAGE_EOS:
                g_print ("End-Of-Stream reached.\n");
                terminate = TRUE;
                break;
            case GST_MESSAGE_STATE_CHANGED:
            /* 仅关注管道自身的状态变化 */
            if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) {
                GstState old_state, new_state, pending_state;
                gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
                g_print ("Pipeline state changed from %s to %s:\n",
                    gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
            }
            break;
            default:
                /* 忽略其他无关消息 */
                break;
      }
      gst_message_unref (msg);
    }
  } while (!terminate);

  /* 释放资源 */
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  return 0;
}

static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *rtph265depay) {
    GstPad *sink_pad = gst_element_get_static_pad (rtph265depay, "sink");
    GstPadLinkReturn ret;
    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));

    /* 如果解封装器已链接,直接返回 */
    if (gst_pad_is_linked (sink_pad)) {
        g_print ("We are already linked. Ignoring.\n");
        goto exit;
    }

    /* 检查Pad的流类型 */
    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);
    
    // 修正:精准匹配H.265的RTP流
    if (!g_str_has_prefix (new_pad_type, "application/x-rtp") || 
        !g_str_has_suffix (gst_structure_get_string(new_pad_struct, "media"), "video") ||
        !g_str_has_prefix (gst_structure_get_string(new_pad_struct, "encoding-name"), "H265")) {
        g_print ("It has type '%s' which is not H.265 RTP. Ignoring.\n", new_pad_type);
        goto exit;
    }

    /* 尝试链接Pad */
    ret = gst_pad_link (new_pad, sink_pad);
    if (GST_PAD_LINK_FAILED (ret)) {
        g_print ("Type is '%s' but link failed.\n", new_pad_type);
    } else {
        g_print ("Link succeeded (type '%s').\n", new_pad_type);
    }

exit:
    /* 释放Pad的caps引用 */
    if (new_pad_caps != NULL)
        gst_caps_unref (new_pad_caps);

    /* 释放sink pad引用 */
    gst_object_unref (sink_pad);
}

关键注意事项

  • 所有元素必须加入pipeline:任何需要参与管道运行的元素,都要通过gst_bin_add或gst_bin_add_many加入pipeline,否则不会被激活。
  • 动态Pad的处理逻辑:rtspsrc是动态Pad元素,只有成功连接RTSP服务器并获取流信息后才会创建src Pad,必须通过pad-added信号动态链接后续元素。
  • 流类型精准匹配:根据实际流的编码格式调整Pad类型判断逻辑,避免错误链接音频或其他非目标流。

内容的提问来源于stack exchange,提问作者Roberto Carlos Cruz Rodríguez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:25:19