注意问题
高版本监控与低版本监控
高版本监控可以在高版本浏览器上使用websocket进行解析播放,低版本监控只能在低版本浏览器上使用插件播放。
针对不同的设备选择不同的集成方案即可。可以在我的资源中下载。
集成方式
- 根据demo,输入ip地址、端口、用户名、密码就可以进行预览测试,测试没问题可以根据demo进行集成。
- 将对应的demo目录下的资源放到我们项目的静态资源中,以vue为例,在vue.config.js中进行配置,导出对应的全局变量变量,也可以直接引入使用。
以vue为例
- 谷歌版本chrome41版本,因为摄像头是低版本,不支持websocket。
- 复制demo\codebase下的文件到vue静态资源目录下,并且针对不同的浏览器位数安装不同的WebComponentsKit.exe文件。
- 配置vue.config.js文件
const JS_CDN = isDevelopment? ['./static/video/jquery-1.7.1.min.js','./static/video/jsPlugin-1.0.0.min.js','./static/video/webVideoCtrl.js',]: ['./static/video/jquery-1.7.1.min.js','./static/video/jsPlugin-1.0.0.min.js','./static/video/webVideoCtrl.js',];// 修改默认webpack配置configureWebpack: config => {// 暴露全局变量(CND方式引入的js)config.externals = {WebVideoCtrl: 'WebVideoCtrl',jquery: 'jQuery',jsPlugin: 'jsPlugin'}},
单个视频监控组件封装
代码
<template><div class="video_wrapper_box" :id="pluginId"></div>
</template><script>
import WebVideoCtrl from 'WebVideoCtrl';
import { Modal } from 'view-design';
import $ from 'jquery'; // 使用JQ操作XML,获取信息
export default {props: {loginIp: {type: String,// default: '192.168.90.xx',default: 'xx.95.38.52'},port: {type: String,// default: '80',default: '17006'},username: {type: String,default: 'admin'},password: {type: String,default: 'xxx'},iChannelIDIndex: { // 通道编号的索引,用来获取通道type: Number,default: 1},},data () {return {pluginId: 'video_' + this.generateUUID(), // 标识渲染的domchannelsList: [], // 通道列表currChannels: {},iDevicePort: '',iRtspPort: '',szDeviceIdentify: '', // ip_端口iWndowType: 1, // 窗口分割的数量 2*2g_iWndIndex: 0, // 窗口}},methods: {// 初始化initVideoCtrl () {// 检查插件是否已经安装过var iRet = WebVideoCtrl.I_CheckPluginInstall();console.log(iRet, '检测是否安装了WebComponentsKit.exe插件');if (iRet === -1) {alert("您还未安装过插件,双击开发包目录里的WebComponentsKit.exe安装!");return false;}// 初始化插件参数及插入插件WebVideoCtrl.I_InitPlugin('100%', '100%', {bWndFull: true, // 是否支持单窗口双击全屏,默认支持 true:支持 false:不支持iPackageType: 2, // 2:PS 11:MP4iWndowType: this.iWndowType,bNoPlugin: true,cbSelWnd: (xmlDoc) => { // 选择窗口this.g_iWndIndex = parseInt($(xmlDoc).find('SelectWnd').eq(0).text(), 10);console.log('窗口ID-当前选择的窗口编号:', this.g_iWndIndex);},cbInitPluginComplete: () => {WebVideoCtrl.I_InsertOBJECTPlugin(this.pluginId); // 嵌入插件console.log('嵌入插件');this.$nextTick(() => {//先调用窗口分割方法this.changeWndNum(this.iWndowType);//调用登录方法this.clickLogin();})// 检查插件是否最新if (WebVideoCtrl.I_CheckPluginVersion() === -1) {alert("检测到新的插件版本,双击开发包目录里的WebComponentsKit.exe升级!");return false;}}});},// 窗口分割changeWndNum (iType) {iType = parseInt(iType, 10);WebVideoCtrl.I_ChangeWndNum(iType);},// 登录clickLogin () {if (this.loginIp === '' || this.port === '') {return;}this.szDeviceIdentify = this.loginIp + '_' + this.port;console.log('登录所需参数', this.loginIp, 1, this.port, this.username, this.password);const iRet = WebVideoCtrl.I_Login(this.loginIp, 1, this.port, this.username, this.password, {success: (xmlDoc) => {console.log(" 登录成功!", xmlDoc);setTimeout(() => {// 获取通道信息this.getChannelInfo();// 获取端口this.getDevicePort();}, 10);// 异步请求,当通道和端口都获取到的时候,开始预览setTimeout(() => {this.clickStartRealPlay();}, 1000)},error: (status, xmlDoc) => {console.log(" 登录失败!", status, xmlDoc);}});if (iRet === -1) {console.log(this.szDeviceIdentify + " 已登录过!");// 登录过直接进行预览this.clickStartRealPlay();}},// 获取通道信息getChannelInfo () {this.channelsList = [];if (this.szDeviceIdentify === '') {return false;}// 数字通道WebVideoCtrl.I_GetDigitalChannelInfo(this.szDeviceIdentify, {async: false,success: (xmlDoc) => {var oChannels = $(xmlDoc).find("InputProxyChannelStatus");const that = this;$.each(oChannels, function (i) {const id = $(this).find("id").eq(0).text();let name = $(this).find("name").eq(0).text();const online = $(this).find("online").eq(0).text();if (online === "false") { // 过滤禁用的数字通道return true;}if (name === "") {name = "IPCamera " + (i < 9 ? "0" + (i + 1) : (i + 1));}that.channelsList.push({id, name, bZero: false});});console.log(this.szDeviceIdentify + " 获取数字通道成功!");return true;},error: (status, xmlDoc) => {console.log(this.szDeviceIdentify + " 获取数字通道失败!", status, xmlDoc);return false;}});},// 获取端口getDevicePort () {if (this.szDeviceIdentify === '') {return false;}const oPort = WebVideoCtrl.I_GetDevicePort(this.szDeviceIdentify);if (oPort != null) {this.iDevicePort = oPort.iDevicePort; // 设备 SDK 端口号,不传的话,插件会自动向设备获取this.iRtspPort = oPort.iRtspPort;console.log(JSON.stringify(oPort) + " 获取端口成功!");return true;} else {console.log(JSON.stringify(oPort) + " 获取端口失败!");return false;}},// 开始预览clickStartRealPlay () {console.log('开始预览');if (!this.channelsList.length) {console.log('通道信息获取异常!')return false;}if (!this.iRtspPort) {console.log('RTSP端口获取异常!')return false;}const oWndInfo = WebVideoCtrl.I_GetWindowStatus(this.g_iWndIndex);const startRealPlay = () => {console.log('预览参数iRtspPort:' + this.iRtspPort);console.log('预览参数-通道列表:' + JSON.stringify(this.channelsList));console.log('预览参数-通道号iChannelID:' + this.channelsList[0].id);WebVideoCtrl.I_StartRealPlay(this.szDeviceIdentify, {iRtspPort: this.iRtspPort,iStreamType: 2, // 码流类型 1:主码流 2:子码流 3:第三码流 4:转码码流iChannelID: this.iChannelIDIndex, // 通道 ID 播放通道号,默认通道 1bZeroChannel: false, // 是否播放零通道,默认为 falseiWndIndex: this.g_iWndIndex,success: () => {console.log('开始预览成功');},error: (status, xmlDoc) => {if (status === 403) {console.log('设备不支持Websocket取流!');} else {console.log('开始预览失败!');}console.log('预览失败', status + " " + xmlDoc);}});};console.log('窗口信息:' + this.g_iWndIndex + '号' + JSON.stringify(oWndInfo));if (oWndInfo !== null) { // 已经在播放了,先停止console.log('已经在播放了,先停止!');console.log('停止窗口编号:' + this.g_iWndIndex);WebVideoCtrl.I_Stop({iWndIndex: this.g_iWndIndex,success: () => {console.log('停止成功,开始播放!');startRealPlay();},error: () => {console.log('停止播放异常!');}});} else {console.log('开始播放!');startRealPlay();}},// 退出登录clickLogout () {// 退出登录let szInfo = "";var iRet = WebVideoCtrl.I_Logout(this.szDeviceIdentify);if (iRet === 0) {szInfo = "退出成功!";this.getChannelInfo();this.getDevicePort();} else {szInfo = "退出失败!";}console.log(this.loginIp + '_' + this.port + " " + szInfo);},// 生成uuidgenerateUUID () {let d = new Date().getTime();let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {let r = (d + Math.random() * 16) % 16 | 0;d = Math.floor(d / 16);return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);});return uuid;}},mounted() {setTimeout(() => {this.initVideoCtrl();}, 200);},beforeDestroy () {this.clickLogout();},
}
</script><style lang="less" scoped>.video_wrapper_box {width: 100%;height: 100%;/deep/ .parent-wnd {> div {background: none !important;}}/deep/ canvas {border: none !important;}}
</style>
效果
多个视频监控组件封装
代码
<!--* @Author: xxx* @Date: 2021-01-12 16:31:38* @Description: 基于chrome42版本使用webVideoCtrl集成海康威视监控
-->
<template><div class="video_wrapper_box" :id="pluginId"></div>
</template><script>
import WebVideoCtrl from 'WebVideoCtrl';
import { Modal } from 'view-design';
import $ from 'jquery'; // 使用JQ操作XML,获取信息
export default {props: {loginIp: {type: String,default: '192.168.90.xxx'},port: {type: String,default: '80'},username: {type: String,default: 'admin'},password: {type: String,default: 'a123xxxxxxxxxxxx'},},data () {return {pluginId: 'video_' + this.generateUUID(), // 标识渲染的domg_iWndIndex: 0, // 窗口IDchannelsList: [], // 通道列表currChannels: {},iDevicePort: '',iRtspPort: '',szDeviceIdentify: '', // ip_端口iWndowType: 2, // 窗口分割的数量 2*2iChannelIDIndexList: [1, 4, 6, 7], // 选择的通道列表}},methods: {// 初始化initVideoCtrl () {// 检查插件是否已经安装过var iRet = WebVideoCtrl.I_CheckPluginInstall();console.log(iRet, '检测是否安装了WebComponentsKit.exe插件');if (iRet === -1) {alert("您还未安装过插件,双击开发包目录里的WebComponentsKit.exe安装!");return false;}// 初始化插件参数及插入插件WebVideoCtrl.I_InitPlugin(866, 740, {bWndFull: true, // 是否支持单窗口双击全屏,默认支持 true:支持 false:不支持iPackageType: 2, // 2:PS 11:MP4iWndowType: this.iWndowType,bNoPlugin: true,cbSelWnd: (xmlDoc) => {this.g_iWndIndex = parseInt($(xmlDoc).find("SelectWnd").eq(0).text(), 10);console.log("当前选择的窗口编号:" + this.g_iWndIndex);},cbInitPluginComplete: () => {WebVideoCtrl.I_InsertOBJECTPlugin(this.pluginId); // 嵌入插件console.log('嵌入插件');this.$nextTick(() => {//先调用窗口分割方法this.changeWndNum(this.iWndowType);//调用登录方法this.clickLogin();})// 检查插件是否最新if (WebVideoCtrl.I_CheckPluginVersion() === -1) {alert("检测到新的插件版本,双击开发包目录里的WebComponentsKit.exe升级!");return false;}}});},// 窗口分割changeWndNum (iType) {iType = parseInt(iType, 10);WebVideoCtrl.I_ChangeWndNum(iType);},// 登录clickLogin () {if (this.loginIp === '' || this.port === '') {return;}this.szDeviceIdentify = this.loginIp + '_' + this.port;console.log('登录所需参数', this.loginIp, 1, this.port, this.username, this.password);const iRet = WebVideoCtrl.I_Login(this.loginIp, 1, this.port, this.username, this.password, {success: (xmlDoc) => {console.log(" 登录成功!");setTimeout(() => {// 获取通道信息this.getChannelInfo();// 获取端口this.getDevicePort();}, 10);// 异步请求,当通道和端口都获取到的时候,开始预览setTimeout(() => {this.setIChannelID();}, 1000)},error: (status, xmlDoc) => {console.log(" 登录失败!", status, xmlDoc);}});if (iRet === -1) {console.log(this.szDeviceIdentify + " 已登录过!,直接预览");this.setIChannelID();}},// 获取通道信息getChannelInfo () {this.channelsList = [];if (this.szDeviceIdentify === '') {return false;}// 数字通道WebVideoCtrl.I_GetDigitalChannelInfo(this.szDeviceIdentify, {async: false,success: (xmlDoc) => {var oChannels = $(xmlDoc).find("InputProxyChannelStatus");const that = this;$.each(oChannels, function (i) {const id = $(this).find("id").eq(0).text();let name = $(this).find("name").eq(0).text();const online = $(this).find("online").eq(0).text();if (online === "false") { // 过滤禁用的数字通道return true;}if (name === "") {name = "IPCamera " + (i < 9 ? "0" + (i + 1) : (i + 1));}that.channelsList.push({id, name, bZero: false});});console.log(this.szDeviceIdentify + " 获取数字通道成功!");return true;},error: (status, xmlDoc) => {console.log(this.szDeviceIdentify + " 获取数字通道失败!", status, xmlDoc);return false;}});},// 获取端口getDevicePort () {if (this.szDeviceIdentify === '') {return false;}const oPort = WebVideoCtrl.I_GetDevicePort(this.szDeviceIdentify);if (oPort != null) {this.iDevicePort = oPort.iDevicePort; // 设备 SDK 端口号,不传的话,插件会自动向设备获取this.iRtspPort = oPort.iRtspPort;console.log(JSON.stringify(oPort) + " 获取端口成功!");return true;} else {console.log(JSON.stringify(oPort) + " 获取端口失败!");return false;}},// 设置预览不同的通道setIChannelID () {if (this.channelsList.length === 0) {return false;}console.log('开始设置通道');// 因为界面调控只能看到通道的名称,为了方便后期维护,所以需要通过通道名称获取通道idlet arr = [];this.iChannelIDIndexList.map((iChannelID, iWndIndex) => {console.log(iChannelID, iWndIndex, '通道编号和窗口编号');setTimeout(() => {// 多个同时播放的时候,g_iWndIndex应该设置上,不能不用,因为在clickStartRealPlay方法中已经在播放了,先停止this.g_iWndIndex = iWndIndex;this.clickStartRealPlay(iChannelID, iWndIndex); // iChannelID为通道号, iWndIndex为窗口编号}, 200 * iWndIndex);})// 开始设置通道// for (let i = 0; i < 4; i++) { //i+1为通道号, i 为窗口// setTimeout(() => {// // 多个同时播放的时候,g_iWndIndex应该设置上,不能不用,因为在clickStartRealPlay方法中已经在播放了,先停止// this.g_iWndIndex = i;// this.clickStartRealPlay(i, i++);// }, 300 * i);// }},// 开始预览clickStartRealPlay (iChannelID, iWndIndex) {console.log('开始预览');if (!this.channelsList.length) {console.log('通道信息获取异常!')return false;}if (!this.iRtspPort) {console.log('RTSP端口获取异常!')return false;}const oWndInfo = WebVideoCtrl.I_GetWindowStatus(this.g_iWndIndex);const startRealPlay = () => {console.log('预览参数iRtspPort:' + this.iRtspPort);console.log('预览参数-通道列表:' + JSON.stringify(this.channelsList));console.log('预览参数-通道号iChannelID:' + this.channelsList[0].id);if (this.channelsList.length <= this.iChannelIDIndex) {console.log('当前通道长度小于传入的通道索引');return false;}WebVideoCtrl.I_StartRealPlay(this.szDeviceIdentify, {iRtspPort: this.iRtspPort,iStreamType: 2, // 码流类型 1:主码流 2:子码流 3:第三码流 4:转码码流iChannelID: iChannelID, // 通道 ID 播放通道号,默认通道bZeroChannel: false, // 是否播放零通道,默认为 falseiWndIndex: iWndIndex,success: () => {console.log('开始预览成功');},error: (status, xmlDoc) => {if (status === 403) {console.log('设备不支持Websocket取流!');} else {console.log('开始预览失败!');}console.log('预览失败', status + " " + xmlDoc);}});};if (oWndInfo !== null) { // 已经在播放了,先停止,多个的时候也需要处理console.log('已经在播放了,先停止!');console.log('停止窗口编号:' + this.g_iWndIndex);WebVideoCtrl.I_Stop({iWndIndex: this.g_iWndIndex,success: () => {console.log('停止成功,开始播放!');startRealPlay();},error: () => {console.log('停止播放异常!');}});} else {console.log('开始播放!');startRealPlay();}},// 退出登录clickLogout () {// 退出登录let szInfo = "";var iRet = WebVideoCtrl.I_Logout(this.szDeviceIdentify);if (iRet === 0) {szInfo = "退出成功!";this.getChannelInfo();this.getDevicePort();} else {szInfo = "退出失败!";}console.log('退出成功', this.loginIp + '_' + this.port + " " + szInfo);},// 生成uuidgenerateUUID () {let d = new Date().getTime();let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {let r = (d + Math.random() * 16) % 16 | 0;d = Math.floor(d / 16);return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);});return uuid;}},mounted() {this.clickLogout();setTimeout(() => {this.initVideoCtrl();}, 200);},beforeDestroy () {this.clickLogout();},
}
</script><style lang="less" scoped>.video_wrapper_box {width: 100%;height: 100%;/deep/ .parent-wnd {> div {background: none !important;}}/deep/ canvas {border: none !important;}}
</style>
效果
闭坑指南
- 根据需要的功能对demo里面的代码进行借鉴即可。
- 代码流程:先进行初始化,然后进行窗口分割和登录,登录成功之后需要获取通道和获取端口,然后进行预览,中间需要对应延迟,保证异步都完成获取到对应的数据。
- 登录的参数:ip、端口、用户名、密码都是进口设备的参数
- 在所有流程走通之后可能会遇到预览成功了,界面却没有显示出来。
- 首先控制台不能打开,控制台要是打开的话,界面视频会不显示,需要在控制台关闭的状态下。
- 还有就是如果监控的外层或者父级组件加了v-if、v-showd等都会不显示出来
- 如果监控的外层有轮播也会导致监控不生效。
- 针对多个监控分窗口的问题,需要单独设置不同的窗口编号同时显示对应的视频监控。