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

225 阅读3分钟
前言

该h5属于硬件产品,websdk版不是默认显示的那个

image.png

硬件产品-websdk插件版

也可以直接下载 image.png www.hikvision.com/en/support/…

优点:

1 不需要后台参与,指转wss流协议在网页播放,官网对照是h5视频播放器开发包 2 只要有超脑账号密码ip

缺点:

1 浏览器出现多窗口都有监控画面显示时,会快速切换时,重复启用海康插件窗口,出现多个画面叠加

2 关闭a页面打开b页面,可能虽然关闭了a但未及时释放监控画面导致b页上出现了a页的监控画面。 异常时任务管理器搜hc结束监控进程就行 image.png 本质是任务管理器开机自启了hc程序,网页调用,没启用也可以手动搜hc一般不用

注意是是HCWebSDKPluginsUserSetup别安装错成VideoWebPlugin.exe

addEventListener如果是vue可以beforeDestroy声明周期执行相同

来自本站另外一个来源:juejin.cn/post/744964…

<!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);
      }
      
        // 1 单窗口;
        // 2 4 宫格,即 2×2 布局;
        // 3 6 宫格;
        // 4 8 宫格;
        // 5 9 宫格,即 3×3 布局;
        // 6 16 宫格。
        // 新 
        // 1	1×1	1
        // 2	2×2	4
        // 3	3×3	9
        // 4	4×4	16

      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, // 1主码流卡顿  2子码流不卡顿
      };

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

     class HikvisionController {
        constructor() {
          this.deviceId = `${CONFIG.IP}_${CONFIG.PORT}`;
          this.isPreviewing = false;
          console.log("[控制器] 初始化设备:", this.deviceId);
          this.init();
        }

        // 参考Vue版本的简单回调流程
        init() {
          if (!window.WebVideoCtrl) {
            showError("<strong>❌ 插件库未加载</strong><br>请检查webVideoCtrl.js路径", 0);
            return;
          }

          console.log("[初始化] 开始...");

          // 1. 初始化插件(回调方式)
          WebVideoCtrl.I_InitPlugin({
            bWndFull: true,
            iWndowType: CONFIG.SPLIT,
            cbInitPluginComplete: () => {
              console.log("[初始化] 插件初始化完成,准备插入...");
              
              // 2. 插入插件
              WebVideoCtrl.I_InsertOBJECTPlugin("divPlugin")
                .then(() => {
                  console.log("[初始化] 插件插入成功");
                  
                  // 3. 设置窗口数量
                  if (WebVideoCtrl.I_ChangeWndNum) {
                    WebVideoCtrl.I_ChangeWndNum(CONFIG.SPLIT);
                  }
                  
                  // 4. 登录设备(回调方式)
                  this.loginAndPreview();
                })
                .catch(err => {
                  showError(`<strong>插件插入失败</strong><br>${err.message || JSON.stringify(err)}`, 0);
                });
            }
          });
        }

        loginAndPreview() {
          console.log(`[登录] 正在连接 ${CONFIG.IP}:${CONFIG.PORT}...`);

          WebVideoCtrl.I_Login(
            CONFIG.IP,
            1, // 协议类型
            CONFIG.PORT,
            CONFIG.USER,
            CONFIG.PASSWORD,
            {
              async: true,
              success: (xmlDoc) => {
                const status = $(xmlDoc).find("statusString").text();
                if (status === "OK") {
                  console.log("[登录] ✓ 成功");
                  this.startPreview();
                } else {
                  const statusCode = $(xmlDoc).find("statusCode").text();
                  showError(`<strong>登录异常</strong><br>状态: ${status} (${statusCode})`, 8000);
                }
              },
              error: (err) => {
                console.error("[登录] ✗ 失败:", err);
                
                let errorMessage = `<strong>🚨 登录失败 (${err.errorCode})</strong><br>`;
                switch(err.errorCode) {
                  case 21:
                    errorMessage += `用户名或密码错误<br><small>用户: ${CONFIG.USER}</small>`;
                    break;
                  case 403:
                    errorMessage += `IP被设备封锁<br><small>请检查安全策略</small>`;
                    break;
                  default:
                    errorMessage += `${err.errorMsg || '未知错误'}`;
                }
                showError(errorMessage, 10000);
              }
            }
          );
        }

        startPreview() {
          if (this.isPreviewing) return;
          this.isPreviewing = true;

          console.log("[预览] 启动所有通道...", CONFIG.CHANNELS);

          // 先停止所有播放(忽略错误)
          if (WebVideoCtrl.I_StopRealPlayAll) {
            WebVideoCtrl.I_StopRealPlayAll(this.deviceId).catch(() => {});
          }

          // 逐个启动预览
          CONFIG.CHANNELS.forEach((channel, index) => {
            setTimeout(() => {
              this.playChannel(channel, index);
            }, index * 200); // 增加微小延迟,避免同时请求过载
          });
        }

        playChannel(iChannelID, wndIndex) {
          WebVideoCtrl.I_StartRealPlay(this.deviceId, {
            iWndIndex: wndIndex,
            iChannelID: iChannelID,
            iStreamType: 2, // 1主 2子码流
            bZeroChannel: false,
            iPort: 554, // RTSP端口
            success: () => {
              console.log(`[预览] ✓ 通道 ${iChannelID} 启动成功`);
            },
            error: (err) => {
              console.error(`[预览] ✗ 通道 ${iChannelID} 失败:`, err);
              if (err.errorCode === 403) {
                showError(`<strong>权限错误 (403)</strong><br>无法访问通道 ${iChannelID}`, 6000);
              }
            }
          });
        }
      }

      // ==========================================
      // 页面加载
      // ==========================================
      document.addEventListener("DOMContentLoaded", () => {
        console.log("[页面] DOM加载完成");
      });

      // 页面卸载清理
      window.addEventListener("beforeunload", () => {
        if (window.WebVideoCtrl) {
          console.log("[页面] 执行清理...");
          try {
            WebVideoCtrl.I_StopAllPlay();
            WebVideoCtrl.I_DestroyPlugin();
            WebVideoCtrl.I_Logout(`${CONFIG.IP}_${CONFIG.PORT}`);
          } catch (e) {
            console.warn("清理警告:", e);
          }
        }
      });
    
    </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版未验证: juejin.cn/post/733393…

