目录

Go 用 RTSPtoWeb 实现摄像头 RTSP2Web 显示

之前用原生库搭 RTSP 转 Web 的方案时,光是调 FFmpeg 转码参数、处理切片缓存就踩了不少坑。

后来发现 deepch 开源的 RTSPtoWeb 库——专门为 RTSP 转 Web 场景设计,Go 开发的轻量框架,不用写复杂转码逻辑,配个配置文件就能跑。

今天把这个“方案”记录分享给大家,希望对大家的开发有所帮助。

一、为什么推荐 RTSPtoWeb ?

核心优势:

  • 零复杂编码 :不用自己调 FFmpeg API,库内部封装了 RTSP 拉流、转码、协议转换逻辑,配置文件驱动开发;
  • 多协议支持 :同时支持转 HLS、WebRTC、WS-FLV 等 Web 友好协议,HLS 兼容所有浏览器,WebRTC 能做到毫秒级延迟;
  • 轻量高效 :Go 原生开发,启动快、内存占用低,单服务支持多摄像头并发流转;
  • 自带前端 :库内置简易播放页面,调试时不用自己写前端,正式部署可自定义页面。

整体流程比原生方案简洁太多:

配置摄像头 RTSP 地址 → 启动 RTSPtoWeb 服务 → Web 端通过协议链接播放 ,中间的转码、切片全由库搞定。

二、安装使用

本文是基于 go 1.18+ 版本开发,建议大家 go 的版本不要太低

安装 RTSPtoWeb 库

# 1. 克隆源码到本地
git clone https://github.com/deepch/RTSPtoWeb.git
cd RTSPtoWeb

# 2. 编译生成可执行文件
go build -o rtsp2web main.go

# 验证编译(生成 rtsp2web 可执行文件即成功)
ls | grep rtsp2web # 输出 rtsp2web

如果不想克隆源码,也可以用 go install 直接安装

三、核心配置

RTSPtoWeb 靠配置文件驱动,源码目录里有个默认配置 config.json,我们只需要修改“摄像头流配置”和“服务端口”即可,其他默认参数足够覆盖基础场景。

打开源码目录的 config.json,重点修改以下 3 部分(其他参数保持默认):

{
  "server": {
    "http": {
      "port": ":8080"  // Web 服务端口,默认 8080,避免占用可改 8081
    }
  },
  "streams": {  // 摄像头流配置,支持多个摄像头(新增键值对即可)
    "camera1": {  // 流名称,自定义(如 camera_lobby、camera_door)
      "url": "rtsp://admin:123456@192.168.1.100:554/stream1",  // 摄像头 RTSP 地址
      "protocols": [  // 支持转换的 Web 协议,选 1-2 个即可
        "hls",        // 兼容性最好,所有浏览器支持(延迟 2-5 秒)
        "webrtc"      // 低延迟,毫秒级(部分旧浏览器不支持)
      ],
      "hls": {
        "segment_duration": 2  // HLS 切片时长(秒),越小延迟越低
      }
    }
  }
}

为了避免大家被默认配置的冗余参数干扰,我整理了一个简化版配置,直接替换原 config.json 即可用:

{
  "server": {
    "http": {
      "port": ":8080",
      "allow_origin": "*"  // 允许跨域,前端部署在不同域名时需要
    },
    "webrtc": {
      "port": ":8081"  // WebRTC 端口,和 HTTP 端口区分开
    }
  },
  "streams": {
    "camera_lobby": {  // 大厅摄像头
      "url": "rtsp://admin:123456@192.168.1.100:554/stream1",
      "protocols": ["hls", "webrtc"],
      "hls": {
        "segment_duration": 1,  // 切片缩为 1 秒,降低延迟
        "max_segment_count": 3  // 最多保留 3 个切片,避免磁盘占满
      },
      "webrtc": {
        "ice_servers": [{"urls": ["stun:stun.l.google.com:19302"]}]  // WebRTC 穿透配置
      }
    },
    "camera_door": {  // 门口摄像头(多摄像头配置示例)
      "url": "rtsp://admin:654321@192.168.1.101:554/stream1",
      "protocols": ["hls"]
    }
  }
}
  • RTSP 地址格式:一般摄像头说明书会写,格式为 rtsp://用户名:密码@摄像头IP:端口/流路径

  • 多摄像头:在 streams 里新增键值对(如 camera_door)即可;

  • 协议选择:只需要兼容所有浏览器选 hls,需要低延迟选 webrtc

