vue+海康的视频播放
播放必须安装和引入海康的插件
引入js文件,安装对应的插件
在public/static的index.html文件下引入对应的js文件和安装VideoWebPlugin.exe文件
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<script src="<%= BASE_URL %>homeLinkConfig.js"></script>
<title>xxxxxxx</title>
</head>
<body>
<script src="jquery-1.12.4.min.js"></script>
<script src="jsencrypt.min.js"></script>
<script src="jsWebControl-1.0.0.min.js"></script>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
对照给的demo文件开发
<template>
<div class="main">
<div class="left">
<div class="top_search">
<el-input
class="selectInput"
placeholder="输入通道名"
:clearable="true"
:suffix-icon="Search"
v-model="filterText"
>
</el-input>
<div class="search_icon" @click="findTd">
<div></div>
</div>
</div>
<div class="top_tree">
<el-tree
v-if="findstatus"
ref="tree"
:data="treeData"
:props="props"
node-key="id"
:load="loadTree"
:lazy="true"
:default-expanded-keys="['001']"
check-strictly
highlight-current
:filter-node-method="filterNode"
@node-click="nodeClick"
>
<!-- @mousedown="onMousedown(node)" -->
<template #default="{ node }">
<div class="custom-tree-node" style="user-select: none">
<span class="name">{{ node.label }}</span>
<span style="color: green; margin-left: 20px">{{
node.data.nodeType === "org" ? "组织" : "通道"
}}</span>
</div>
</template>
</el-tree>
<el-tree
v-if="!findstatus"
ref="tree"
:data="treeData"
:props="props1"
node-key="id"
:default-expanded-keys="['001']"
check-strictly
highlight-current
:filter-node-method="filterNode"
@node-click="nodeClick"
>
<!-- @mousedown="onMousedown(node)" -->
<template #default="{ node }">
<div class="custom-tree-node" style="user-select: none">
<span class="name">{{ node.label }}</span>
<span style="color: green; margin-left: 20px">{{
node.data.nodeType === "org" ? "组织" : "通道"
}}</span>
</div>
</template>
</el-tree>
</div>
</div>
<div class="right">
<div class="title">
<div class="text">{{ showTitle }}</div>
<div class="exit" title="退出">
<svg-icon
:icon-class="'close'"
class="close"
@click="toclose"
></svg-icon>
<div class="close_text" @click="toclose">关闭</div>
</div>
</div>
<div class="right_main" ref="right_main">
<div class="window1" ref="window1" v-if="videoType === 'video1'">
<div
id="playWnd"
v-show="lookStatus==='预览'"
:style="{
height: playWndHeight + 'px',
width: playWndWidth + 'px',
}"
></div>
<div
id="playWnd1"
v-show="lookStatus==='录像'"
:style="{
height: playWndHeight + 'px',
width: playWndWidth + 'px',
}"
></div>
</div>
</div>
<div class="right_bottom">
<div class="left_b">
<!-- <div class="zero" @click="closeVideo" title="关闭视频"></div>
<div class="one" @click="snapshot" title="截图"></div>
<div class="two" @click="download" title="录制视频"></div>
<div class="three" title="云台控制" @click="changeControl"></div> -->
</div>
<div class="right_b">
<div class="show_type">
<div
class="one_t"
:class="lookStatus === '预览' ? 'blue_t' : ''"
@click="goLook('预览')"
>
预览
</div>
<div
class="two_t"
:class="lookStatus === '录像' ? 'blue_t' : ''"
@click="goLook('录像')"
>
录像
</div>
</div>
</div>
</div>
</div>
</div>
<transition name="fadeBox">
<div class="Console" v-if="controlStatus">
<div class="top">
<div class="text">云台控制</div>
<div class="xxx" @click="closeControl"></div>
</div>
<div class="bottom">
<div class="circular">
<div class="b1" @mousedown="down('top')"></div>
<div class="b2"></div>
<div class="b3"></div>
<div class="b4"></div>
<div class="small-circular"></div>
</div>
</div>
</div>
</transition>
</template>
<script>
import {
setTimers,
getTree,
treeLazyLoading,
searchTreeByPassage,
getPassageByGis,
getOrgDevTreePassage,
getOrgDevTreeEquipment,
realMonitor,
iccVideorealMonitor,
queryPassage,
} from "./service/index.js";
import { mapGetters } from "vuex";
import { Search } from "@element-plus/icons-vue";
import DHPlayer from "@/views/view-page/DaHua/com/DHPlayer";
let oWebControl = null;
var initCount = 0;
var pubKey = "";
export default {
name: "DhPlayer",
components: { DHPlayer, Search },
data() {
return {
//海康
playWndHeight: "", // 视频盒子的高度
playWndWidth: "", // 视频盒子的宽度
argument: {
appkey: "xxxxxxx",
ip: "xxx.xx.xxx.xxx",
port: 443,
secret: "xxxxxxx",
enableHTTPS: 1,
language: "zh_CN",
layout: "2x2",
playMode: 0,
reconnectDuration: 5,
reconnectTimes: 5,
showSmart: 0,
showToolbar: 1,
toolBarButtonIDs:
"2048,2049,2050,2304,2306,2305,2307,2308,2309,4096,4608,4097,4099,4098,4609,4100",
buttonIDs: "0,16,256,257,258,259,260,512,514,515,516,517,768,769,770",
snapDir: "D:/snap",
videoDir: "D:/video",
},
result: "",
findstatus: false,
lookStatus: "预览",
filterText: "",
props: {
label: "name",
value: "id",
isLeaf: "leaf",
},
props1: {
label: "text",
value: "id",
children: "children",
},
treeData: [{
text: '2-1',
id: '123123331',
left: false
}],
showModal: false,
showTitle: "",
controlStatus: false,
currentNum: 0,
videoType: "video1",
pathList: [],
pathList2: [],
};
},
watch: {
videoType(val, oldVal) {
this.currentNum = 0;
this.$nextTick(() => {
// this.$refs[val].initVideo();
});
// setTimeout(() => {
// this.setDragEnable(false);
// }, 700);
},
},
computed: {
...mapGetters(["videoNumArray"]),
},
beforeMount() {
let that = this;
// document.addEventListener("visibilitychange", function () {
// if (document.visibilityState == "hidden") {
// console.log(11111);
// //切离该页面时执行
// that.$refs[that.videoType].hide();
// } else if (document.visibilityState == "visible") {
// console.log(22222);
// //切换到该页面时执行
// that.$refs[that.videoType].show();
// }
// });
},
mounted() {
this.playWndHeight = this.$refs.window1.clientHeight; // 首次加载时的到父容器的高度
this.playWndWidth = this.$refs.window1.clientWidth; // 首次加载时的到父容器的宽度
let that = this;
this.$nextTick(async () => {
// 初始化摄像头
await this.initPlugin("playWnd");
});
// 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
window.addEventListener("resize", () => {
if (oWebControl != null) {
oWebControl.JS_Resize(this.playWndWidth, this.playWndHeight);
}
});
// window.onunload = function () {
// if (flag) {
// console.log("关闭操作");
// } else {
// //切离该页面时执行
// this.$refs[this.videoType].hide();
// console.log("关闭操作");
// }
// };
window.onbeforeunload = function () {
if (!flag) {
console.log("关闭操作");
} else {
//切离该页面时执行
this.$refs[this.videoType].hide();
console.log("关闭操作");
}
};
},
methods: {
//海康
initPlugin(wndId) {
let that = this;
oWebControl = new window.WebControl({
szPluginContainer: "playWnd",
iServicePortStart: 15900,
iServicePortEnd: 15909,
szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: function () {
initCount = 0;
that.setCallbacks();
oWebControl
.JS_StartService("window", {
dllPath: "./VideoPluginConnect.dll",
})
.then(
function () {
oWebControl
.JS_CreateWnd(
wndId,
that.playWndWidth,
that.playWndHeight
)
.then(function () {
oWebControl
.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
oWebControl.JS_Resize(
that.playWndWidth,
that.playWndHeight
);
that.initPlayer();
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
}
});
});
},
function () {}
);
},
cbConnectError: function () {
console.log("cbConnectError");
oWebControl = null;
$("#playWnd").html("插件未启动,正在尝试启动,请稍候...");
window.WebControl.JS_WakeUp("VideoWebPlugin://");
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
$("#playWnd").html("插件启动失败,请检查插件是否安装!");
}
},
cbConnectClose: function (bNormalClose) {
// 异常断开:bNormalClose = false
// JS_Disconnect正常断开:bNormalClose = true
console.log("cbConnectClose");
oWebControl = null;
},
});
},
// 设置窗口控制回调
setCallbacks() {
oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: this.cbIntegrationCallBack,
});
},
// 推送消息
cbIntegrationCallBack(oData) {
// this.showCBInfo(JSON.stringify(oData.responseMsg));
},
//初始化窗口的数据
initialization() {},
// 初始化窗口预览
initPlayer() {
let json = {
argument: JSON.stringify(this.argument),
funcName: "init",
};
let that = this;
oWebControl.JS_RequestInterface(json).then(function (oData) {
// this.showCBInfo(JSON.stringify(oData ? oData.responseMsg : ""));
// UpdatePlayParamValue();
oWebControl.JS_Resize(that.playWndWidth, that.playWndHeight);
that.changeSrc()
});
},
// 初始化窗口回放
initPlayerBack() {
let json = {
argument: JSON.stringify({
appkey: "xxxxx",
ip: "xxx.xx.xxx.xxx",
port: 443,
secret: "xxxxxxxxx",
enableHTTPS: 1,
language: "zh_CN",
layout: "2x2",
playMode: 1,
reconnectDuration: 5,
reconnectTimes: 5,
showSmart: 0,
showToolbar: 1,
toolBarButtonIDs:
"2048,2049,2050,2304,2306,2305,2307,2308,2309,4096,4608,4097,4099,4098,4609,4100",
buttonIDs: "0,16,256,257,258,259,260,512,514,515,516,517,768,769,770",
snapDir: "D:/snap",
videoDir: "D:/video",
}),
funcName: "init",
};
console.log(json, "json");
oWebControl.JS_RequestInterface(json).then(function (oData) {
console.log(oData);
// this.showCBInfo(JSON.stringify(oData ? oData.responseMsg : ""));
// UpdatePlayParamValue();
oWebControl.JS_Resize(this.playWndWidth, this.playWndHeight);
});
},
// 显示接口返回的消息及插件回调信息
showCBInfo(szInfo, type) {
if (type === "error") {
szInfo =
"<div style='color: red;'>" +
this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss") +
" " +
szInfo +
"</div>";
} else {
szInfo =
"<div>" +
this.dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss") +
" " +
szInfo +
"</div>";
}
$("#cbInfo").html(szInfo + $("#cbInfo").html());
},
// 格式化时间
dateFormat(oDate, fmt) {
var o = {
"M+": oDate.getMonth() + 1, //月份
"d+": oDate.getDate(), //日
"h+": oDate.getHours(), //小时
"m+": oDate.getMinutes(), //分
"s+": oDate.getSeconds(), //秒
"q+": Math.floor((oDate.getMonth() + 3) / 3), //季度
S: oDate.getMilliseconds(), //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
(oDate.getFullYear() + "").substr(4 - RegExp.$1.length)
);
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1
? o[k]
: ("00" + o[k]).substr(("" + o[k]).length)
);
}
}
return fmt;
},
// 判断字符串是否为json
isJSON(str) {
if (typeof str == "string") {
try {
var obj = JSON.parse(str);
if (typeof obj == "object" && obj) {
return true;
} else {
// this.showCBInfo("param is not the correct JSON message");
return false;
}
} catch (e) {
// this.showCBInfo("param is not the correct JSON message");
return false;
}
}
console.log("It is not a string!");
},
// value为字符串,JS_RequestInterface仅接收json格式的变量,且需要先解析出argument,并且将argument字段的内容转为字符串
requestInterface(value)
{
this.isJSON(value);
var JsonParam = JSON.parse(value);
var JsonArgument = JsonParam.argument;
JsonParam.argument = JSON.stringify(JsonArgument);
oWebControl.JS_RequestInterface(JsonParam).then(function (oData) {
console.log(oData)
// this.showCBInfo(JSON.stringify(oData ? oData.responseMsg : ''));
});
},
// 获取公钥
getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
console.log(oData);
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
},
//反初始化
uninit() {
oWebControl.JS_RequestInterface({
funcName: "uninit",
});
},
// RSA加密
setEncrypt(value) {
var encrypt = new window.JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
},
goLook(text) {
this.uninit();
this.lookStatus = text;
switch (text) {
case "预览":
this.initPlayer();
break;
case "录像":
this.initPlayerBack();
break;
default:
break;
}
},
//修改播放源
changeSrc() {
let json;
if (this.lookStatus === "预览") {
json = {
argument: {
authUuid: "",
cameraIndexCode: "xxxxxxxxxx",
ezvizDirect: 0,
gpuMode: 0,
streamMode: 0,
transMode: 1,
wndId: -1,
cascade: 1,
},
funcName: "startPreview",
};
json.argument = JSON.stringify(json.argument)
oWebControl.JS_RequestInterface(json).then(function (oData) {
console.log(oData)
// this.showCBInfo(JSON.stringify(oData ? oData.responseMsg : ''));
});
}
},
async nodeClick(node) {
this.changeSrc()
},
//隐藏播放器
HideWnd(){
oWebControl.JS_HideWnd()
},
//显示播放器
ShowWnd(){
oWebControl.JS_ShowWnd();
},
toclose() {
this.HideWnd()
this.$confirm("是否确定关闭?", "关闭窗口", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
window.close();
})
.catch((e) => {
this.ShowWnd()
console.log(e);
});
},
//模糊搜索的通道
async searchTreeByPassage() {
try {
let { data } = await searchTreeByPassage({
type: "001;00_1;1",
checkStat: "0",
act: "search",
searchKey: this.filterText,
});
} catch (error) {}
},
},
};
</script>
<style scoped lang='scss'>
.top_tree::-webkit-scrollbar {
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
}
/*定义滚动条轨道*/
.top_tree::-webkit-scrollbar-track {
border-radius: 5px;
background: #2f4c5b;
}
/*定义滑块*/
.top_tree::-webkit-scrollbar-thumb {
border-radius: 1px;
background: rgba(45, 183, 244);
}
//屏蔽单击暂停
.vjs-tech {
pointer-events: none;
}
.activeBorder {
video:first-child {
border: 1px solid red !important;
}
}
.main {
width: 100vw;
height: 100vh;
display: flex;
background: rgba(7, 23, 45, 1);
.left {
flex: 0 0 14%;
height: 100%;
background: #0b2444;
.top_tree {
height: calc(100% - 45px);
width: 100%;
overflow: auto;
}
.top_search {
height: 45px;
width: 100%;
background: #0b2444;
display: flex;
.search_icon {
width: 45px;
height: 35px;
background: rgb(15, 49, 96, 1);
display: flex;
justify-content: center;
align-items: center;
div {
// margin-top: -7px;
background: rgb(15, 49, 96, 1);
width: 18px;
height: 18px;
background: url("./images/findsearch.png") no-repeat center;
}
}
}
.selectInput {
margin-bottom: 10px;
background: rgb(15, 49, 96, 1);
border-radius: 0px 0px 4px 0px;
:deep(.el-input__inner) {
background: transparent;
border: none;
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #cfd8e3;
line-height: 10px;
}
}
:deep(.el-tree) {
background-color: rgb(15, 49, 96, 1);
font-size: 18px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #e5e5e5;
line-height: 10px;
}
:deep(.el-tree--highlight-current) {
background-color: rgb(15, 49, 96, 1);
}
:deep(.is-focusable) {
background-color: rgb(15, 49, 96, 1);
}
:deep(.is-focusable:hover) {
background-color: rgb(15, 49, 96, 1);
}
:deep(.is-current) {
color: #2dc2fe;
background: #294466;
border-radius: 8px;
}
:deep(.is-current:hover) {
background-color: transparent;
}
:deep(.el-tree-node__content) {
background-color: transparent;
}
:deep(.el-tree-node) {
padding: 5px 0px;
}
}
.right {
flex: 0 0 85%;
height: 100%;
background: rgba(15, 49, 96, 1);
display: flex;
margin-left: 1%;
flex-direction: column;
.title {
display: flex;
align-items: center;
justify-content: space-between;
flex: 0 0 50px;
background: rgba(15, 45, 96, 1);
.exit {
width: 80px;
height: 30px;
cursor: pointer;
margin-right: 5px;
display: flex;
align-items: center;
.close {
color: #9bc5d4;
font-size: 20px;
margin-left: 5px;
margin-right: 0px;
cursor: pointer;
}
.close_text {
cursor: pointer;
font-family: Microsoft YaHei;
font-weight: bold;
color: #88b4c9;
}
}
.text {
margin-left: 10px;
font-size: 20px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #00ccff;
line-height: 10px;
}
}
.right_bottom {
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(12, 38, 76, 1);
flex: 0 0 50px;
.left_b {
display: flex;
align-items: center;
justify-content: left;
height: 100%;
.zero {
width: 26px;
height: 22px;
cursor: pointer;
margin: 0 39px;
background-image: url("./images/暂停.png");
background-size: 100% 100%;
background-position: center;
}
.one {
width: 26px;
height: 22px;
cursor: pointer;
margin-right: 39px;
background-image: url("./images/相机.png");
background-size: 100% 100%;
background-position: center;
}
.two {
width: 26px;
height: 22px;
cursor: pointer;
margin-right: 39px;
background-image: url("./images/video.png");
background-size: 100% 100%;
background-position: center;
}
.three {
width: 26px;
height: 22px;
cursor: pointer;
margin-right: 39px;
background-image: url("./images/control.png");
background-size: 100% 100%;
background-position: center;
}
}
.right_b {
display: flex;
align-items: center;
justify-content: right;
height: 100%;
margin-right: 10px;
.show_type {
width: 164px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #125dcc;
border-radius: 4px;
cursor: pointer;
.one_t {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
flex: 1;
font-size: 18px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #e5e5e5;
line-height: 10px;
background: transparent;
border-radius: 4px 0 0 4px;
}
.two_t {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
flex: 1;
font-size: 18px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #e5e5e5;
line-height: 10px;
background: transparent;
}
.blue_t {
background: #125dcc !important;
}
}
.one {
width: 26px;
height: 22px;
cursor: pointer;
margin: 0 39px;
background-image: url("./images/s1.png");
background-size: 100% 100%;
background-position: center;
}
.two {
width: 26px;
height: 22px;
cursor: pointer;
margin-right: 39px;
background-image: url("./images/s2.png");
background-size: 100% 100%;
background-position: center;
}
.three {
width: 26px;
height: 22px;
cursor: pointer;
margin-right: 39px;
background-image: url("./images/s3.png");
background-size: 100% 100%;
background-position: center;
}
}
}
.right_main {
flex: 1;
display: flex;
overflow: auto;
.window1 {
display: flex;
flex: 1;
:deep(#playwnd) {
flex: 1;
}
:deep(#testPlayer2) {
flex: 1;
}
}
}
}
}
.Console {
width: 230px;
height: 230px;
position: relative;
bottom: 235px;
left: 16px;
display: flex;
flex-direction: column;
z-index: 1500;
.top {
display: flex;
justify-content: space-between;
align-items: center;
flex: 0 0 45px;
width: 100%;
background: #132b4c;
.text {
font-size: 18px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #e5e5e5;
line-height: 10px;
margin-left: 10px;
}
.xxx {
width: 13px;
height: 12px;
margin-right: 10px;
background: url("./images/xxx.png");
background-position: center;
background-size: 100% 100%;
cursor: pointer;
}
}
.bottom {
flex: 1;
width: 100%;
background: #07172d;
display: flex;
justify-content: center;
align-items: center;
.circular {
display: flex;
justify-content: center;
align-items: center;
width: 150px;
height: 150px;
border-top: 1px solid #ffffff;
border-bottom: 1px solid #ffffff;
border-radius: 50%;
position: relative;
.b1 {
width: 48px;
height: 44px;
background: url("./images/topblack.png") no-repeat center;
background-size: 100% 100%;
position: absolute;
left: 50px;
top: 1px;
}
.b1:hover {
background: url("./images/toplight.png") no-repeat center;
cursor: pointer;
}
.b2 {
width: 48px;
height: 44px;
background: url("./images/rightblack.png") no-repeat center;
background-size: 100% 100%;
position: absolute;
left: 100px;
top: 53px;
}
.b2:hover {
background: url("./images/rightlight.png") no-repeat center;
cursor: pointer;
}
.b3 {
width: 48px;
height: 44px;
background: url("./images/leftblack.png") no-repeat center;
background-size: 100% 100%;
position: absolute;
left: 0px;
top: 53px;
}
.b3:hover {
background: url("./images/leftlight.png") no-repeat center;
cursor: pointer;
}
.b4 {
width: 48px;
height: 44px;
background: url("./images/bottomblack.png") no-repeat center;
background-size: 100% 100%;
position: absolute;
left: 50px;
bottom: 0px;
}
.b4:hover {
background: url("./images/downlight.png") no-repeat center;
cursor: pointer;
}
.small-circular {
width: 60px;
height: 60px;
border-right: 1px solid #ffffff;
border-left: 1px solid #ffffff;
border-radius: 50%;
}
}
}
}
.fadeBox-enter-active {
animation: fadeInUp 0.5s;
}
.fadeBox-leave-active {
animation: fadeOutDown 0.5s;
}
</style>