跳到主要内容Vue2 纯前端对接海康威视摄像头实时预览方案 | 极客日志JavaScript大前端
Vue2 纯前端对接海康威视摄像头实时预览方案
综述由AI生成Vue2 环境下通过 WebRTC 技术将海康威视 RTSP 流转换为浏览器可播放格式。主要步骤包括摄像头 RTSP 端口映射与链接验证、引入 webrtcstreamer.js 客户端库、封装 Vue 视频组件处理信令交互、以及本地部署 webrtc-streamer 服务作为中转。该方案解决了纯前端无法直接解析 RTSP 协议的难题,实现了监控画面的无缝嵌入。
云朵棉花糖11 浏览 Vue2 纯前端对接海康威视摄像头实现实时视频预览
要实现海康威视摄像头的实时流在浏览器中播放,核心思路是将 RTSP 协议转换为 WebRTC。通常摄像头支持端口映射后可以直接访问,但无法嵌入自研系统。通过 webrtc-streamer 进行中转推流,再在 Vue2 中接流渲染,是解决这一问题的成熟方案。
环境准备
首先确保设备可在网页端浏览,并完成以下基础设置:
- 登录摄像头管理界面,进入网络配置或视频编码设置。
- 开启 RTSP 服务,确认端口号(默认通常是 554)。
- 获取 RTSP 链接。格式通常为
rtsp://user:password@ip:port/Streaming/Channels/xxx。官方说明文档可参考海康威视开发者中心。
- 验证连通性。建议使用 VLC 播放器输入 RTSP 地址测试,确保流媒体正常。




