欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ONVIF客户端

程序员文章站 2022-07-14 17:06:18
...

根据博主以下三篇文章,你是否已经搭建好了ONVIF开发环境?
1、windows下利用gsoap生成onvif框架代码(带鉴权):
https://blog.csdn.net/ysdzkj/article/details/109383456
2、windows下利用vs2013工具编译openssl库:
https://blog.csdn.net/ysdzkj/article/details/109327761
3、windows下vs2013工程调用onvif框架源码(带鉴权):
https://blog.csdn.net/ysdzkj/article/details/109388642

搭建好ONVIF开发环境后,直接上代码:
1、OnvifClient类声明

// OnvifClient.h 
#include "soapH.h"
#include "wsseapi.h" // 鉴权

class COnvifClient
{
public:
	COnvifClient();
	virtual ~COnvifClient();
	
	bool InitSoap();
	bool UserAuthentication(const char *pUsername, const char *pPassword);
	//const char * GetResponseBuf();
	bool DiscoverDevices(void(*DiscoverDevicesCallBack)(struct __wsdd__ProbeMatches *pstProbeMatches,int index,void *pUserData),void *pUserData);
	bool GetScopes(const char *pServiceAddress, struct _tds__GetScopesResponse *pstScopesResp);
	bool GetCapabilities(const char *pServiceAddress, struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp);
	bool GetDeviceInformation(const char *pServiceAddress, struct _tds__GetDeviceInformationResponse *pstDeviceInformationResp);
	bool GetProfiles(struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp, struct _trt__GetProfilesResponse *pstProfilesResp);
	bool GetStreamUri(struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp, struct _trt__GetProfilesResponse *pstProfilesResp, struct _trt__GetStreamUriResponse *pstStreamUriResp);
private:

	struct soap *_pstSoap;
	struct SOAP_ENV__Header _stEnvHeader;
	struct wsdd__ScopesType _stScopesType;
	struct wsdd__ProbeType _stProbeType;
	struct __wsdd__ProbeMatches _stProbeMatches;

	void DestorySoap();
};

2、OnvifClient类实现

// OnvifClient.cpp
#include "stdafx.h"
#include "OnvifClient.h"


COnvifClient::COnvifClient() :
_pstSoap(NULL)
{
}


COnvifClient::~COnvifClient()
{
	DestorySoap();
}

void COnvifClient::DestorySoap()
{
	if (NULL != _pstSoap)
	{
		soap_end(_pstSoap);
		soap_delete(_pstSoap, NULL);
		_pstSoap = NULL;
	}
}

bool COnvifClient::InitSoap()
{
	GUID guid;
	char cguid[64] = { 0 };
	int timeout = 3;

	DestorySoap();

	_pstSoap = soap_new();
	if (_pstSoap == NULL)
	{
		return false;
	}

	//struct in_addr if_req;
	//if_req.s_addr = inet_addr("10.15.0.66");  // 想绑定的IP地址

	//_pstSoap->ipv4_multicast_if = (char*)soap_malloc(_pstSoap, sizeof(struct in_addr));
	//memset(_pstSoap->ipv4_multicast_if, 0, sizeof(struct in_addr));
	//memcpy(_pstSoap->ipv4_multicast_if, (char*)&if_req, sizeof(if_req));

	//_pstSoap->ipv4_multicast_ttl = 255;


	_pstSoap->recv_timeout = timeout;
	_pstSoap->send_timeout = timeout;
	_pstSoap->connect_timeout = timeout;

	soap_set_namespaces(_pstSoap, namespaces);

	soap_default_SOAP_ENV__Header(_pstSoap, &_stEnvHeader);

	CoCreateGuid(&guid);
	_snprintf(cguid, 64, "urn:uuid:%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
		guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
		guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);

	_stEnvHeader.wsa__MessageID = cguid;
	_stEnvHeader.wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
	_stEnvHeader.wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";

	_pstSoap->header = &_stEnvHeader;

	//设置所需寻找设备的类型和范围
	soap_default_wsdd__ScopesType(_pstSoap, &_stScopesType);
	_stScopesType.__item = "";// "onvif://www.onvif.org";

	soap_default_wsdd__ProbeType(_pstSoap, &_stProbeType);
	_stProbeType.Scopes = &_stScopesType;
	_stProbeType.Types = "tdn:NetworkVideoTransmitter";

	return true;
}

