简介:这是一份基于 Vue 的 webrtc-streamer 前端演示代码,面向需要将 RTSP 视频流接入网页的开发者,尤其适合刚接触 WebRTC 实时视频通信、希望快速跑通播放链路的初中级前端人员。资源包共 2015 个文件,以 704 个 js 脚本、1134 个 md 说明文档、150 个 json 配置为主,另含少量 html、xml 与 txt,压缩包约 25.86MB,整体结构便于按模块查阅。代码默认展示四个视频窗口,运行前需配置 RTSP 地址并启动 webrtc-streamer.exe 推流服务,配合 Node 16 即可直接运行,内置依赖库省去繁琐安装。已有 550 人学习下载。通过这份 demo,读者可以理解 RTSP 转 WebRTC 流的完整前端接入方式、视频元素与流地址的绑定逻辑,并以此为骨架扩展多路播放、控件布局与前后端交互,是入门实时视频展示的实用参考。
1. 从 RTSP 到浏览器:这个 Vue 前端 Demo 到底解决了什么问题
如果你手头有一台 IP 摄像头,RTSP 地址在 VLC 里跑得好好的,但老板突然说“把它嵌到我们后台管理系统的网页里”,你就知道这事有多别扭了。浏览器原生不支持 RTSP,直接<video src="rtsp://...">是行不通的。这个项目就是一个专门用来打通这条链路的 Vue 前端 Demo——后端用 webrtc-streamer 把 RTSP 转成 WebRTC 流,前端用 Vue 封装播放器组件,最终在浏览器里实现低延迟的实时视频预览。
它适合两类人:一是正在做安防监控、工业巡检、智慧园区这类需要网页看实时视频的开发者;二是想学 WebRTC 播放器封装、Vue 组件设计的前端同学。整个 Demo 不复杂,但麻雀虽小五脏俱全,从连接建立、视频渲染到多路切换、异常处理都有涉及,拿来当项目起点或者技术验证都很合适。
2. 技术选型与整体架构:为什么是 WebRTC 而不是 HLS
2.1 延迟对比决定了方案走向
在网页上播放 RTSP 流,常见的有三种方案:服务端转 HLS、服务端转 FLV、服务端转 WebRTC。HLS 兼容性最好,但延迟通常在 5 到 20 秒,适合点播不适合实时监控;HTTP-FLV 延迟能压到 1 到 3 秒,但依赖 flv.js 且对浏览器有一定要求;WebRTC 延迟可以做到 500 毫秒以内,是实时性要求高的场景首选。
这个 Demo 选择 webrtc-streamer 作为信令和转码服务,核心原因就是延迟。webrtc-streamer 是一个轻量级的 C++ 服务,启动后监听一个 HTTP 端口,前端通过它提供的 API 建立 WebRTC 连接,它负责把 RTSP 拉流、解码、再编码成 WebRTC 需要的格式推给浏览器。整个链路是:摄像头 RTSP → webrtc-streamer → WebRTC → 浏览器。
2.2 前端架构分层
Vue 这边没有用太重的状态管理,整体分三层:
- 视图层:一个视频播放组件,负责渲染
<video>标签和加载状态 - 逻辑层:封装 webrtc-streamer 的 JS SDK,处理连接、断开、错误回调
- 配置层:管理 RTSP 地址列表、webrtc-streamer 服务地址等参数
这种分层的好处是,播放器逻辑和业务逻辑解耦,后面要换播放器内核或者加多路切换,改动范围可控。
2.3 目录结构一览
src/ ├── components/ │ └── WebRtcPlayer.vue # 核心播放器组件 ├── utils/ │ └── webrtc-streamer.js # SDK 封装与连接管理 ├── views/ │ └── Monitor.vue # 监控页面,多路视频入口 ├── config/ │ └── stream.js # RTSP 地址与服务器配置 └── main.jsWebRtcPlayer.vue是对外暴露的组件,接收rtspUrl和serverUrl两个 props;webrtc-streamer.js里做了 SDK 的初始化和生命周期管理;Monitor.vue演示了如何在一个页面里同时播放多路视频。
3. 核心模块拆解:播放器组件与连接管理
3.1 WebRtcPlayer.vue 的 props 与生命周期
播放器组件的设计思路是:父组件只负责传 RTSP 地址,组件内部自己管理连接状态。核心 props 如下:
props: { rtspUrl: { type: String, required: true, default: '' }, serverUrl: { type: String, default: 'http://127.0.0.1:8000' }, autoPlay: { type: Boolean, default: true } }rtspUrl是摄像头的 RTSP 地址,格式通常是rtsp://user:pass@ip:554/stream;serverUrl是 webrtc-streamer 服务的地址,默认本地 8000 端口;autoPlay控制是否在组件挂载后自动建立连接。
组件挂载时调用初始化方法:
mounted() { if (this.autoPlay && this.rtspUrl) { this.initPlayer() } }, beforeDestroy() { this.destroyPlayer() }这里有个容易翻车的点:beforeDestroy里必须显式关闭 WebRTC 连接,否则页面切换后连接还挂着,服务端会积累大量僵尸会话,时间一长内存就爆了。
3.2 连接建立与视频渲染
初始化播放器的核心逻辑在initPlayer方法里:
initPlayer() { const videoElement = this.$refs.video // 创建 WebRtcStreamer 实例,传入 video 元素和服务地址 this.streamer = new WebRtcStreamer(videoElement, this.serverUrl) // 调用 connect 方法,传入 RTSP 地址和音频开关 this.streamer.connect(this.rtspUrl, null, 'rtptransport=tcp') this.streamer.onError = (err) => { this.$emit('error', err) this.status = 'error' } this.streamer.onClose = () => { this.status = 'closed' } this.status = 'connecting' }connect方法的第二个参数是音频设备 ID,传null表示不启用音频;第三个参数是传输选项,rtptransport=tcp表示强制走 TCP 传输。为什么强调 TCP?因为 UDP 在公网或复杂网络环境下丢包严重,视频会花屏甚至黑屏,TCP 虽然延迟略高但稳定性好得多,这是踩过坑之后的经验。
视频渲染依赖<video>标签的autoplay和playsinline属性:
<video ref="video" autoplay playsinline muted class="video-canvas" ></video>playsinline在移动端 Safari 上必须加,否则视频会强制全屏播放;muted是为了绕过浏览器的自动播放策略,不加的话autoplay可能不生效。
3.3 多路视频与状态管理
Monitor.vue里演示了多路视频的用法,核心是维护一个摄像头列表,然后循环渲染播放器组件:
data() { return { cameraList: [ { id: 1, name: '入口', rtspUrl: 'rtsp://192.168.1.10:554/stream1' }, { id: 2, name: '走廊', rtspUrl: 'rtsp://192.168.1.11:554/stream1' } ], serverUrl: 'http://127.0.0.1:8000' } }模板里用v-for渲染:
<div class="video-grid"> <WebRtcPlayer v-for="camera in cameraList" :key="camera.id" :rtsp-url="camera.rtspUrl" :server-url="serverUrl" @error="handleError" /> </div>多路场景下要注意:每路视频都会建立一个独立的 WebRTC 连接,对服务端和浏览器都是压力。一般建议单页面不超过 9 路,超过的话要么做分页,要么降低分辨率。另外key必须用唯一 ID,不能用 index,否则列表变化时组件复用会导致连接错乱。
4. 避坑与常见问题排查
4.1 视频黑屏但控制台无报错
现象:组件挂载后<video>标签是黑的,控制台没有明显错误,网络面板能看到 WebRTC 连接已建立。
原因:最常见的是 RTSP 地址格式不对,或者摄像头编码格式不是 H.264。webrtc-streamer 对 H.265 支持有限,如果摄像头是 H.265 编码,转码会失败但前端不一定报错。
解决:先用 VLC 验证 RTSP 地址是否可播;然后在摄像头后台把编码格式改成 H.264;如果还不行,检查 webrtc-streamer 启动日志,看有没有codec not supported之类的提示。
4.2 连接建立后几秒自动断开
现象:视频能播出来,但几秒后画面卡住,连接状态变成 closed。
原因:通常是 UDP 传输丢包导致的。WebRTC 默认优先走 UDP,在跨网段或无线网络下丢包率一高,连接就会被判定为不可用。
解决:在connect方法里强制指定 TCP 传输,就是前面代码里的'rtptransport=tcp'。这个参数加上之后,稳定性会明显提升,代价是延迟增加 100 到 200 毫秒,对监控场景完全可以接受。
4.3 多路视频时页面卡顿
现象:单路视频流畅,开到 4 路以上浏览器开始卡,CPU 占用飙升。
原因:每路 WebRTC 连接都需要浏览器解码渲染,4 路 1080P 对普通电脑来说已经是极限。另外如果用了v-if而不是v-show切换页面,组件反复销毁重建也会加重负担。
解决:降低摄像头子码流分辨率,监控场景一般用 720P 就够了;页面切换用v-show保持组件存活;如果路数确实多,考虑用keep-alive缓存但限制最大缓存数。
4.4 webrtc-streamer 服务启动后前端连不上
现象:前端报Failed to fetch或WebSocket connection failed。
原因:webrtc-streamer 默认只监听本地回环地址,如果前端和服务不在同一台机器,需要显式指定监听地址。另外跨域问题也常见,服务端没有配置 CORS 头。
解决:启动 webrtc-streamer 时加-H 0.0.0.0参数让它监听所有网卡;如果跨域,在服务端配置里加上Access-Control-Allow-Origin头,或者用 Nginx 做反向代理把前端和服务端放到同源下。
5. 二次开发与改造思路
5.1 封装成通用组件库
这个 Demo 里的WebRtcPlayer.vue已经具备通用组件的雏形,但要做成组件库还需要补几件事。第一是增加loading和error插槽,让父组件可以自定义加载中和错误状态的 UI;第二是暴露reconnect方法,允许外部手动触发重连;第三是把 webrtc-streamer 的 SDK 作为 peer dependency,而不是直接打包进去,避免版本冲突。
改造后的 props 可以扩展成这样:
props: { rtspUrl: { type: String, required: true }, serverUrl: { type: String, default: 'http://127.0.0.1:8000' }, autoPlay: { type: Boolean, default: true }, transport: { type: String, default: 'tcp' }, reconnectInterval: { type: Number, default: 5000 }, maxReconnectAttempts: { type: Number, default: 3 } }transport让使用者自己选 TCP 还是 UDP;reconnectInterval和maxReconnectAttempts控制断线重连策略。重连逻辑我一般会放在onClose回调里,用setTimeout做延迟重试,同时用一个计数器防止无限重连。
5.2 接入实际业务系统的注意事项
如果要把这个 Demo 用到真实项目里,有几个地方需要提前想清楚。鉴权:RTSP 地址里带用户名密码不安全,常见做法是后端提供一个接口,前端传摄像头 ID,后端返回临时 token 拼进 RTSP 地址,或者由后端代理拉流。录像回放:WebRTC 适合实时预览,回放还是得走 HLS 或 FLV,所以播放器组件最好设计成可切换内核的架构。移动端适配:iOS 上 WebRTC 支持还行,但 Android 低端机解码能力弱,可能需要降级到 FLV 方案。
5.3 一个验证技巧
改完代码之后怎么快速验证有没有引入回归问题?我的习惯是准备一个本地 RTSP 测试源,用 FFmpeg 循环推一个测试视频流:
ffmpeg -re -stream_loop -1 -i test.mp4 -c copy -f rtsp rtsp://127.0.0.1:8554/live这样不依赖真实摄像头,随时可以起一个流来测。每次改完播放器逻辑,先跑这个测试源看能不能正常播放、断开、重连,确认没问题再上真实设备。从那以后我每次改 WebRTC 相关代码,都强制走一遍“本地流 → 单路真机 → 多路真机”的验证流程,能挡掉大部分低级错误。希望帮到你。
本文还有配套的精品资源,点击获取