海康威视WEB3.2无插件版本开发与踩坑(嵌入UE4-CEF)

3,779 阅读2分钟

前言

非海康ISC综合安防平台, 是硬件SDK集成-设备SDK二次开发对接,直接使用web3.2无插件版进行开发

准备

开发
  1. 打开nginx里的conf文件夹,修改nginx.conf配置,将server_name修改成启动ng服务的ip,端口如果被占用,也可修改为其他(如不修改,在Chrome浏览器中打开127.0.0.1也可看到demo,但是无法登录成功,ie因为使用的是插件,所以不会有这个问题)

image.png

  1. 打开webs里的cn文件夹,编辑demo.js,代码中修改登录参数。如果是测试,那么直接打开刚才设置的nginx的代理地址,直接输入ip,端口(默认80,非取流端口),用户名,密码,登录成功后,点击开始预览即可。

image.png

image.png 3.登录成功,但却预览失败。启用websocket取流已启用,但是还是预览失败,查看是否websocket认证失败,可抓包分享给海康技术支持,请求支援。(大佬可以自行查看codebase中的webVideoCtrl.js修改)

4 .基本上预览成功就可以开发了,值得一提的就是要及时清除浏览器缓存(嵌入ue4中更是需要去WindowsNoEditor\Ggnhcs2\Saved\webcache\Cache清除cef缓存,否则你会发现根本更新不了)以及获取端口和通道信息时需要执行一下定时器,来让这两个请求能顺利获取。

代码蛮贴一下,主要是实现登录预览,以及云台控制功能,基本都是demo.js里面cv过来的

HTML

<!DOCTYPE html>
<html lang="zh-CN" style="height: 100%;width: 100%;">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
    <meta http-equiv="Expires" content="0" />
    <title>鹰眼</title>
</head>
<script>
    document.write("<link type='text/css' href='./eagleEye.css?version=" + new Date().getTime() + "' rel='stylesheet' />");
</script>
<style>

</style>

<body style="width: 100%;height: 100%; margin: 0;position: relative;">
    <div class="container">
        <div id="divPlugin" class="plugin"></div>
    </div>
    <select id="channels" class="sel"></select>
</body>
<script src="../jquery-1.7.1.min.js"></script>
<script src="../codebase/encryption/AES.js"></script>
<script src="../codebase/encryption/cryptico.min.js"></script>
<script>
    // ue4全局帮助函数,非ue4开发不需要加 create the global ue4(...) helper function
    "object" != typeof ue || "object" != typeof ue.interface ? ("object" != typeof ue && (ue = {}), ue.interface = {}, ue.interface.broadcast = function (e, t) { if ("string" == typeof e) { var o = [e, ""]; void 0 !== t && (o[1] = t); var n = encodeURIComponent(JSON.stringify(o)); "object" == typeof history && "function" == typeof history.pushState ? (history.pushState({}, "", "#" + n), history.pushState({}, "", "#" + encodeURIComponent("[]"))) : (document.location.hash = n, document.location.hash = encodeURIComponent("[]")) } }) : function (e) { ue.interface = {}, ue.interface.broadcast = function (t, o) { "string" == typeof t && (void 0 !== o ? e.broadcast(t, JSON.stringify(o)) : e.broadcast(t, "")) } }(ue.interface), (ue4 = ue.interface.broadcast);
</script>
<!-- <script src="../codebase/encryption/encryption.js"></script> -->
<script src="../codebase/encryption/crypto-3.1.2.min.js"></script>
<script src="./config.json"></script>
<script id="videonode" src="../codebase/webVideoCtrl.js"></script>
<script src="./eagleEye.js"></script>

</html>

CSS