//const char * COnvifClient::GetResponseBuf()
//{
//	return _pstSoap->buf;
//}

bool COnvifClient::UserAuthentication(const char *pUsername, const char *pPassword)
{
	if (pUsername && pPassword)
	{
		int ret = soap_wsse_add_UsernameTokenDigest(_pstSoap, NULL, pUsername, pPassword);
		if (ret == SOAP_OK)
		{
			return true;
		}
	}
	return false;
}

bool COnvifClient::DiscoverDevices(void(*DiscoverDevicesCallBack)(struct __wsdd__ProbeMatches *pstProbeMatches, int index, void *pUserData),void *pUserData)
{
	int ret = 0;

	ret = soap_send___wsdd__Probe(_pstSoap, "soap.udp://239.255.255.250:3702", NULL, &_stProbeType);
	if (ret != SOAP_OK)
	{
		return false;
	}

	int count = 0;
	do
	{
		ret = soap_recv___wsdd__ProbeMatches(_pstSoap, &_stProbeMatches);
		if (ret != SOAP_OK)
		{
			break;
		}

		DiscoverDevicesCallBack(&_stProbeMatches, count++, pUserData);

		//cout << "-------- " << "NO." << count++ << " --------" << endl;
		//cout << "UUID:" << "" << _stProbeMatches.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address << endl;
		//cout << "Type:" << "" << _stProbeMatches.wsdd__ProbeMatches->ProbeMatch->Types << endl;
		//cout << "Scopes:" << "" << _stProbeMatches.wsdd__ProbeMatches->ProbeMatch->Scopes->__item << endl;
		//cout << "DeviceService Address:" << "" << _stProbeMatches.wsdd__ProbeMatches->ProbeMatch->XAddrs << endl;
		//cout << "MetadataVersion:" << "" << _stProbeMatches.wsdd__ProbeMatches->ProbeMatch->MetadataVersion << endl;

	} while (true);

	return true;
}

bool COnvifClient::GetScopes(const char *pServiceAddress, struct _tds__GetScopesResponse *pstScopesResp)
{
	int ret;
	struct _tds__GetScopes			req;
	struct _tds__GetScopesResponse	resp;

	memset(&req, 0, sizeof(struct _tds__GetScopes));
	memset(&resp, 0, sizeof(struct _tds__GetScopesResponse));

	ret = soap_call___tds__GetScopes(_pstSoap, pServiceAddress, NULL, &req, &resp);
	if (ret == SOAP_OK)
	{
		memcpy(pstScopesResp, &resp, sizeof(struct _tds__GetScopesResponse));
	}
	soap_stream_fault(_pstSoap, std::cerr);

	return ret == SOAP_OK ? true : false;
}

bool COnvifClient::GetCapabilities(const char *pServiceAddress, struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp)
{
	int ret;
	struct _tds__GetCapabilities			req;
	struct _tds__GetCapabilitiesResponse	resp;

	memset(&req, 0, sizeof(struct _tds__GetCapabilities));
	memset(&resp, 0, sizeof(struct _tds__GetCapabilitiesResponse));

	if (!this->InitSoap())
		return false;

	req.__sizeCategory = 1;
	req.Category = (enum tt__CapabilityCategory *)soap_malloc(_pstSoap, sizeof(int));
	*req.Category = tt__CapabilityCategory__All;

	ret = soap_call___tds__GetCapabilities(_pstSoap, pServiceAddress, NULL, &req, &resp);
	if (ret == SOAP_OK)
	{
		memcpy(pstCapabilitiesResp, &resp, sizeof(struct _tds__GetCapabilitiesResponse));
	}

	soap_dealloc(_pstSoap, req.Category);

	return ret == SOAP_OK ? true : false;
}

bool COnvifClient::GetDeviceInformation(const char *pServiceAddress, struct _tds__GetDeviceInformationResponse *pstDeviceInformationResp)
{
	int ret;
	struct _tds__GetDeviceInformation			req;
	struct _tds__GetDeviceInformationResponse   resp;

	memset(&req, 0, sizeof(struct _tds__GetDeviceInformation));
	memset(&resp, 0, sizeof(struct _tds__GetDeviceInformationResponse));

	ret = soap_call___tds__GetDeviceInformation(_pstSoap, pServiceAddress, NULL, &req, &resp);
	if (ret == SOAP_OK)
	{
		//soap_stream_fault(_pstSoap, std::cerr);
		memcpy(pstDeviceInformationResp, &resp, sizeof(struct _tds__GetDeviceInformationResponse));
	}
	//soap_stream_fault(_pstSoap, std::cerr);
	return ret == SOAP_OK ? true : false;
}

