
海康威视的 HCNetSDK 官方不提供纯 C++ 封装,所谓“sdk_c++”只是社区或厂商基于 C 接口做的薄层 C++ 封装(如 CHCNetSDK 类),实际调用仍是 C 风格函数。直接用 C 接口更可控,也避免封装层引入的资源管理漏洞和线程安全陷阱。
初始化 SDK 并登录设备前必须调用 NET_DVR_Init()
这是所有操作的前提,漏掉会导致后续所有接口返回失败(如 NET_DVR_Login_V40 返回 -1)。它内部初始化网络、日志、内存池等全局资源,且**只能调用一次**——重复调用可能引发崩溃或句柄泄漏。
- 建议在程序启动时尽早调用,例如
main()开头或单例类构造中 - 若需卸载(极少见),用
NET_DVR_Cleanup(),但必须确保所有设备已登出、所有预览/回放已停止 - 调试时可启用 SDK 日志:调用
NET_DVR_SetLogToFile(3, "log/", true),日志级别 3 覆盖大部分错误
NET_DVR_Login_V40() 登录失败常见原因
返回值为 -1 时不能只看返回码,要立刻调用 NET_DVR_GetLastError() 获取真实错误码。高频问题包括:
-
ERROR_INVALID_PARAMETER (5):NET_DVR_USER_LOGIN_INFO结构体未 memset 初始化,或sDeviceAddress含多余空格/换行 -
ERROR_SDK_VERSION_NOT_SUPPORT (7):SDK 版本低于设备固件要求,需升级 SDK 或降级设备固件 -
ERROR_PASSWORD_ERROR (6):密码错误,或设备开启了“密码复杂度校验”但未满足(如长度、大小写、特殊字符) -
ERROR_DEVICE_ONLINE (28):设备已在线,但 SDK 默认不允许重复登录;需设置struLoginInfo.bUseAsynLogin = false并检查struDeviceInfo.byChanNum是否为 0(设备未就绪)
用 NET_DVR_RealPlay_V40() 拉流必须配对处理回调
实时流数据通过回调函数传递,不是同步返回。关键点在于:
立即学习“C++免费学习笔记(深入)”;
- 回调函数必须是 C 风格(
extern "C"),不能是类成员函数(除非用 static 包装并传void* pUserData) - 回调中收到的
lpBuffer是 H.264/H.265 原始帧(含 SPS/PPS),**不是 RGB/BGR 图像**;需用 FFmpeg 或硬解码器进一步解码渲染 - 务必检查
dwDataType:值为NET_DVR_SYSHEAD表示帧头(含 SPS/PPS),需缓存供解码器初始化;值为NET_DVR_STREAMDATA才是视频帧数据 - 回调里禁止做耗时操作(如图像显示、文件写入),应仅 memcpy 到队列,由另一线程处理,否则 SDK 内部缓冲区会满导致断流
extern "C" void CALLBACK fRealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
{
if (dwDataType == NET_DVR_SYSHEAD) {
// 缓存 SPS/PPS
g_sps_pps.assign(pBuffer, pBuffer + dwBufSize);
} else if (dwDataType == NET_DVR_STREAMDATA) {
// 推入解码队列
g_video_queue.push(std::vector(pBuffer, pBuffer + dwBufSize));
}
} 退出时按顺序释放资源,顺序错会 crash
SDK 资源释放有强依赖顺序,颠倒极易导致访问非法内存:
- 先停止预览:
NET_DVR_StopRealPlay(lRealHandle) - 再登出设备:
NET_DVR_Logout(lUserID)(注意是lUserID,不是lRealHandle) - 最后才清理 SDK:
NET_DVR_Cleanup() - 如果用了语音对讲,需额外调用
NET_DVR_CloseSound()和NET_DVR_StopVoiceCom()
多路拉流时,每个 lRealHandle 必须对应一次 NET_DVR_StopRealPlay(),漏掉一路就会让该路线程卡死在 SDK 内部。