* {
  padding: 0;
  margin: 0;
}
body {
  display: flex;
}
/* 容器 */
.container {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
/*插件*/
.plugin {
  width: 100%;
  height: 100%;
}
.ptz {
  display: none;
}
.sel {
  width: 0px;
  height: 0px;
  display: none;
}

JS

// 初始化插件

// 全局保存当前选中窗口
let g_iWndIndex = 0; //可以不用设置这个变量,有窗口参数的接口中,不用传值,开发包会默认使用当前选择窗口
let version = "websdk3.220191023";
let iRtspPort = 0;
let oPlugin = {
  iWidth: "100%", // plugin width
  iHeight: "100%", // plugin height
};
let oLiveView = {
  iProtocol: 1, // protocol 1:http, 2:https
  szIP: config.ip, // protocol ip
  szPort: config.port, // protocol port
  szUsername: config.user, // device username
  szPassword: config.pwd, // device password
  iStreamType: 1, // stream 1:main stream  2:sub-stream  3:third stream  4:transcode stream
  iChannelID: 1, // channel no
  bZeroChannel: false, // zero channel
};
$(function () {
  // 检查插件是否已经安装过(谷歌高版本理论上是不需要安装插件的,但是为了保持完整性就蛮放着)
  let iRet = window.WebVideoCtrl.I_CheckPluginInstall();
  if (-1 == iRet) {
    alert("您还未安装过插件,双击开发包目录里的WebComponentsKit.exe安装!");
    return;
  }
  // 初始化插件参数及插入插件
  WebVideoCtrl.I_InitPlugin(oPlugin.iWidth, oPlugin.iHeight, {
    bWndFull: true, //是否支持单窗口双击全屏,默认支持 true:支持 false:不支持
    iWndowType: 1,
    cbInitPluginComplete: function () {
      WebVideoCtrl.I_InsertOBJECTPlugin("divPlugin");

      // 检查插件是否最新
      if (-1 == WebVideoCtrl.I_CheckPluginVersion()) {
        alert(
          "检测到新的插件版本,双击开发包目录里的WebComponentsKit.exe升级!"
        );
        return;
      }

      // 登录设备
      WebVideoCtrl.I_Login(
        oLiveView.szIP,
        oLiveView.iProtocol,
        oLiveView.szPort,
        oLiveView.szUsername,
        oLiveView.szPassword,
        {
          success: function (xmlDoc) {
            setOperaInfo("登录成功1:", xmlDoc);
            setTimeout(function () {
              //获取端口
              getDevicePort();
              //获取通道
              getChannelInfo();
            }, 10);
            // 开始预览
            let szDeviceIdentify = oLiveView.szIP + "_" + oLiveView.szPort;

            setTimeout(function () {
              WebVideoCtrl.I_StartRealPlay(szDeviceIdentify, {
                iRtspPort: parseInt(iRtspPort, 10),
                iStreamType: oLiveView.iStreamType,
                iChannelID: oLiveView.iChannelID,
                bZeroChannel: oLiveView.bZeroChannel,
                success: function () {
                  setOperaInfo(szDeviceIdentify + " " + "开始预览成功!");
                },
                error: function (status, xmlDoc) {
                  let szInfo = "";
                  if (403 === status) {
                    szInfo = "设备不支持Websocket取流!";
                  } else {
                    szInfo = "开始预览失败!";
                  }
                  setOperaInfo(szDeviceIdentify + " " + szInfo);
                },
              });
            }, 1000);
          },
          error: function (status, xmlDoc) {
            setOperaInfo(" 登录失败!", status, xmlDoc);
          },
        }
      );
    },
  });
     //处理ue4传过来的数据
  function handleSet(order) {
    let strArr = order.split("_");
    let type = strArr[0];
    let option = strArr[1];
    switch (type) {
      case "move":
        !!Number(option)
          ? mouseDownPTZControl(Number(option))
          : mouseUpPTZControl();
        break;
      case "zoom":
        option == "in"
          ? PTZZoomIn()
          : option == "out"
          ? PTZZoomout()
          : PTZZoomStop();
        break;
      case "focus":
        option == "in"
          ? PTZFocusIn()
          : option == "out"
          ? PTZFoucusOut()
          : PTZFoucusStop();
        break;
      default:
        console.log("命令错误:", order);
    }
  }
  //给ue4调用的函数
  ue.interface.setOperation = function (order) {
    handleSet(order);
  };
  // 关闭浏览器
  $(window).unload(function () {
    WebVideoCtrl.I_Stop();
  });
});

// 全屏
function clickFullScreen() {
  WebVideoCtrl.I_FullScreen(true);
}
// 获取通道
function getChannelInfo() {
  let szDeviceIdentify = oLiveView.szIP,
    oSel = $("#channels").empty();

  if (null == szDeviceIdentify) {
    return;
  }

  // 模拟通道
  WebVideoCtrl.I_GetAnalogChannelInfo(szDeviceIdentify, {
    async: false,
    success: function (xmlDoc) {
      let oChannels = $(xmlDoc).find("VideoInputChannel");
      $.each(oChannels, function (i) {
        let id = $(this).find("id").eq(0).text(),
          name = $(this).find("name").eq(0).text();
        if ("" == name) {
          name = "Camera " + (i < 9 ? "0" + (i + 1) : i + 1);
        }
        oSel.append(
          "<option value='" + id + "' bZero='false'>" + name + "</option>"
        );
      });
      setOperaInfo(szDeviceIdentify + " 获取模拟通道成功!");
    },
    error: function (status, xmlDoc) {
      setOperaInfo(szDeviceIdentify + " 获取模拟通道失败!", status, xmlDoc);
    },
  });
  // 数字通道
  WebVideoCtrl.I_GetDigitalChannelInfo(szDeviceIdentify, {
    async: false,
    success: function (xmlDoc) {
      let oChannels = $(xmlDoc).find("InputProxyChannelStatus");
      setOperaInfo(szDeviceIdentify + " 获取数字通道成功!");
    },
    error: function (status, xmlDoc) {
      setOperaInfo(szDeviceIdentify + " 获取数字通道失败!", status, xmlDoc);
    },
  });
  // 零通道
  WebVideoCtrl.I_GetZeroChannelInfo(szDeviceIdentify, {
    async: false,
    success: function (xmlDoc) {
      let oChannels = $(xmlDoc).find("ZeroVideoChannel");

      setOperaInfo(szDeviceIdentify + " 获取零通道成功!");
    },
    error: function (status, xmlDoc) {
      setOperaInfo(szDeviceIdentify + " 获取零通道失败!", status, xmlDoc);
    },
  });
}

// 获取端口
function getDevicePort() {
  let szDeviceIdentify = oLiveView.szIP;
  if (null == szDeviceIdentify) {
    return;
  }

  let oPort = WebVideoCtrl.I_GetDevicePort(szDeviceIdentify);
  if (oPort != null) {
    iRtspPort = oPort.iRtspPort;
    setOperaInfo(szDeviceIdentify + " 获取端口成功!", "端口:" + iRtspPort);
  } else {
    setOperaInfo(szDeviceIdentify + " 获取端口失败!");
  }
}

//云台控制
// PTZ控制 9为自动,1,2,3,4,5,6,7,8为方向PTZ
let g_bPTZAuto = false;
function mouseDownPTZControl(iPTZIndex) {
  console.log("方向控制开始:", iPTZIndex);
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex),
    bZeroChannel =
      $("#channels option")
        .eq($("#channels").get(0).selectedIndex)
        .attr("bZero") == "true"
        ? true
        : false,
    iPTZSpeed = config.speed || 0;

  if (bZeroChannel) {
    // 零通道不支持云台
    return;
  }

  if (oWndInfo != null) {
    if (9 == iPTZIndex && g_bPTZAuto) {
      iPTZSpeed = 0; // 自动开启后,速度置为0可以关闭自动
    } else {
      g_bPTZAuto = false; // 点击其他方向,自动肯定会被关闭
    }

    WebVideoCtrl.I_PTZControl(iPTZIndex, false, {
      iPTZSpeed: iPTZSpeed,
      success: function (xmlDoc) {
        if (9 == iPTZIndex && g_bPTZAuto) {
          setOperaInfo(oWndInfo.szDeviceIdentify + " 停止云台成功!");
        } else {
          setOperaInfo(oWndInfo.szDeviceIdentify + " 开启云台成功!");
        }
        if (9 == iPTZIndex) {
          g_bPTZAuto = !g_bPTZAuto;
        }
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + " 开启云台失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}

// 方向PTZ停止
function mouseUpPTZControl() {
  console.log("方向控制停止");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);
  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(1, true, {
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 停止云台成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + " 停止云台失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}

// 调倍数
function PTZZoomIn() {
  console.log("调焦in");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);
  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(10, false, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 调焦+成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  调焦+失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}

function PTZZoomout() {
  console.log("调焦out");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);
  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(11, false, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 调焦-成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  调焦-失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}
function PTZZoomStop() {
  console.log("调焦stop");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);
  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(11, true, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 调焦停止成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  调焦停止失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}
//调焦
function PTZFocusIn() {
  console.log("聚焦in");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);

  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(12, false, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 聚焦+成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  聚焦+失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}

function PTZFoucusOut() {
  console.log("聚焦out");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);

  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(13, false, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 聚焦-成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  聚焦-失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}
function PTZFoucusStop() {
  console.log("聚焦stop");
  let oWndInfo = WebVideoCtrl.I_GetWindowStatus(g_iWndIndex);

  if (oWndInfo != null) {
    WebVideoCtrl.I_PTZControl(12, true, {
      iWndIndex: g_iWndIndex,
      success: function (xmlDoc) {
        setOperaInfo(oWndInfo.szDeviceIdentify + " 聚焦停止成功!");
      },
      error: function (status, xmlDoc) {
        setOperaInfo(
          oWndInfo.szDeviceIdentify + "  聚焦停止失败!",
          status,
          xmlDoc
        );
      },
    });
  }
}
function setOperaInfo(info, status, xmlDoc) {
  let szTip =
    "<div>" + dateFormat(new Date(), "yyyy-MM-dd hh:mm:ss") + " " + info;
  if (typeof status != "undefined" && status != 200) {
    let szStatusString = $(xmlDoc).find("statusString").eq(0).text();
    let szSubStatusCode = $(xmlDoc).find("subStatusCode").eq(0).text();
    if ("" === szSubStatusCode) {
      if ("" === szSubStatusCode && "" === szStatusString) {
        szTip += "(" + status + ")";
      } else {
        szTip += "(" + status + ", " + szStatusString + ")";
      }
    } else {
      szTip += "(" + status + ", " + szSubStatusCode + ")";
    }
  }
  szTip += "</div>";
  $(".tip").html(szTip + $(".tip").html());
}
// 格式化时间
function dateFormat(oDate, fmt) {
  let 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 (let 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;
}