首先要注意的是库必须要更新,在开发的时候,发现5.2的库没有上传人脸库的一个结构体,因此有必要更新库到5.3
其他 我这里是由海康原来的demo,生成一个动态库,然后再由python调用这个动态库实现人脸上传和视频码流返回
,码流返回我采用的是在c++里面传入python的函数,然后将函数全局化,然后在回调函数里面调用python的函数将码流信息通过参数形式返回到python
首先要修改的是makefile,修改之后的makefile如下:
CC = gcc
CXX = g++
CFLAGS = -g
CXXFLAGS = $(CFLAGS)
LIBPATH = ./
LIBS = -Wl,-rpath=./:./HCNetSDKCom -lhcnetsdk
SRC = ./main.cpp
TARGET = ./getpsdata.so
all:
$(CXX) $(OPTI) $(CXXFLAGS) -shared -fPIC $(SRC) -o $(TARGET) -L$(LIBPATH) $(LIBS)
.PHONY: clean
clean:
rm -f $(TARGET)
makefile 主要修改的是生成的目标,以及编译的时候多带了编译共享库的选项
修改后的main文件如下:
/*
* Copyright(C) 2011,Hikvision Digital Technology Co., Ltd
*
* File name��main.cpp
* Discription��demo for muti thread get stream
* Version ��1.0
* Author ��luoyuhua
* Create Date��2011-12-10
* Modification History��
*/
#include
#include
#include
#include
#include "HCNetSDK.h"
#include "iniFile.h"
// ȡ�������Ϣ�������̴߳���
typedef struct tagREAL_PLAY_INFO
{
char szIP[16];
int iUserID;
int iChannel;
}REAL_PLAY_INFO, *LPREAL_PLAY_INFO;
//导入人脸数据条件
FILE *g_pFile = NULL;
typedef void (*Func)(BYTE*);
Func rePyGetData = NULL;
void g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer,DWORD dwBufSize,void* dwUser)
{
//LPREAL_PLAY_INFO pPlayInfo = (LPREAL_PLAY_INFO)dwUser;
//printf("[g_RealDataCallBack_V30]Get data, ip=%s, channel=%d, handle=%d, data size is %d, thread=%d\n",
//pPlayInfo->szIP, pPlayInfo->iChannel, lRealHandle, dwBufSize, pthread_self());
//printf("[g_RealDataCallBack_V30]Get data, handle=%d, data size is %d, thread=%d\n",
//lRealHandle, dwBufSize, pthread_self());
//NET_DVR_SaveRealData(lRealHandle, cFilename);
}
void PsDataCallBack(LONG lRealHandle, DWORD dwDataType,BYTE *pPacketBuffer,DWORD nPacketSize, void* pUser)
{
if (dwDataType == NET_DVR_SYSHEAD)
{
//д��ͷ����
g_pFile = fopen("./record/ps.dat", "wb");
if (g_pFile == NULL)
{
printf("CreateFileHead fail\n");
return;
}
//д��ͷ����
fwrite(pPacketBuffer, sizeof(unsigned char), nPacketSize, g_pFile);
printf("write head len=%d\n", nPacketSize);
}
else
{
if(g_pFile != NULL)
{
fwrite(pPacketBuffer, sizeof(unsigned char), nPacketSize, g_pFile);
printf("write data len=%d\n", nPacketSize);
rePyGetData(pPacketBuffer);
}
}
}
extern "C"{
void GetStream(Func getData)
{
rePyGetData = getData;
printf("GetSteam+++++++++++++++++++++++++++++++++++++++++++\n");
NET_DVR_Init();
NET_DVR_SetLogToFile(3, "./record/");
// �������ļ���ȡ�豸��Ϣ
/*
IniFile ini("Device.ini");
unsigned int dwSize = 0;
char sSection[16] = "DEVICE";
char *sIP = ini.readstring(sSection, "ip", "error", dwSize);
int iPort = ini.readinteger(sSection, "port", 0);
char *sUserName = ini.readstring(sSection, "username", "error", dwSize);
char *sPassword = ini.readstring(sSection, "password", "error", dwSize);
int iChannel = ini.readinteger(sSection, "channel", 0);
*/
NET_DVR_DEVICEINFO_V30 struDeviceInfo;
// printf("登录信息,sIP:%s,iPort:%d,sUserName:%s,sPassword:%s",sIP, iPort, sUserName, sPassword);
int iUserID = NET_DVR_Login_V30("192.168.1.63", 8000, "admin", "guoji123", &struDeviceInfo);
printf("注册返回值:%d!!!\n",iUserID);
if(iUserID >= 0)
{
//NET_DVR_CLIENTINFO ClientInfo = {0};
//ClientInfo.lChannel = iChannel; //channel NO.
//ClientInfo.lLinkMode = 0;
//ClientInfo.sMultiCastIP = NULL;
//int iRealPlayHandle = NET_DVR_RealPlay_V30(iUserID, &ClientInfo, PsDataCallBack, NULL, 0);
NET_DVR_PREVIEWINFO struPreviewInfo = {0};
struPreviewInfo.lChannel =1;
struPreviewInfo.dwStreamType = 0;
struPreviewInfo.dwLinkMode = 0;
struPreviewInfo.bBlocked = 1;
struPreviewInfo.bPassbackRecord = 1;
int iRealPlayHandle = NET_DVR_RealPlay_V40(iUserID, &struPreviewInfo, PsDataCallBack, NULL);
if(iRealPlayHandle >= 0)
{
printf("[GetStream]---RealPlay %s:%d success, \n", "192.168.1.63", 1, NET_DVR_GetLastError());
//int iRet = NET_DVR_SaveRealData(iRealPlayHandle, "./record/realplay.dat");
//NET_DVR_SetStandardDataCallBack(iRealPlayHandle, StandardDataCallBack, 0);
}
else
{
printf("[GetStream]---RealPlay %s:%d failed, error = %d\n", "192.168.1.63", 1, NET_DVR_GetLastError());
}
}
else
{
printf("[GetStream]---Login %s failed, error = %d\n", "192.168.1.63", NET_DVR_GetLastError());
}
while (1){
}
NET_DVR_Cleanup();
}
int UploadFile(char* DeviceIP,int port,char* userName,char* password,char* picPath){
NET_DVR_Init();
NET_DVR_LOCAL_SDK_PATH struLocalPath;
strcpy(struLocalPath.sPath,"/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/HCNetSDKCom");
bool set_path = NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_SDK_PATH,&struLocalPath);
printf("设置组件路径结果:%d\n",set_path);
NET_DVR_SetLogToFile(3, "/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/record/");
NET_DVR_DEVICEINFO_V30 struDeviceInfo;
printf("传进来的参数,IP:%s,端口:%d,用户名:%s,密码:%s,图片路径:%s\n",DeviceIP,port,userName,password,picPath);
int iUserID = NET_DVR_Login_V30(DeviceIP, port, userName, password, &struDeviceInfo);
if (iUserID >=0){
NET_DVR_FACELIB_COND FaceInBuffer = {0};
FaceInBuffer.dwSize = sizeof(FaceInBuffer);
printf("结构体大小:%d\n",FaceInBuffer.dwSize);
strcpy(FaceInBuffer.szFDID,"1");
FaceInBuffer.byCover = 1;
FaceInBuffer.byConcurrent = 0;
int m_lUploadHandle = NET_DVR_UploadFile_V40(iUserID,IMPORT_DATA_TO_FACELIB,&FaceInBuffer,FaceInBuffer.dwSize,NULL,NULL,0);
printf("上传文件:%d\n",m_lUploadHandle);
printf("错误类型:%d\n",NET_DVR_GetLastError());
//读取文件数据
BYTE* pSendAppendData;
BYTE* pSendPicData;
printf("BYTE*定义完成!!\n");
NET_DVR_SEND_PARAM_IN m_struSendParam;
/*
if(NULL!= pSendAppendData){
delete[] pSendAppendData;
pSendAppendData = NULL;
}
if(NULL!= pSendPicData){
delete[] pSendPicData;
pSendPicData = NULL;
}*/
printf("数据类型定义完成!\n");
memset(&m_struSendParam,0,sizeof(m_struSendParam));
printf("内存清零操作完成!!\n");
char szLan[1280]={0};
char szFileName[255];//注,MFC综合实例中给出的长度是MAX_PATH,未找到定义
DWORD dwFileSize = 0;
//读取XML文件
printf("开始读取xml文件!!\n");
strcpy(szFileName,"/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/tmp.xml");
FILE *fp;
if ((fp = fopen(szFileName,"r"))==NULL){
printf("文件打开不成功!\n");
}
fseek(fp,0L,SEEK_END);
dwFileSize = ftell(fp);
printf("XML文件大小:%d\n",dwFileSize);
if (dwFileSize == 0){
printf("XML文件为空!!\n");
}
fseek(fp,0L,SEEK_SET);
pSendAppendData = new BYTE[dwFileSize];
fread(pSendAppendData,sizeof(BYTE),dwFileSize,fp);
m_struSendParam.pSendAppendData = pSendAppendData;
m_struSendParam.dwSendAppendDataLen = dwFileSize;
fclose(fp);
printf("xml文件读取完成,开始读取图片文件!!\n");
//读取图片文件
strcpy(szFileName,picPath);
FILE *picFP;
if ((picFP = fopen(szFileName,"r"))==NULL){
printf("图片打开失败!!\n");
}
fseek(picFP,0L,SEEK_END);
dwFileSize = ftell(picFP);
fseek(picFP,0L,SEEK_SET);
printf("图片文件大小:%d\n",dwFileSize);
if(dwFileSize == 0){
printf("图片文件为空!!\n");
}
pSendPicData = new BYTE[dwFileSize];
fread(pSendPicData,sizeof(BYTE),dwFileSize,picFP);
m_struSendParam.pSendData = pSendPicData;
m_struSendParam.dwSendDataLen = dwFileSize;
m_struSendParam.byPicType = 1;
m_struSendParam.byPicURL = 0;
fclose(picFP);
printf("开始上传图片数据!!!\n");
if(NET_DVR_UploadSend(m_lUploadHandle,&m_struSendParam,NULL)<0){
printf("\n上传失败,错误代号:%d\n",NET_DVR_GetLastError());
return 0;
}
else{
uint pProgress = 0;
while(pProgress < 100){
int iStatus = NET_DVR_GetUploadState(m_lUploadHandle,&pProgress);
if(iStatus == -1){
printf("上传失败,错误号:%d\n",NET_DVR_GetLastError());
usleep(100000);
break;
}
else if(iStatus == 2){
printf("文件正在上传,进度:%d\n",pProgress);
usleep(100000);
}
else if(iStatus == 1){
printf("上传成功!!!!!\n");
usleep(100000);
break;
}
else{
printf("上传失败,状态标志位:%d,错误标志号:%d\n",iStatus,NET_DVR_GetLastError());
break;
}
}
}
NET_DVR_UPLOAD_FILE_RET struFaceData;
BOOL res;
res = NET_DVR_GetUploadResult(m_lUploadHandle,&struFaceData,sizeof(struFaceData));
if(res == true){
printf("上传成功!!!!!!!\n");
NET_DVR_UploadClose(m_lUploadHandle);
}else{
printf("错误!!!\n");
NET_DVR_UploadClose(m_lUploadHandle);
}
}
return 0;
}
}
/*
int main()
{
NET_DVR_Init();
NET_DVR_SetLogToFile(3, "./record/");
GetStream();
char c = 0;
while('q' != c)
{
printf("input 'q' to quit\n");
printf("input: ");
scanf("%c", &c);
}
NET_DVR_Cleanup();
return 0;
}*/
//两个函数都是直接在main.cpp中实现了,但是去掉了原来的main函数
在python中调用的时候,上传人脸库需要先将xml文件写好,xml中的男女信息必须是 male和female,否则
人脸图片将上传不上去
以下是python调用生成的库,实现人脸上传的代码:
####上传人脸信息库 def uploadFace(name = "小红",sex = "female",IDNum = "12345678",DeviceIP = "192.168.1.64",userName = "admin",password = "guoji123", picpath = "/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/tmp.jpg"): f = open("/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/tmp.xml",'w') f.writelines("\'1.0\' encoding=\'UTF-8\'?>\n") f.writelines("\n") f.writelines(" " +name+"\n") f.writelines("" +sex+"\n") f.writelines("ID " +IDNum +"\n") f.writelines("\n") f.close() sDVRIP = bytes(DeviceIP, "ascii") sUserName = bytes(userName, "ascii") sPassword = bytes(password, "ascii") picPath = bytes(picpath,"ascii") h_dll_ = ctypes.cdll.LoadLibrary( "/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/getpsdata.so") h_dll_.UploadFile(sDVRIP,8000,sUserName,sPassword,picPath)
以下是python调用生成的库,获取码流的代码:
h_dll_ = ctypes.cdll.LoadLibrary("/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/psdatacall_demo/getpsdata.so") list_data = [] def func_called(mydata): # print("print by python,called by cpp!") print("print by python:"+str(len(mydata))) list_data.append(mydata) # def WriteFaceRes(): # os.system( # r'"/home/caobin/chike/chike/CH_HCNetSDK_V5.2.7.4_build20170606_Linux64/consoleDemo/linux64/lib/sdkTest" "192.168.1.64" 8000 "admin" "guoji123" 3') # # FUNCCALLED = ctypes.CFUNCTYPE(ctypes.c_void_p,ctypes.c_char_p) # h_dll_.GetStream(FUNCCALLED(func_called))