1 Windows 注意DLL存放路径
1. 更新设备网络SDK时,SDK开发包【库文件】里的HCNetSDK.dll、HCCore.dll、HCNetSDKCom文件夹、PlayCtrl.dll、SuperRender.dll、AudioRender.dll、ssleay32.dll、libeay32.dll等文件均要加载到程序里面,【HCNetSDKCom文件夹】(包含里面的功能组件dll库文件)需要和HCNetSDK.dll、HCCore.dll一起加载,放在同一个目录下,且HCNetSDKCom文件夹名不能修改。
2. 如果自行开发软件不能正常实现相应功能,而且程序没有指定加载的dll库路径,请在程序运行的情况下尝试删除HCNetSDK.dll。如果可以删除,说明程序可能调用到系统盘Windows->System32目录下的dll文件,建议删除或者更新该目录下的相关dll文件;如果不能删除,dll文件右键选择属性确认SDK库版本。
3. 如按上述步骤操作后还是不能实现相应功能,请根据NET_DVR_GetLastError返回的错误号判断原因。
2 头文件冲突error C2059: 语法错误:“常量”
场景
添加海康,宇视SDK对接的头文件和库文件,编译出错提示error C2059: 语法错误:“常量”。显示宇视SDK头文件NetDEVSDK.h中宏定义异常
typedef enum tagNETDEV_PASSIVEDECODE_CMD
{
PASSIVE_DEC_PAUSE = 1, /* 被动解码暂停(仅文件流有效) */
PASSIVE_DEC_RESUME = 2, /* 恢复被动解码(仅文件流有效) */
PASSIVE_DEC_FAST = 3, /* 快速被动解码(仅文件流有效) */
PASSIVE_DEC_SLOW = 4, /* 慢速被动解码(仅文件流有效) */
PASSIVE_DEC_NORMAL = 5, /* 正常被动解码(仅文件流有效) */
PASSIVE_DEC_ONEBYONE = 6, /* 被动解码单帧播放(保留) */
PASSIVE_DEC_AUDIO_ON = 7, /* 音频开启 */
PASSIVE_DEC_AUDIO_OFF = 8, /* 音频关闭 */
PASSIVE_DEC_RESETBUFFER = 9 /* 清空缓冲区 */
}NETDEV_PASSIVEDECODE_CMD_E;
NetDEVSDK.h(5082): error C2059: 语法错误:“常量”
NetDEVSDK.h(5091): error C2143: 语法错误: 缺少“;”(在“}”的前面)
鼠标放在PASSIVE_DEC_PAUSE,看到错误提示:#define PASSIVE_DEC_PAUSE 1
排查过程
在Notepad++对整个工程目录进行宏定义搜索PASSIVE_DEC_PAUSE,发现在海康的头文件中已有定义HCNetSDK.h
#define PASSIVE_DEC_PAUSE 1 /*被动解码暂停(仅文件流有效)*/
#define PASSIVE_DEC_RESUME 2 /*恢复被动解码(仅文件流有效)*/
#define PASSIVE_DEC_FAST 3 /*快速被动解码(仅文件流有效)*/
#define PASSIVE_DEC_SLOW 4 /*慢速被动解码(仅文件流有效)*/
#define PASSIVE_DEC_NORMAL 5 /*正常被动解码(仅文件流有效)*/
#define PASSIVE_DEC_ONEBYONE 6 /*被动解码单帧播放(保留)*/
#define PASSIVE_DEC_AUDIO_ON 7 /*音频开启*/
#define PASSIVE_DEC_AUDIO_OFF 8 /*音频关闭*/
#define PASSIVE_DEC_RESETBUFFER 9 /*清空缓冲区*/
所以才会出现上面的提示错误
解决方案
在宇视SDK头文件中没有搜索到NETDEV_PASSIVEDECODE_CMD_E宏定义的使用,因此,直接注释掉整个宏定义解决问题
3 透传方式转台状态获取
(1)操作类型:GET
(2)命令字符串:
/ISAPI/DisplayDev/Video/inputs/config/0/0/devNo
其中devNo表示设备号,编码板一个485接4个转台,所以设备号从1~4
比如想要获取转台1的状态,则下发命令字符串:
/ISAPI/DisplayDev/Video/inputs/config/0/0/1
(3)代码
NET_DVR_XML_CONFIG_INPUT struInput = { 0 };
NET_DVR_XML_CONFIG_OUTPUT struOuput = { 0 };
struInput.dwSize = sizeof(struInput);
struOuput.dwSize = sizeof(struOuput);
char szUrl[256] = { 0 };
sprintf(szUrl, "GET /ISAPI/DisplayDev/Video/inputs/config/0/0/%d", chan->chan_no);
DWORD dwBufferLen = 1024 * 1024;
char *pBuffer = new char[dwBufferLen];
memset(pBuffer, 0, dwBufferLen);
struInput.lpRequestUrl = szUrl;
struInput.dwRequestUrlLen = strlen(szUrl);
struInput.dwRecvTimeOut = 5000;
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
bool bSuccess = false;
if (!NET_DVR_STDXMLConfig(m_nLoginId, &struInput, &struOuput))
{
bSuccess = false;
auto lec = NET_DVR_GetLastError();
LONG * no = (LONG *)&lec;
}
else
{
bSuccess = true;
LOGE(pBuffer);
std::string strXML(pBuffer, struOuput.dwReturnedXMLSize);
int nPanStartPos = strXML.find("<panRange>", 0);
int nPanEndPos = strXML.find("</panRange>", 0);
std::string strPanPos = strXML.substr(nPanStartPos + 10, nPanEndPos - nPanStartPos - 10);
int nTiltStartPos = strXML.find("<tiltRange>", 0);
int nTileEndPos = strXML.find("</tiltRange>", 0);
std::string strTiltPos = strXML.substr(nTiltStartPos + 11, nTileEndPos - nTiltStartPos - 11);
int nZoomStartPos = strXML.find("<visibFocul>", 0);
int nZoomEndPos = strXML.find("</visibFocul>", 0);
std::string strZoomPos = strXML.substr(nZoomStartPos + 12, nZoomEndPos - nZoomStartPos - 12);
float fPanPosValue = atof(strPanPos.c_str()) / 100;
float fTiltPosValue = -atof(strTiltPos.c_str()) / 100;
float fZoomValue = 0.0;
if (chan->focus_instance < 1)
{
fZoomValue = atof(strZoomPos.c_str()) / 100 / 12.5;
}
else
{
fZoomValue = atof(strZoomPos.c_str()) / 100 / chan->focus_instance;
}
}
问题1)查询是阻塞的,无法异步,多线程无效
问题2)延时严重,并且查询过程中无法调用其他的函数
4 透传方式转动云台设置
(1)操作类型:PUT
(2)命令字符串:
/ISAPI/DisplayDev/Video/inputs/setptz
(3)输入参数:json格式的参数,如下所示
{"devNo":1, "pan":1000, "tilt":100, "zoom": 100}
devNo:设备号
pan:水平位置值
tilt:垂直位置值
zoom:zoom位置值
(4)代码
NET_DVR_XML_CONFIG_INPUT struInput = { 0 };
NET_DVR_XML_CONFIG_OUTPUT struOuput = { 0 };
struInput.dwSize = sizeof(struInput);
struOuput.dwSize = sizeof(struOuput);
char szUrl[256] = { 0 };
sprintf(szUrl, "PUT /ISAPI/DisplayDev/Video/inputs/setptz");
int nPanPos = dPanPos * 100;
int nTiltPos = 0;
if (dNewTiltPos > 0)
{
nTiltPos = dNewTiltPos * 100;
}
else
{
nTiltPos = (dNewTiltPos + 360) * 100;
}
int nZoomPos = dZoomPos / 60 * 65536;
{
DWORD dwInBufferLen = 1024 * 1024;
char *pInBuffer = new char[dwInBufferLen];
memset(pInBuffer, 0, dwInBufferLen);
sprintf(pInBuffer, "{\"devNo\":%d,\"zoom\":%d}", chan_no, nZoomPos);
{
char log[1024] = { 0 };
sprintf_s(log, "SetPTZPos:%s", pInBuffer);
LOG_E(log);
}
DWORD dwBufferLen = 1024 * 1024;
char *pBuffer = new char[dwBufferLen];
memset(pBuffer, 0, dwBufferLen);
struInput.lpRequestUrl = szUrl;
struInput.dwRequestUrlLen = strlen(szUrl);
struInput.dwRecvTimeOut = 5000;
struInput.lpInBuffer = pInBuffer;
struInput.dwInBufferSize = strlen(pInBuffer);
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
bool bSuccess = false;
if (!NET_DVR_STDXMLConfig(m_login_id, &struInput, &struOuput))
{
auto lec = NET_DVR_GetLastError();
LONG * no = (LONG *)&lec;
}
else
{
bSuccess = true;
}
}
::Sleep(2000);
{
DWORD dwInBufferLen = 1024 * 1024;
char *pInBuffer = new char[dwInBufferLen];
memset(pInBuffer, 0, dwInBufferLen);
sprintf(pInBuffer, "{\"devNo\":%d,\"pan\":%d}", chan_no, nPanPos);
{
char log[1024] = { 0 };
sprintf_s(log, "SetPTZPos:%s", pInBuffer);
LOG_E(log);
}
DWORD dwBufferLen = 1024 * 1024;
char *pBuffer = new char[dwBufferLen];
memset(pBuffer, 0, dwBufferLen);
struInput.lpRequestUrl = szUrl;
struInput.dwRequestUrlLen = strlen(szUrl);
struInput.dwRecvTimeOut = 5000;
struInput.lpInBuffer = pInBuffer;
struInput.dwInBufferSize = strlen(pInBuffer);
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
bool bSuccess = false;
if (!NET_DVR_STDXMLConfig(m_login_id, &struInput, &struOuput))
{
auto lec = NET_DVR_GetLastError();
LONG * no = (LONG *)&lec;
}
else
{
bSuccess = true;
}
}
::Sleep(2000);
{
DWORD dwInBufferLen = 1024 * 1024;
char *pInBuffer = new char[dwInBufferLen];
memset(pInBuffer, 0, dwInBufferLen);
sprintf(pInBuffer, "{\"devNo\":%d,\"tilt\":%d}", chan_no, nTiltPos);
{
char log[1024] = { 0 };
sprintf_s(log, "SetPTZPos:%s", pInBuffer);
LOG_E(log);
}
DWORD dwBufferLen = 1024 * 1024;
char *pBuffer = new char[dwBufferLen];
memset(pBuffer, 0, dwBufferLen);
struInput.lpRequestUrl = szUrl;
struInput.dwRequestUrlLen = strlen(szUrl);
struInput.dwRecvTimeOut = 5000;
struInput.lpInBuffer = pInBuffer;
struInput.dwInBufferSize = strlen(pInBuffer);
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
struOuput.lpOutBuffer = pBuffer;
struOuput.dwOutBufferSize = dwBufferLen;
bool bSuccess = false;
if (!NET_DVR_STDXMLConfig(m_login_id, &struInput, &struOuput))
{
auto lec = NET_DVR_GetLastError();
LONG * no = (LONG *)&lec;
}
else
{
bSuccess = true;
}
}
问题1)PTZ设置需要分三次,并且中间需要加延时,否则会造成上一次操作未完成的中断
5 函数NET_DVR_GetLastError的使用
场景
同事发现新拉SVN版本分支调用海康SDK,无法实现功能。
排查过程
调用接口NET_DVR_GetLastError,返回错误码113
调用接口NET_DVR_GetErrorMsg,返回错误信息Failed to load the HCGeneralCfgMgr
通过load就可以知道是加载DLL出现的问题,查看可执行程序目录文件下并没有HCGeneralCfgMgr.dll 定位问题
错误码记录
NET_DVR_DVROPRATEFAILED | 29 | 设备操作失败。 |
当前摄像机在线用户超过了28个,其他海康设备取流正常,可能是在线用户点播过多,导致登陆失败
6 全景取流失败
目前在内蒙古现场,发现海康鹰眼全景取流失败,通过修改码流格式(原来是H265)为H264解决问题,暂时不清楚是哪里引起,其他现场也有H265格式的,都没有问题
7 获取NVR通道的音频类型
#include "HCNetSDK.h"
int GetHaiKangNVRAudioType()
{
// 初始化海康威视 SDK
NET_DVR_Init();
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
// 登录设备
LONG user_id = NET_DVR_Login_V30("192.168.12.39", 8000, "admin", "admin123456", NULL);
if (user_id < 0) {
cerr << "Error: Failed to login the device." << endl;
NET_DVR_Cleanup();
return -1;
}
// 获取通道信息
NET_DVR_IPPARACFG_V40 ip_para_cfg = { 0 };
DWORD bytes_returned = 0;
if (!NET_DVR_GetDVRConfig(user_id, NET_DVR_GET_IPPARACFG_V40, 0, &ip_para_cfg, sizeof(ip_para_cfg), &bytes_returned)) {
cerr << "Error: Failed to get channel configuration." << endl;
NET_DVR_Logout(user_id);
NET_DVR_Cleanup();
return -1;
}
// 获取通道信息
int channel_no = 44;
LPNET_DVR_COMPRESSIONCFG_V30 compress_cfg = new NET_DVR_COMPRESSIONCFG_V30;
//DWORD bytes_returned = 0;
if (!NET_DVR_GetDVRConfig(user_id, NET_DVR_GET_COMPRESSCFG_V30, channel_no, compress_cfg, sizeof(NET_DVR_COMPRESSIONCFG_V30), &bytes_returned)) {
cerr << "Error: Failed to get channel configuration." << endl;
NET_DVR_Logout(user_id);
NET_DVR_Cleanup();
return -1;
}
//音频编码类型 0-G722;1-G711_U;2-G711_A;5-MP2L2;6-G276;7-AAC;8-PCM;0xff-无效
//byAudioSamplingRate;//音频采样率0-默认,1- 16kHZ, 2-32kHZ, 3-48kHZ, 4- 44.1kHZ,5-8kHZ
//main是主码流 sub是子码流
BYTE byMainAudioType = compress_cfg->struNormHighRecordPara.byAudioEncType;
BYTE byMainAudioSamplingRate = compress_cfg->struNormHighRecordPara.byAudioSamplingRate;
BYTE bySubAudioType = compress_cfg->struNetPara.byAudioEncType;
BYTE bySubAudioSamplingRate = compress_cfg->struNetPara.byAudioSamplingRate;
// 注销用户并清理海康威视 SDK
NET_DVR_Logout(user_id);
NET_DVR_Cleanup();
return 0;
}
备注
1)无法获取音频采样率,返回值都是0
2)NVR的通道从33开始
8 海康ClientDemo工程编译错误
1错误 C4839 将类 "CFileException" 作为可变参数函数的参数的非标准用法
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2280 “CFileException::CFileException(const CFileException &)”: 尝试引用已删除的函数 (编译源文件 DlgScreenLogoCfg.cpp)
错误 C4839 将类 "CFileException" 作为可变参数函数的参数的非标准用法 (编译源文件 DlgScreenLogoCfg.cpp)
错误 C4839 将类 "CFileException" 作为可变参数函数的参数的非标准用法 (编译源文件 DlgScreenLogoCfgUniform.cpp)
错误 C2280 “CFileException::CFileException(const CFileException &)”: 尝试引用已删除的函数 (编译源文件 DlgScreenLogoCfgUniform.cpp)
解决方案
将代码
csStr.Format("File Open failed , err = %d\n", fileException);
修改为
csStr.Format("File Open failed , err = %d\n", fileException.m_cause);
修改原理
m_cause包含由 CFileException 枚举类型定义的值。
注解
此数据成员是类型 int
的公共变量。 枚举器及其含义如下所示:
错误 | 值和含义 |
| 0:未发生任何错误。 |
| 1:发生了未指定的错误。 |
| 2::无法找到该文件。 |
| 3:全部或部分路径无效。 |
| 4:已超出允许打开的文件数。 |
| 5:无法访问该文件。 |
| 6:已尝试使用无效的文件句柄。 |
| 7:无法删除当前工作目录。 |
| 8:没有更多的目录项。 |
| 9:已在尝试设置文件指针时出错。 |
| 10:出现了硬件错误。 |
| 11:未加载 |
| 12:已尝试锁定已经锁定的区域。 |
| 13:磁盘已满。 |
| 14:已到达文件末尾。 |
2 error D8016 :/ZI”和“/Gy-”命令行选项不兼容
解决方案
"C/C++"->“代码生成”->“启用函数集链接”->选择“是 (/Gy)”
3 C3690 应该为字符串文本,但找到的是用户定义的字符串文本
解决方案
DecodeCardSdk.h文件
将
#define DLLEXPORT_API extern "C"__declspec(dllexport)
修改为
#define DLLEXPORT_API extern "C" __declspec(dllexport)
9海康ClientDemo工程单步调试
场景
下载CH-HCNetSDKV6.0.2.35_build20190411_Win32版本SDK,进入Demo示例,选择1- MFC综合示例工程,通过VS2017打开工程,编译运行,无法单步调试,出错提示:当前不会命中断点 还没有为该文档加载任何符号。目前通过void CClientDemoDlg::AddLog(int iDeviceIndex, int iLogType, const char* format, ...)该函数接口,将日志输出到指定的文件
解决方案
调试模式 当前不会命中断点 解决方案_宁静致远的技术博客_51CTO博客
尝试方案
1)工程属性/C/C++/优化:已禁用
2)工具——选项——调试——常规中的“要求源文件和原始版本完全匹配”的勾去掉
3)检查设置断点的模块在调试时有没有输出。调试时遇到最多的警告“当前不会命中断点 还没有为该文档加载任何符号 ”。原因是我们设置断点的代码块并没有编译输出。找到程序的生成目录,通常是在bin文件夹下,删除设置断点代码文件对应的dll文件或exe文件。重新调试项目