萤石摄像头视频备份实战:从 RTSP 回放到 HCNetSDK 原生下载
更新日期:
家里的萤石摄像头(CS-S20)录的是事件触发型录像(人形/移动报警),不是全天连续。最近想把 SD 卡里的历史录像备份到 NAS 上,踩了不少坑,最终落地了两条路径:RTSP 回放流(兜底,1x 实时)和 HCNetSDK 原生文件下载(主力,18x 实时速度)。这篇文章完整记录:两种方式的原理、示例代码、以及怎么把萤石 APK 逆向出来的登录凭据用起来。
文中所有 IP 用 192.168.1.* 占位,密码/序列号用占位符,不包含真实凭证。
背景:为什么 RTSP 回放不够快
萤石摄像头支持标准 RTSP 协议,可以直接拉流:
1 | rtsp://admin:验证码@192.168.1.100:554/Streaming/tracks/101?starttime=20261011T090000Z&endtime=20261011T100000Z |
但这个「回放」本质上是流式播放——设备把录像当直播流推给你,码流被限制在 1x 实时速度。一天有 48 分钟的事件录像,你就得花 48 分钟下载。要备份一个月的录像,得挂一个月。
后来研究发现,萤石摄像头(海康代工)在 8000 端口还跑着海康私有 SDK 协议,其中的 GetFileByTime 接口是文件传输模式——设备把录像文件直接发给你,不受 1x 限制,实测 18x 实时速度(WiFi 下 2.14 MB/s)。
方案一:RTSP 回放备份(兜底)
最简单的方式,不需要任何额外依赖,ffmpeg 直接拉:
1 | import subprocess |
**关键参数 -use_wallclock_as_timestamps 1**:萤石回放流的 DTS/PTS 是从设备开机起算的 90kHz 时钟值(可能达到几十万小时),不修正的话 MP4 时长会错乱、fps 显示上万、播放器快进。
缺点:1x 实时速度,适合短片段兜底,不适合全量备份。
前置准备
萤石开放平台账号
使用开放平台 API 查询录像片段清单需要先注册萤石账号并创建应用获取 AppKey/AppSecret:
- 注册地址:https://open.ys7.com/register
- 开放平台控制台:https://open.ys7.com(创建应用后获取 AppKey/AppSecret)
- API 文档:https://open.ys7.com/help/29(视频回放相关接口)
HCNetSDK 下载
SDK 库需要从海康威视官网手动下载(约 100MB,需浏览器访问,curl 被 403 拦截):
- 下载地址:https://www.hikvision.com/en/support/download/sdk/(搜索 “Device Network SDK for Linux 64bit”)
- 下载后解压,取
库文件/目录下的libhcnetsdk.so、libHCCore.so、HCNetSDKCom/等
方案二:HCNetSDK 原生下载(主力)
登录凭据:萤石 APK 逆向的关键发现
海康 HCNetSDK 的 NET_DVR_Login_V30 需要用户名密码。海康 NVR 用 admin + 设备密码,但萤石消费级摄像头不是这套——admin + 验证码会被拒(错误码 1)。
通过读 pyezvizapi(一个 Python 萤石库)源码中的 APK 逆向注释,发现萤石 APP 局域网登录有三个候选凭据,按顺序尝试:
| 顺序 | 接口 | 端口 | 用户名 | 密码 |
|---|---|---|---|---|
| 1 | Login_V40 (HTTPS) |
8443 | admin | 验证码原文 |
| 2 | Login_V30 |
8000 | admin | 验证码原文 |
| 3 | Login_V30 |
8000 | EZ_LOCAL_USER |
md5(验证码)[8:24] |
候选 3 是成败关键:密码是 MD5 十六进制的中段 16 位(第 8~23 字符,小写),不是完整 32 位。
1 | import hashlib |
SDK 下载流程
HCNetSDK 是纯 C 库(libhcnetsdk.so),Python 用 ctypes 直接调:
1 | import ctypes |
PS 流转 MP4
SDK 下载的产物是海康私有 PS 流(IMKH 头),ffmpeg 可以直接读:
1 | def ps_to_mp4(ps_file, mp4_file): |
片段枚举:萤石开放平台 API
事件录像设备需要先知道「有哪些片段」,才能逐段下载。萤石开放平台提供免费 API:
1 | import urllib.request |
返回的片段列表类似:
1 | [ |
localType 表示录像类型(1=事件录像),startTime/endTime 是毫秒时间戳。有了片段清单,就可以逐段精确下载。
完整备份流程
1 | 萤石开放平台 API(查片段清单) |
踩坑记录
| 坑 | 原因 | 解决 |
|---|---|---|
| SDK 登录报错误码 1 | 萤石消费机 SDK 密码独立于 RTSP 密码 | 用 EZ_LOCAL_USER + md5 中段 16 位 |
| 回放组件加载失败 err=110 | LD_LIBRARY_PATH 在 Python 内设置无效 |
必须在进程启动前 export,或 re-exec |
| HTTPS 证书校验失败 | SDK 目录的海康版 libssl 被 Python 优先加载 | 设 SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt |
| 连续下载 PLAYSTART err=12 | 消费机回放会话资源少,会话未释放 | 启动失败重试 3 次 + 段间静置 0.5s |
| 设备重启后下载卡死 | PLAYGETPOS 返回失败但文件仍在增长 |
忽略返回值,只认 pos.value >= 100 或文件增长停滞 |
| RTSP 回放时长错乱 | 回放流时间戳是开机起算的 90kHz 时钟 | 加 -use_wallclock_as_timestamps 1 |
性能对比
| 方式 | 速度 | 一天 48 分钟录像 |
|---|---|---|
| RTSP 回放 | 1x 实时(~0.2 MB/s) | ~48 分钟 |
| HCNetSDK 下载 | 18x 实时(~2.1 MB/s) | ~2.7 分钟 |
实测数据
以 2026-10-11 全天事件录像为例(14 个片段,合计 48.5 分钟视频):
| 方式 | 平均速度 | 下载耗时 | 备注 |
|---|---|---|---|
| RTSP 回放 | 1x 实时(~0.2 MB/s) | ~48.5 分钟 | 码流被设备限制在 1x |
| HCNetSDK 下载 | 18x 实时(~2.1 MB/s) | ~2.7 分钟 | 文件传输模式,WiFi 下实测 |
全量备份一个月(30 天,每天 ~48 分钟事件录像):
| 方式 | 预估总耗时 |
|---|---|
| RTSP 回放 | ~24 小时(连续不断) |
| HCNetSDK 下载 | ~1.4 小时 |
小结
- 片段枚举继续用萤石开放平台 API(免费、精确),下载换成 HCNetSDK 文件传输
- 登录凭据是
EZ_LOCAL_USER+md5(验证码)[8:24],来自萤石 APK 逆向 - SDK 库需要手动下载海康 Linux 版 HCNetSDK(约 100MB),用 ctypes 调用
- 断连防护:忽略 PLAYGETPOS 返回值(不可靠),只认 pos 或文件增长停滞;时长校验 + 自动重连
附录:SDK 直接枚举片段的可行性
一个自然的疑问是:能否跳过开放平台 API,直接用 HCNetSDK 的 FindFile 枚举片段?
实测结果:**NET_DVR_FindFile_V40 对 EZ_LOCAL_USER 返回 0 文件**(该用户无检索权限)。因此片段枚举仍需依赖开放平台 API,SDK 只负责下载。这也解释了为什么萤石 APP 本地回放需要先走云端鉴权——本地 SDK 用户的权限被刻意限制了。