前端对接海康ws实时视频流,回放基础使用
1.首先在海康开放平台下载这个官方demo
这里我用的是h5player开发

2.将插件引入项目
将下载的demo 文件放到项目的静态资源中,
找到官网下载好的demo点进去,将里边的文件复制到项目的public下,这里使用的是vue,如果是react也和项目位置是一样的
我这里是在public新建了一个lib文件夹放进去
3.然后在index.html进行插件的导入

4.封装海康组件方便使用
封装hkPlayer.js,注意szBasePath的路径,如果跟我一样可以直接cv
javascript
const IS_MOVE_DEVICE = document.body.clientWidth < 992;
const MSE_IS_SUPPORT = !!window.MediaSource; // 是否支持mse
/**
* 海康播放器
* @param {*} domid 容器id
*/
export default class HkPlayer {
constructor(domid) {
this.createPlayer(domid);
}
createPlayer(domid) {
console.log('IS_MOVE_DEVICE', domid);
const player = new window.JSPlugin({
szId: domid,
szBasePath: '/lib',
iMaxSplit: 1,
iCurrentSplit: IS_MOVE_DEVICE ? 1 : 2,
openDebug: true,
muted: true,
// iWidth: 425,
// iHeight: 350,
mseWorkerEnable: false, //是否开启多线程解码,分辨率大于1080P建议开启,否则可能卡顿
mseSupport: MSE_IS_SUPPORT,
tabActive: MSE_IS_SUPPORT ? 'mse' : 'decoder',
oStyle: {
borderSelect: IS_MOVE_DEVICE ? '#000' : '#FFCC00'
}
});
// 事件回调绑定
player.JS_SetWindowControlCallback({
windowEventSelect: function (iWndIndex) {
//插件选中窗口回调
console.log('windowSelect callback: ', iWndIndex);
},
pluginErrorHandler: function (iWndIndex, iErrorCode, oError) {
//插件错误回调
console.log('pluginError callback: ', iWndIndex, iErrorCode, oError);
},
windowEventOver: function (iWndIndex) {
//鼠标移过回调
//console.log(iWndIndex);
},
windowEventOut: function (iWndIndex) {
//鼠标移出回调
//console.log(iWndIndex);
},
windowEventUp: function (iWndIndex) {
//鼠标mouseup事件回调
//console.log(iWndIndex);
},
windowFullCcreenChange: function (bFull) {
//全屏切换回调
console.log('fullScreen callback: ', bFull);
},
firstFrameDisplay: function (iWndIndex, iWidth, iHeight) {
//首帧显示回调
console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
},
performanceLack: function (iWndIndex) {
//性能不足回调
console.log('performanceLack callback: ', iWndIndex);
},
StreamEnd: function (iWndIndex) {
//性能不足回调
console.log('recv StreamEnd: ', iWndIndex);
},
StreamHeadChanged: function (iWndIndex) {
console.log('recv StreamHeadChanged: ', iWndIndex);
},
ThumbnailsEvent: (iWndIndex, eventType, eventCode) => {
console.log('recv ThumbnailsEvent: ' + iWndIndex + ', eventType:' + eventType + ', eventCode:' + eventCode);
},
InterruptStream: (iWndIndex, iTime) => {
console.log('recv InterruptStream: ' + iWndIndex + ', iTime:' + iTime);
},
ElementChanged: (iWndIndex, szElementType) => {
//回调采用的是video还是canvas
console.log('recv ElementChanged: ' + iWndIndex + ', szElementType:' + szElementType);
}
});
this.player = player;
}
// 实时播放
startplay(url) {
const playURL = url;
const index = 1;
this.player.JS_Play(playURL, { playURL, mode: 1 }, index).then(
(res) => {
console.log('播放成功', res);
},
(e) => {
console.error('播放失败', e);
}
);
}
stopPlay() {
this.player.JS_Stop().then(
() => {
console.log('stop realplay success');
},
(e) => {
console.error(e);
}
);
}
// 回放
startBackPlay(url, startTime, endTime) {
const index = 1;
this.player
.JS_Play(
url,
{
playURL: url, // 流媒体播放时必传
mode: 0, // 解码类型:0=普通模式; 1=高级模式 默认为0
PlayBackMode: 1, //1:绝对时间正放; 3 绝对时间倒放 默认为1
keepDecoder: 0 // 0:回收解码资源; 1:不回收解码资源。为1时相同的编码格式,通过直接调用js_play接口切换点位不黑屏。默认0
// ...
},
index, //当前窗口下标
// 回放参数
startTime,
endTime
)
.then(
() => {
console.info('JS_Play success', startTime, endTime);
// do you want...
},
(err) => {
console.info('JS_Play failed:', err);
// do you want...
}
);
}
}
5.对接实时视频和回放
这里使用的流为ws,不同的流传参不一样,具体的可以登录海康官网查看
注意:回放的传参跟实时的有点区别,还有时间格式为iso的,需要toISOString转一下
javascript
<template>
<div class="centeredVideo" :id="'videoElement'+ playitem.cameraCode" style="width: 100%;height: 100%;"></div>
</template>
<script>
import { string } from 'vue-types';
import HkPlayer from '../utils/hkPlayer';
import { videoList, videoByCameraId, videoBack } from '@/api/tjh/video';
import moment from 'moment';
export default {
name: 'PlayVideoCom',
props: {
playitem: {
type: Object,
required: true
},
videoType: {
type: String,
default: () => 'real' // real: 实时视频,back: 回放视频
},
startTimeStamp: {
type: Date,
default: () => ''
},
endTimeStamp: {
type: Date,
default: () => ''
}
},
data() {
return {
VideoEltype: [0, 6],
HkPlayerObj: null
}
},
watch: {
playitem: {
immediate: true,
handler(newVal) {
if (newVal) {
console.log(newVal,this, 'newVal');
this.$nextTick(() => {
this.HKplayVideo();
})
}
}
}
},
beforeUnmount() {
this.HKclosePlaying();
},
methods: {
// 海康
async HKplayVideo() {
try {
this.HkPlayerObj = new HkPlayer('videoElement'+this.playitem.cameraCode);
if(this.videoType === 'real'){
const res = await videoByCameraId(this.playitem.cameraCode);
if (res.msg) {
this.HkPlayerObj.startplay(res.msg);
}
}else {
let data = {
cameraId: this.playitem.cameraCode,
beginTime: moment(this.startTimeStamp).format('YYYY-MM-DD HH:mm:ss'),
endTime: moment(this.endTimeStamp).format('YYYY-MM-DD HH:mm:ss'),
"recordLocation": "1",
"protocol": "ws"
}
const res = await videoBack(data);
if (res.msg) {
this.HkPlayerObj = new HkPlayer('videoElement' + this.playitem.cameraCode);
}
// let str = 'ws://169.16.10.7:559/openUrl/RRxMHQc?beginTime=20250817T000000&endTime=20250818T000000'
this.HkPlayerObj.startBackPlay(res.msg, this.startTimeStamp.toISOString(), this.endTimeStamp.toISOString());
}
} catch (error) {
console.error('Failed to play video:', error);
}
},
HKclosePlaying() {
if (this.HkPlayerObj) {
console.log('关闭播放');
this.HkPlayerObj.stopPlay(() => {});
}
}
}
};
</script>