ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

海康威视摄像头V3.4 SDK升级与Vue3迁移实战指南

海康威视摄像头V3.4 SDK升级与Vue3迁移实战指南 1. 从 V2 到 V3 的升级背景与整体思路海康威视摄像头的 Web 端对接一直是安防可视化项目里绕不开的一块硬骨头。早期绝大多数项目都是基于 Vue2 搭建的配套的是海康官方那套WebVideoCtrl.js加HCWebSDKPlugin的插件方案。这套方案在当年确实能跑通但它对浏览器插件、ActiveX 控件的依赖太重随着浏览器内核不断收紧安全策略老方案在新环境里越来越吃力。我手上这个项目就是从 Vue2 迁移到 Vue3 的典型案例标题里说的“V3.4 升级改造 VUE3”指的就是把海康 Web 插件从旧版本 SDK 升级到 V3.4同时把整个前端框架从 Vue2 迁到 Vue3。先说清楚这个项目到底在做什么。它要解决的核心问题是在一个后台管理系统里实时预览多路海康摄像头画面支持云台控制、录像回放、抓图这些基础能力同时还要兼容新版浏览器。适合谁来参考如果你正在做安防监控平台、智慧园区、工厂可视化这类项目并且前端用的是 Vue3那这篇内容基本可以当作一份实操手册来用。关键词里的WebVideoCtrl、HCWebSDKPlugin、jsVideoPlugin这三个东西是整个对接过程的技术核心后面我会逐个拆开讲。为什么非要升级我踩过的坑很直接Vue2 项目里用的老版WebVideoCtrl.js依赖 NPAPI 插件Chrome 从 45 版本之后就不再支持这类插件了Edge 换了 Chromium 内核之后同样不行。用户打开页面要么提示“请使用以下最新版本的浏览器打开”要么干脆黑屏。海康后来推出了基于 WebSocket 和 WebAssembly 的新方案也就是 V3.4 这一代 SDK它不再依赖浏览器插件而是通过本地服务或者 WebSocket 通道来取流。这个变化是根本性的也是我们必须升级的原因。整体思路分三层。第一层是 SDK 层把旧的WebVideoCtrl.js替换成 V3.4 的jsVideoPlugin或者HCWebSDKPlugin这两个是海康新 SDK 的不同封装形态前者偏纯 JS 调用后者偏插件化集成。第二层是框架层Vue2 的 Options API 要改成 Vue3 的 Composition APIthis.$refs那一套要换成ref和onMounted。第三层是通信层新 SDK 的取流地址、鉴权方式、事件回调都和老版本不一样需要重新对接。这三层里SDK 层是难点框架层是工作量通信层是最容易出问题的地方。我选择 Vue3 而不是继续留在 Vue2除了技术栈统一之外还有一个现实原因Vue3 的setup语法在管理多个摄像头实例时更清晰。一个页面挂 16 路摄像头每路都有自己的状态、句柄、事件监听用 Options API 写会非常乱data里塞一堆数组methods里全是回调。用 Composition API 可以把每个摄像头的逻辑抽成一个useCamera组合式函数复用和维护都方便很多。这也是我在实际改造中体会最深的一点。2. 海康 V3.4 SDK 的核心变化与选型解析2.1 新旧 SDK 的本质差异老版本的WebVideoCtrl.js走的是浏览器插件路线安装一个本地 exe注册成浏览器插件然后 JS 通过插件提供的接口去调用摄像头。这种方式的问题在于插件和浏览器版本强绑定Chrome 一升级就可能失效而且用户端部署极其麻烦每台电脑都要装插件、调权限。V3.4 的jsVideoPlugin换了个思路它把取流和解码放在本地的一个轻量服务里前端通过 WebSocket 或者 HTTP 和这个服务通信浏览器只负责渲染视频画面。这样一来浏览器升级不再影响功能部署也简化成安装一个本地服务程序。HCWebSDKPlugin和jsVideoPlugin的区别我实际用下来是这样HCWebSDKPlugin更偏向于把海康的能力封装成一个类似插件的对象调用方式和老版本接近迁移成本低jsVideoPlugin更纯粹是一套 JS 库需要你自己管理初始化和销毁。如果你的项目是从老版本迁移过来的我建议先用HCWebSDKPlugin因为方法名和回调结构变化小改起来快。如果是全新项目jsVideoPlugin更灵活尤其是配合 Vue3 的组合式 API能写出很干净的代码。这里有个关键点必须说清楚V3.4 的取流格式和老版本完全不同。老版本用的是rtsp://地址直接丢给插件新版本需要通过 SDK 提供的startRealPlay方法传入摄像头索引和码流类型由 SDK 内部去协商取流。热词里提到的“海康威视摄像头 rtsp 地址”和“海康摄像头取流地址”在新方案里其实不再是前端直接拼的东西而是配置在 SDK 初始化参数里的。这个认知转变很重要很多人卡在这里就是因为还在用老思路去找 RTSP 地址。2.2 选型背后的考量与参数计算为什么选 V3.4 而不是其他方案我对比过三种第一种是继续用老插件直接放弃浏览器不支持第二种是用 WebRTC 自己转流需要搭流媒体服务器成本高第三种就是海康官方的 V3.4 SDK开箱即用虽然也有坑但至少是官方维护的。从项目周期和稳定性来看V3.4 是最优解。在参数配置上有几个数值需要根据实际场景算。比如分屏数量一个页面同时预览 16 路 1080P 画面每路码流按 2Mbps 算总带宽就是 32Mbps。如果走的是本地服务取流这个带宽压力在局域网内没问题但如果是跨网段就要考虑降码流或者降分辨率。我在项目里用的是主码流预览、子码流回放主码流 1080P子码流 720P这样在保证预览清晰度的同时回放时不会把带宽打满。还有一个参数是iWndowType也就是窗口分割类型。V3.4 SDK 里这个值决定了画面怎么分屏1 是 1x12 是 2x23 是 3x34 是 4x4。我实测下来4x4 也就是 16 路在普通办公电脑上 CPU 占用会到 60% 左右如果电脑配置一般建议最多开到 3x3。这个数值不是随便设的要根据客户端硬件来定。我在代码里做了一个自适应逻辑根据navigator.hardwareConcurrency判断 CPU 核心数小于 4 核就限制到 2x2。2.3 与 Vue3 生态的契合点Vue3 的响应式系统和新 SDK 的事件回调配合得很好。老版本 SDK 的回调是全局函数比如WebVideoCtrl.I_Login的回调直接挂在 window 上Vue2 里要用this去访问组件实例很别扭。V3.4 的 SDK 支持传入回调函数我可以在setup里定义回调直接操作ref变量不需要this逻辑清晰很多。另外Vue3 的onBeforeUnmount生命周期在销毁摄像头实例时特别有用。老项目里经常出现页面切走了摄像头还在后台取流内存泄漏。用 Vue3 的组合式 API我可以在onBeforeUnmount里统一调用stopRealPlay和destroy确保资源释放干净。这一点在多个摄像头实例的场景下尤其重要我见过太多项目因为没做好销毁跑几个小时浏览器就卡死了。3. Vue3 项目环境搭建与 SDK 集成实操3.1 开发环境准备与依赖安装先说一下环境。我用的是 Vite 创建的 Vue3 项目Node 版本 18包管理器用 pnpm。为什么用 Vite 而不是 Webpack因为 Vite 的冷启动快改代码热更新几乎无感这在调试摄像头这种需要频繁刷新的场景下体验好很多。创建项目的命令很简单pnpm create vite hikvision-vue3 --template vue cd hikvision-vue3 pnpm install接下来是安装海康 SDK。V3.4 的 SDK 一般是一个压缩包里面包含jsVideoPlugin.js、HCWebSDKPlugin.js和相关的 wasm 文件。这些文件不能直接放src里用 import 引入因为 SDK 内部会去加载同目录下的资源。我的做法是在public目录下建一个hikvision文件夹把 SDK 所有文件丢进去然后在index.html里用 script 标签引入script src/hikvision/jsVideoPlugin.js/script script src/hikvision/HCWebSDKPlugin.js/script这样做的好处是 SDK 的资源路径不会被打包工具处理避免 wasm 加载失败。我试过用 import 方式引入结果 wasm 文件路径不对控制台报 404折腾了很久才改成 public 方案。3.2 SDK 初始化与登录流程SDK 初始化的核心是initPlugin方法。在 Vue3 里我把它放在onMounted里执行确保 DOM 已经渲染完成。初始化需要传入容器 ID 和窗口分割类型import { ref, onMounted, onBeforeUnmount } from vue const playerContainer ref(null) const g_iWndIndex ref(0) onMounted(() { const iWndowType 2 // 2x2 分屏 const bWndFull false const initResult window.JSPlugin.initPlugin(playerContainer, iWndowType, bWndFull) if (initResult ! 0) { console.error(SDK 初始化失败错误码, initResult) return } loginCamera() })登录摄像头用的是JSPlugin.login方法需要传入 IP、端口、用户名、密码。这里有个细节V3.4 的登录是异步的返回一个 Promise我建议用async/await写比回调清晰const loginCamera async () { const loginParam { ip: 192.168.1.64, port: 8000, username: admin, password: hik12345 } try { const result await window.JSPlugin.login(loginParam.ip, loginParam.port, loginParam.username, loginParam.password) if (result 0) { console.log(登录成功) startPreview() } } catch (err) { console.error(登录失败, err) } }注意海康摄像头的默认端口是 8000但有些项目改过端口一定要确认清楚。另外密码如果包含特殊字符建议先做 URL 编码我遇到过密码里有导致登录失败的案例。3.3 实时预览与多路分屏实现登录成功后就可以开始预览了。startRealPlay方法需要传入窗口索引、码流类型和摄像头通道号const startPreview () { const iWndIndex g_iWndIndex.value const iStreamType 1 // 1 主码流2 子码流 const iChannel 1 window.JSPlugin.startRealPlay(iWndIndex, iStreamType, iChannel) }多路分屏的关键在于窗口索引的管理。2x2 分屏有 4 个窗口索引从 0 到 3。我一般会维护一个摄像头列表每个摄像头对应一个窗口索引循环调用startRealPlay。这里有个坑如果某个窗口已经有人在预览再次调用会失败所以要先判断窗口状态。我的做法是维护一个windowStatus数组记录每个窗口是否被占用。const cameraList [ { ip: 192.168.1.64, channel: 1, windowIndex: 0 }, { ip: 192.168.1.65, channel: 1, windowIndex: 1 }, { ip: 192.168.1.66, channel: 1, windowIndex: 2 }, { ip: 192.168.1.67, channel: 1, windowIndex: 3 } ] const startAllPreview async () { for (const cam of cameraList) { await window.JSPlugin.login(cam.ip, 8000, admin, hik12345) window.JSPlugin.startRealPlay(cam.windowIndex, 1, cam.channel) } }实测下来4 路 1080P 同时预览在 i5 处理器的电脑上 CPU 占用大概 35%内存 500MB 左右属于可接受范围。如果路数更多建议用子码流预览清晰度降一点但流畅度有保障。4. 云台控制、回放与事件对接的细节处理4.1 云台控制与抓图功能实现云台控制是安防项目里的高频需求。V3.4 SDK 提供了ptzControl方法参数包括命令、速度、窗口索引。命令有上、下、左、右、放大、缩小等速度范围一般是 1 到 7。我封装了一个通用的云台控制函数const ptzControl (command, speed 4) { const iWndIndex g_iWndIndex.value window.JSPlugin.ptzControl(iWndIndex, command, speed, 0) }命令值我整理了一个对照表方便查命令含义命令值上向上转动1下向下转动2左向左转动3右向右转动4放大焦距拉近11缩小焦距拉远12停止停止转动0抓图用的是capturePic方法可以把当前画面保存成图片。这里要注意抓图是异步的需要监听回调const capturePicture () { window.JSPlugin.capturePic(g_iWndIndex.value, (data) { const blob new Blob([data], { type: image/jpeg }) const url URL.createObjectURL(blob) const a document.createElement(a) a.href url a.download capture_${Date.now()}.jpg a.click() URL.revokeObjectURL(url) }) }提示抓图的回调数据是二进制流不要直接当 base64 用。我一开始没注意直接把 data 塞到 img 的 src 里结果图片显示不出来后来改成 Blob 才正常。4.2 录像回放与时间轴对接回放功能比预览复杂因为涉及到时间范围查询和文件定位。V3.4 SDK 的startPlayback方法需要传入开始时间和结束时间格式是YYYY-MM-DD HH:mm:ss。我一般会做一个时间选择器让用户选时间段然后调用回放const startPlayback (startTime, endTime) { const iWndIndex g_iWndIndex.value window.JSPlugin.startPlayback(iWndIndex, startTime, endTime) }回放过程中可以调用pausePlayback和resumePlayback控制暂停和继续setPlaybackSpeed调整倍速。倍速支持 1、2、4、8 倍实测 4 倍速以上画面会有点卡顿建议最高用 4 倍。时间轴对接是回放功能的难点。海康 SDK 本身不提供时间轴 UI需要自己画。我用的是canvas绘制时间轴把一天 24 小时分成 1440 个刻度有录像的时段用绿色标记没有的用灰色。点击时间轴时把点击位置换算成时间再调用startPlayback。这个换算逻辑要小心像素和时间之间的比例要算准否则定位会偏。4.3 事件订阅与 28181 对接说明热词里提到了“海康威视摄像头怎么通过 28181 上传事件”这里我简单说一下。GB28181 是国标协议摄像头通过这个协议把报警事件、移动侦测等上传到平台。前端这边一般不直接处理 28181而是由后端平台接收事件再通过 WebSocket 推给前端。我在项目里的做法是后端订阅 28181 事件前端用 WebSocket 接收收到事件后在画面上叠加报警图标。V3.4 SDK 本身也支持事件回调比如JSPlugin.setEventCallback可以监听报警、移动侦测等。但实际用下来SDK 的事件回调不如后端推送稳定因为 SDK 依赖本地服务服务一断事件就丢了。所以我的建议是关键事件走后端 28181 推送SDK 回调作为辅助。5. 常见问题排查与避坑经验实录5.1 浏览器兼容性与插件加载失败最常见的问题就是浏览器提示“请使用以下最新版本的浏览器打开”。这个提示一般出现在老版本 SDK 上V3.4 已经解决了这个问题。如果你升级到 V3.4 还看到这个提示大概率是 SDK 文件没加载成功。排查步骤打开浏览器控制台看JSPlugin对象是否存在如果undefined说明 script 标签没生效检查路径是否正确。还有一个坑是 Edge 浏览器有时候无法关闭右上角的最小化按钮这是浏览器自身的 bug和 SDK 无关。我试过用window.close()和window.open(, _self).close()都不行最后是通过window.open打开新窗口再关闭的方式绕过的。这个方案不完美但能用。5.2 取流失败与网络排查取流失败的原因很多我整理了一个排查表现象可能原因解决方法登录成功但黑屏码流类型不对切换主/子码流试试提示连接超时网络不通ping 摄像头 IP检查端口画面卡顿带宽不足降码流或降分辨率部分窗口黑屏窗口索引冲突检查窗口是否被占用登录失败密码错误或端口不对确认密码和端口我遇到最诡异的一次是摄像头能 ping 通端口也通但就是登录失败。后来发现是摄像头开启了 IP 白名单只允许特定 IP 访问。这个在摄像头配置里改一下就行但如果不熟悉海康的配置界面很难想到。5.3 Vue3 迁移中的典型报错从 Vue2 迁到 Vue3报错主要集中在几个地方。一个是this指向问题Vue3 的setup里没有this所有老代码里的this.$refs都要改成ref。另一个是router路由跳转后组件内容不渲染这个一般是router-view没配好或者路由守卫里next()没调用。还有一个热词里提到的vue3 uncaught syntaxerror: invalid or unexpected token这个报错一般是 SDK 文件里有特殊字符或者编码不对。我的解决方法是把 SDK 文件用 UTF-8 重新保存一遍然后在 script 标签上加charsetutf-8。5.4 性能优化与内存泄漏防范多路摄像头预览最怕内存泄漏。我踩过的坑是页面切换后没有销毁摄像头实例跑了一晚上浏览器直接崩溃。后来在onBeforeUnmount里加了清理逻辑onBeforeUnmount(() { window.JSPlugin.stopRealPlay(g_iWndIndex.value) window.JSPlugin.logout() window.JSPlugin.destroy() })另外setInterval和setTimeout也要记得清理尤其是轮询摄像头状态的定时器。我一般会把定时器 ID 存在ref里销毁时统一clearInterval。性能优化方面我建议开启硬件加速。V3.4 SDK 支持 GPU 解码在初始化时传入bHWAcceleration: trueCPU 占用能降一半。但这个参数不是所有显卡都支持如果开启后画面花屏就关掉。6. 升级改造后的效果与个人实操体会改造完成后整个项目的体验提升很明显。首先是浏览器兼容性Chrome、Edge、Firefox 都能正常预览不再需要装插件。其次是稳定性连续跑 72 小时没有出现崩溃或内存泄漏。最后是开发效率Vue3 的组合式 API 让代码复用变得容易新增一个摄像头页面只需要复制一个组合式函数改改配置就行。我个人在实际操作中的体会是海康 SDK 的文档写得不够细很多方法参数没有说明清楚需要自己试。比如startRealPlay的第三个参数iChannel文档里说是通道号但实际用的时候如果摄像头是 NVR 下的通道这个值要对应 NVR 的通道号不是摄像头的通道号。这个坑我踩了两天才搞明白。还有一点SDK 的版本一定要和本地服务版本匹配。我有一次只升级了前端 SDK没升级本地服务结果登录一直失败报错信息还不明确。后来把本地服务也升到 V3.4 对应版本问题就解决了。所以升级的时候前端 SDK 和本地服务要一起升别只升一半。最后分享一个小技巧调试摄像头的时候我一般会先用海康官方的 demo 页面测试确认摄像头和网络没问题再集成到项目里。这样能把问题范围缩小避免在项目代码里瞎找。这个习惯帮我省了很多时间。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进