推荐个另外的vue版,同样public下index.html需要引入jq和官方的webVideo.js

<template>
  <div ref="divPlugin" id="divPlugin" class="plugin-container"></div>
</template>

<script>
export default {
  name: 'HikvisionMonitor',
  props: {
    config: {
      type: Object,
      required: true,
      default: () => ({})
    }
  },
  data() {
    return {
      webVideoCtrl: null,
      isPreviewing: false,
      controller: null,
      initInProgress: false,
      deviceId: '',
      channels: []
    }
  },
  watch: {
    config: {
      handler(newVal) {
        // this.handleConfigChange(newVal)
      },
      deep: true
    }
  },
  mounted() {
    // 初始化插件容器
    this.initPlugin()
  },
  beforeDestroy() {
    // 组件销毁前清理插件资源
    console.log('组件销毁前清理插件资源')
    this.closeHk()
  },
  methods: {
    // 获取查询参数(此处可根据实际需求调整)
    getQueryStringParam(paramName) {
      const urlParams = new URLSearchParams(window.location.search)
      return urlParams.get(paramName)
    },
    handleConfigChange(newConfig) {
      // 当配置改变时,重新初始化或更新预览
      this.closeHk() // 先关闭当前预览
      this.initPlugin() // 重新初始化
    },
    initPlugin() {
      if (this.initInProgress) return
      this.initInProgress = true
      this.deviceId = `${this.config.ip}_${this.config.port || 80}`
      this.channels = this.config.channel || [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 根据传入配置解析通道

      if (!window.WebVideoCtrl) {
        console.error('WebVideoCtrl 插件未加载')
        this.initInProgress = false
        return
      }

      // 初始化插件
      WebVideoCtrl.I_InitPlugin({
        bWndFull: true,
        cbInitPluginComplete: () => {
          console.log('插件初始化完成')
          this.$nextTick(() => {
            if (this.$refs.divPlugin) {
              // 插入插件到容器中
              WebVideoCtrl.I_InsertOBJECTPlugin('divPlugin')
                .then(() => {
                  this.loginDeviceAndSetupDisplay()
                })
                .catch(err => {
                  console.error(1, err)
                })
            } else {
              console.error('未找到插件容器')
            }
          })
        }
      })
    },
    loginDeviceAndSetupDisplay() {
      // 登录设备并设置显示
      if (window.WebVideoCtrl && WebVideoCtrl.I_Login) {
        WebVideoCtrl.I_Login(
          this.config.ip,
          1, // 假设协议为 1(可根据实际情况调整)
          this.config.port || 80,
          this.config.user,
          this.config.pwd,
          {
            success: xmlDoc => {
              if ($(xmlDoc).find('statusString').text() === 'OK') {
                this.setupDisplay()
              } else {
                console.error('登录状态异常')
              }
            },
            error: err => {
              console.error('登录失败:', err)
            }
          }
        )
      } else {
        console.error('WebVideoCtrl.I_Login 方法未定义')
      }
    },
    setupDisplay() {
      // 设置显示布局
      if (window.WebVideoCtrl && WebVideoCtrl.I_ChangeWndNum) {
        // 切割画面要求数字
        WebVideoCtrl.I_ChangeWndNum(this.config.split || 2)
      }
      //   window.addEventListener('resize', () => {
      //     if (window.WebVideoCtrl && WebVideoCtrl.I_Resize) {
      //       WebVideoCtrl.I_Resize(window.innerWidth, window.innerHeight)
      //     }
      //   })
      this.startPreviewAllChannels() // 启动所有通道预览
    },
    startPreviewAllChannels() {
      if (this.isPreviewing) return
      this.isPreviewing = true

      try {
        if (window.WebVideoCtrl && WebVideoCtrl.I_StopRealPlayAll) {
          WebVideoCtrl.I_StopRealPlayAll(this.deviceId)
        }

        this.channels.forEach((channel, index) => {
          this.playChannel(channel, index)
        })
      } catch (error) {
        console.error('预览启动失败:', error)
      } finally {
        this.isPreviewing = false
      }
    },
    playChannel(iChannelID, wndIndex) {
      if (!window.WebVideoCtrl || !WebVideoCtrl.I_StartRealPlay) {
        console.error('WebVideoCtrl.I_StartRealPlay 方法未定义')
        return
      }

      WebVideoCtrl.I_StartRealPlay(this.deviceId, {
        iWndIndex: wndIndex,
        iChannelID: parseInt(iChannelID), // 确保通道 ID 为数字类型
        iStreamType: 2, // 假设流类型为 2(可根据实际情况调整)
        bZeroChannel: false,
        iPort: 554, // RTSP 端口(可根据实际情况调整)
        success: () => {
          console.log(`通道 ${iChannelID} 预览启动成功`)
        },
        error: err => {
          console.error(`通道 ${iChannelID} 预览启动失败:`, err)
        }
      })
    },
    closeHk() {
      if (window.WebVideoCtrl) {
        console.log('关闭预览')
        window.WebVideoCtrl.I_StopAllPlay()
        console.log('销毁插件')
        window.WebVideoCtrl.I_DestroyPlugin()
        window.WebVideoCtrl.I_Logout(this.deviceId)
      }
    }
  }
}
</script>

<style scoped>
.plugin-container {
  width: 100%;
  height: 100%;
}
</style>