如何用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
相关产品推荐
相关产品推荐

