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个接口前都调用了鉴权认证接口。但也不是绝对的,主要取决于设备端,若设备端无鉴权认证,则也能正常调用。
上一篇: Handler 使用
下一篇: Handler 使用