bool COnvifClient::GetProfiles(struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp, struct _trt__GetProfilesResponse *pstProfilesResp)
{
	int ret;
	struct _trt__GetProfiles req;
	struct _trt__GetProfilesResponse resp;

	memset(&req, 0, sizeof(struct _trt__GetProfiles));
	memset(&resp, 0, sizeof(struct _trt__GetProfilesResponse));

	ret = soap_call___trt__GetProfiles(_pstSoap, pstCapabilitiesResp->Capabilities->Media->XAddr, NULL, &req, &resp);
	if (ret == SOAP_OK)
	{
		memcpy(pstProfilesResp, &resp, sizeof(struct _trt__GetProfilesResponse));
	}
	//soap_stream_fault(_pstSoap, std::cerr);
	return ret == SOAP_OK ? true : false;
}

bool COnvifClient::GetStreamUri(struct _tds__GetCapabilitiesResponse *pstCapabilitiesResp, struct _trt__GetProfilesResponse *pstProfilesResp, struct _trt__GetStreamUriResponse *pstStreamUriResp)
{
	int ret;
	struct _trt__GetStreamUri req;
	struct _trt__GetStreamUriResponse resp;

	memset(&req, 0, sizeof(struct _trt__GetStreamUri));
	memset(&resp, 0, sizeof(struct _trt__GetStreamUriResponse));

	req.StreamSetup = (struct tt__StreamSetup*)soap_malloc(_pstSoap, sizeof(struct tt__StreamSetup));//初始化,分配空间
	req.StreamSetup->Stream = tt__StreamType__RTP_Unicast;//stream type
	req.StreamSetup->Transport = (struct tt__Transport *)soap_malloc(_pstSoap, sizeof(struct tt__Transport));//初始化,分配空间
	req.StreamSetup->Transport->Protocol = tt__TransportProtocol__RTSP;
	req.StreamSetup->Transport->Tunnel = 0;
	req.StreamSetup->__size = 1;
	req.StreamSetup->__any = NULL;
	req.StreamSetup->__anyAttribute = NULL;
	req.ProfileToken = pstProfilesResp->Profiles->token;

	ret = soap_call___trt__GetStreamUri(_pstSoap, pstCapabilitiesResp->Capabilities->Media->XAddr, NULL, &req, &resp);
	if (ret == SOAP_OK)
	{
		memcpy(pstStreamUriResp, &resp, sizeof(struct _trt__GetStreamUriResponse));
	}
	
	soap_dealloc(_pstSoap, req.StreamSetup->Transport);
	soap_dealloc(_pstSoap, req.StreamSetup);

	//soap_stream_fault(_pstSoap, std::cerr);
	return ret == SOAP_OK ? true : false;
}

3、OnvifClient类调用

#include "OnvifClient.h"
#include "soapH.h"

#define USERNAME "admin"
#define PASSWORD "admin123456"

void CDeviceMgmtDlg::OnBnClickedBtnGetScopes()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _tds__GetScopesResponse stScopesResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	pClient->UserAuthentication(USERNAME, PASSWORD);
	pClient->GetScopes(_serviceAddress, &stScopesResp);
	delete pClient;
}

void CDeviceMgmtDlg::OnBnClickedBtnGetCapa()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _tds__GetCapabilitiesResponse stCapabilitiesResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	pClient->GetCapabilities(_serviceAddress, &stCapabilitiesResp);
	//m_debugLogCtrl.Clear();
	//m_debugLogCtrl.SetWindowText(pClient->GetResponseBuf());
	delete pClient;
}


void CDeviceMgmtDlg::OnBnClickedBtnGetDevinfo()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _tds__GetDeviceInformationResponse stDeviceInformationResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	pClient->UserAuthentication(USERNAME, PASSWORD);
	pClient->GetDeviceInformation(_serviceAddress, &stDeviceInformationResp);
	delete pClient;
}


