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

如何正确使用gst-rtsp-server?官方示例播放异常及OpenCV推流需求

解决Gst-RTSP-Server + OpenCV流无法在VLC播放的问题

你的问题核心出在数据尺寸不匹配、帧率配置无效、编码链路兼容性三个方面,以下是具体的排查和修改方案:

问题拆解

  1. Buffer尺寸错误:原代码中size = 385 * 288 * 2,但appsrc配置的宽度是384,导致数据长度与格式不匹配,解码器无法解析。
  2. 无效帧率配置:caps里的framerate设为0/1,下游编码元素(如x264enc)无法确定固定帧率,引发编码异常。
  3. 格式转换链路模糊:直接用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 06:15:13