简介:这份资源是面向Linux平台监控视频开发者的Qt示例工程源码,适合具备C++基础、希望将海康摄像头接入自研客户端或做系统集成的技术人员。源码围绕网络通信、多媒体播放、视频解码、设备发现与配置、多线程处理及错误日志等环节展开,可帮助读者理解RTSP视频流的拉取、解码与界面显示流程,并掌握播放控制、通道参数配置等交互逻辑。压缩包为rar格式,共220个文件,约1.2MB,其中62个h头文件与58个cpp源文件构成核心实现,51个ui文件描述界面布局,另有png、bmp等图片资源及pro、pri工程配置,目录结构完整,便于按模块阅读与二次开发。目前已有1152人学习下载,可作为监控客户端开发与课程设计的参考范例。
1. 拆开一份 Linux 下海康监控视频 QT demo 源码:它到底能跑通什么
很多做安防上位机的兄弟,第一次拿到“Linux 下海康监控视频 QT demo 源码”这类资源时,心里其实是打鼓的:这玩意儿是能直接编译出画面,还是只是个空壳框架?我拆过几份类似的包,结论是——只要它带了设备网络 SDK 的调用封装和 QT 的显示层,这东西就能帮你省掉至少一周的对接时间。它解决的核心问题很具体:在 Linux 桌面环境里,用 QT 做界面,通过海康设备网络 SDK 去拉 RTSP 流或者直接取裸流,然后解码显示。适合谁?适合正在做 NVR 客户端、视频监控平台、或者需要把海康摄像头画面嵌到自己 QT 程序里的开发者。如果你还在用 ffmpeg 硬解 RTSP 地址,这份源码能让你看到另一种更贴近设备原厂的取流方式。
2. 环境搭不起来,后面全是白扯:依赖、SDK 与 QT 版本对齐
2.1 先确认你的 Linux 发行版和 QT 版本
这份源码大概率是在某个特定发行版上验证过的,常见的是 Ubuntu 18.04 或 20.04,QT 版本多为 5.9 到 5.15 之间。别上来就怼 QT6,海康 SDK 的库大多是按 QT5 的 ABI 编的,混用容易出玄学问题。我一般会先跑qmake -v和ldd --version看一眼基础环境。
# 查看 QT 版本 qmake -v # 查看 glibc 版本,海康 SDK 对 glibc 有最低要求 ldd --version | head -n 1 # 查看系统架构,必须是 x86_64 或 aarch64 对应 SDK 版本 uname -m逻辑说明:qmake -v确认 QT 主版本,避免 QT6 编译 QT5 工程;ldd --version看 glibc,海康 SDK 的 so 文件通常要求 2.27 以上;uname -m决定你下载的 SDK 是 x86 还是 ARM 版。参数上,如果输出是aarch64,那你要找的是海康的 ARM 版设备网络 SDK,不是 Linux64 那个包。
2.2 海康 SDK 的库文件怎么放
源码包里一般不会直接带海康的 SDK 二进制库,因为版权问题。你需要自己去海康官网下载“设备网络 SDK(Linux 64 位)”,解压后把lib目录下的libhcnetsdk.so、libhpr.so、libhlog.so等拷到工程目录的lib/下,或者放到/usr/lib并ldconfig。
# 假设 SDK 解压到了 ~/hik_sdk cd ~/hik_sdk # 查看库文件列表 ls -l lib/ # 拷贝到工程目录(假设工程在 ~/qt_hik_demo) cp lib/*.so ~/qt_hik_demo/lib/ # 如果选择系统级安装 sudo cp lib/*.so /usr/lib/ sudo ldconfig逻辑说明:cp到工程目录是为了让pro文件里用LIBS += -L$$PWD/lib -lhcnetsdk能直接找到;ldconfig是刷新动态链接器缓存,否则运行时会报error while loading shared libraries: libhcnetsdk.so: cannot open shared object file。参数上,注意libhcnetsdk.so可能还依赖libssl和libcrypto,如果系统里没有,ldd libhcnetsdk.so会显示not found,这时候装libssl-dev就行。
2.3 QT 工程文件里必须改的几个路径
源码里的.pro文件通常写死了 SDK 路径,你得改成自己的。重点看INCLUDEPATH和LIBS这两行。
# 打开 pro 文件 vim qt_hik_demo.pro# 修改前可能是 INCLUDEPATH += /home/xxx/hik_sdk/include LIBS += -L/home/xxx/hik_sdk/lib -lhcnetsdk # 修改后(用相对路径更稳) INCLUDEPATH += $$PWD/include LIBS += -L$$PWD/lib -lhcnetsdk -lhpr -lhlog逻辑说明:$$PWD是 qmake 的内置变量,指向当前 pro 文件所在目录,这样换机器不用改绝对路径。-lhcnetsdk对应libhcnetsdk.so,-lhpr对应libhpr.so,-lhlog对应libhlog.so。如果链接时报undefined reference to某个函数,多半是漏了某个-l参数,用nm -D libhcnetsdk.so | grep 函数名确认符号在哪个库里。
3. 从登录设备到出画面:核心调用链与 QT 显示层对接
3.1 设备登录与句柄管理
海康 SDK 的调用是典型的 C 接口风格,先NET_DVR_Init,再NET_DVR_Login_V40拿用户 ID,后面所有操作都靠这个 ID。源码里一般会封装一个HikDevice类,把登录、登出、布防都包起来。
// 初始化 if (!NET_DVR_Init()) { qDebug() << "NET_DVR_Init failed:" << NET_DVR_GetLastError(); return; } // 设置连接超时和重连 NET_DVR_SetConnectTime(2000, 1); NET_DVR_SetReconnect(10000, true); // 登录参数 NET_DVR_USER_LOGIN_INFO loginInfo = {0}; strcpy(loginInfo.sDeviceAddress, "192.168.1.64"); loginInfo.wPort = 8000; strcpy(loginInfo.sUserName, "admin"); strcpy(loginInfo.sPassword, "password"); loginInfo.bUseAsynLogin = false; NET_DVR_DEVICEINFO_V40 deviceInfo = {0}; LONG lUserID = NET_DVR_Login_V40(&loginInfo, &deviceInfo); if (lUserID < 0) { qDebug() << "Login failed:" << NET_DVR_GetLastError(); }逻辑说明:NET_DVR_Init必须最先调用,且整个进程只调一次;NET_DVR_SetConnectTime第一个参数是超时毫秒数,第二个是重试次数;NET_DVR_SetReconnect第一个参数是重连间隔,第二个是是否启用。NET_DVR_Login_V40的bUseAsynLogin设为 false 是同步登录,方便后面直接拿lUserID。常见坑是密码里带特殊字符,strcpy不会转义,得确保密码本身没有\0截断问题。
3.2 取流方式:RTSP 还是 SDK 私有流
源码里通常有两种取流路径:一种是拼 RTSP 地址丢给 ffmpeg 或 live555,另一种是用NET_DVR_RealPlay_V40直接拿裸流回调。前者通用但延迟高,后者延迟低但绑死海康设备。
// 方式一:RTSP 地址(通用) QString rtspUrl = QString("rtsp://admin:password@192.168.1.64:554/Streaming/Channels/101"); // 方式二:SDK 私有流(低延迟) NET_DVR_PREVIEWINFO previewInfo = {0}; previewInfo.lChannel = 1; // 通道号 previewInfo.dwStreamType = 0; // 0-主码流,1-子码流 previewInfo.dwLinkMode = 0; // 0-TCP,1-UDP previewInfo.bBlocked = 1; // 阻塞取流 LONG lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &previewInfo, RealDataCallBack, nullptr);逻辑说明:lChannel从 1 开始,不是 0;dwStreamType选 0 是主码流,画质好但带宽高,选 1 是子码流,适合多路预览;dwLinkMode选 0 是 TCP,穿透性好但延迟略高,选 1 是 UDP,延迟低但可能丢包。RealDataCallBack是回调函数,数据到手后要自己送解码器。如果回调里直接做 QT 界面更新,会崩,因为回调在 SDK 的线程里,必须用QMetaObject::invokeMethod切回主线程。
3.3 解码与显示:QImage 还是 QLabel 直接刷
回调拿到的是 PS 流或裸 H264,得解码。源码里常见做法是接一个解码器(比如 ffmpeg 的avcodec),解出 YUV 再转 RGB,最后包成QImage刷到QLabel上。
// 回调中缓存数据,主线程解码 void RealDataCallBack(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser) { if (dwDataType == NET_DVR_SYSHEAD) { // 系统头,送解码器初始化 } else if (dwDataType == NET_DVR_STREAMDATA) { // 码流数据,入队列 QMetaObject::invokeMethod((QObject*)pUser, "onStreamData", Qt::QueuedConnection, Q_ARG(QByteArray, QByteArray((char*)pBuffer, dwBufSize))); } }逻辑说明:NET_DVR_SYSHEAD是流的头信息,解码器需要它来初始化解码上下文;NET_DVR_STREAMDATA是实际码流。用QByteArray拷贝一份数据再投递到主线程,避免回调返回后 buffer 被 SDK 回收。Qt::QueuedConnection保证槽函数在主线程执行。如果画面花屏,多半是解码器没收到 SYSHEAD 或者 SPS/PPS 丢失,可以在回调里把 SYSHEAD 也存一份,解码前先喂进去。
4. 避坑排查:登录失败、花屏、内存泄漏这三座大山
4.1 登录返回 1 或 2:网络通但认证不过
现象:NET_DVR_Login_V40返回 -1,NET_DVR_GetLastError拿到 1 或 2。原因:错误码 1 是用户名密码错,2 是权限不够。但很多时候密码是对的,问题出在设备端开了“锁定”或者 SDK 版本和设备固件不匹配。解决:先用ping确认网络通,再用海康的 SADP 工具确认设备端口是 8000 不是 80。如果设备固件是较新版本,换用最新版设备网络 SDK 重新编译。
4.2 画面花屏或绿屏:解码器没吃全 SPS/PPS
现象:能出画面但满屏马赛克,或者一半绿一半正常。原因:H264 的 SPS/PPS 在 SYSHEAD 里,如果只把 STREAMDATA 送解码器,解码器不知道分辨率。解决:在回调里把NET_DVR_SYSHEAD的数据也存到一个 buffer,每次解码前先送 SPS/PPS。或者直接用NET_DVR_SetStandardDataCallBack拿标准流。
4.3 程序跑几小时就崩:回调里直接操作 UI
现象:运行一段时间后段错误,gdb 回溯显示在QWidget::update附近。原因:SDK 回调线程直接调了 QT 的 UI 函数,QT 要求 UI 操作必须在主线程。解决:回调里只做数据拷贝和信号发射,用Qt::QueuedConnection连到主线程槽。如果数据量大,加一个环形缓冲队列,主线程定时取。
4.4 退出时卡死:NET_DVR_Cleanup 没调或调早了
现象:点关闭按钮后进程不退出,或者退出时报double free。原因:NET_DVR_Cleanup必须在所有NET_DVR_Logout和NET_DVR_StopRealPlay之后调用,且只能调一次。解决:在QMainWindow的closeEvent里按顺序:先NET_DVR_StopRealPlay,再NET_DVR_Logout,最后NET_DVR_Cleanup。如果用了多线程,确保所有线程都退出了再 cleanup。
4.5 编译报错cannot find -lhcnetsdk:库路径没对
现象:链接阶段报cannot find -lhcnetsdk。原因:LIBS里的-L路径不对,或者库文件名不是libhcnetsdk.so而是libhcnetsdk.so.1。解决:ls lib/看实际文件名,如果是带版本号的,要么建软链ln -s libhcnetsdk.so.1 libhcnetsdk.so,要么在 pro 里直接写全名LIBS += $$PWD/lib/libhcnetsdk.so。
5. 进阶:把 demo 改成多路预览与录像回放
5.1 多路预览的句柄数组与布局
单路跑通后,多路就是循环登录和取流。但注意,海康 SDK 对同时取流的路数有限制,一般 64 路以内没问题,但 QT 界面刷新要控制帧率。
// 多路登录 QVector<LONG> userIDs; for (int i = 0; i < 4; i++) { NET_DVR_USER_LOGIN_INFO info = {0}; // 填不同 IP LONG id = NET_DVR_Login_V40(&info, &devInfo); userIDs.append(id); } // 多路取流 QVector<LONG> playHandles; for (LONG id : userIDs) { NET_DVR_PREVIEWINFO pv = {0}; pv.lChannel = 1; pv.dwStreamType = 1; // 子码流,降低带宽 LONG h = NET_DVR_RealPlay_V40(id, &pv, RealDataCallBack, this); playHandles.append(h); }逻辑说明:userIDs和playHandles要一一对应,退出时先遍历playHandles调NET_DVR_StopRealPlay,再遍历userIDs调NET_DVR_Logout。dwStreamType设 1 用子码流,4 路 1080p 主码流对 CPU 解码压力很大,子码流 D1 分辨率足够预览。
5.2 录像回放:按时间取流
回放和实时预览类似,但用NET_DVR_PlayBackByTime_V40。
NET_DVR_VOD_PARA vodPara = {0}; vodPara.struIDInfo.dwChannel = 1; vodPara.struBeginTime.dwYear = 2025; vodPara.struBeginTime.dwMonth = 1; vodPara.struBeginTime.dwDay = 1; vodPara.struBeginTime.dwHour = 0; vodPara.struBeginTime.dwMinute = 0; vodPara.struBeginTime.dwSecond = 0; vodPara.struEndTime = vodPara.struBeginTime; vodPara.struEndTime.dwHour = 1; // 回放一小时 LONG lPlayBackHandle = NET_DVR_PlayBackByTime_V40(lUserID, &vodPara); NET_DVR_PlayBackControl_V40(lPlayBackHandle, NET_DVR_PLAYSTART, nullptr, 0, nullptr, nullptr);逻辑说明:struBeginTime和struEndTime是回放时间段,dwChannel是通道号。NET_DVR_PlayBackControl_V40的NET_DVR_PLAYSTART是开始播放,还有NET_DVR_PLAYPAUSE、NET_DVR_PLAYRESTART等控制命令。回放的数据回调也是RealDataCallBack那套,但数据类型里会多出NET_DVR_PLAYBACK_HEAD之类的标记,解码前要判断。
5.3 验证方法:用 gdb 和 valgrind 盯内存
改完多路后,别急着上生产。我一般会跑valgrind --leak-check=full ./qt_hik_demo看有没有泄漏,再用gdbattach 上去看线程状态。
# 内存泄漏检查 valgrind --leak-check=full --show-leak-kinds=all ./qt_hik_demo 2>&1 | tee valgrind.log # 查看线程 gdb -p $(pidof qt_hik_demo) (gdb) info threads (gdb) thread apply all bt逻辑说明:valgrind会报告definitely lost和indirectly lost,如果libhcnetsdk.so内部有泄漏,那是 SDK 自己的问题,你只能确保自己 new 的对象都 delete 了。gdb的info threads看有没有线程卡在pthread_cond_wait上,如果有,多半是回调线程没退出。
5.4 一个我踩过的坑:SDK 日志把磁盘写满
海康 SDK 默认会写日志到./HCNetSDKLog或者/tmp下,跑几天能把分区写满。我一般会在NET_DVR_Init之后立刻调NET_DVR_SetLogToFile(3, "./sdklog", true)把日志级别降到只写错误,或者干脆关掉。
// 设置日志级别:0-不写,1-写错误,2-写调试,3-写全部 NET_DVR_SetLogToFile(1, "./sdklog", false);逻辑说明:第一个参数是级别,第二个是目录,第三个是是否按天切分。设成 1 只写错误,能大幅减少磁盘占用。如果调试阶段要看详细日志,设成 3,但记得定期清理。
从那以后我每次拿到新的 SDK demo,第一件事就是先改日志路径和级别,再跑ldd确认依赖,最后才编译。这套流程走下来,基本能避开八成以上的环境问题。希望帮到你。
本文还有配套的精品资源,点击获取