特别说明:个人笔记,不惜勿喷。
Qt获取海康摄像头图像方法很多,比如可以只用RTSP的方式直接拉流获取。但是RTSP拉流的方式我也尝试过,需要用到FFMPEG,由于这个库东西比较多,而且里面很多流程需要自己去做解析,程序员本就是图方便和高效,与其去折腾,还不如直接用官方提供的SDK。这样省很多事情。
海康SDK开发心得:在预览图像的时候图像时延是非常低的,相比ffmpeg的rtsp要低很多,因此如果项目对于时延要去高的地方可以考虑用sdk来试试。
于是乎,自己研究了下,发现比较简单,此处仅作笔记,无技术含量。
1、首先工程文件添加海康SDK的库和头文件
- LIBS += -L$$PWD/hiklib/lib/ -lHCNetSDK
- INCLUDEPATH += $$PWD/hiklib/include
- DEPENDPATH += $$PWD/hiklib/include
2、登录摄像头
- NET_DVR_Init();
- NET_DVR_SetConnectTime(2000, 1);
- NET_DVR_SetReconnect(10000, true);
-
- NET_DVR_USER_LOGIN_INFO struLoginInfo;
- NET_DVR_DEVICEINFO_V40 struDeviceInfoV40;
- memset(&struLoginInfo, 0x00, sizeof(NET_DVR_USER_LOGIN_INFO));
- memset(&struDeviceInfoV40, 0x00, sizeof(NET_DVR_DEVICEINFO_V40));
-
- struLoginInfo.bUseAsynLogin = 0; // 同步登录方式
- strcpy(struLoginInfo.sDeviceAddress, "192.168.0.143"); // 设备IP地址
- struLoginInfo.wPort = 8000 ; // 设备服务端口
- strcpy_s(struLoginInfo.sUserName, "admin"); // 设备登录用户名
- strcpy_s(struLoginInfo.sPassword, "123456"); // 设备登录密码
-
- m_userId = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
- if (m_userId < 0)
- {
- qDebug() << "登录失败" << m_userId << NET_DVR_GetErrorMsg();
- }
3、登录成功后就可以直接启动图像预览了。
- NET_DVR_PREVIEWINFO struPreviewInfo;
- memset(&struPreviewInfo, 0x00, sizeof(NET_DVR_PREVIEWINFO));
- struPreviewInfo.lChannel = 1; // 通道id
- struPreviewInfo.hPlayWnd = (HWND)ui->labelPreview->winId();
- struPreviewInfo.dwStreamType = 0; // 码流类型: 0-主码流
- struPreviewInfo.dwLinkMode = 0; // 链接方式: 0- TCP方式
- struPreviewInfo.bBlocked = 0; // 0 - 非阻塞取流,1 - 阻塞取流
-
- m_previewHandle = NET_DVR_RealPlay_V40(m_userId, &struPreviewInfo, NULL, NULL);
4、云台控制
- #define START 0
- #define STOP 1
- NET_DVR_PTZControl(m_previewHandle, TILT_UP, START);
- NET_DVR_PTZControl(m_previewHandle, TILT_UP, STOP);
- /* 下 */
- NET_DVR_PTZControl(m_previewHandle, TILT_DOWN, START);
- NET_DVR_PTZControl(m_previewHandle, TILT_DOWN, STOP);
- /* 其他方向可以自行查看头文件,方法一样 */
5、辅助功能:网络摄像头局域网扫描通信协议,方便在不知道摄像头ip的情况下进行
通过UDP报文广播的方式扫描在线摄像头
- QString strData = QString("<?xml version=\"1.0\" encoding=\"utf-8\"?><Probe><Uuid>");
- m_strUuid = QUuid::createUuid().toString(QUuid::WithoutBraces).toUpper();
- strData += m_strUuid;
- strData += "</Uuid><Types>inquiry</Types></Probe>";
-
- qint64 len = m_udpSocket->writeDatagram(strData.toLatin1(), QHostAddress("239.255.255.250"), 37020);
- qDebug() << "==>" << len << strData;
协议解析:
- void ScanIPCameras::sltUdpSocketRead()
- {
- QByteArray byData;
- // qDebug() << "udp recv" << m_udpSocket->pendingDatagramSize();
- while (m_udpSocket->hasPendingDatagrams()) {
- #if (QT_VERSION > QT_VERSION_CHECK(5, 8, 0))
- QNetworkDatagram datagram = m_udpSocket->receiveDatagram();
- QHostAddress host = datagram.senderAddress();
- byData += datagram.data();
- #else
- QByteArray datagram;
- datagram.resize(m_udpSocket->pendingDatagramSize());
- m_udpSocket->readDatagram(datagram.data(), datagram.size());
- byData += datagram;
- #endif
- }
- parseXmlData(byData);
- }
解析如下:
- void ScanIPCameras::parseXmlData(const QByteArray &_byContent)
- {
- QDomDocument document;
- QString error;
- int row = 0, column = 0;
- if (!document.setContent(_byContent, false, &error, &row, &column))
- {
- return;
- }
-
- if (document.isNull())
- {
- return;
- }
-
- QDomElement root = document.documentElement();
- for(QDomNode node = root.firstChild(); !node.isNull(); node = node.nextSibling())
- {
- QDomElement e = node.toElement();
- QString tag = node.nodeName();
- QString value = e.text();
- if ("Uuid" == tag) {
- qDebug() << "value" << value;
- qDebug() << "Uuid " << m_strUuid;
- m_strUuid = value;
- }
- else if ("DeviceDescription" == tag) {
-
- }
- else if ("IPv4Address" == tag) {
- emit signalCamera(value);
- emit signalNotify(QString("摄像头扫描: 扫描完成,发现设备[%1]!~").arg(value));
- }
- else if ("CommandPort" == tag) {
-
- }
- else if ("HttpPort" == tag) {
-
- }
- else if ("DHCP" == tag) {
-
- }
- else if ("DeviceSN" == tag) {
-
- }
- else {
- qDebug() << tag << value;
- }
- }
- }
效果图:
