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 的公共变量。 枚举器及其含义如下所示:

错误

值和含义

CFileException::none

0:未发生任何错误。

CFileException::genericException

1:发生了未指定的错误。

CFileException::fileNotFound

2::无法找到该文件。

CFileException::badPath

   3:全部或部分路径无效。

CFileException::tooManyOpenFiles

4:已超出允许打开的文件数。

CFileException::accessDenied

5:无法访问该文件。

CFileException::invalidFile

6:已尝试使用无效的文件句柄。

CFileException::removeCurrentDir

7:无法删除当前工作目录。

CFileException::directoryFull

8:没有更多的目录项。

CFileException::badSeek

9:已在尝试设置文件指针时出错。

CFileException::hardIO

10:出现了硬件错误。

CFileException::sharingViolation

11:未加载 SHARE.EXE,或已锁定共享区域。

CFileException::lockViolation

12:已尝试锁定已经锁定的区域。

CFileException::diskFull

13:磁盘已满。

CFileException::endOfFile

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文件。重新调试项目

对接海康网络摄像机Windows版SDK_海康 SDK


对接海康网络摄像机Windows版SDK_海康 SDK_02