写在前头:这个华为sdk他不更新了,只是维护,所以可能有的功能不是很对,技术支持那边推荐用restful接口去调用,具体怎么调用可以参见我的其他文章。

目录

摘要

在c++中的准备

新建dll项目

pyhon方面的准备


摘要

大致流程就是:在c++先开发调用sdk的对应内容,正确返回结果之后,用vc编写dll库,将需要的功能封装成1个dll库中的函数,最后在python中用ctypes调用这个函数,输入对应参数,实现在python中调用sdk的功能。

在c++中的准备

第一步,把华为sdk的库和依赖的dll放好。

我用的是vs2017

主要是以下几个步骤

1、把相关文件放到该放的位置

首先,创建新项目,我是在这个hwsdk文件夹下创建的

 创建完成后点进去应该是这个界面,我的解决方案名字也是hwsdk

 然后点进hwsdk文件夹,把从官网下载的32位的华为dll依赖全部放进去,要用32位的

 注意这个里面还有HWPuSDK.h和HWPuSDK.lib,我们后面要用到,也要放进去

2、在vc里设置依赖

项目->属性->链接器->输入,在附加依赖项里面添加

 3、加入头文件

我试着导入了几次都不行,我就自己新建了一个头文件,名字还叫HWPuSDK.h把里面内容拷贝过来。会出现几个问题:

一个是预编译头报错,直接删掉导入的include

一个是要导入#include <wtypes.h>这个头文件

4、设置合规

项目->属性->c/c++语言->是否合规选否,2017就可以了,2022最后输入参数char 和const char要强制类型转换

第二步、开发c++代码

c++写这个不难


#include <string>
#include <stdio.h>
#include "HWPuSDK.h"
#include <Windows.h>

//初始化函数--返回值0代表失败1代表成功
BOOL CamInit()
{
	// 初始化标记1为成功0为失败
	BOOL INIT_FLAG = IVS_PU_Init(3, NULL, 6060);
	//判断初始化是否成功
	if (INIT_FLAG)
	{
		printf("%s\n", "初始化sdk成功");
	}
	else
	{
		printf("%s\n", "初始化sdk失败");
		//输出错误码
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "一般错误");
			break;
		case 5:
			printf("%s\n", "SDK已被初始化");
			break;
		case 101:
			printf("%s\n", "SDK初始化连接模式出错");
			break;
		case 102:
			printf("%s\n", "SDK初始化本地IP出错");
			break;
		default:
			printf("%s\n", "未知错误");
			break;
		}
	}
	return INIT_FLAG;
}

// 登录返回函数--返回正整数代表获得id返回其他代表失败
ULONG CamLogin(CHAR *ip, CHAR *user, CHAR *password)
{
	//返回正整数id
	ULONG login_id = IVS_PU_Login(ip, 6060, user, password);
	if (login_id > 0)
	{
		printf("%s\n", "获得登录id成功");
	}
	else
	{
		printf("%s\n", "获得登录id失败");
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "一般错误");
			break;
		case 2:
			printf("%s\n", "用户名或密码错误");
			break;
		case 4:
			printf("%s\n", "SDK未初始化");
			break;
		case 6:
			printf("%s\n", "SDK与设备版本不匹配");
			break;
		case 7:
			printf("%s\n", "入参为空");
			break;
		case 10106:
			printf("%s\n", "SDK仍为初始密码,建议尽快修改");
			break;
		default:
			printf("%s\n", "未知错误");
			break;
		}
	}
	return login_id;
}

void procMetaData(PU_META_DATA *pstMetaData)
{
	UINT SpeopleNum = 0;
	UINT peopleNum = 0;
	LONGLONG time_offset = 0;
	printf("%s%d%s\n", "共有", pstMetaData->usValidNumber, "个有效数目");
	for (UINT uIndex = 0; uIndex < pstMetaData->usValidNumber; ++uIndex)
	{
		//printf("%d\n", pstMetaData->pstMetaUserData[uIndex].eType);
		// 标记数据类型
		switch (pstMetaData->pstMetaUserData[uIndex].eType)
		{
		case TARGET_TYPE:    //target类型,当前用于区分人脸后处理抠图和人脸识别以及人脸识别多机协同
			printf("数据类型为target类型\n");
			break;
		case 0x07000904:    //离岗监测--岗位人数
			SpeopleNum = pstMetaData->pstMetaUserData[uIndex].unMetaData.uIntValue;
			printf("离岗监测--应有岗位人数%d\n", SpeopleNum);
			break;
		case 0x07000905:    //离岗监测--在岗人数
			peopleNum = pstMetaData->pstMetaUserData[uIndex].unMetaData.uIntValue;
			printf("离岗监测--在岗人数%d\n", peopleNum);
			break;
		//case 0x08000085:    //夏令时偏移时间
		//	time_offset = pstMetaData->pstMetaUserData[uIndex].unMetaData.longlongValue;
		//	printf("夏令时偏移时间%l64d\n", time_offset);
		default:
			break;
		}
	}
}

//实况回调函数
void CALLBACK fRealDataCallBack(CHAR *szBuffer, LONG lSize, VOID *pUsrData)
{
	BOOL bRet = PU_FALSE;
	//第二层元数据TYPE
	PU_META_DATA *pstMetaTargetData = NULL;
	bRet = IVS_User_GetMetaData(szBuffer, lSize, TARGET, &pstMetaTargetData);
	if ((PU_TRUE == bRet) && (NULL != pstMetaTargetData))
	{
		//printf("%s%d%s\n", "数据长度为", lSize, "字节");
		procMetaData(pstMetaTargetData);
		IVS_User_FreeMetaData(&pstMetaTargetData);
	}
}


//实况函数
ULONG Real(ULONG id)
{
	//结构体赋值
	PU_REAL_PLAY_INFO_S stRealPlayInfo = {0};
	//通道号
	stRealPlayInfo.ulChannelId = 101;
	//传输类型
	stRealPlayInfo.enProtocolType = PU_PROTOCOL_TYPE_TCP;
	//码流类型
	stRealPlayInfo.enStreamType = PU_VIDEO_MAIN_STREAM;
	//保活
	stRealPlayInfo.bKeepLive = TRUE;
	//码流加密方式
	stRealPlayInfo.enMediaCryptoType = PU_MEDIA_CRYPTO_NONE;
	//数据类型
	stRealPlayInfo.enVideoType = PU_VIDEO_TYPE_META;
	//媒体回调类型
	stRealPlayInfo.enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE_META_FRAME;
	//元数据返回标记位置
	stRealPlayInfo.szReserved[22] = 1;
	//只返回检测框内容
	stRealPlayInfo.szReserved[23] = PU_METADATA_REQUEST_REST;
	//返回元数据时句柄为空
	stRealPlayInfo.hPlayWnd = NULL;

	//调用实时预览函数
	ULONG real_id = IVS_PU_RealPlay(id, &stRealPlayInfo, fRealDataCallBack, NULL);
	if (real_id > 0)
	{
		printf("%s\n", "获得实时播放id成功");
	}
	else
	{
		printf("%s\n", "获得实时播放id失败");
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "一般错误");
			break;
		case 4:
			printf("%s\n", "SDK未初始化");
			break;
		case 9:
			printf("%s\n", "网络连接错误");
			break;
		case 10:
			printf("%s\n", "发送消息超时");
			break;
		case 11:
			printf("%s\n", "接收消息超时");
		case 15:
			printf("%s\n", "接收消息超时");
			break;
		case 106:
			printf("%s\n", "错误的用户ID号");
			break;
		case 137:
			printf("%s\n", "播放库函数调用出错");
			break;
		default:
			printf("%s\n", "未知错误");
			break;
	}
	
	}

	return real_id;
}

//程序入口
int main()
{
	//初始化变量
	CHAR *ip = "ip";
	CHAR *user = "user";
	CHAR *password = "password";
	//初始化sdk
	CamInit();
	//获得登录id
	ULONG id = CamLogin(ip, user, password);
	//实时数据返回
	Real(id);
	while (1)
	{
		Sleep(1 * 60000);
		printf("%s\n", "程序运行");
	}

	}



以离岗监测为例子,就是这样写的内容。返回的回调函数的内容需要对着sdk的文档去获得回调函数返回的数据类型,具体返回的含义要对着TLV全网数据格式对照文档去看。

