#include <ros/ros.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <iomanip>
#include <opencv2/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include "std_msgs/Int32.h"
#include <vector>
#include <std_msgs/String.h>
#include "dhnetsdk.h"
#include "dhconfigsdk.h"
#include <stdio.h>
using namespace cv;
using namespace std;
static BOOL g_bNetSDKInitFlag = FALSE;
static LLONG g_lLoginHandle = 0L;
//static char g_szDevIp[32] = "";
static char g_szDevIp[32] = "192.168.1.4";
static WORD g_nPort = 37777; // tcp 连接端口,需与期望登录设备页面 tcp 端口配置一致
static char g_szUserName[64] = "admin";
static char g_szPasswd[64] = "111111111";
static short g_nCmdSerial = 0; // 抓图序列号
//*********************************************************************************
// 常用回调集合声明
// 设备断线回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK 会调用该函数。
void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser);
//void CALL_METHOD Disconnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
//{
// cout << "Receive disconnect message, where ip:" << pchDVRIP << " and port:"
// << nDVRPort << " and login handle:" << lLoginID << endl;
//}
// 断线重连成功回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK 会调用该函数。
void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser);
// 抓图回调函数
// 不建议在该回调函数中调用 SDK 接口
// 通过 CLIENT_SetSnapRevCallBack 设置该回调函数,当前端设备有抓图数据发送过来时,SDK 会调用该函数
void CALLBACK SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser);
//*********************************************************************************
// 常用函数声明
// 获取输入的整形
int GetIntInput(char *szPromt, int& nError);
// 获取输入的字符串
void GetStringInput(const char *szPromt , char *szBuffer);
//*********************************************************************************
void InitTest()
{
// 初始化 SDK
g_bNetSDKInitFlag = CLIENT_Init((fDisConnect)DisConnectFunc, (LDWORD)0);
//g_bNetSDKInitFlag =CLIENT_Init(Disconnect, NULL);
if (FALSE == g_bNetSDKInitFlag)
{
printf("Initialize client SDK fail; \n");
return;
}
else
{
printf("Initialize client SDK done; \n");
}
// 获取 SDK 版本信息
// 此操作为可选操作
DWORD dwNetSdkVersion = CLIENT_GetSDKVersion();
printf("NetSDK version is [%d]\n", dwNetSdkVersion);
// 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作
// 此操作为可选操作,但建议用户进行设置
CLIENT_SetAutoReconnect(&HaveReConnect, 0);
// 设置登录超时时间和尝试次数
// 此操作为可选操作
int nWaitTime = 5000;
// 登录请求响应超时时间设置为 5s
int nTryTimes = 3;
// 登录时尝试建立链接 3 次
CLIENT_SetConnectTime(nWaitTime, nTryTimes);
// 设 置 更 多 网 络 参 数 , NET_PARAM 的 nWaittime , nConnectTryNum 成 员 与CLIENT_SetConnectTime 接口设置的登录设备超时时间和尝试次数意义相同
// 此操作为可选操作
NET_PARAM stuNetParm = {0};
stuNetParm.nConnectTime = 3000; // 登录时尝试建立链接的超时时间
CLIENT_SetNetworkParam(&stuNetParm);
NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stInparam;
NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;
memset(&stInparam, 0, sizeof(stInparam));
stInparam.dwSize = sizeof(stInparam);
strncpy(stInparam.szIP, g_szDevIp, sizeof(stInparam.szIP) - 1);
strncpy(stInparam.szPassword, g_szPasswd, sizeof(stInparam.szPassword) - 1);
strncpy(stInparam.szUserName, g_szUserName, sizeof(stInparam.szUserName) - 1);
stInparam.nPort = g_nPort;
stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;
//while(0 == g_lLoginHandle)
//{
// 登录设备
g_lLoginHandle = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
if(0 == g_lLoginHandle)
{
// 根据错误码,可以在 dhnetsdk.h 中找到相应的解释,此处打印的是 16 进制,头文件中是十进制,其中的转换需注意
// 例如:
// #define NET_NOT_SUPPORTED_EC(23) // 当前 SDK 未支持该功能,对应的错误码为 0x80000017, 23 对应的 16 进制为 0x17
printf("CLIENT_LoginWithHighLevelSecurity %s[%d]Failed!Last Error[%x]\n" ,g_szDevIp , g_nPort , CLIENT_GetLastError());
}
else
{
printf("CLIENT_LoginWithHighLevelSecurity %s[%d] Success\n" , g_szDevIp ,g_nPort);
}
// 用户初次登录设备,需要初始化一些数据才能正常实现业务功能,建议登录后等待一小段时间,具体等待时间因设备而异。
usleep(1*1000);
printf("\n");
//}
}
void RunTest()
{
if (FALSE == g_bNetSDKInitFlag)
{
return;
}
if (0 == g_lLoginHandle)
{
return;
}
// 设置抓图回调函数
CLIENT_SetSnapRevCallBack(SnapRev, NULL);
char szUserChoose[1];
do
{
//事例中默认通道 ID 为 0、抓图模式为抓一幅图,用户可根据实际情况自行选择
int nChannelId = 0;
int nSnapType = 0;// 抓图模式;-1:表示停止抓图, 0:表示请求一帧, 1:表示定时发送请求, 2:表示连续请求
// 发送抓图命令给前端设备
SNAP_PARAMS stuSnapParams;
stuSnapParams.Channel = nChannelId;
stuSnapParams.mode = nSnapType;
stuSnapParams.CmdSerial = ++g_nCmdSerial; // 请求序列号,有效值范围 0~65535,超过范围会被截断为 unsigned short
if (FALSE == CLIENT_SnapPictureEx(g_lLoginHandle, &stuSnapParams))
{
printf("CLIENT_SnapPictureExFailed!LastError[%x]\n", CLIENT_GetLastError());
return;
}
else
{
printf("CLIENT_SnapPictureEx succ\n");
}
GetStringInput("'q': 退出; 'c': 继续\n", szUserChoose);
}while('q' != szUserChoose[0]);
return;
}
void EndTest()
{
printf("input any key to quit!\n");
getchar();
// 退出设备
if (0 != g_lLoginHandle)
{
if(FALSE == CLIENT_Logout(g_lLoginHandle))
{
printf("CLIENT_Logout Failed!Last Error[%x]\n", CLIENT_GetLastError());
}
else
{
g_lLoginHandle = 0;
}
}
// 清理初始化资源
if (TRUE == g_bNetSDKInitFlag)
{
CLIENT_Cleanup();
g_bNetSDKInitFlag = FALSE;
}
exit(0);
}
//*********************************************************************************
// 常用回调集合定义
void CALL_METHOD DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser)
{
printf("Call DisConnectFunc\n");
printf("lLoginID[0x%x]", lLoginID);
if (NULL != pchDVRIP)
{
printf("pchDVRIP[%s]\n", pchDVRIP);
}
printf("nDVRPort[%d]\n", nDVRPort);
printf("dwUser[%p]\n", dwUser);
printf("\n");
}
void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
{
printf("Call HaveReConnect\n");
printf("lLoginID[0x%x]", lLoginID);
if (NULL != pchDVRIP)
{
printf("pchDVRIP[%s]\n", pchDVRIP);
}
printf("nDVRPort[%d]\n", nDVRPort);
printf("dwUser[%p]\n", dwUser);
printf("\n");
}
void CALLBACK SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
printf("[SnapRev] -- receive data!\n");
if(lLoginID == g_lLoginHandle)
{
if (NULL != pBuf && RevLen > 0)
{
char szPicturePath[256] = "";
time_t stuTime;
time(&stuTime);
char szTmpTime[128] = "";
strftime(szTmpTime,sizeof(szTmpTime) - 1, "%y%m%d_%H%M%S", gmtime(&stuTime));
snprintf(szPicturePath, sizeof(szPicturePath)-1, "%d_%s.jpg", CmdSerial, szTmpTime);
//保存图片数据方式一(方式一和方式二都可以用,根据需求选择一个即可)
//直接写入文件中并保持
printf("szPicturePath: %s\n", szPicturePath);
FILE* pFile = fopen(szPicturePath, "wb");
if (NULL == pFile)
{
return;
}
int nWrite = 0;
while(nWrite != RevLen)
{
nWrite += fwrite(pBuf + nWrite, 1, RevLen - nWrite, pFile);
}
fclose(pFile);
//保存图片数据方式二(方式一和方式二都可以用,根据需求选择一个即可)
//转换到opencv图片格式并保持图片
Mat hik_image;
std::vector<char> data;
for(int i = 0; i < RevLen; i++)
{
data.push_back(pBuf[i]);
}
hik_image = imdecode(Mat(data),1);
std::string image_name = szPicturePath;
std::string path = "/tmp/dahua" + image_name;
cv::imwrite(path.c_str(), hik_image);
data.clear();
hik_image.release();
}
}
}
//*********************************************************************************
// 常用函数定义
int GetIntInput(char *szPromt, int& nError)
{
long int nGet = 0;
char* pError = NULL;
printf(szPromt);
char szUserInput[32] = "";
gets(szUserInput);
nGet = strtol(szUserInput, &pError, 10);
if ('\0' != *pError)
{
// 入参有误
nError = -1;
}
else
{
nError = 0;
}
return nGet;
}
void GetStringInput(const char *szPromt , char *szBuffer)
{
printf(szPromt);
gets(szBuffer);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "test_carema");
ros::NodeHandle nh;
ros::Rate loop_rate(1.0);
ROS_INFO_STREAM("Hello, ROS!");
InitTest();
RunTest();
EndTest();
ros::MultiThreadedSpinner spinner(0);
spinner.spin();
return 0;
}
结果: