海康威视WEBSDK3.3控件开发-分屏预览多个摄像头

翻斗花园正门保安小夏 2024-08-26 09:33:04 阅读 58

海康威视

WEB3.3控件开发包 V3.3

在这里插入图片描述

下载得到海康威视的demo。按照说明文档启动项目。

如果是公司内部,一般都是配置好了对应的WiFi,不需要启动NGINX,直接启动<code>.html文件即可

海康威视视频教程 注意:很多需要海康平台支持,需要付费

参考:

在vue3 中使用海康威视WEB3.3控件开发包 V3.3 抓图

如果你使用vue+vite对接遇到问题,可以参考Giteedemo

有可能是路径问题。参考vite静态资源处理

const getPath = () => {

let path = new URL(`../../../plugin.html`, import.meta.url).href;

console.log(path, "path");

return path;

};

web端对接海康视频3.2开发包以及遇到的坑

Electron+vite+vue3+海康威视SDK开发过程踩坑

海康插件

海康威视通过 HCWebSDKPlugin.exe 绘制出摄像头的播放画面。注意他找这个层级非常非常的高,并且是脱离文档流的,只要它被绘制出来,就是你把页面所有dom都删除,他依然纯在。它是单页面的。如果使用div去初始化多个插件是可以的,但是登录的时候,每次选择的插件是相同的海康威视对接有多种方式,通过网上查阅和观看源码发现,每种方式的最底层用的都是一套代码,对于不同的开发,进行了不同的封装

在这里插入图片描述

在这里插入图片描述

同一页面预览多个摄像头

使用nvr设备

使用nvr设备,一个账号配置多个摄像头。使用海康威视的demo可以实现分屏预览。如果只有一个摄像机是没有办法实现分屏预览的。500元就搞定。页面渲染直接使用div就行。代码放最下面了

在这里插入图片描述

使用nvr后,每个摄像头都是一个数字通道,参照编程指南传参

在这里插入图片描述

使用iframe 不推荐使用

上面说了海康威视插件是单页面的,不能使用div,那就要使用<code>iframe

但是效果很不好。问题如下:

图层会出现闪烁以至于消失。比如切屏、点击任务栏、点击Electron的窗口栏

图层渲染位置不正确。海康插件是根据网页的左上角做渲染的,但是<div class="plugin" id="divplugin"></div>code>的位置是会影响最终结果的。比如使用绝对定位,设置top、left会使图层向右下移动。虽然说iframe是打开了一个新网页,但是它这个插架还是会根据最外层的网页为基准点,内部逻辑没办法探究。当渲染多个iframe的时候或者进行一些布局的时候,就会出现图层渲染位置不正确的问题

iframe中每个摄像头的登录顺序不固定。正确顺序为:1,2, 3, 4。实际为:2, 4, 1, 3

对于登录操作,也不按照顺序渲染(好像是)

如果要重新更换摄像头,需要全部退出再登录。上面说了,图层一旦出现,就不会改变,所以必须这样的。采用的是给每个组件添加一个key,每次选择摄像头的时候刷新key实现组件的刷新

图层的层级太大了,该页面不能打开modalelectron中使用打开新标签页实现

实现麻烦

海康的源码是common.jsvitees moudle,所以html和js必须如下放置

路径处理

const getPath = () => {

let path = new URL(`../../../../public/html/plugin.html`, import.meta.url)

.href;

return path;

};

页面渲染顺序:父组件onMounted=>iframe,所以需要判断iframe加载完成,然后通知父组件才能进行通信。父组件将摄像头信息传入进行初始化、登录等操作

在这里插入图片描述

使用nvr预览踩坑

停止播放

查看源码后,很明显停止播放还做了其他操作。它会把当前窗口关闭,不能再继续使用。改用”全部停止播放“—— I_StopAllPlay ()。这个编程指南并没有写清楚(糟称冯 😊)

在这里插入图片描述

在这里插入图片描述

插件销毁

在离开页面后,图层依旧存在,即使退出登录也不好使。

bing 海康销毁插件找到了<code>JS_DestroyPlugin,然后源码中搜一下找到了可以使用的api。这个api编程指南中也是没有的(糟称冯 😆)

在这里插入图片描述

组件初始化失败

插件已经安装并启动,demo中可以,另个一vue中也可以,之前iframe也可以,但是换成div就不行了。莫名过了一段时间自己好了。我换成iframe,iframe有g了,很奇怪

在这里插入图片描述

代码

<code>webVideoCtrl.js和jquery放置在public/js文件夹中,如上图

camera.vue

<template>

<div ref="playerRef" id="divPlugin" style="width: 100%; height: 100%"></div>code>

</template>

<script setup>

const props = defineProps({

camera: {

type: Object,

},

});

const playerRef = ref();

const { camera } = toRefs(props);

const cameraAll = ref([1, 2, 3, 4]); // 数字通道

const cameraView = ref([1, 2, 3, 4]);

const closeNum = ref([]);

let g_iWndIndex = 0;

/**

* 初始化相机

*/

