如何正确使用gst-rtsp-server?官方示例播放异常及OpenCV推流需求
解决Gst-RTSP-Server + OpenCV流无法在VLC播放的问题
你的问题核心出在数据尺寸不匹配、帧率配置无效、编码链路兼容性三个方面,以下是具体的排查和修改方案:
问题拆解
- Buffer尺寸错误:原代码中
size = 385 * 288 * 2,但appsrc配置的宽度是384,导致数据长度与格式不匹配,解码器无法解析。 - 无效帧率配置:caps里的
framerate设为0/1,下游编码元素(如x264enc)无法确定固定帧率,引发编码异常。 - 格式转换链路模糊:直接用
videoconvert转换RGB16到x264enc支持的格式,兼容性差;x264enc对I420(YUV420P)格式支持最稳定,但需严格匹配数据尺寸。
具体修改方案
1. 对齐数据格式与Buffer尺寸
OpenCV输出的图像默认是BGR格式(CV_8UC3),直接在appsrc中配置BGR格式,让videoconvert自动转换为x264enc需要的I420,同时Buffer尺寸设为width * height * 3(BGR每个像素占3字节)。
2. 配置固定帧率
将caps中的framerate设为固定值(如25/1),同步调整时间戳递增逻辑,确保与帧率匹配。
3. 优化编码参数
给x264enc添加speed-preset=ultrafast(降低编码延迟)、tune=zerolatency(适配实时流)参数,避免编码兼容性问题。
4. 适配OpenCV图像输入
在need_data回调中直接读取OpenCV帧,复制到GstBuffer中,确保数据格式与appsrc配置一致。
修改后的完整代码
#include <gst/gst.h> #include <gst/rtsp-server/rtsp-server.h> #include <opencv2/opencv.hpp> typedef struct { cv::VideoCapture cap; GstClockTime timestamp; guint width; guint height; guint fps; } MyContext; /* 当appsrc需要数据时触发 */ static void need_data (GstElement * appsrc, guint unused, MyContext * ctx) { GstBuffer *buffer; GstFlowReturn ret; cv::Mat frame; // 读取OpenCV帧,循环播放(如果是视频文件) if (!ctx->cap.read(frame)) { ctx->cap.set(cv::CAP_PROP_POS_FRAMES, 0); ctx->cap.read(frame); } // 确保帧尺寸与配置一致 cv::resize(frame, frame, cv::Size(ctx->width, ctx->height)); // 计算BGR格式的Buffer大小 guint size = ctx->width * ctx->height * 3; buffer = gst_buffer_new_allocate(NULL, size, NULL); // 将OpenCV数据复制到GstBuffer GstMapInfo map; gst_buffer_map(buffer, &map, GST_MAP_WRITE); memcpy(map.data, frame.data, size); gst_buffer_unmap(buffer, &map); // 设置时间戳,与帧率同步 GST_BUFFER_PTS(buffer) = ctx->timestamp; GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, ctx->fps); ctx->timestamp += GST_BUFFER_DURATION(buffer); // 推送Buffer到appsrc g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret); gst_buffer_unref(buffer); if (ret != GST_FLOW_OK) { g_warning("推送Buffer失败: %s", gst_flow_return_get_name(ret)); } } /* 媒体管道初始化时配置appsrc */ static void media_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media, gpointer user_data) { GstElement *element, *appsrc; MyContext *ctx; element = gst_rtsp_media_get_element(media); appsrc = gst_bin_get_by_name_recurse_up(GST_BIN(element), "mysrc"); // 配置appsrc使用时间戳模式 gst_util_set_object_arg(G_OBJECT(appsrc), "format", "time"); // 初始化上下文参数(可替换为自己的分辨率、帧率、视频路径/摄像头ID) ctx = g_new0(MyContext, 1); ctx->width = 640; ctx->height = 480; ctx->fps = 25; ctx->timestamp = 0; // 打开视频源:0为默认摄像头,也可替换为视频文件路径(如"./test.mp4") if (!ctx->cap.open(0)) { g_error("无法打开视频捕获设备"); g_free(ctx); return; } // 设置appsrc的Caps,匹配OpenCV输出的BGR格式 g_object_set(G_OBJECT(appsrc), "caps", gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGR", "width", G_TYPE_INT, ctx->width, "height", G_TYPE_INT, ctx->height, "framerate", GST_TYPE_FRACTION, ctx->fps, 1, NULL), NULL); // 绑定上下文,释放时清理资源 g_object_set_data_full(G_OBJECT(media), "my-extra-data", ctx, (GDestroyNotify) [](MyContext* ctx) { ctx->cap.release(); g_free(ctx); }); // 绑定数据回调 g_signal_connect(appsrc, "need-data", (GCallback) need_data, ctx); gst_object_unref(appsrc); gst_object_unref(element); } int main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; // 初始化GStreamer和OpenCV gst_init(&argc, &argv); cv::initModule_highgui(); loop = g_main_loop_new(NULL, FALSE); // 创建RTSP服务器实例 server = gst_rtsp_server_new(); mounts = gst_rtsp_server_get_mount_points(server); // 构建媒体管道:appsrc -> 格式转换 -> 实时编码 -> RTP打包 factory = gst_rtsp_media_factory_new(); gst_rtsp_media_factory_set_launch(factory, "( appsrc name=mysrc ! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency ! rtph264pay name=pay0 pt=96 )"); // 绑定管道配置回调 g_signal_connect(factory, "media-configure", (GCallback) media_configure, NULL); // 挂载到/test路径 gst_rtsp_mount_points_add_factory(mounts, "/test", factory); g_object_unref(mounts); // 启动服务器 gst_rtsp_server_attach(server, NULL); g_print("流已就绪:rtsp://127.0.0.1:8554/test\n"); g_main_loop_run(loop); return 0; }
编译运行说明
编译时需要链接GStreamer和OpenCV库,示例编译命令:
gcc -o rtsp_opencv rtsp_opencv.c `pkg-config --cflags --libs gstreamer-1.0 gstreamer-rtsp-server-1.0 opencv4`
运行后用VLC打开rtsp://127.0.0.1:8554/test即可播放。
内容的提问来源于stack exchange,提问作者tms2003
相关产品推荐
相关产品推荐

