vue+海康威视视频web插件开发

一、环境准备

下载地址:海康威视官网

下载页面

文件解压后的目录

运行bin文件下的VideoWebPlugin.exe

二、插件demo测试

demo/demo_window_integration.html 包含了插件所有功能的,可参照此demo来开发、验证功能、排查问题

demo/demo_window_simple_playback.html.html  视频回放,可在此基础上二次开发

demo/demo_window_simple_preview.html 实时预览,可在基础上二次开发

在浏览器中打开 demo/demo_window_integration.html 文件如下

 在进入官网运行管理平台获取到 Appkey、AppSecret、Ip、Port,就能连接到自己的摄像头进行调试开发了

三、api相关介绍

1、JS_StartService(szType,options) 启动插件服务接口 (返回值Promise)

        szType:服务类型 固定填充 “window”(必填)

        options:可选参数对象 固定填充{dllPath: "./VideoPluginConnect.dll"}(对象选填)

2、JS_Disconnect() 断开服务接口 (返回值Promise)

3、JS_CreateWnd(szId, iWidth, iHeight) 创建插件窗口接口 (返回值Promise)

        szId:父窗口的id (必填)

        iWidth:元素 ID 标识窗口的宽度 (必填)

        iHeight:元素 ID 标识窗口的高度 (必填)

4、JS_SetWindowControlCallback(callback) 设置消息回调接口

       callback(对象 必填) 示例

       {

                cbIntegrationCallBack(必要属性): function(oData){ // oData 是封装的视频 web 插件回调消息的消息体
                console.log(JSON.stringify(oData)); // 打印消息体至控制台

         }

5、JS_Resize(iWidth,iHeight) 调整插件窗口大小、位置接口

        iWidth:DIV 窗口宽度 (必填)

        iHeight:DIV 窗口高度(必填)

6、JS_CuttingPartWindow(iLeft, iTop, iWidth, iHeight) 扣除部分插件窗口接口

        场景:插件窗口创建后,会始终置顶,因此当和其它组件一同使用时,会遮挡其它组件内容,该接口 的作用是,当部分插件窗口不需要置顶时,我们会隐藏部分插件窗口。也就是向上滚动的时候会隐藏

        iLeft:距离插件窗口左边距(必填)

        iTop:距离插件窗口上边距(必填)

        iWidth:需要扣除的宽度(必填)

        iHeight:需要扣除的高度(必填)

7、JS_RepairPartWindow(iLeft, iTop, iWidth, iHeight) 还原扣除部分窗口后的插件窗口

        场景:一般联合 JS_CuttingPartWindow 一起使用,在还原部分窗口后 在扣除

        iLeft:扣除窗口的顶点距离插件窗 口左边距 (必填)

        iTop:扣除窗口的顶点距离插件窗 口上边距 (必填)

        iWidth:扣除窗口的宽度(必填)

        iHeight:扣除窗口的高度(必填)

8、JS_HideWnd() 插件窗口隐藏接口

9、JS_ShowWnd() 插件窗口显示接口

10、JS_DestroyWnd() 插件窗口销毁接口

11、JS_WakeUp(szProtocal) 唤醒 WebControl.exe 接口

        场景 当 WebControl.exe 未启动时唤醒 WebControl.exe。若 WebControl.exe 已启动则忽略

        szProtocal:唤醒协议 内容固定为("VideoWebPlugin://")

12、JS_RequestInterface({funcName,argument})通过请求响应接口 (返回值Promise)

        funcName:功能标识(必填)

        argument:功能参数 (object 格式的字符串)

  • 例 申请 RSA 公钥
 { funcName: "getRSAPubKey", argument: "{ keyLength: 1024 }" }
  • 初始化    
{
 funcName: "init",
 argument: "{
 appkey: "afsgnhmj34567dgh", // API 网关提供的 appkey
 secret: "vgkk3g0jaoj0igoigj", // API 网关提供的 secret
 ip: "10.33.31.4", // API 网关 IP 地址
 port: 9016, // API 网关端口
 playMode: 0, //播放模式(决定显示预览还是回放界面),0-预览 1-录像播放
 encryptedFields: "appkey,secret", //secret 和 appkey 已加密,对多个字段加密存在初始化耗时问题
 snapDir: "D:\SnapDir", // 抓图存储路径
 layout: "2x2" // 初始化 2x2 布局
 showToolbar: 1, // 显示工具栏
 showIntelligent: 1, // 显示智能信息
 buttonIDs: "0,16,256,257,258"
 }"
}
  • 根据监控点编号视频预览
{
 funcName: "startPreview",
 argument: "{
 cameraIndexCode: "afsgnhmj34567dgh", // 监控点编号
 streamMode: 0, // 主子码流标识,0-主码流 1-子码流
 transMode: 1, // 传输协议,0-UDP 1-TCP
 gpuMode: 0 // 是否开启 GPU 硬解,不建议开启,0-不开启 1-开启
 }"
}
  • 停止所有视频预览
{
 funcName: "stopAllPreview"
}
  • 根据监控点编号录像回放
{
  funcName: "startPlayback",
  argument: "{
    cameraIndexCode: "afsgnhmj34567dgh", // 监控点编号
    startTimeStamp: "10237898985", // 录像查询开始时间戳,单位:秒
    endTimeStamp: "10237899985", // 录像查询结束时间戳,单位:秒
    recordLocation: 0, // 录像存储类型 0-中心存储 1-设备存储
    transMode: 1, // 传输协议 ,0-UDP 1-TCP
    gpuMode: 0 // 是否开启 GPU 硬解,0-不开启 1-开启
   }"
}
  • 停止所有录像回放
{
 funcName: "stopAllPlayback"
}
  • 销毁播放实例
{
 funcName: "destroyWnd"
}
  •  获取当前布局
{
 funcName: "getLayout"
}
  • 设置当前布局 
{
 funcName: " setLayout",
 argument: "{
 layout: "2x2" // 窗口布局 
 }"
}