const init = () => {

WebVideoCtrl.I_InitPlugin({

bWndFull: true, //是否支持单窗口双击全屏,默认支持 true:支持 false:不支持

iWndowType: 1,

cbSelWnd: function (xmlDoc) {

g_iWndIndex = parseInt($(xmlDoc).find("SelectWnd").eq(0).text(), 10);

},

cbDoubleClickWnd: function () {},

cbEvent: (iEventType, iParam1) => {

if (2 == iEventType) {

// 回放正常结束

console.log("窗口" + iParam1 + "回放结束!");

} else if (-1 == iEventType) {

console.log("设备" + iParam1 + "网络错误!");

}

},

cbInitPluginComplete: function () {

WebVideoCtrl.I_InsertOBJECTPlugin("divPlugin").then(

() => {

// 检查插件是否最新

WebVideoCtrl.I_CheckPluginVersion().then((bFlag) => {

if (bFlag) {

alert("检测到新的插件版本,请升级HCWebSDKPlugin.exe!");

} else {

console.log("初始化成功");

login();

}

});

},

() => {

alert("插件初始化失败,请确认是否已安装插件");

}

);

},

});

};

/**

* 登录

*/

const login = () => {

WebVideoCtrl.I_Login(

camera.value.ip,

1,

camera.value.port,

camera.value.username,

camera.value.pwd,

{

timeout: 60000,

success: function (xmlDoc) {

console.log("登录成功");

setTimeout(function () {

getChannelInfo(`${camera.value.ip}_${camera.value.port}`);

}, 1000);

getDevicePort(`${camera.value.ip}_${camera.value.port}`); //获取端口

},

error: function (error) {

console.log(error, "登录失败");

},

}

);

};

// 数字通道

const getChannelInfo = (szDeviceIdentify) => {

WebVideoCtrl.I_GetDigitalChannelInfo(szDeviceIdentify, {

success: function (xmlDoc) {

var oChannels = $(xmlDoc).find("InputProxyChannelStatus");

cameraAll.value = [];

$.each(oChannels, function (i) {

var id = $(this).find("id").eq(0).text(),

name = $(this).find("name").eq(0).text(),

online = $(this).find("online").eq(0).text();

if ("false" == online) {

// 过滤禁用的数字通道

return true;

}

cameraAll.value[i] = id;

if (i < 4) {

cameraView.value[i] = id;

} else {

closeNum.value[i - 4] = id;

}

});

},

error: function (oError) {},

});

};

// 获取端口

const getDevicePort = (szDeviceIdentify) => {

if (!szDeviceIdentify) {

return;

}

WebVideoCtrl.I_GetDevicePort(szDeviceIdentify).then(

(oPort) => {

WebVideoCtrl.I_ChangeWndNum(2).then(

() => {

// console.log("分屏成功");

startRealPlay();

},

(oError) => {}

);

},

(oError) => {

console.log(oError.errorMsg, "获取端口失败");

}

);

};

const logout = () => {

let ip_port = `${camera.value.ip}_${camera.value.port}`;

WebVideoCtrl.I_Logout(ip_port).then(

() => {

console.log("退出成功");

},

() => {

console.log("退出失败!");

}

);

};

const destroy = (item) => {

WebVideoCtrl.I_HidPlugin().then(

() => {

console.log("销毁组件成功");

},

(error) => {

console.log(error);

}

);

};

const play = (iWndIndex, iChannelID) => {

// console.log("窗口:", iWndIndex, "----数字通道:", iChannelID, "预览");

WebVideoCtrl.I_StartRealPlay(`${camera.value.ip}_${camera.value.port}`, {

iStreamType: 1,

iChannelID: iChannelID, //播放通道

bZeroChannel: false,

iWndIndex: iWndIndex,

success: function () {

// console.log(

// "窗口:",

// iWndIndex,

// "----数字通道:",

// iChannelID,

// "开始预览成功!"

// );

},

error: function (oError) {

console.log(

"窗口:",

iWndIndex,

"----数字通道:",

iChannelID,

"开始预览失败!",

oError.errorMsg

);

},

});

};

// 预览

const startRealPlay = () => {

for (let i = 0; i < 4; i++) {

let iChannelID = cameraView.value[i];

if (iChannelID) play(i, iChannelID);

}

};

const rePlay = () => {

WebVideoCtrl.I_StopAllPlay().then((item) => {

startRealPlay();

});

};

// 停止预览

const clickStopRealPlay = () => {

WebVideoCtrl.I_StopAllPlay().then(() => {

console.log("停止播放成功");

});

};

const changeIndex = (num) => {

// num 为通道号

let isClose = closeNum.value.findIndex((item) => item == num);

if (isClose > -1) {

// 重新打开

closeNum.value.splice(isClose, 1);

} else {

// 关闭

closeNum.value.push(num);

}

cameraView.value = cameraAll.value.filter(

(item) => !closeNum.value.includes(item)

);

rePlay();

};

onMounted(() => {

init();

});

onBeforeUnmount(() => {

clickStopRealPlay();

logout();

destroy();

});

defineExpose({

changeIndex,

});

</script>

index.html

<!DOCTYPE html>

<html lang="en">code>

<head>

<meta charset="UTF-8" />code>

<link rel="icon" type="image/svg+xml" href="/vite.svg" />code>

<meta name="viewport" content="width=device-width, initial-scale=1.0" />code>

<title>摄像头预览</title>

</head>

<body>

<div id="app"></div>code>

<script type="module" src="/src/main.js"></script>code>

<script id="videonode" src="/js/webVideoCtrl.js"></script>code>

<script src="/js/jquery-1.7.1.min.js"></script>code>

<!-- 好像不需要。。。 -->

<!-- <script id="videonode" src="/js/jsVideoPlugin-1.0.0.min.js"></script> -->code>

</body>

</html>



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。