新建dll项目

新建一个hwdll解决项目,项目类型是dll库类型啊,别选错了

然后还是把哪些dll和lib放到对应的跟目录下

这次把这个函数功能当做导出函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"

#include <string>
#include <stdio.h>
#include "HWPuSDK.h"
#include <Windows.h>

//初始化函数--返回值0代表失败1代表成功
BOOL CamInit()
{
	// 初始化标记1为成功0为失败
	BOOL INIT_FLAG = IVS_PU_Init(3, NULL, 6060);
	//判断初始化是否成功
	if (INIT_FLAG)
	{
		printf("%s\n", "init sdk success");
	}
	else
	{
		printf("%s\n", "init sdk failed");
		//输出错误码
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "common error");
			break;
		case 5:
			printf("%s\n", "SDK has been initialed");
			break;
		case 101:
			printf("%s\n", "SDK init connection mode error");
			break;
		case 102:
			printf("%s\n", "SDK init local IP error");
			break;
		default:
			printf("%s\n", "unknown error");
			break;
		}
	}
	return INIT_FLAG;
}

// 登录返回函数--返回正整数代表获得id返回其他代表失败
ULONG CamLogin(CHAR *ip, CHAR *user, CHAR *password)
{
	//返回正整数id
	ULONG login_id = IVS_PU_Login(ip, 6060, user, password);
	if (login_id > 0)
	{
		printf("%s\n", "get login id success");
	}
	else
	{
		printf("%s\n", "get login id failed");
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "common error");
			break;
		case 2:
			printf("%s\n", "username or password error");
			break;
		case 4:
			printf("%s\n", "SDK not init");
			break;
		case 6:
			printf("%s\n", "SDK version not match equipment");
			break;
		case 7:
			printf("%s\n", "params is NULL");
			break;
		case 10106:
			printf("%s\n", "SDK password is init,please change");
			break;
		default:
			printf("%s\n", "unknown error");
			break;
		}
	}
	return login_id;
}

void procMetaData(PU_META_DATA *pstMetaData)
{
	UINT SpeopleNum = 0;
	UINT peopleNum = 0;
	LONGLONG time_offset = 0;
	//printf("%s%d%s\n", "共有", pstMetaData->usValidNumber, "个有效数目");
	for (UINT uIndex = 0; uIndex < pstMetaData->usValidNumber; ++uIndex)
	{
		//printf("%d\n", pstMetaData->pstMetaUserData[uIndex].eType);
		// 标记数据类型
		switch (pstMetaData->pstMetaUserData[uIndex].eType)
		{
		case TARGET_TYPE:    //target类型,当前用于区分人脸后处理抠图和人脸识别以及人脸识别多机协同
			//printf("数据类型为target类型\n");
			break;
		case 0x07000904:    //离岗监测--岗位人数
			SpeopleNum = pstMetaData->pstMetaUserData[uIndex].unMetaData.uIntValue;
			printf("%s%d%s\n", "should have ", SpeopleNum, " people working");
			break;
		case 0x07000905:    //离岗监测--在岗人数
			peopleNum = pstMetaData->pstMetaUserData[uIndex].unMetaData.uIntValue;
			printf("%s%d%s\n", "now have ", peopleNum, " people working");
			break;
			//case 0x08000085:    //夏令时偏移时间
			//	time_offset = pstMetaData->pstMetaUserData[uIndex].unMetaData.longlongValue;
			//	printf("夏令时偏移时间%l64d\n", time_offset);
		default:
			break;
		}
	}
}

//实况回调函数
void CALLBACK fRealDataCallBack(CHAR *szBuffer, LONG lSize, VOID *pUsrData)
{
	BOOL bRet = PU_FALSE;
	//第二层元数据TYPE
	PU_META_DATA *pstMetaTargetData = NULL;
	bRet = IVS_User_GetMetaData(szBuffer, lSize, TARGET, &pstMetaTargetData);
	if ((PU_TRUE == bRet) && (NULL != pstMetaTargetData))
	{
		//printf("%s%d%s\n", "数据长度为", lSize, "字节");
		procMetaData(pstMetaTargetData);
		IVS_User_FreeMetaData(&pstMetaTargetData);
	}
}