// 布局可选值有“1x1”、
    “2x2”、“3x3”、“4x4”、“5x5”、“1x2”、
    “1+2”、“1+5”、“1+7”、 “1+8”、“1+9”、
    “1+12”、“1+16”、“4+9”、“1+1+12”、
    “3+4”、“1x4”、“4x6”
  • 画面字符叠加
{
 "funcName": "drawOSD",
 "argument": "{
     text: "温度:50\n 湿度:38", // 窗口布局
     x: 5, // 相对播放窗口左上角的横坐标起点
     y: 5, // 相对播放窗口左上角的纵坐标起点
     color: red // 字体颜色
 }"
}

根据监控点编号批量视频预览

{
"funcName": "startMultiPreviewByCameraIndexCode",
 "argument": {
  "list": [
   {
    "cameraIndexCode": "c633ef048fe141e1ac6dbeb36aaf21d3", // 监控点编号 
    "ezvizDirect": 0, // 是否直连萤石预览 未指定或为 0-非直连 其它值-直连
    "gpuMode": 0, // 是否启用 GPU 硬解  0-不启用 1-启用
    "streamMode": 0, // 主子码流标识  0-主码流 1-子码流
    "transMode": 1, // 传输协议 0-UDP 1-TCP
    "wndId": 1 // 播放窗口序号
   },
   {
    "cameraIndexCode": "c633ef048fe141e1ac6dbeb36aaf21d3",
    "ezvizDirect": 0,
    "gpuMode": 0,
    "streamMode": 0,
    "transMode": 1,
    "wndId": 2 
  }
 ]
 }
}
  •  根据监控点编号批量录像回放
{
 "funcName": "startMultiPlaybackByCameraIndexCode",
 "argument": 
{
 "list":[{
   "cameraIndexCode": "58e90452772a4d9da7c7ba4cef26dbf0", // 监控点编号
   "startTimeStamp": "10237898985", // 录像查询开始时间戳,单位:秒
   "endTimeStamp": "10237899985", // 录像查询结束时间戳,单位:秒
   "recordLocation": 0, // 录像存储类型 0-中心存储 1-设备存储
   "transMode": 1, // 传输协议 ,0-UDP 1-TCP
   "wndId": 1, // 窗口序号
   "gpuMode": 0 // 是否开启 GPU 硬解,0-不开启 1-开启
  }]
 }
}
  • 批量停止播放
{
 "funcName": "stopMultiPlay",
 "argument": 
{
 "list":[{
   "wndId": 1 // 窗口序号
  },
 {
   "wndId": 2 // 窗口序号
  }]
 }
}

 四、开发流程示意图

       图中灰色部分为可选步骤。其中申请 RSA 公钥可选。申请 RSA 公钥是为了加密初始化中 的一些敏感参数,对安全性要求高的用户可以考虑对敏感参数加密。但需要注意的是,使用 RSA 公 钥加密机制必然会导致初始化耗时。一般情况下不需要调 JS_DestroyWnd 来销毁插件窗口 (JS_Disconnect 中会自行销毁),但一些特殊的场景如浏览器页面上需随时启用和禁用视频播放时, 需调 JS_DestroyWnd 来禁用视频播放,需要调 JS_CreateWnd 来启用视频播放。JS_DestroyWnd 和 JS_Disconnect 中会反初始化插件,这里无需调 JS_RequestInterface/uninit 反初始化。

 五、在vue中使用(实时预览完整示例)

 1、在public目录下的index.html中引入文件(资源文件在demo目录下

  <script src="./jquery-1.9.1.min.js"></script>
  <script src="./jsencrypt.min.js"></script>  // 用于 RSA 公钥加密
  <script src="./jsWebControl-1.0.0.min.js"></script> // 用于前端与插件交互

 2、线预览模块完整实例,其他的模块功能以此内推(如有疑惑,可参考doc目录下的文档,里面记载很清楚)

html 示例

 <div class="right" ref="playWndBox">
      <!-- 视频数据站位 -->
        <div
          id="playWnd"
          class="playWnd"
          :style="{
            height: playWndHeight + 'px',
            width: playWndWidth + 'px'
          }"
        ></div>
    </div>

 js 示例

