自行下载
海康开放平台
demo 都写得很清楚,不多描述
注意,两者需要的数据不一样,web是需要第三方标识,下载安装插件到电脑,要配置海康数据。h5是视频流,只需传接口返回的流地址
1.视频web插件
ps: 逆天插件,层级非常高,打开弹窗都会被挡住,需要做限制
vue2写法,公共vue文件写法,调用文件即可
开始时需要以下配置,不知道的找对接平台数据的人,必须要,否则播不了
getParameterData: { port: 443, ip: "10.10.2.22", appKey: "20224202", appSecret: "ndqXXXXXt1jHY2r8Uy", enableHTTPS: 1,}, //海康数据
// 注意版本不一样,加载插件的声明不一样,下面vue3的是最新的,声明实例new WebControl切换下
<!-- 海康插件组件 --><template> <div class="video-center" ref="videoCenter"> <div :id="playWnd" class="playWnd"></div> </div> </template> <script> const control = require("../video/jsWebControl-1.0.0.min.js"); const jsencrypt = require("../video/jsencrypt.min.js"); export default { data() { return { oWebControl: null, pubKey: "", initCount: 0, w: 0, h: 0, winId: 1, }; }, props: { playWnd: { type: String, default: 'playWnd', }, //播放类型 0预览 1回放 playMode: { type: Number, default: 0, }, //初始化数据 initData: { type: Object, default() { return { enableHttps: 1, encryptedFields: "secret", layout: "1x1", btIds: "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769", showSmart: 1, showToolbar: 1, snapDir: "D:\\SnapDir", videoDir: "D:\\VideoDir", }; }, }, }, created: function () { this.initPlugin(); }, mounted: function () { this.$nextTick(()=>{ this.h = this.$refs["videoCenter"].clientHeight; this.w = this.$refs["videoCenter"].clientWidth; }) window.addEventListener("resize",() => { if (this.$refs["videoCenter"]) { this.h = this.$refs["videoCenter"].clientHeight; this.w = this.$refs["videoCenter"].clientWidth; this.resetFun(); } }); }, computed: {}, methods: { // 设置窗口裁剪,当因滚动条滚动导致窗口需要被遮住的情况下需要JS_CuttingPartWindow部分窗口 setWndCover() { var iWidth = window.width; var iHeight = window.height; var oDivRect = document .querySelector("#"+this.playWnd) .getBoundingClientRect(); var iCoverLeft = oDivRect.left < 0 ? Math.abs(oDivRect.left) : 0; var iCoverTop = oDivRect.top < 0 ? Math.abs(oDivRect.top) : 0; var iCoverRight = oDivRect.right - iWidth > 0 ? Math.round(oDivRect.right - iWidth) : 0; var iCoverBottom = oDivRect.bottom - iHeight > 0 ? Math.round(oDivRect.bottom - iHeight) : 0; iCoverLeft = iCoverLeft > this.w ? this.w : iCoverLeft; iCoverTop = iCoverTop > this.h ? this.h : iCoverTop; iCoverRight = iCoverRight > this.w ? this.w : iCoverRight; iCoverBottom = iCoverBottom > this.h ? this.h : iCoverBottom; this.oWebControl.JS_RepairPartWindow(0, 0, this.w + 1, this.h); // 多1个像素点防止还原后边界缺失一个像素条 if (iCoverLeft != 0) { this.oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, this.h); } if (iCoverTop != 0) { this.oWebControl.JS_CuttingPartWindow( 0, 0, this.w + 1, iCoverTop ); // 多剪掉一个像素条,防止出现剪掉一部分窗口后出现一个像素条 } if (iCoverRight != 0) { this.oWebControl.JS_CuttingPartWindow( this.w - iCoverRight, 0, iCoverRight, this.h ); } if (iCoverBottom != 0) { this.oWebControl.JS_CuttingPartWindow( 0, this.h - iCoverBottom, this.w, iCoverBottom ); } }, // 初始化 init() { this.getPubKey(() => { let { appSecret, ...hkData } = this.$store.state.getParameterData;//海康提供的认证信息 this.oWebControl.JS_RequestInterface({ funcName: "init", argument: JSON.stringify({ appkey: hkData.appKey, //API网关提供的appkey secret: this.setEncrypt(appSecret), //API网关提供的secret ip: hkData.ip, //API网关IP地址 playMode: this.playMode, //播放模式(决定显示预览还是回放界面) port: hkData.port, //端口 snapDir: this.initData.snapDir, //抓图存储路径 videoDir: this.initData.videoDir, //紧急录像或录像剪辑存储路径 layout: this.initData.layout, //布局 enableHTTPS: hkData.enableHTTPS, //是否启用HTTPS协议 encryptedFields: this.initData.encryptedFields, //加密字段 showToolbar: this.initData.showToolbar, //是否显示工具栏 showSmart: this.initData.showSmart, //是否显示智能信息 }) }).then((oData) => { // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题 this.oWebControl.JS_Resize(this.w, this.h); }); }); }, /* 视频预览业务功能 */ startPreviewFun(val) { this.oWebControl.JS_RequestInterface({ funcName: "startPreview", argument: JSON.stringify({ cameraIndexCode: val, streamMode: 0, transMode: 1, gpuMode: 0, wndId: this.winId, }), }).then((oData) => { console.log('播放成功',oData) }); }, /* 视频回放业务功能 */ startPlaybackFun(val, start, end, streamMode = 1) { this.oWebControl.JS_RequestInterface({ funcName: "startPlayback", argument: JSON.stringify({ cameraIndexCode: val, //监控点编号 startTimeStamp: start, //录像查询开始时间戳,单位:秒 endTimeStamp: end, //录像结束开始时间戳,单位:秒 streamMode: streamMode,//主子码流标识:0-主码流,1-子码流 recordLocation: 0, //录像存储类型:0-中心存储,1-设备存储 transMode: 1, //传输协议:0-UDP,1-TCP gpuMode: 0, //是否启用GPU硬解,0-不启用,1-启用 wndId: this.wndId //可指定播放窗口 }) }).then((oData) => { console.log('回放',oData) }); }, // RSA加密 setEncrypt(value) { var encrypt = new jsencrypt.JSEncrypt(); encrypt.setPublicKey(this.pubKey); return encrypt.encrypt(value); }, // 推送消息 cbIntegrationCallBack(oData) { // 窗口选中 if (oData.responseMsg.type === 1) { this.winId = oData.responseMsg.msg.wndId } }, // 设置窗口控制回调 setCallbacks() { this.oWebControl.JS_SetWindowControlCallback({ cbIntegrationCallBack: this.cbIntegrationCallBack, }); }, /* 获取公钥 */ 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(); } }); }, // 加载插件 initPlugin() { let _this = this; this.oWebControl = new control.WebControl({ szPluginContainer: this.playWnd, iServicePortStart: 15900, iServicePortEnd: 15909, szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid cbConnectSuccess: function () { _this.setCallbacks(); _this.oWebControl .JS_StartService("window", { dllPath: "./VideoPluginConnect.dll"}).then(() => { _this.oWebControl.JS_CreateWnd(_this.playWnd, _this.w, _this.h).then(() => { _this.init(); }); }, function () {} ); }, cbConnectError: function () { _this.oWebControl = null; initCount ++; if (initCount < 3) { setTimeout(function () { initPlugin(); }, 3000) } else { console.log('插件启动失败,请检查插件是否安装!') } }, cbConnectClose: function (bNormalClose) { console.log("cbConnectClose"); _this.oWebControl = null; }, }); }, // 重置窗口大小 resetFun() { if (this.oWebControl != null) { this.oWebControl.JS_Resize(this.w, this.h); this.setWndCover(); } }, }, destroyed() { this.oWebControl.JS_HideWnd(); this.oWebControl.JS_DestroyWnd().then( function () { console.log("销毁插件窗口成功"); }, function () { console.log("销毁插件窗口失败"); } ); }, }; </script> <style scoped="scoped"> .video-center { width: 100%; height: 100%; } </style>
不完整,自行补充
<template><PreviewVideo ref="webVideo" :playMode="0" :initData="initData"/></template><script>export default { data() { return { initData: { enableHttps: 0, encryptedFields: "secret", layout: "2x2", // 4个窗口 showSmart: 1, showToolbar: 1, snapDir: "D:SnapDir", videoDir: "D:VideoDir",}, } }, method () { //播放时调用videoPlayFun() {//预览//第三方标识,由海康提供,后端传回this.$refs['webVideo'].startPreviewFun(data.deviceNameEn)//回放,需要回放时间,若使用element的时间戳,需要/1000,变为秒单位//playMode传1this.$refs['webVideo'].startPlaybackFun( data.deviceNameEn, startTime, endTime ) } }}</script>
vue3+vite
使用版本
index文件引入
playVideo传第三方标识,请自行修改以下变量值如上
可直接复制使用vue,点击播放
能直接使用,测试如下,可测试第三方标识能否使用
<template> <div class="video-center" ref="videoCenter"> <div @click="playVideo('1005ede4f95a4447897b8fd1fa8cd6f7', 1)">"1005ede4f95a4447897b8fd1fa8cd6f7"</div> <div @click="playVideo('933d67747cb248ba93e0a65b5ac751ac', 2)">"933d67747cb248ba93e0a65b5ac751ac"</div> <div @click="playVideo('e77fa1c7d9f04c9b893a74d441d5a53b', 3)">"e77fa1c7d9f04c9b893a74d441d5a53b"</div> <div id="playWnd" class="playWnd"></div> </div></template><script setup lang="ts">import { onMounted, ref, reactive, unref } from 'vue'var initCount = 0;var oWebControl = nullvar pubKey = '';// 创建播放实例const initPlugin = () => { oWebControl = new WebControl({ szPluginContainer: "playWnd", // 指定容器idiServicePortStart: 15900, // 指定起止端口号,建议使用该值iServicePortEnd: 15900, szClassId:"23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsidcbConnectSuccess: function () { // 创建WebControl实例成功oWebControl.JS_StartService("window", { // WebControl实例创建成功后需要启动服务dllPath: "./VideoPluginConnect.dll" // 值"./VideoPluginConnect.dll"写死 }).then(function () { // 启动插件服务成功oWebControl.JS_SetWindowControlCallback({ // 设置消息回调cbIntegrationCallBack: cbIntegrationCallBack});oWebControl.JS_CreateWnd("playWnd", 1000, 600).then(function () { //JS_CreateWnd创建视频播放窗口,宽高可设定init(); // 创建播放实例成功后初始化});}, function () { // 启动插件服务失败});},cbConnectError: function () { // 创建WebControl实例失败oWebControl = null;WebControl.JS_WakeUp("VideoWebPlugin://"); // 程序未启动时执行error函数,采用wakeup来启动程序initCount ++;if (initCount < 3) { setTimeout(function () {initPlugin();}, 3000)} else { console.log('插件启动失败,请检查插件是否安装!')// $("#playWnd").html("插件启动失败,请检查插件是否安装!");}},cbConnectClose: function (bNormalClose) { // 异常断开:bNormalClose = false// JS_Disconnect正常断开:bNormalClose = trueconsole.log("cbConnectClose");oWebControl = null; console.log('插件未启动,正在尝试启动,请稍候...')// $("#playWnd").html("插件未启动,正在尝试启动,请稍候...");WebControl.JS_WakeUp("VideoWebPlugin://");initCount ++;if (initCount < 3) {setTimeout(function () {initPlugin();}, 3000)} else { console.log('插件启动失败,请检查插件是否安装!')// $("#playWnd").html("插件启动失败,请检查插件是否安装!");}}});}// 推送消息const cbIntegrationCallBack = (oData) => { console.log(JSON.stringify(oData.responseMsg))}const init = () => { getPubKey(function () { // 请自行修改以下变量值 var appkey = "20224202"; //综合安防管理平台提供的appkey,必填 var secret = setEncrypt("xxxCAFyke4t1jHY2r8Uy"); //综合安防管理平台提供的secret,必填 var ip = "10.10.11.12"; //综合安防管理平台IP地址,必填 var playMode = 0; //初始播放模式:0-预览,1-回放 var port = 443; //综合安防管理平台端口,若启用HTTPS协议,默认443 var snapDir = "D:\\SnapDir"; //抓图存储路径 var videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径 var layout = "2x2"; //playMode指定模式的布局 var enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1 var encryptedFields = 'secret'; //加密字段,默认加密领域为secret var showToolbar = 1; //是否显示工具栏,0-不显示,非0-显示 var showSmart = 1; //是否显示智能信息(如配置移动侦测后画面上的线框),0-不显示,非0-显示 var buttonIDs = "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮 // 请自行修改以上变量值 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 //自定义工具条按钮 }) }).then(function (oData) { oWebControl.JS_Resize(1000, 600); // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题 }); });} //获取公钥const 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() } })} //RSA加密const setEncrypt = (value) => { var encrypt = new JSEncrypt(); encrypt.setPublicKey(pubKey); return encrypt.encrypt(value);}onMounted(() => { initPlugin() window.addEventListener('unload', () => { if (oWebControl != null){ oWebControl.JS_HideWnd(); } }) window.addEventListener('resize', () => { if (oWebControl != null) { oWebControl.JS_Resize(1000, 600); setWndCover(); } }) window.addEventListener('scroll', () => { if (oWebControl != null) { oWebControl.JS_Resize(1000, 600); setWndCover(); } })})const setWndCover = () => { var iWidth = window.innerWidth; var iHeight = window.innerHeight; var oDivRect = document.querySelector("#playWnd").getBoundingClientRect(); console.log('oDivRect', oDivRect) var iCoverLeft = (oDivRect.left < 0) ? Math.abs(oDivRect.left): 0; var iCoverTop = (oDivRect.top < 0) ? Math.abs(oDivRect.top): 0; var iCoverRight = (oDivRect.right - iWidth > 0) ? Math.round(oDivRect.right - iWidth) : 0; var 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; oWebControl.JS_RepairPartWindow(0, 0, 1001, 600); // 多1个像素点防止还原后边界缺失一个像素条 if (iCoverLeft != 0) { oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, 600); } if (iCoverTop != 0) { oWebControl.JS_CuttingPartWindow(0, 0, 1001, iCoverTop); // 多剪掉一个像素条,防止出现剪掉一部分窗口后出现一个像素条 } if (iCoverRight != 0) { oWebControl.JS_CuttingPartWindow(1000 - iCoverRight, 0, iCoverRight, 600); } if (iCoverBottom != 0) { oWebControl.JS_CuttingPartWindow(0, 600 - iCoverBottom, 1000, iCoverBottom); }}const playVideo = (val:string, i) => { oWebControl.JS_RequestInterface({ funcName: "startPreview", argument: JSON.stringify({ cameraIndexCode:val, //监控点编号 streamMode: 0, //主子码流标识 transMode: 1, //传输协议 gpuMode: 0, //是否开启GPU硬解 wndId: i //可指定播放窗口 }) })}</script><style> .playWnd { width: 1000px; /*播放容器的宽和高设定*/ height: 600px; border: 1px solid red; }</style>
2.H5视频播放器
vue3写法,将下载的文件复制到public下
在index.html 引入
<script src="/js/h5player.min.js"></script>
<!-- 海康插件 --><template> <div :id="props.playId" class="w-full"></div></template><script setup lang="ts">const message = useMessage() // 消息弹窗const props = defineProps({ playId: { require: true, type: String, default: () => { return 'player' } }})const player = ref()onMounted(() => { initPlayer() // 设置播放容器的宽高并监听窗口大小变化 window.addEventListener('resize', () => { player.value.JS_Resize() })})const emit = defineEmits(['error'])const initPlayer = () => { // @ts-ignore player.value = new JSPlugin({ szId: props.playId, szBasePath: '/js', //public下命名的文件名 bSupporDoubleClickFull: true, // 当容器div#play_window有固定宽高时,可不传iWidth和iHeight,窗口大小将自适应容器宽高 // iWidth: props.iWidth, // iHeight: props.iHeight, // 分屏播放,默认最大分屏4*4 iMaxSplit: 4, iCurrentSplit: 1 }) // 事件回调绑定 player.value.JS_SetWindowControlCallback({ //插件选中窗口回调 windowEventSelect: (iWndIndex) => { console.log('windowSelect callback: ', iWndIndex) wndIndex.value = iWndIndex }, // @ts-ignore 取流失败,流中断等错误都会触发该回调函数 pluginErrorHandler: (index, iErrorCode, oError) => { // 取流失败 if (iErrorCode === '0x12f910011') emit('error') } })}const wndIndex = ref(0)const createPlayer = (url: string, i = wndIndex.value) => { console.log('视频流地址:', url, props.playId) if (!url) return player.value.JS_Play(url, { playURL: url, mode: 0 }, i).then( () => { console.log('play success=============') }, (err) => { // message.warning('播放失败!') console.info('JS_Play failed:', err) } )}// 分屏const splitPlayer = (num) => { if (num === 1) wndIndex.value = 0 player.value.JS_ArrangeWindow(num)}// 全屏const fullScreen = (isFull) => { player.value.JS_FullScreenDisplay(isFull)}// 回放const replayFun = (data) => {player.value .JS_Play(data.url, { playURL: data.url, mode: 0 }, 0, data.startTime, data.endTime) .then( () => { console.log('playbackStart success') }, (err) => { console.info('JS_Play failed:', err) } )}// 设置窗口大小const resizeFun = (iWidth, iHeight) => { player.value.JS_Resize(iWidth, iHeight)}const stopAllPlay = () => { player.value.JS_StopRealPlayAll().then(() => { console.info('JS_StopRealPlayAll success') })}const playerFun = { createPlayer, splitPlayer, fullScreen, replayFun, resizeFun, stopAllPlay}defineExpose({ playerFun })</script>
不完整,自行补充
上传了代码,可以参考下,在hkvideo.vue文件下
测试代码地址
<player class="w-full h-400px" ref="playRef" />
这是我本地的地址,需要后端返回类似的
ws和hls都试过可以播放,ws基本没延迟,优先使用
unref(playRef).playerFun.createPlayer(item, index) 回放时间格式要转为 format('YYYY-MM-DDTHH:mm:ss.SSSZ') unref(playRef).playerFun.replayFun({ ... })