搞定这些基础设置后,接下来就是代码集成阶段了。
代码集成
引入核心脚本
我们需要一个客户端库来处理 WebRTC 信令交互。这里直接使用封装好的 webrtcstreamer.js,无需修改内部逻辑,直接复制即可。
var WebRtcStreamer =(function(){varWebRtcStreamer=(videoElement, srvurl){( videoElement ===){. = .(videoElement);}{. = videoElement;}. = srvurl || location.++..++..;. =;. ={ :, :};. =;. =[];}..=(){(!response.){(response.);} response;}..=(){.();
..=(){. = iceServers;. = iceServers ||{:[]};{.(); callurl =. ++.. ++(videourl);(audiourl){ callurl +=+(audiourl);}(options){ callurl +=+(options);}(stream){..(stream);}
..=(){ .(+.(.));. =(.); pc =.; pc. = .(); pc.=.(evt); pc.=.(evt); pc.={ .(+ pc.);(.){(pc. ===){... =;}(){... =;}(){... =;}(){.();}}} pc.=(){ .(+.(evt)); evt..=(){ .();.();} evt..=(){ .(+.(event.));}}{ dataChannel = pc.(); dataChannel.=(){ .();.();} dataChannel.=(){ .(+.(evt.));}}(e){ .(+ e);} .(+.(.)); pc;}
..=(){(event.){(..){.(.., event.);}{..(event.);}}{ .();}}..=(){(. ++peerid,{ :, :.(candidate)}).(.).((response.())).({.(+ response)}).(.(+ error ))}
..=(){ .(+.(event));.. = event.; promise =..();(promise !==){ promise.({ .(+error);..(,);});}}
..=(){ .(+.(dataJson)); descr =(dataJson);..(descr).({ .();(..){ candidate =..();.(.., candidate);}.()},{ .(+.(error));});}
..=(){ .(+.(dataJson));(dataJson){( i=; i<dataJson.; i++){ candidate =(dataJson[i]); .(+.(candidate));..(candidate).({ .();},{ .(+.(error));});}..();}}
..=(){ .(+ status);} ;})();( !==&& . !==){ . = ;}( !==&& . !==){ . = ;}
string
srvurl
functionWebRtcStreamer
if
typeof
"string"
this
videoElement
document
getElementById
else
this
videoElement
this
srvurl
protocol
"//"
window
location
hostname
":"
window
location
port
this
pc
null
this
mediaConstraints
offerToReceiveAudio
true
offerToReceiveVideo
true
this
iceServers
null
this
earlyCandidates
WebRtcStreamer
prototype
_handleHttpErrors
function
response
if
ok
throwError
statusText
return
WebRtcStreamer
prototype
connect
function
videourl, audiourl, options, localstream, prefmime
this
disconnect
WebRtcStreamer
prototype
onReceiveGetIceServers
function
iceServers, videourl, audiourl, options, stream, prefmime
this
iceServers
this
pcConfig
"iceServers"
try
this
createPeerConnection
let
this
srvurl
"/api/call?peerid="
this
pc
peerid
"&url="
encodeURIComponent
if
"&audiourl="
encodeURIComponent
if
"&options="
encodeURIComponent
if
this
pc
addStream
WebRtcStreamer
prototype
createPeerConnection
function
console
log
"createPeerConnection config: "
JSON
stringify
this
pcConfig
this
pc
newRTCPeerConnection
this
pcConfig
let
this
pc
peerid
Math
random
onicecandidate
(evt)=>
this
onIceCandidate
onaddstream
(evt)=>
this
onAddStream
oniceconnectionstatechange
(evt)=>
console
log
"oniceconnectionstatechange state: "
iceConnectionState
if
this
videoElement
if
iceConnectionState
"connected"
this
videoElement
style
opacity
"1.0"
elseif
pc.iceConnectionState ==="disconnected"
this
videoElement
style
opacity
"0.25"
elseif
(pc.iceConnectionState ==="failed")||(pc.iceConnectionState ==="closed")
this
videoElement
style
opacity
"0.5"
elseif
pc.iceConnectionState ==="new"
this
getIceCandidate
ondatachannel
function
evt
console
log
"remote datachannel created:"
JSON
stringify
channel
onopen
function
console
log
"remote datachannel open"
this
send
"remote channel openned"
channel
onmessage
function
event
console
log
"remote datachannel recv:"
JSON
stringify
data
try
let
createDataChannel
"ClientDataChannel"
onopen
function
console
log
"local datachannel open"
this
send
"local channel openned"
onmessage
function
evt
console
log
"local datachannel recv:"
JSON
stringify
data
catch
console
log
"Cannor create datachannel error: "
console
log
"Created RTCPeerConnnection with config: "
JSON
stringify
this
pcConfig
return
WebRtcStreamer
prototype
onIceCandidate
function
event
if
candidate
if
this
pc
currentRemoteDescription
this
addIceCandidate
this
pc
peerid
candidate
else
this
earlyCandidates
push
candidate
else
console
log
"End of candidates."
WebRtcStreamer
prototype
addIceCandidate
function
peerid, candidate
fetch
this
srvurl
"/api/addIceCandidate?peerid="
method
"POST"
body
JSON
stringify
then
this
_handleHttpErrors
then
(response)=>
json
then
(response)=>
console
log
"addIceCandidate ok:"
catch
(error)=>
this
onError
"addIceCandidate "
WebRtcStreamer
prototype
onAddStream
function
event
console
log
"Remote track added:"
JSON
stringify
this
videoElement
srcObject
stream
let
this
videoElement
play
if
undefined
catch
(error)=>
console
warn
"error:"
this
videoElement
setAttribute
"controls"
true
WebRtcStreamer
prototype
onReceiveCall
function
dataJson
console
log
"offer: "
JSON
stringify
let
newRTCSessionDescription
this
pc
setRemoteDescription
then
()=>
console
log
"setRemoteDescription ok"
while
this
earlyCandidates
length
let
this
earlyCandidates
shift
this
addIceCandidate
this
pc
peerid
this
getIceCandidate
(error)=>
console
log
"setRemoteDescription error:"
JSON
stringify
WebRtcStreamer
prototype
onReceiveCandidate
function
dataJson
console
log
"candidate: "
JSON
stringify
if
for
let
0
length
let
newRTCIceCandidate
console
log
"Adding ICE candidate :"
JSON
stringify
this
pc
addIceCandidate
then
()=>
console
log
"addIceCandidate OK"
(error)=>
console
log
"addIceCandidate error:"
JSON
stringify
this
pc
addIceCandidate
WebRtcStreamer
prototype
onError
function
status
console
log
"onError:"
return
WebRtcStreamer
if
typeof
window
'undefined'
typeof
window
document
'undefined'
window
WebRtcStreamer
WebRtcStreamer
if
typeof
module
'undefined'
typeof
module
exports
'undefined'
module
exports
WebRtcStreamer
封装 Vue 组件
为了复用方便,建议将视频播放逻辑封装成独立组件。这样在父组件中只需传入 RTSP URL 数组即可。
注意:import 路径需根据实际项目结构调整,同时 cameraIp 必须指向本地运行的 webrtc-streamer 服务地址。
<template>
<div class="rtsp_video_container">
<div v-if="videoUrls.length === 1"class="rtsp_video single-video">
<video :id="'video_0'" controls autoPlay muted width="100%" height="100%" style="object-fit: fill"></video>
</div>
<div v-if="videoUrls.length >1" v-for="(videoUrl, index) in videoUrls":key="index"class="rtsp_video">
<video :id="'video_' + index" controls autoPlay muted width="100%" height="100%" style="object-fit: fill"></video>
</div>
</div>
</template>
<script>
import WebRtcStreamer from'../utils/webrtcstreamer';// 注意此处替换为 webrtcstreamer.js 所在的路径
exportdefault{
name:'RtspVideo',
props:{
videoUrls:{
type: Array,
required:true,
}},
data(){
return{
cameraIp:'localhost:8000',// 这里的 IP 固定为本地,不要修改,是用来与本地的 webrtc-streamer 插件进行通讯的
webRtcServers:[],// 存储 WebRtcStreamer 实例
};
},
mounted(){
this.initializeStreams();
},
watch:{
// 监听 videoUrls 或 cameraIp 的变化,重新初始化流
videoUrls:{
handler(newUrls, oldUrls){
if(newUrls.length !== oldUrls.length ||!this.isSameArray(newUrls, oldUrls)){
this.resetStreams();
this.initializeStreams();
}},
deep:true,
},
cameraIp(newIp, oldIp){
if(newIp !== oldIp){
this.resetStreams();
this.initializeStreams();
}}
},
methods:{
// 初始化视频流连接
initializeStreams(){
if(this.webRtcServers.length ===0){
this.videoUrls.forEach((videoUrl, index)=>{
const videoElement = document.getElementById(`video_${index}`);
const webRtcServer =newWebRtcStreamer(videoElement,`http://${this.cameraIp}`);
this.webRtcServers.push(webRtcServer);
webRtcServer.connect(videoUrl,null,'rtptransport=tcp',null);
});
}},
// 检查新旧数组是否相同
isSameArray(arr1, arr2){
return arr1.length === arr2.length && arr1.every((value, index)=> value === arr2[index]);
},
// 清除 WebRtcStreamer 实例
resetStreams(){
this.webRtcServers.forEach((webRtcServer)=>{
if(webRtcServer){
webRtcServer.disconnect();// 断开连接
}});
this.webRtcServers =[];// 清空实例
},
},
beforeDestroy(){
this.resetStreams();// 页面销毁时清理 WebRtcStreamer 实例,避免内存泄漏
},
};
</script>
<style lang="less" scoped>
.rtsp_video_container { display: flex; flex-wrap: wrap; gap:10px; justify-content: space-between;}
.rtsp_video { flex:1148%; height:225px; max-width:48%; background: #000; border-radius:8px; overflow: hidden;}
.single-video { flex:11100%; height:100%; max-width:100%; background: #000;}
video { width:100%; height:100%; object-fit: cover;}
</style>
<template>
<div style="margin-top: 10px;width: 100%;height: 100%;">
<rtsp-video :videoUrls="selectedUrls":key="selectedUrls.join(',')"></rtsp-video>
</div>
</template>
<script>
import RtspVideo from"../views/video";
components:{ RtspVideo }
data(){
return{
selectedUrls:['rtsp://user:[email protected]:xxxx/Streaming/Channels/101','rtsp://user:[email protected]:xxxx/Streaming/Channels/201'],
}}
</script>
启动本地服务
最后一步,需要在运行 Vue 应用的本地 PC 上启动 webrtc-streamer 服务。这是将 RTSP 转为 WebRTC 的关键中间件。
下载解压后,需要配套使用 exe 和 js 文件。exe 位于 bin 目录,js 位于 share\webrtc-streamer\html 目录。确保版本对应,否则可能出现画面无法加载的问题。
如果启动 webrtc-streamer.exe 导致客户端卡顿,或者需要更改端口号,可以通过命令行参数调整。例如使用批处理脚本启动指定端口:
@echo off
cd C:
start webrtc-streamer.exe -o -H 0.0.0.0:8124
exit
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online