<script>
// 声明公用变量 摄像头实例对现象,为了方便引用 定义在全局
let oWebControl = null
var initCount = 0
var pubKey = ''
export default {
  name: 'videoRuntime',
  data() {
    return {
      playWndHeight: '', // 视频盒子的高度
      playWndWidth: '' // 视频盒子的宽度
    }
  },
  mounted() {
    this.playWndHeight = this.$refs.playWndBox.clientHeight // 首次加载时的到父容器的高度
    this.playWndWidth = this.$refs.playWndBox.clientWidth // 首次加载时的到父容器的宽度
    this.$nextTick(() => {
      // 初始化摄像头
      this.initPlugin()
    })

    // 监听resize事件,使插件窗口尺寸跟随DIV窗口变化
    window.addEventListener('resize', () => {
      if (oWebControl != null) {
        if (this.$refs.playWndBox)
          oWebControl.JS_Resize(this.$refs.playWndBox.clientWidth,         this.$refs.playWndBox.clientHeight)
      }
    })
  },
  methods: {
    // 创建播放实例
    initPlugin() {
      let that = this
      oWebControl = new window.WebControl({
        szPluginContainer: 'playWnd', // 指定容器id
        iServicePortStart: 15900, // 指定起止端口号,建议使用该值
        iServicePortEnd: 15909,
        szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // 用于IE10使用ActiveX的clsid
        cbConnectSuccess: () => {
          // 创建WebControl实例成功
          oWebControl
            .JS_StartService('window', {
              // WebControl实例创建成功后需要启动服务
              dllPath: './VideoPluginConnect.dll' // 值"./VideoPluginConnect.dll"写死
            })
            .then(
              function() {
                // 启动插件服务成功
                oWebControl.JS_SetWindowControlCallback({
                  // 设置消息回调
                  cbIntegrationCallBack: that.cbIntegrationCallBack
                })

                oWebControl.JS_CreateWnd('playWnd', 0,0).then(function() {
                  //JS_CreateWnd创建视频播放窗口,宽高可设定  默认设置为0 消除初始化闪白问题
                  that.init() // 创建播放实例成功后初始化
                })
              },
              function() {
                // 启动插件服务失败
              }
            )
        },
        cbConnectError: function() {
          // 创建WebControl实例失败
          oWebControl = null
          that.$message.warning('插件未启动,正在尝试启动,请稍候...')
          window.WebControl.JS_WakeUp('VideoWebPlugin://') // 程序未启动时执行error函数,采用wakeup来启动程序
          initCount++
          if (initCount < 3) {
            setTimeout(function() {
              that.initPlugin()
            }, 3000)
          } else {
            that.$message.warning('插件启动失败,请检查插件是否安装!')
          }
        },
        cbConnectClose: () => {
          // 异常断开:bNormalClose = false
          // JS_Disconnect正常断开:bNormalClose = true
          console.log('cbConnectClose')
          oWebControl = null
        }
      })
    },
    // 初始化
    init() {
      let that = this
      this.getPubKey(() => {
        var appkey = '28730366' //综合安防管理平台提供的appkey,必填
        var secret = this.setEncrypt('HSZkCJpSJ7gSUYrO6wVi') //综合安防管理平台提供的secret,必填
        var ip = '10.19.132.75' //综合安防管理平台IP地址,必填
        var playMode = 0 //初始播放模式:0-预览,1-回放
        var port = 443 //综合安防管理平台端口,若启用HTTPS协议,默认443
        var snapDir = 'D:\\SnapDir' //抓图存储路径
        var videoDir = 'D:\\VideoDir' //紧急录像或录像剪辑存储路径
        var layout = '1x1' //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' //自定义工具条按钮
        // var toolBarButtonIDs = "2049,2304" // 工具栏上自定义按钮

        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 //自定义工具条按钮
            })
          })
          .then(function(oData) {
            console.log(oData)
            oWebControl.JS_Resize(that.playWndWidth, that.playWndHeight) // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
            // 一进来就隐藏
            oWebControl.JS_HideWnd() // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
          })
      })
    },
    // 获取公钥
    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 加密
    setEncrypt(value) {
      var encrypt = new window.JSEncrypt()
      encrypt.setPublicKey(pubKey)
      return encrypt.encrypt(value)
    },
    // 回调的消息
    cbIntegrationCallBack(oData) {
      let { responseMsg: type, responseMsg: msg } = oData

      if (type === 'error') {
        console.log(type, msg, this.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'))
      } else {
        console.log(type, msg, this.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'))
      }
    },
    // 预览
    startPreview(cameraCode) {
      // 点击查询后显示
      oWebControl.JS_ShowWnd()
      var cameraIndexCode = cameraCode //获取输入的监控点编号值,必填
      console.log(cameraCode)
      var streamMode = 0 //主子码流标识:0-主码流,1-子码流
      var transMode = 1 //传输协议:0-UDP,1-TCP
      var gpuMode = 0 //是否启用GPU硬解,0-不启用,1-启用
      var wndId = -1 //播放窗口序号(在2x2以上布局下可指定播放窗口)

      cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, '')
      cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, '')

      oWebControl.JS_RequestInterface({
        funcName: 'startPreview',
        argument: JSON.stringify({
          cameraIndexCode: cameraIndexCode, //监控点编号
          streamMode: streamMode, //主子码流标识
          transMode: transMode, //传输协议
          gpuMode: gpuMode, //是否开启GPU硬解
          wndId: wndId //可指定播放窗口
        })
      })
    },
    // 停止全部预览
    stopAllPreview() {
      oWebControl.JS_RequestInterface({
        funcName: 'stopAllPreview'
      })
    },

    // 格式化时间
    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;
    }
  },
  destroyed() { // 组件销毁后
    if (oWebControl != null) {
      oWebControl.JS_HideWnd() // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
      oWebControl.JS_RequestInterface({funcName: "destroyWnd"}) // 销毁当前播放的视频
      oWebControl.JS_Disconnect() // 断开与插件服务连接
    }
  }
}
</script>

注:由于本页面没有滚动条,不会出现因滚动条滚动导致窗口需要被遮住的情况,所以就没有添加scroll,如有滚动条,请参考demo文件下 demo_window_simple_preview.html 中的setWndCover事件

猜你喜欢

转载自blog.csdn.net/qq_45689385/article/details/121393508