使用的海康插件版本1.2.5
个人将播放单个画面和多个画面分别抽离为两个组件,多个画面的也可以播放单个画面,但是单个画面的组件逻辑相对更好一点(如果要求是一次最多播放单个画面的话)
多个画面组件的使用:
注意:传入的'boxId', 'cameraIndexCode'这两个参数都是必传。cameraIndexCode为海康接口的监控列表返回值中的cameraIndexCode属性
多个播放画面组件
<!--
* @Author:
* @LastEditTime: 2023-07-20 18:54:31
* @Description: 多个监控画面播放
-->
<template>
<div :id="boxId" class="box"></div>
</template>
<script>
export default {
name: 'hkPlay',
props: {
boxId: {
required: true,
}, // 窗口容器id
cameraIndexCodeList: {
type: Array,
required: true,
}, // 监控摄像头唯一编码
playCount: {
type: Number,
default: 1,
}, // 正在播放监控画面的窗口数
// layout: {
// type: String,
// default: '1x1',
// }, // 同一画面中播放监控个数
},
watch: {
cameraIndexCodeList: {
handler() {
this.$nextTick(() => {
const closeWndIdList = [] // 需要关闭的窗口
const openWndCodeList = [] // 需要新增的窗口(值为cameraIndexCode)
_.forEach(this.lastCameraIndexCodeList, (lastItem) => {
if (!this.cameraIndexCodeList.includes(lastItem)) {
if (this.playWindowObj[lastItem]) {
closeWndIdList.push({
wndId: this.playWindowObj[lastItem],
})
// 剩余窗口新增释放的窗口
this.residueList.push(this.playWindowObj[lastItem])
// 正在使用的窗口去掉释放的窗口
const useIndex = this.usingList.indexOf(this.playWindowObj[lastItem])
if (useIndex !== -1) {
this.usingList.splice(useIndex, 1)
}
// 正在播放的窗口信息去掉该项
Reflect.deleteProperty(this.playWindowObj, lastItem)
}
}
})
_.forEach(this.cameraIndexCodeList, (item) => {
if (!this.lastCameraIndexCodeList.includes(item)) {
openWndCodeList.push(item)
}
})
// 关闭窗口
console.log('需关闭的窗口', closeWndIdList)
if (closeWndIdList.length) {
this.multiPlayStop(closeWndIdList)
}
// 播放
this.$nextTick(() => {
console.log('释放窗口完毕,需打开的窗口', openWndCodeList)
_.forEach(openWndCodeList, (codeItem) => {
if (!this.playWindowObj[codeItem] && this.residueList.length) {
const usingWndId = this.residueList.shift()
this.playWindowObj[codeItem] = usingWndId
this.usingList.push(usingWndId)
this.startPreview(codeItem, usingWndId)
}
})
this.lastCameraIndexCodeList = _.cloneDeep(this.cameraIndexCodeList)
})
})
},
// immediate: true, 父组件中使用了v-if,数据进来时,组件还未初始化完成,不使用v-if提前初始化的情况下可使用该配置(去掉初始化完成后的cameraIndexCodeList遍历播放操作)
},
playCount(newValue) {
// 重新建立窗口数量
this.residueList = []
for (let index = 1; index <= newValue; index += 1) {
this.residueList.push(index)
}
// 排除掉已经使用的窗口
this.residueList = _.filter(this.residueList, (item) => {
return !this.usingList.includes(item)
})
console.log('this.residueList', this.residueList)
},
},
data() {
return {
oWebControl: null, // 插件实例
initCount: 0, // 启动程序次数
playWindowObj: {}, // 正在播放的窗口信息
residueList: [1], // 剩余窗口
usingList: [], // 正在使用的窗口
lastCameraIndexCodeList: [], // 上一刻状态的cameraIndexCodeList
}
},
methods: {
/**
* @description 启动插件(创建监控播放实例)
*/
initWebControl() {
console.log('创建监控播放实例')
const that = this
this.oWebControl = new WebControl({
szPluginContainer: that.boxId, // 指定DIV窗口标识
iServicePortStart: 15900, // 指定服务的起止端口号,建议使用该值
iServicePortEnd: 15909, // 起止端口号10个,只有一个会用上,所以会有其它9条报错
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
cbConnectSuccess: () => {
// 创建WebControl实例成功
// 实例创建成功后启动服务
that.oWebControl
.JS_StartService('window', {
dllPath: './VideoPluginConnect.dll', // 固定值
})
.then(
() => {
// 启动插件服务成功
console.log('启动插件服务成功')
// 设置消息回调
that.oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: that.cbIntegrationCallBack,
})
// 创建视频播放窗口, 宽高可设定(第二个和第三个参数)
that.oWebControl.JS_CreateWnd(that.boxId).then(() => {
// 创建播放实例成功后初始化
that.initPlugin()
console.log('创建播放实例成功后初始化')
})
},
() => {
// 启动插件服务失败
}
)
},
cbConnectError: () => {
// 创建WebControl实例失败(当插件服务未启动或进程被结束,创建实例时会触发)
that.oWebControl = null
WebControl.JS_WakeUp('VideoWebPlugin://') // 程序未启动时执行error函数,采用wakeup来启动程序
if (that.initCount < 3) {
// 尝试启动插件3次
that.initCount += 1
setTimeout(() => {
that.$message.warning('插件未启动,正在尝试启动,请稍候...')
that.initWebControl()
}, 3000)
}
},
cbConnectClose: (bNormalClose) => {
// bNormalClose = false 表示异常断开
// bNormalClose = true 表示正常断开
if (!bNormalClose) {
that.$message.error('插件服务异常断开')
}
that.oWebControl = null
},
})
},
/**
* @description 获取监控公钥
*/
getPubKey(callback) {
this.oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then((oData) => {
if (oData.responseMsg.data) {
this.pubKey = oData.responseMsg.data
callback()
}
})
},
/**
* @description 接收插件消息回调(窗口选中消息,预览或回放播放消息,抓图结果消息,预览紧急录像或回放录像剪辑结果消息)
* @param {Object} oData 是封装的视频web插件回调消息的消息体
*/
cbIntegrationCallBack(oData) {
console.log('oData', oData)
// oData.responseMsg.type === 1 窗口选中消息(鼠标左键,右键,左键双击)
// oData.responseMsg.type === 2 预览或回放播放消息
// oData.responseMsg.type === 3 抓图结果消息
// oData.responseMsg.type === 4 预览紧急录像或回放录像剪辑结果消息
// oData.responseMsg.type === 5 进入全屏/退出全屏消息
// oData.responseMsg.type === 6 切换布局信息
// oData.responseMsg.type === 7 播放窗口双击消息
// oData.responseMsg.type === 8 时间轴级别变化消息
if (oData.responseMsg.type === 7) {
// 全屏
this.oWebControl.JS_RequestInterface({
funcName: 'setFullScreen',
})
} else if (oData.responseMsg.type === 6) {
// 切换播放数
console.log('oData.responseMsg.wndNum', oData.responseMsg.msg.wndNum)
this.$emit('layoutChange', oData.responseMsg.msg.wndNum)
}
},
/**
* @description 插件初始化
*/
initPlugin() {
console.log('插件初始化')
const that = this
that.getPubKey(function() {
// 请自行修改以下变量值
let appkey = `${currentEnv.VUE_APP_CAMERA_KEY}` //综合安防管理平台提供的appkey,必填
let secret = `${currentEnv.VUE_APP_CAMERA_ENCRYPT}` //综合安防管理平台提供的secret,必填
let ip = `${currentEnv.VUE_APP_CAMERAIP}` //综合安防管理平台IP地址,必填
let playMode = 0 //初始播放模式:0-预览,1-回放
let port = 443 //综合安防管理平台端口,若启用HTTPS协议,默认443
let snapDir = 'D:\\SnapDir' //抓图存储路径
let videoDir = 'D:\\VideoDir' //紧急录像或录像剪辑存储路径
let layout = '1x1' //playMode指定模式的布局
let enableHTTPS = 1 //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1
// let encryptedFields = 'secret' //加密字段,默认加密领域为secret
let showToolbar = 1 //是否显示工具栏,0-不显示,非0-显示
let showSmart = 1 //是否显示智能信息(如配置移动侦测后画面上的线框),0-不显示,非0-显示
let buttonIDs = '' //自定义工具条按钮
let reconnectTimes = 0 // 断流后无限次重连
// 请自行修改以上变量值
that.oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
snapDir: snapDir, //抓图存储路径
videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
// encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs: buttonIDs, //自定义工具条按钮
reconnectTimes: reconnectTimes, // 断流后无限次重连
}),
})
.then(function(oData) {
let height = document.getElementById(that.boxId).offsetHeight
let width = document.getElementById(that.boxId).offsetWidth
that.oWebControl.JS_Resize(width, height) // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
_.forEach(that.cameraIndexCodeList, (item) => {
// that.startPreview(item, index + 1)
console.log('初始化播放', that.playWindowObj, that.residueList)
if (!that.playWindowObj[item] && that.residueList.length) {
const usingWndId = that.residueList.shift()
that.playWindowObj[item] = usingWndId
that.usingList.push(usingWndId)
that.startPreview(item, usingWndId)
}
})
console.log('插件初始化完成')
})
})
},
/**
* @description 监控视频预览功能(批量播放)
*/
// startPreview() {
// const indexCodeList = []
// _.forEach(this.cameraIndexCodeList, (item, index) => {
// indexCodeList.push({
// authUuid: '',
// cameraIndexCode: item,
// ezvizDirect: 0,
// gpuMode: 0,
// streamMode: 0,
// transMode: 1,
// wndId: index + 1, // 不要从0初始化, 从1开始
// })
// })
// this.oWebControl
// .JS_RequestInterface({
// funcName: 'startMultiPreviewByCameraIndexCode', // 批量播放
// argument: JSON.stringify({
// list: [...indexCodeList],
// }),
// })
// .then(
// (res) => {
// console.log('批量播放成功', res)
// },
// (err) => {
// console.log('批量播放失败', err)
// }
// )
// },
// 监控视频预览功能
startPreview(cameraIndexCode, wndId) {
console.log('监控视频预览功能')
let _this = this
// let cameraIndexCode = _this.cameraIndexCode //获取输入的监控点编号值,必填
let streamMode = 0 //主子码流标识:0-主码流,1-子码流
let transMode = 1 //传输协议:0-UDP,1-TCP
let gpuMode = 0 //是否启用GPU硬解,0-不启用,1-启用
// let wndId = -1 //播放窗口序号(在2x2以上布局下可指定播放窗口)
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, '')
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, '')
_this.oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId: wndId, //可指定播放窗口
}),
})
},
/**
* @description 监控RSA加密
*/
setEncrypt(value) {
let encrypt = new JSEncrypt()
encrypt.setPublicKey(this.pubKey)
return encrypt.encrypt(value)
},
/**
* @description 判断播放器是否销毁
*/
initVideoView() {
if (this.oWebControl == null) {
this.initWebControl()
} else {
this.destroyedView()
setTimeout(this.initVideoView, 1000)
}
},
/**
* @description 断开插件服务连接
*/
destroyedView() {
if (this.oWebControl != null) {
this.stopPreview()
this.oWebControl.JS_HideWnd() // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
this.oWebControl.JS_Disconnect().then(
function() {
// 断开与插件服务连接成功
},
function() {
// 断开与插件服务连接失败
}
)
}
},
/**
* @description 批量停止播放
*/
multiPlayStop(list) {
this.oWebControl
.JS_RequestInterface({
funcName: 'stopMultiPlay', // 批量播放
argument: JSON.stringify({
list,
}),
})
.then(
(res) => {
console.log('批量停止播放成功', res)
},
(err) => {
console.log('批量停止播放失败', err)
}
)
},
/**
* @description 停止监控预览
*/
stopPreview() {
this.oWebControl.JS_RequestInterface({
funcName: 'stopPreview',
})
},
},
created() {
console.log('created')
this.lastCameraIndexCodeList = _.cloneDeep(this.cameraIndexCodeList)
console.log('this.lastCameraIndexCodeList', this.lastCameraIndexCodeList)
},
mounted() {
this.initVideoView()
},
beforeDestroy() {
this.destroyedView()
},
}
/**
* 备注:
* 1. JS_RequestInterface是插件实例上挂载的方法,通用请求响应接口,
* 监控插件要完成某个功能,可以通过这个方法去调用已设定的插件方法就能实现这个功能
* 例如全屏:
* this.oWebControl.JS_RequestInterface({
* funcName: 'setFullScreen',
* })
*/
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
}
</style>
多个画面组件在父组件中的使用:
屏蔽掉目录树逻辑就行
<template>
<el-row class="h-100">
<!-- 播放视频start -->
<el-col :span="20" class="h-100 p-r-20">
<div class="h-100">
<div class="video-box h-100" ref="videoBoxRef">
<hikPlay
boxId="indexCodeList"
:cameraIndexCodeList="cameraIndexCodeList"
:playCount="gridNumber"
@downloadDialog="downloadDialog"
@layoutChange="layoutChange"
v-if="cameraIndexCodeList.length"
></hikPlay>
</div>
</div>
</el-col>
<!-- 播放视频end -->
<!-- 列表strat -->
<el-col :span="4" class="h-100">
<el-tabs v-model="activeModule" class="h-100">
<el-tab-pane label="监控点目录树" name="area" class="h-100">
<div class="w-100 h-100 tree-container p-10">
<el-input
size="small"
placeholder="请输入监控点名称"
clearable
v-model.trim="monitorKeyword"
>
</el-input>
<el-tree
class="filter-tree m-t-10"
lazy
highlight-current
show-checkbox
node-key="indexCode"
:data="monitorTreeData"
:props="defaultProps"
:load="loadNode"
@check="monitorCheck"
ref="monitorTreeRef"
>
</el-tree>
</div>
</el-tab-pane>
</el-tabs>
</el-col>
<!-- 列表end -->
</el-row>
</template>
<script>
const hikPlay = () => {
return import('@/components/monitor/hkPlay')
}
import MonitorService from '@/services/MonitorService'
export default {
name: 'realTimeMonitor',
components: {
hikPlay,
},
watch: {
monitorKeyword: {
async handler(newValue) {
if (newValue !== '') {
this.$refs.monitorTreeRef.$data.store.lazy = false // 当输入框有值时关闭懒加载
this.monitorTreeData = await this.searchMonitor()
console.log('当输入框有值时关闭懒加载', this.monitorTreeData)
} else {
this.$refs.monitorTreeRef.$data.store.lazy = true // 开启懒加载
this.getRoot()
console.log('开启懒加载')
}
},
},
async selectedMonitorList(newValue) {
if (this.lastSelectedMonitorList.length > newValue.length) {
// 勾选减少
// 查找变化项数据位置
_.forEach(this.lastSelectedMonitorList, (lastItem) => {
const existIndex = _.findIndex(
this.selectedMonitorList,
(listItem) => listItem.indexCode === lastItem.indexCode
)
if (existIndex === -1) {
// 取消勾选项
const deleteIndex = _.findIndex(
this.playMonitorList,
(playItem) => playItem.indexCode === lastItem.indexCode
)
if (deleteIndex !== -1) {
this.playMonitorList = this.selectedMonitorList.slice(0, this.gridNumber)
}
}
})
} else {
// 勾选增加
if (this.playMonitorList.length < this.gridNumber) {
this.playMonitorList = this.selectedMonitorList.slice(0, this.gridNumber)
}
console.log('勾选增加', this.playMonitorList)
}
this.lastSelectedMonitorList = [...this.selectedMonitorList]
},
async gridNumber(newValue, oldValue) {
if (newValue > oldValue) {
this.playMonitorList = this.selectedMonitorList.slice(0, newValue)
} else if (newValue < oldValue) {
this.playMonitorList = this.playMonitorList.slice(0, newValue)
}
console.log('this.playMonitorList', this.playMonitorList)
},
playMonitorList(newValue) {
// this.cameraIndexCodeList = newValue
this.indexCodeList = _.map(newValue, 'indexCode')
console.log('this.indexCodeList', this.indexCodeList)
},
indexCodeList(newValue) {
const requestList = []
_.forEach(newValue, (item) => {
requestList.push(
MonitorService.getCameraDetail({
cameraIndexCode: item,
})
)
})
Promise.all(requestList).then((resList) => {
console.log('resList', resList)
this.cameraIndexCodeList = []
_.forEach(resList, (res) => {
if (res && res.data && res.code === 0) {
const result = JSON.parse(res.data)
console.log('res', result)
if (result.data && result.code === '0') {
this.cameraIndexCodeList.push(result.data.cameraIndexCode)
}
}
})
console.log('this.cameraIndexCodeList', this.cameraIndexCodeList)
})
},
},
data() {
return {
activeModule: 'area', // tab页当前选中项
gridNumber: 1, // 监控画面总窗口数
areaKeyword: '', // 区域目录树查询关键字
selectedDevice: [], // 目录树勾选的数据
isPageFullscreen: false, // 是否全屏
defaultProps: {
label: 'name',
isLeaf: 'isLeaf',
}, // 目录树默认配置
currentArea: null, // 当前点击的区域节点数据
monitorKeyword: '', // 监控点列表查询关键字
monitorList: [], // 监控点列表数据
monitorLoading: false, // 监控点列表loading
selectedMonitorList: [], // 监控点列表选中项
lastSelectedMonitorList: [], // 上一个状态的监控点列表选中项
playMonitorList: [], // 正在播放的监控列表
indexCodeList: [], // 监控点唯一编码
cameraIndexCodeList: [], // 视频播放所需参数
monitorTreeData: [], // 监控点数据
}
},
methods: {
/**
* @description 监控画面总数变化
* @param {Number} layoutCount 监控画面总数
*/
layoutChange(layoutCount) {
this.gridNumber = layoutCount
},
/**
* @description 勾选发生变化
*/
monitorCheck() {
this.selectedMonitorList = this.$refs.monitorTreeRef.getCheckedNodes(true)
console.log('勾选发生变化', this.selectedMonitorList)
},
/**
* @description 获取根区域节点
* @returns {Array} 根区域节点
*/
async getRoot() {
const res = await MonitorService.getRegionsRoot({
treeCode: '0',
})
console.log('获取根区域节点', res)
if (res && res.data && res.code === 0) {
const result = JSON.parse(res.data)
console.log('result', result)
if (result) {
return [result.data]
}
}
},
/**
* @description 根据查询条件获取区域列表
* @param {String} parentCode 父节点编号
* @param {String} keyword 查询条件
* @returns {Array} 区域列表
*/
async getNodes(parentCode, keyword = '') {
const res = await MonitorService.getNodesByParams({
resourceType: 'region', // 必填,资源类型
regionName: keyword, // 非必填,区域名称,可模糊查询
parentIndexCodes: parentCode ? [parentCode] : [], // 非必填,父编号集合
pageNo: 1, // 必填
pageSize: 1000, // 必填
})
console.log('根据查询条件获取区域列表', res)
if (res && res.data && res.code === 0) {
const result = JSON.parse(res.data)
console.log('result', result)
if (result) {
_.forEach(result.data.list, (listItem) => {
listItem.isLeaf = false
})
return result.data.list
} else {
return []
}
}
},
/**
* @description 目录树节点懒加载
* @param {Object} node 目录树节点
* @param {Function} resolve 节点渲染回调方法
*/
async loadNode(node, resolve) {
console.log('目录树节点', node)
if (node.level === 0) {
const nodes = await this.getRoot()
if (nodes) {
return resolve(nodes)
}
} else if (node && node.data && node.data.leaf) {
const nodes = await this.searchMonitor(node.parent.data.indexCode)
if (nodes) {
return resolve(nodes)
}
} else {
if (node && node.data && node.data.indexCode) {
const nodes = await this.getNodes(node.data.indexCode)
if (nodes) {
return resolve(nodes)
}
}
}
return resolve([])
},
/**
* @description 监控点列表查询
* @param {String} indexCode 区域节点编码
*/
async searchMonitor(indexCode) {
const res = await MonitorService.getCameraList({
name: this.monitorKeyword, // 非必填,名称,模糊搜索
regionIndexCodes: [indexCode], // 区域编号
pageNo: 1, // 必填
pageSize: 1000, // 必填
})
console.log('监控点列表查询', res)
if (res && res.data && res.code === 0) {
const result = JSON.parse(res.data)
if (result) {
_.forEach(this.monitorList, (listItem) => {
listItem.isLeaf = true
})
return result.data.list
} else {
return []
}
}
},
/**
* 监听是否安装海康播放器插件
* 当用户未下载插件时,弹出弹框支持在线下载
*/
downloadDialog() {
if (this.showDialog) {
this.$confirm('插件启动失败,请检查插件是否安装或点击下载按钮进行下载!', '提示', {
confirmButtonText: '下载',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
window.location.href = '/static/hik/VideoWebPlugin.exe'
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消下载',
})
})
this.showDialog = false
}
},
},
}
</script>
<style lang="scss" scoped>
.video-box {
// height: calc(100% - 44px);
background: #fff;
}
.operation-box {
height: 24px;
line-height: 24px;
background: #fff;
}
.icon-font {
font-size: 19px;
}
.tree-container {
border: 1px solid #ccc;
}
.filter-tree {
height: calc(100% - 42px);
overflow: auto;
}
/deep/ .el-tree-node > .el-tree-node__children {
overflow: visible;
}
</style>
单个画面组件的使用:
注意:传入的'id', 'cameraIndexCode'这两个参数都是必传。cameraIndexCode为海康接口的监控列表返回值中的cameraIndexCode属性
单个播放画面组件
<!--
* @Author:
* @LastEditTime: 2023-07-20 18:54:31
* @Description: 单个监控画面播放
-->
<template>
<div :id="id" class="w-100 h-100"></div>
</template>
<script>
export default {
name: 'hikPlay',
props: ['id', 'cameraIndexCode'],
data() {
return {
oWebControl: null, // 播放器实例
pubKey: '',
initCount: 0, // 重连次数
cameraIp: `${currentEnv.VUE_APP_CAMERAIP}`, //综合安防管理平台IP地址
showVideo: false,
timer: null,
}
},
mounted() {
this.initVideoView()
},
watch: {
cameraIndexCode() {
this.initVideoView()
},
},
methods: {
resizeVideo() {
const node = document.getElementById(this.id)
if (node.childNodes.length > 0) {
node.removeChild(node.childNodes[0])
}
if (this.showVideo) {
if (this.timer) clearInterval(this.timer)
this.timer = setTimeout(() => {
let height = document.getElementById(this.id).offsetHeight - 20
let width = document.getElementById(this.id).offsetWidth
this.oWebControl.JS_Resize(width, height)
this.setWndCover()
}, 100)
}
},
// 设置窗口裁剪,当因滚动条滚动导致窗口需要被遮住的情况下需要JS_CuttingPartWindow部分窗口
setWndCover() {
let iWidth = $(window).width()
let iHeight = $(window).height()
console.log(iWidth, iHeight)
let oDivRect = $(`#${this.id}`)
.get(0)
.getBoundingClientRect()
console.log(oDivRect, $(this.id).get(0))
let iCoverLeft = oDivRect.left < 0 ? Math.abs(oDivRect.left) : 0
let iCoverTop = oDivRect.top < 0 ? Math.abs(oDivRect.top) : 0
let iCoverRight = oDivRect.right - iWidth > 0 ? Math.round(oDivRect.right - iWidth) : 0
let iCoverBottom = oDivRect.bottom - iHeight > 0 ? Math.round(oDivRect.bottom - iHeight) : 0
iCoverLeft = iCoverLeft > 1000 ? 1000 : iCoverLeft
iCoverTop = iCoverTop > 600 ? 600 : iCoverTop
iCoverRight = iCoverRight > 1000 ? 1000 : iCoverRight
iCoverBottom = iCoverBottom > 600 ? 600 : iCoverBottom
this.oWebControl.JS_RepairPartWindow(0, 0, 1001, 600) // 多1个像素点防止还原后边界缺失一个像素条
if (iCoverLeft != 0) {
this.oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, 600)
}
if (iCoverTop != 0) {
this.oWebControl.JS_CuttingPartWindow(0, 0, 1001, iCoverTop) // 多剪掉一个像素条,防止出现剪掉一部分窗口后出现一个像素条
}
if (iCoverRight != 0) {
this.oWebControl.JS_CuttingPartWindow(1000 - iCoverRight, 0, iCoverRight, 600)
}
if (iCoverBottom != 0) {
this.oWebControl.JS_CuttingPartWindow(0, 600 - iCoverBottom, 1000, iCoverBottom)
}
},
// 判断播放器是否销毁
initVideoView() {
if (this.cameraIndexCode) {
if (this.oWebControl == null) {
this.initVideoPlugin()
} else {
this.destroyedView()
setTimeout(this.initVideoView, 1000)
}
}
},
// 创建监控播放实例
initVideoPlugin() {
const _this = this
_this.oWebControl = new WebControl({
szPluginContainer: _this.id, // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
cbConnectSuccess: function() {
// 创建WebControl实例成功
console.log('创建WebControl实例成功')
_this.oWebControl
.JS_StartService('window', {
// WebControl实例创建成功后需要启动服务
dllPath: './VideoPluginConnect.dll', // 值"./VideoPluginConnect.dll"写死
})
.then(
function() {
// 启动插件服务成功
console.log('启动插件服务成功')
_this.oWebControl.JS_SetWindowControlCallback({
// 设置消息回调
cbIntegrationCallBack: _this.cbIntegrationCallBack,
})
let height = document.getElementById(_this.id).offsetHeight - 20
let width = document.getElementById(_this.id).offsetWidth
_this.oWebControl.JS_CreateWnd(_this.id, width, height).then(function() {
//JS_CreateWnd创建视频播放窗口,宽高可设定
_this.init() // 创建区域监控播放实例成功后初始化
})
},
function() {
// 启动插件服务失败
}
)
},
cbConnectError: function() {
// 创建WebControl实例失败
_this.oWebControl = null
WebControl.JS_WakeUp('VideoWebPlugin://') // 程序未启动时执行error函数,采用wakeup来启动程序
_this.initCount++
if (_this.initCount < 3) {
setTimeout(function() {
_this.$message.warning('插件未启动,正在尝试启动,请稍候...')
_this.initVideoPlugin()
}, 3000)
} else {
// 父组件提供下载弹框,避免组件触发多次下载弹框
_this.$emit('downloadDialog')
}
},
cbConnectClose: function(bNormalClose) {
// 异常断开:bNormalClose = false
// JS_Disconnect正常断开:bNormalClose = true
if (!bNormalClose) {
_this.$message.error('视屏链接异常中断!')
}
_this.oWebControl = null
},
})
},
init() {
const _this = this
_this.getPubKey(function() {
// 请自行修改以下变量值
let appkey = `${currentEnv.VUE_APP_CAMERA_KEY}` //综合安防管理平台提供的appkey,必填
let secret = _this.setEncrypt(`${currentEnv.VUE_APP_CAMERA_ENCRYPT}`) //综合安防管理平台提供的secret,必填
let ip = _this.cameraIp //综合安防管理平台IP地址,必填
let playMode = 0 //初始播放模式:0-预览,1-回放
let port = 8443 //综合安防管理平台端口,若启用HTTPS协议,默认443
let snapDir = 'D:\\SnapDir' //抓图存储路径
let videoDir = 'D:\\VideoDir' //紧急录像或录像剪辑存储路径
let layout = '1x1' //playMode指定模式的布局
let enableHTTPS = 1 //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1
let encryptedFields = 'secret' //加密字段,默认加密领域为secret
let showToolbar = 0 //是否显示工具栏,0-不显示,非0-显示
let showSmart = 1 //是否显示智能信息(如配置移动侦测后画面上的线框),0-不显示,非0-显示
let buttonIDs = '' //自定义工具条按钮
let reconnectTimes = 0 // 断流后无限次重连
// 请自行修改以上变量值
_this.oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
snapDir: snapDir, //抓图存储路径
videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs: buttonIDs, //自定义工具条按钮
reconnectTimes: reconnectTimes, // 断流后无限次重连
}),
})
.then(function(oData) {
let height = document.getElementById(_this.id).offsetHeight - 20
let width = document.getElementById(_this.id).offsetWidth
_this.oWebControl.JS_Resize(width, height) // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
_this.startPreview()
})
})
},
// 监控视频预览功能
startPreview() {
let _this = this
let cameraIndexCode = _this.cameraIndexCode //获取输入的监控点编号值,必填
let streamMode = 0 //主子码流标识:0-主码流,1-子码流
let transMode = 1 //传输协议:0-UDP,1-TCP
let gpuMode = 0 //是否启用GPU硬解,0-不启用,1-启用
let wndId = -1 //播放窗口序号(在2x2以上布局下可指定播放窗口)
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, '')
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, '')
_this.oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: JSON.stringify({
cameraIndexCode: cameraIndexCode, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId: wndId, //可指定播放窗口
}),
})
this.showVideo = true
},
//停止监控预览
stopPreview() {
this.oWebControl.JS_RequestInterface({
funcName: 'stopPreview',
})
},
// 摧毁播放器
destroyedView() {
if (this.oWebControl != null) {
this.stopPreview()
this.oWebControl.JS_HideWnd() // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
this.oWebControl.JS_Disconnect().then(
function() {
// 断开与插件服务连接成功
},
function() {
// 断开与插件服务连接失败
}
)
}
},
// 获取监控公钥
getPubKey(callback) {
this.oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then((oData) => {
if (oData.responseMsg.data) {
this.pubKey = oData.responseMsg.data
callback()
}
})
},
// 监控RSA加密
setEncrypt(value) {
let encrypt = new JSEncrypt()
encrypt.setPublicKey(this.pubKey)
return encrypt.encrypt(value)
},
// 设置窗口回调
setCallBack() {
this.oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: this.cbIntegrationCallBack,
})
},
// 推送消息
cbIntegrationCallBack(oData) {
// type =7 播放窗口双击事件
if (oData.responseMsg.type === 7) {
// 全屏
this.oWebControl.JS_RequestInterface({
funcName: 'setFullScreen',
})
this.$emit('videoFullScreen', {
id: this.id,
isFullScreen: true,
})
} else if (oData.responseMsg.type === 5) {
/**
* type = 5 插件窗口是否全屏
* 向父组件传递是否退出全屏信息 控制其他播放器的显示和隐藏
* result = 1024 进入全屏 result = 1025 退出全屏
*/
let isFullScreen = oData.responseMsg.msg.result === 1025 ? false : true
this.$emit('videoFullScreen', {
id: this.id,
isFullScreen,
})
} else if (oData.responseMsg.type === 2) {
if (oData.responseMsg.msg.result === 769) {
this.hideWnd()
let height = document.getElementById(this.id).offsetHeight - 20
let width = document.getElementById(this.id).offsetWidth
this.oWebControl.JS_CreateWnd(this.id, width, height).then(() => {
this.init()
})
} else if (oData.responseMsg.msg.result === 768) {
this.showWnd()
}
}
console.log(oData)
},
// 隐藏窗口
hideWnd() {
this.oWebControl.JS_HideWnd()
},
// 显示窗口
showWnd() {
this.oWebControl.JS_ShowWnd()
},
},
beforeDestroy() {
this.destroyedView()
clearInterval(this.timer)
},
}
</script>