四、启动服务 & Web 播放

配置好之后,启动服务和播放都很简单,甚至不用自己写前端(库内置调试页面)。

在源码目录执行以下命令,启动服务(确保配置文件 config.json 在当前目录):

# 启动服务(默认读取当前目录的 config.json)
./rtsp2web -config config.json

# 启动成功会输出类似日志
# 2025/12/20 10:00:00 HTTP server started on :8080
# 2025/12/20 10:00:00 WebRTC server started on :8081
# 2025/12/20 10:00:00 Stream camera_lobby started

服务启动后,直接打开浏览器访问 http://服务器IP:8080,就能看到库内置的调试页面,不用写一行前端代码:

  1. 页面下拉找到“Streams”区域,选择要播放的摄像头(如 camera_lobby);

  2. 选择播放协议(HLS 或 WebRTC),点击“Play”按钮,就能看到实时画面;

  3. 调试页面还能查看流状态、切换协议,非常方便。

参考图示:

/img/go-rstp-2-web/1.png
摄像头展示

五、自定义播放器

内置页面只适合调试,正式部署需要自定义前端。

这里提供 HLS 和 WebRTC 两种协议的播放代码,直接嵌入自己的页面即可。

HLS 协议播放(兼容性最好)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>大厅摄像头监控</title>
  <style>video { width: 80%; max-width: 1280px; margin: 50px auto; display: block; }</style>
</head>
<body>
  <video id="hlsPlayer" controls autoplay muted playsinline>

    <source src="http://192.168.1.10:8080/hls/camera_lobby.m3u8" type="application/x-mpegURL">
    您的浏览器不支持 HLS 播放,请升级浏览器。
  </video>
</body>
</html>

WebRTC 协议播放(低延迟)

WebRTC 需要简单的 JS 逻辑建立连接,依赖库内置的信号服务:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>门口摄像头监控(低延迟)</title>
  <style>video { width: 80%; max-width: 1280px; margin: 50px auto; display: block; }</style>
</head>
<body>
  <video id="webrtcPlayer" autoplay muted playsinline></video>

  <script>
    // 1. 建立 WebSocket 连接(信号服务)
    const ws = new WebSocket('ws://192.168.1.10:8080/webrtc/camera_door');
    const video = document.getElementById('webrtcPlayer');

    // 2. 接收 WebRTC 配置并播放
    ws.onmessage = async (event) => {
      const data = JSON.parse(event.data);
      if (data.type === 'offer') {
        // 创建 RTCPeerConnection
        const pc = new RTCPeerConnection({
          iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
        });

        // 接收视频流
        pc.ontrack = (e) => { video.srcObject = e.streams[0]; };

        // 响应 offer
        await pc.setRemoteDescription(new RTCSessionDescription(data));
        const answer = await pc.createAnswer();
        await pc.setLocalDescription(answer);

        // 发送 answer 给服务端
        ws.send(JSON.stringify({ type: 'answer', sdp: pc.localDescription.sdp }));

        // 处理 ICE 候选
        pc.onicecandidate = (e) => {
          if (e.candidate) {
            ws.send(JSON.stringify({ type: 'candidate', candidate: e.candidate }));
          }
        };
      } else if (data.type === 'candidate') {
        // 添加 ICE 候选
        await pc.addIceCandidate(new RTCIceCandidate(data.candidate));
      }
    };
  </script>
</body>
</html>

常见问题

