Windows下如何用Gst-RTSP-Server结合OpenCV C++实现RTSP推流?
嘿,我看你已经有GStreamer RTSP推流和OpenCV UDP推流的基础了,那咱们直接解决用OpenCV的cv::Mat帧推RTSP的问题,给你两个实用方案,重点推荐第一个,因为和你之前用的gst-rtsp-server逻辑衔接更顺畅:
方案一:基于gst-rtsp-server自定义媒体工厂(推荐)
这个方案是把gst-rtsp-server的示例逻辑和OpenCV结合,用appsrc作为数据源,手动把OpenCV的帧推送到GStreamer管道里,稳定性和灵活性都更好。
完整代码示例
#include <gst/gst.h> #include <gst/rtsp-server/rtsp-server.h> #include <opencv2/opencv.hpp> using namespace cv; static GstElement *appsrc = nullptr; static VideoCapture cap; // 当GStreamer需要数据时触发的回调,负责从OpenCV获取帧并推送 static void need_data(GstElement *src, guint size, gpointer user_data) { Mat frame; cap >> frame; if (frame.empty()) { // 视频结束,发送EOS信号终止流 gst_element_send_event(src, gst_event_new_eos()); return; } // 把OpenCV的BGR格式转成GStreamer常用的I420格式 Mat frame_converted; cvtColor(frame, frame_converted, COLOR_BGR2YUV_I420); // 创建GStreamer缓冲区并复制帧数据 GstBuffer *buffer = gst_buffer_new_allocate(nullptr, frame_converted.total() * frame_converted.elemSize(), nullptr); GstMapInfo map; gst_buffer_map(buffer, &map, GST_MAP_WRITE); memcpy(map.data, frame_converted.data, map.size); gst_buffer_unmap(buffer, &map); // 设置时间戳,保证播放器同步(30fps的话每帧时长约33ms) GstClockTime timestamp = gst_util_get_timestamp(); GST_BUFFER_PTS(buffer) = timestamp; GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, 30); // 把缓冲区推送到appsrc GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(src), buffer); if (ret != GST_FLOW_OK) { g_printerr("推送帧失败: %s\n", gst_flow_get_name(ret)); } // 控制帧率,和视频原帧率匹配 cv::waitKey(30); // 同时显示原帧(可选) imshow("OpenCV Source Frame", frame); } int main(int argc, char *argv[]) { // 初始化GStreamer和OpenCV gst_init(&argc, &argv); cv::namedWindow("OpenCV Source Frame", WINDOW_AUTOSIZE); // 打开视频文件(换成0可以调用摄像头) cap.open("Wildlife.mp4"); if (!cap.isOpened()) { g_printerr("无法打开视频源!\n"); return -1; } // 创建RTSP服务器实例 GstRTSPServer *server = gst_rtsp_server_new(); gst_rtsp_server_set_service(server, "8554"); // 设置RTSP端口,默认8554 // 创建媒体映射,用于绑定路径和媒体工厂 GstRTSPMediaMapping *mapping = gst_rtsp_server_get_media_mapping(server); GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new(); // 定义GStreamer管道:appsrc -> 格式转换 -> H.264编码 -> RTP打包 // 这里用x264enc的zerolatency调优参数,适合实时推流 gst_rtsp_media_factory_set_launch(factory, "( appsrc name=source is-live=true format=GST_FORMAT_TIME " "! videoconvert ! video/x-raw,format=I420,width=640,height=360,framerate=30/1 " "! x264enc tune=zerolatency bitrate=500 speed-preset=superfast " "! rtph264pay name=pay0 pt=96 )"); // 设置共享模式,允许多个客户端同时连接 gst_rtsp_media_factory_set_shared(factory, TRUE); // 当媒体配置完成时,获取appsrc并绑定need-data回调 g_signal_connect(factory, "media-configure", G_CALLBACK([](GstRTSPMediaFactory *factory, GstRTSPMedia *media, gpointer user_data) { GstElement *element = gst_rtsp_media_get_element(media); appsrc = gst_bin_get_by_name(GST_BIN(element), "source"); g_signal_connect(appsrc, "need-data", G_CALLBACK(need_data), nullptr); g_object_unref(element); }), nullptr); // 把媒体工厂绑定到RTSP路径/test gst_rtsp_media_mapping_add_factory(mapping, "/test", factory); g_object_unref(mapping); // 启动服务器 gst_rtsp_server_attach(server, nullptr); g_print("RTSP服务器已启动,播放地址:rtsp://localhost:8554/test\n"); // 启动GStreamer主循环 GMainLoop *loop = g_main_loop_new(nullptr, FALSE); g_main_loop_run(loop); // 清理资源 g_main_loop_unref(loop); g_object_unref(server); cap.release(); cv::destroyAllWindows(); return 0; }
编译命令
确保你的系统安装了gstreamer-1.0、gstreamer-rtsp-server-1.0和OpenCV开发包,然后用以下命令编译:
g++ -o opencv_rtsp_pusher opencv_rtsp_pusher.cpp `pkg-config --cflags --libs gstreamer-1.0 gstreamer-rtsp-server-1.0 opencv4`
关键说明
- 用
appsrc作为GStreamer的数据源,它允许我们手动推送帧数据,完美适配OpenCV的cv::Mat - 转换帧格式时,把OpenCV默认的BGR转成I420,这是GStreamer处理视频的通用格式
x264enc的tune=zerolatency参数是实时推流的关键,能大幅降低延迟- 时间戳的设置很重要,否则播放器可能出现卡顿或音视频不同步
方案二:用OpenCV VideoWriter直接推RTSP(简易版)
如果你想快速实现,也可以用OpenCV的VideoWriter结合GStreamer的RTSP sink,但这个方案依赖GStreamer的rtspclientsink,需要你先启动一个RTSP服务器(比如用gst-launch-1.0临时启动)。
步骤1:启动临时RTSP服务器
先在终端运行这个命令,启动一个接收UDP流并转为RTSP的服务器:
gst-launch-1.0 udpsrc port=5004 ! application/x-rtp,payload=96 ! rtph264depay ! h264parse ! rtspclientsink location=rtsp://localhost:8554/test
步骤2:OpenCV推流代码
修改你原来的UDP推流代码,把GStreamer管道改成推送到上面的UDP端口:
#include <opencv2/opencv.hpp> using namespace cv; int main(int argc, char* argv[]) { VideoCapture cap("Wildlife.mp4"); if (!cap.isOpened()) { printf("无法打开视频!\n"); return -1; } // 用H.264编码推送到UDP,再由临时RTSP服务器转成RTSP流 VideoWriter out = VideoWriter( "appsrc ! queue ! videoconvert ! video/x-raw, format=I420, width=640, height=360, framerate=30/1 " "! x264enc tune=zerolatency ! rtph264pay ! udpsink host=127.0.0.1 port=5004", CAP_GSTREAMER, 0, 30, Size(640, 360) ); if (!out.isOpened()) { printf("VideoWriter初始化失败!\n"); return -1; } Mat frame; while (cap.read(frame)) { if (frame.empty()) break; out.write(frame); imshow("Frame", frame); waitKey(30); } cap.release(); out.release(); destroyAllWindows(); return 0; }
说明
这个方案更简单,但需要额外启动一个中间RTSP服务器,稳定性不如方案一,适合快速测试。
注意事项
- 确保安装了GStreamer的H.264编码插件(Ubuntu下是
gstreamer1.0-plugins-ugly,Windows下需要在安装GStreamer时勾选对应组件) - 调整分辨率、帧率参数时,要和视频源(文件/摄像头)的实际参数匹配,否则会出现格式不兼容
- 如果用摄像头,把
cap.open("Wildlife.mp4")改成cap.open(0)即可
内容的提问来源于stack exchange,提问作者A.k.
相关产品推荐
相关产品推荐