//实况函数
ULONG Real(ULONG id)
{
	//结构体赋值
	PU_REAL_PLAY_INFO_S stRealPlayInfo = { 0 };
	//通道号
	stRealPlayInfo.ulChannelId = 101;
	//传输类型
	stRealPlayInfo.enProtocolType = PU_PROTOCOL_TYPE_TCP;
	//码流类型
	stRealPlayInfo.enStreamType = PU_VIDEO_MAIN_STREAM;
	//保活
	stRealPlayInfo.bKeepLive = TRUE;
	//码流加密方式
	stRealPlayInfo.enMediaCryptoType = PU_MEDIA_CRYPTO_NONE;
	//数据类型
	stRealPlayInfo.enVideoType = PU_VIDEO_TYPE_META;
	//媒体回调类型
	stRealPlayInfo.enMediaCallbackType = PU_MEDIA_CALLBACK_TYPE_META_FRAME;
	//元数据返回标记位置
	stRealPlayInfo.szReserved[22] = 1;
	//只返回检测框内容
	stRealPlayInfo.szReserved[23] = PU_METADATA_REQUEST_REST;
	//返回元数据时句柄为空
	stRealPlayInfo.hPlayWnd = NULL;

	//调用实时预览函数
	ULONG real_id = IVS_PU_RealPlay(id, &stRealPlayInfo, fRealDataCallBack, NULL);
	if (real_id > 0)
	{
		printf("%s\n", "get realplay id success");
	}
	else
	{
		printf("%s\n", "get realplay id failed");
		ULONG error_code = IVS_PU_GetLastError();
		switch (error_code)
		{
		case 1:
			printf("%s\n", "common error");
			break;
		case 4:
			printf("%s\n", "SDK not init");
			break;
		case 9:
			printf("%s\n", "connection error");
			break;
		case 10:
			printf("%s\n", "message send timeout");
			break;
		case 11:
			printf("%s\n", "message get timeout");
		case 15:
			printf("%s\n", "message get timeout");
			break;
		case 106:
			printf("%s\n", "wrong user id");
			break;
		case 137:
			printf("%s\n", "function use error");
			break;
		default:
			printf("%s\n", "unknown error");
			break;
		}

	}

	return real_id;
}



extern "C" __declspec(dllexport)  int lgjc(CHAR *ip, CHAR *user, CHAR *password)
{
	//初始化变量
	//CHAR *ip = ip;
	//CHAR *user = "admin";
	//CHAR *password = "zjkjc123";
	//初始化sdk
	CamInit();
	//获得登录id
	ULONG id = CamLogin(ip, user, password);
	//实时数据返回
	int real_id = Real(id);
	return real_id;
	//while (1)
	//{
	//	Sleep(1 * 60000);
	//	printf("%s\n", "程序运行");
	//}
}





这就好了,点击生成。就会在项目跟目录下的debug生成对应的dll和lib文件。这个就是我们要的。

pyhon方面的准备

hwsdk只能用32位的sdk,所以python解释器也要是32位的

创建一个32位的环境3.6
设置这个
set CONDA_FORCE_32BIT=1
创建环境

我创建了3.6的环境,据说别的不稳健
改回来
set CONDA_FORCE_32BIT=0

好,接下来用ctypes就行了

import ctypes
import os
import time
from ctypes import wintypes
import struct
import _ctypes


# 加载sdk
# 获得当前目录
cur_path = os.getcwd()
# 定位到lib文件夹
dllPath = os.path.join(cur_path, "lib")
# 更改工作目录到指定目录
os.chdir(dllPath)
# 导入dll 文件夹中其他dll是相关依赖
hw_dll = ctypes.cdll.LoadLibrary('hwdll.dll')
print('get dll success!')

ip = ctypes.c_char_p(b'ip')
acc = ctypes.c_char_p(b'user')
passa = ctypes.c_char_p(b'password')

a = hw_dll.lgjc(ip, acc, passa)
print(a)
while True:
    time.sleep(1)

我的工作目录,里面也是添加了所有的dll依赖。


 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