Q1. 启动服务报错“invalid RTSP URL”?

问题原因:RTSP 地址格式错误、用户名密码错误,或摄像头未联网。

解决方案

  • 用 FFmpeg 命令验证 RTSP 地址有效性:ffmpeg -i rtsp://admin:123456@192.168.1.100:554/stream1 -vcodec copy -f mp4 test.mp4,能生成视频文件说明地址正常;

  • 检查摄像头 IP 是否能 ping 通:ping 192.168.1.100,不通则检查摄像头网络配置;

  • 登录摄像头管理后台,确认 RTSP 端口(默认 554)已开放,且“匿名访问”或“用户名密码”正确。

Q2. 浏览器访问 http://IP:8080 打不开?

问题原因:端口被占用,或防火墙拦截。

解决方案

  • 更换端口:修改 config.json 里 server.http.port:8081,重新启动服务;

  • 检查端口占用(Linux):netstat -tulpn | grep 8080,杀死占用进程:kill -9 进程ID

  • 开放防火墙端口(Linux):sudo ufw allow 8080/tcp,Windows 在“防火墙高级设置”里添加端口规则。

Q3. HLS 播放延迟很高(超过 5 秒)?

问题原因:默认切片时长和缓存过多,HLS 天生延迟比 WebRTC 高。

解决方案

  • 缩小切片时长:修改 config.json 里 hls.segment_duration 为 1(最小 1 秒);

  • 减少缓存切片数:添加 "max_segment_count": 2 到 hls 配置里,只保留 2 个切片;

  • 前端添加低延迟属性:<video id="hlsPlayer" controls autoplay muted playsinline lowlatency>

  • 极致低延迟需求:改用 WebRTC 协议,延迟可降到 100-500 毫秒。

Q4. 多摄像头配置后,部分流无法播放?

问题原因:摄像头 RTSP 端口冲突,或服务资源不足。

解决方案

  • 确认每个摄像头的 RTSP 端口不同(部分摄像头默认都是 554,可在管理后台修改);

  • 降低单个流的比特率:如果摄像头支持,在管理后台将分辨率从 1080P 降到 720P,减少服务压力;

  • 检查服务日志:启动服务时添加日志参数 ./rtsp2web -config config.json -log debug,查看具体流的报错信息。

Q5. WebRTC 播放时画面卡顿、频繁断连?

问题原因:网络穿透失败(内网可以播放,外网不行),或带宽不足。

解决方案

  • 优化穿透配置:在 config.json 的 webrtc 里添加多个 STUN/TURN 服务器(推荐用阿里云 TURN 服务,需申请);

  • 检查带宽:确保服务器上行带宽 ≥ 每个流比特率 × 摄像头数量(720P 流约 1Mbps,4 个摄像头需 4Mbps 以上);

  • 内网测试:先在同一网段的电脑上播放,排除外网穿透问题,再处理公网访问。

总结

RTSPtoWeb 库把复杂的 RTSP 转 Web 逻辑封装得非常好,基础场景下配个 config.json 就能用,比原生开发效率高太多。

实际部署时,可以再做这些优化:

  1. 权限控制:内置页面只用于调试,正式环境要给 Web 服务加登录验证(如用 Go 的 gin 框架加 JWT 认证)。

  2. 后台运行:Linux 下用 nohup ./rtsp2web -config config.json & 让服务后台运行,日志输出到 nohup.out。

  3. 容器化部署:源码目录有 Dockerfile,直接打包成 Docker 镜像,避免环境依赖问题。

  4. 监控告警:用 Prometheus + Grafana 监控服务状态,流断连时通过邮件/短信告警。

如果你的需求是快速实现摄像头 Web 显示,且不想折腾转码逻辑,RTSPtoWeb 绝对是首选。

亲测可用。如果有其他特殊场景,欢迎在评论区交流~

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-rstp-2-web/

备用原文链接: https://blog.fiveyoboy.com/articles/go-rstp-2-web/