HTML5原生不支持RTSP,需服务端转协议;推荐FFmpeg+Nginx-rtmp转HTTP-FLV,延迟1–3秒,兼容性好,前端用flv.js播放;HLS延迟高(≥10秒),WebRTC延迟最低但部署复杂。

HTML5 原生不支持 RTSP,必须转协议
浏览器(包括所有 HTML5 实现)从底层就不支持 RTSP 协议。你直接在 标签里写 src="rtsp://..." 一定失败,控制台会报 MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED 或直接静默无响应。
根本原因是:RTSP 是控制协议,不定义媒体封装格式;而 HTML5 只接受 HTTP(S) 传输的 MP4/WebM/FLV(需配合 MSE)等可随机访问、有明确时间戳和索引的格式。
- RTSP 流通常来自 IPC 摄像头,原始输出是 H.264/H.265 + AAC/G.711 的裸流或 RTP 包
- 浏览器无法解析 RTP 包,也不能处理 RTSP 的 SETUP/PLAY 交互
- 所以必须在服务端做协议转换:把 RTSP → HTTP-FLV / HLS / WebRTC / MSE-compatible fragmented MP4
推荐方案:用 FFmpeg + Nginx-rtmp-module 转成 HTTP-FLV
这是目前延迟最低(1–3 秒)、兼容性最好、前端最省事的方案。HTTP-FLV 可通过 fetch + MediaSource + flv.js 播放,无需后端信令或 WebSocket。
关键步骤:
立即学习“前端免费学习笔记(深入)”;
- 安装
ffmpeg,运行命令拉流并推到本地 Nginx-rtmp 服务器:ffmpeg -i "rtsp://192.168.1.100:554/stream" -c copy -f flv rtmp://127.0.0.1:1935/live/stream1 - Nginx 配置启用
rtmp模块,并开启http_flv:application live { live on; http_flv on; } - 前端用
flv.js加载:const flvPlayer = flvjs.createPlayer({ type: 'flv', isLive: true, url: 'http://localhost:8080/live/stream1.flv' }); - 注意:
flv.js不支持 H.265,若摄像头输出 H.265,必须加-c:v libx264转码
替代方案对比:HLS vs WebRTC vs MSE-raw
选型要看延迟容忍度和终端覆盖范围:
-
HLS(.m3u8):iOS/macOS 原生支持,但延迟高(通常 ≥10 秒),且需要切片器(如ffmpeg -f hls或nginx-http-flv-module的 HLS 模块)。Safari 不能用 MSE 加载 HLS,只能靠原生 -
WebRTC:延迟最低(RTCPeerConnection,服务端需支持 WebRTC 接入(如mediasoup、Janus)。对 RTSP 源需额外做 RTP → WebRTC 封装 -
MSE + 自定义解复用:用ffmpeg.wasm在浏览器内转码 RTSP?不可行——RTSP 需要 TCP/RTP socket,WebAssembly 无法直接建 RTP 连接;纯 JS 解析 RTP 包性能差且不实用
容易被忽略的坑:跨域、CORS、HTTPS 混合内容、时间戳对齐
即使协议转对了,播放仍可能失败,常见卡点:
-
flv.js加载时浏览器报Cross-Origin Read Blocking (CORB)?确保 Nginx 返回Access-Control-Allow-Origin: *,且flv.js的withCredentials设为false(默认) - 页面是
https://,但 FLV 地址是http://?现代浏览器禁止混合内容,必须全站 HTTPS,或用自签名证书跑本地https://localhost - 画面卡顿/音画不同步?检查 RTSP 源的时间戳(PTS/DTS)是否连续;
ffmpeg转发时加-fflags +genpts强制生成 PTS - 某些海康/NVR 设备 RTSP URL 含特殊参数(如
channel=1&subtype=0),URL 必须完整编码,否则ffmpeg解析失败
真正麻烦的从来不是“怎么播”,而是“怎么让每一帧都按时、按序、不丢包地送进 MediaSource”。协议转换链路上任意一环的时间戳错位或缓冲区溢出,都会导致花屏或卡死——这点在低码率移动网络下尤其明显。










