vue系列

海康web视频插件h5网页账号密码预览监控

2025-06-09  本文已影响0人  litielongxx

web视频插件,是指windos下安装海康官网的exe在网页中通过中间js,实现网页上预览监控画面的形式。
这是iframe接入任意网页账号密码接入的形式
优点:
1 不需要后台参与,指转wss流协议在网页播放,官网对照是h5视频播放器开发包
2 只要有超脑账号密码ip
缺点:
1 浏览器出现多窗口都有监控画面显示时,会快速切换时,重复启用海康插件窗口,出现多个画面叠加
2 关闭a页面打开b页面,可能虽然关闭了a但未及时释放监控画面导致b页上出现了a页的监控画面。
https://open.hikvision.com/download/5c67f1e2f05948198c909700?type=10

image.png

本质是后台有个exe播放器,海康通过调整在电脑屏幕上的位置实现视觉上的引入网页,显示的不是video而是实打实的exe软件

<!DOCTYPE html>
<html>
  <head>
    <title>海康威视自动监控</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <style>
      body,
      html {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
      }
      #divPlugin {
        width: 100%;
        height: 100%;
      }
    </style>
  </head>
  <body>
    <div id="divPlugin"></div>
    <script src="../../../public/static/lib/jquery-3.3.1.min.js"></script>
    <!--  海康账号登录视频插件 -->
    <script src="../../../public/static/js/webVideoCtrl.js"></script>
    <script>
      function getQueryStringParam(paramName) {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get(paramName);
      }

      const CONFIG = {
        IP: getQueryStringParam("ip"),
        PORT: "80",
        PROTOCOL: 1,
        USER: getQueryStringParam("user"),
        PASSWORD: getQueryStringParam("pwd"),
        RTSP_PORT: "554",
        iWndowType: getQueryStringParam("split") * 1, // 必须数字
        // 1 单窗口;
        // 2 4 宫格,即 2×2 布局;
        // 3 6 宫格;
        // 4 8 宫格;
        // 5 9 宫格,即 3×3 布局;
        // 6 16 宫格。
        channels: getQueryStringParam("channel")
          ? getQueryStringParam("channel").split(",")
          : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        STREAM_TYPE: 2,
      };

      let webVideoCtrl = null;
      let isPreviewing = false;
      let controller = null;
      let initInProgress = false; // 跟踪初始化状态

      class HikvisionController {
        constructor() {
          this.deviceId = `${CONFIG.IP}_${CONFIG.PORT}`;
          this.init();
        }

        async init() {
          if (initInProgress) return; // 防止重复初始化
          initInProgress = true;

          try {
            closeHk();

            await this.initPlugin();
            await this.loginDevice();
            await this.setupDisplay();
            await this.startPreviewAllChannels();
          } catch (error) {
            console.error(1, error);
          } finally {
            initInProgress = false;
          }
        }

        async initPlugin() {
          return new Promise((resolve, reject) => {
            if (!window.WebVideoCtrl) {
              reject(new Error("WebVideoCtrl插件未加载"));
              return;
            }

            WebVideoCtrl.I_InitPlugin({
              bWndFull: true,
              cbInitPluginComplete: () => {
                console.log("插件初始化完成");
                if (document.getElementById("divPlugin")) {
                  WebVideoCtrl.I_InsertOBJECTPlugin("divPlugin")
                    .then(() => {
                      // 调整插件位置
                      this.adjustPluginPosition();
                      resolve();
                    })
                    .catch((err) =>
                      reject(new Error(`插件插入失败: ${err.message}`))
                    );
                } else {
                  reject(new Error("divPlugin容器不存在"));
                }
              },
            });
          });
        }

        adjustPluginPosition() {
          // 获取iframe的DOM元素
          const iframe = window.frameElement;
          console.log("获取iframe的DOM元素");
          console.log(iframe);
          if (iframe) {
            // 获取iframe相对于窗口的偏移量
            console.log("获取iframe相对于窗口的偏移量");
            const iframeRect = iframe.getBoundingClientRect();
            const iframeOffsetTop = iframeRect.top;
            const iframeOffsetLeft = iframeRect.left;

            // 获取视频插件元素
            const pluginElement = document.getElementById("divPlugin");

            // 设置插件的定位方式
            pluginElement.style.position = "absolute";
            pluginElement.style.top = iframeOffsetTop + "px";
            pluginElement.style.left = iframeOffsetLeft + "px";

            // 调整插件大小
            if (WebVideoCtrl) {
              WebVideoCtrl.I_Resize(
                pluginElement.offsetWidth,
                pluginElement.offsetHeight
              );
            }
          }
        }

        loginDevice() {
          return new Promise((resolve, reject) => {
            if (!window.WebVideoCtrl || !WebVideoCtrl.I_Login) {
              reject(new Error("WebVideoCtrl.I_Login方法未定义"));
              return;
            }

            WebVideoCtrl.I_Login(
              CONFIG.IP,
              CONFIG.PROTOCOL,
              CONFIG.PORT,
              CONFIG.USER,
              CONFIG.PASSWORD,
              {
                success: (xmlDoc) => {
                  if ($(xmlDoc).find("statusString").text() === "OK") {
                    resolve();
                  } else {
                    reject(new Error("登录状态异常"));
                  }
                },
                error: (err) =>
                  reject(
                    new Error(`登录失败: ${err.errorCode} ${err.errorMsg}`)
                  ),
              }
            );
          });
        }

        setupDisplay() {
          return new Promise((resolve) => {
            // 设置为指定窗口布局
            if (WebVideoCtrl && WebVideoCtrl.I_ChangeWndNum) {
              WebVideoCtrl.I_ChangeWndNum(CONFIG.iWndowType);
            }
            if (WebVideoCtrl && WebVideoCtrl.I_Resize) {
              WebVideoCtrl.I_Resize(window.innerWidth, window.innerHeight);
            }
            window.addEventListener("resize", () => {
              if (WebVideoCtrl && WebVideoCtrl.I_Resize) {
                WebVideoCtrl.I_Resize(window.innerWidth, window.innerHeight);
              }
            });
            resolve();
          });
        }

        async startPreviewAllChannels() {
          if (isPreviewing) return;
          isPreviewing = true;

          try {
            // 强制停止所有预览
            if (WebVideoCtrl.I_StopRealPlayAll) {
              WebVideoCtrl.I_StopRealPlayAll(this.deviceId);
            }

            const previewPromises = CONFIG.channels.map((channel, index) =>
              this.playChannel(channel, index)
            );

            await Promise.allSettled(previewPromises);
          } catch (error) {
            console.error("预览启动失败:", error);
          } finally {
            isPreviewing = false;
          }
        }

        playChannel(iChannelID, wndIndex) {
          return new Promise((resolve, reject) => {
            if (!window.WebVideoCtrl || !WebVideoCtrl.I_StartRealPlay) {
              reject(new Error("WebVideoCtrl.I_StartRealPlay方法未定义"));
              return;
            }

            WebVideoCtrl.I_StartRealPlay(this.deviceId, {
              iWndIndex: wndIndex,
              iChannelID: iChannelID,
              iStreamType: CONFIG.STREAM_TYPE,
              bZeroChannel: false,
              iPort: CONFIG.RTSP_PORT,
              success: () => resolve(),
              error: (err) => reject(new Error(err.errorMsg)),
            });
          });
        }
      }

      function closeHk() {
        if (window.WebVideoCtrl.I_StopAllPlay) {
          window.WebVideoCtrl.I_DestroyPlugin();
          window.WebVideoCtrl.I_StopAllPlay();
        } else {
          console.log(0, window.WebVideoCtrl, "未检测到已有控件");
        }
      }

      document.addEventListener("DOMContentLoaded", () => {
        // 加载时关闭
        closeHk();
        // 确保DOM完全加载后再释放旧资源
        // setTimeout(() => {
        controller = new HikvisionController();
        // }, 100); // 延迟初始化确保DOM稳定
      });

      window.addEventListener("beforeunload", () => {
        closeHk();
      });

      // 监听iframe卸载
      window.addEventListener("unload", () => {
        closeHk();
      });
    </script>
  </body>
</html>

使用方式

https://xx.com/index.html?ip=192.168.0.2&user=admin&pwd=xx&split=2&channel=3,2,6,7

超脑的ip账号密码
注意下载官网插件后的js,要两个放入对应,js是动态加载的会自行加载另外一个虽然html未引入


image.png

vue版未验证:
https://juejin.cn/post/7333936808789917708

上一篇 下一篇

猜你喜欢

热点阅读