void CDeviceMgmtDlg::OnBnClickedBtnGetProfiles()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _trt__GetProfilesResponse stProfilesResp = { 0 };
	struct _tds__GetCapabilitiesResponse stCapabilitiesResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	if (pClient->GetCapabilities(_serviceAddress, &stCapabilitiesResp))
	{
		pClient->UserAuthentication(USERNAME, PASSWORD);
		pClient->GetProfiles(&stCapabilitiesResp, &stProfilesResp);
	}
	delete pClient;
}
// 获取rtsp流地址
void CDeviceMgmtDlg::OnBnClickedBtnGetStreamuri()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _trt__GetProfilesResponse stProfilesResp = { 0 };
	struct _tds__GetCapabilitiesResponse stCapabilitiesResp = { 0 };
	struct _trt__GetStreamUriResponse stStreamUriResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	if (pClient->GetCapabilities(_serviceAddress, &stCapabilitiesResp))
	{
		pClient->UserAuthentication(USERNAME, PASSWORD);
		if (pClient->GetProfiles(&stCapabilitiesResp, &stProfilesResp))
		{
			pClient->UserAuthentication(USERNAME, PASSWORD);
			pClient->GetStreamUri(&stCapabilitiesResp, &stProfilesResp, &stStreamUriResp);
		}
	}
	delete pClient;
}
// 设备搜索
void g_funDiscoverDevices(struct __wsdd__ProbeMatches *pstProbeMatches,int index,void *pUserData)
{
	CMFC_OnvifClientDlg *pThis = (CMFC_OnvifClientDlg *)pUserData;

	char *pEPAddress = pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address;
	char *pServiceAddress = pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->XAddrs;

	pThis->InsertDeviceItem(index,pEPAddress,pServiceAddress);

	//cout << "-------- " << "NO." << index << " --------" << endl;
	//cout << "UUID:" << "" << pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address << endl;
	//cout << "Type:" << "" << pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->Types << endl;
	//cout << "Scopes:" << "" << pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->Scopes->__item << endl;
	//cout << "DeviceService Address:" << "" << pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->XAddrs << endl;
	//cout << "MetadataVersion:" << "" << pstProbeMatches->wsdd__ProbeMatches->ProbeMatch->MetadataVersion << endl;
}

void CMFC_OnvifClientDlg::OnBnClickedBtnOnvifSearch()
{
	// TODO:  在此添加控件通知处理程序代码
	SetDlgItemText(IDC_BTN_ONVIF_SEARCH, "正在搜索...");

	COnvifClient *pOnvifClient = new COnvifClient();
	pOnvifClient->InitSoap();
	pOnvifClient->DiscoverDevices(g_funDiscoverDevices,this);
	delete pOnvifClient;

	SetDlgItemText(IDC_BTN_ONVIF_SEARCH, "设备搜索");
}

注意事项:
1、设备搜索不能设定IP段,这个问题博主尝试过其他网友的方法,但未成功,希望网友们能提供方法;
2、对于需要鉴权的接口,每次在调用前都必须调用一次用户认证接口,即

pClient->UserAuthentication(USERNAME, PASSWORD);

例如:

// 获取rtsp流地址
void CDeviceMgmtDlg::OnBnClickedBtnGetStreamuri()
{
	// TODO:  在此添加控件通知处理程序代码
	struct _trt__GetProfilesResponse stProfilesResp = { 0 };
	struct _tds__GetCapabilitiesResponse stCapabilitiesResp = { 0 };
	struct _trt__GetStreamUriResponse stStreamUriResp = { 0 };

	COnvifClient *pClient = new COnvifClient();
	pClient->InitSoap();
	if (pClient->GetCapabilities(_serviceAddress, &stCapabilitiesResp))
	{
		pClient->UserAuthentication(USERNAME, PASSWORD);
		if (pClient->GetProfiles(&stCapabilitiesResp, &stProfilesResp))
		{
			pClient->UserAuthentication(USERNAME, PASSWORD);
			pClient->GetStreamUri(&stCapabilitiesResp, &stProfilesResp, &stStreamUriResp);
		}
	}
	delete pClient;
}

根据ONVIF官方文档,GetProfiles和GetStreamUri都必须经过用户认证,所以在调用这2个接口前都调用了鉴权认证接口。但也不是绝对的,主要取决于设备端,若设备端无鉴权认证,则也能正常调用。

相关标签: ONVIF onvif gsoap

上一篇: Handler 使用

下一篇: Handler 使用