Onvif协议:IPC客户端开发之获取设备能力
生活随笔
收集整理的這篇文章主要介紹了
Onvif协议:IPC客户端开发之获取设备能力
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
原理簡(jiǎn)介
ONVIF協(xié)議接口由多個(gè)模塊組成,每個(gè)模塊分別對(duì)應(yīng)著不同的WSDL文檔,在ONVIF官網(wǎng)中能查看到這些模塊,以及每個(gè)模塊中的接口函數(shù),這里列舉幾個(gè)模塊:
- DeviceMgmt(設(shè)備管理)
- 使用GetDeviceInformation接口獲取設(shè)備基本信息
- 使用GetSystemDateAndTime接口和SetSystemDateAndTime接口對(duì)設(shè)備進(jìn)行校時(shí)
- DeviceIO(設(shè)備IO服務(wù))
- Event(事件處理)
- Analytics(視頻分析)
- AnalyticsDevice(分析設(shè)備)
- Display(顯示服務(wù))
- Imaging(圖像配置)
- Media(媒體配置)
- PTZ(PTZ控制)
- Receiver(接收端配置)
- RemoteDiscovery(設(shè)備發(fā)現(xiàn))
- Recording(錄像控制)
- Replay(重放控制)
- Search(記錄搜索)
除了「RemoteDiscovery」模塊之外,每個(gè)模塊都有各自的「服務(wù)地址」,客戶端要使用這些模塊接口之前,必須先知道對(duì)應(yīng)模塊的「服務(wù)地址」。
怎樣才能獲取這些模塊的「服務(wù)地址」呢?分兩步:
-
利用WS-Discovery搜索到IPC,就能得知該設(shè)備「DeviceMgmt」模塊的「服務(wù)地址」,我們稱之為「設(shè)備服務(wù)地址」(就是我們搜索設(shè)備的時(shí)候獲取到的http://10.0.0.47/onvif/device_service)。
-
使用「設(shè)備服務(wù)地址」調(diào)用「DeviceMgmt」模塊的GetCapabilities接口(這個(gè)接口不需要鑒權(quán)就可以得到),就能獲取到所有模塊的「服務(wù)地址」。
實(shí)踐
具體請(qǐng)參考
但是main.cpp修改為:
#include <assert.h> #include "soapH.h" #include "wsdd.nsmap" #include "soapStub.h" #include "wsseapi.h" #include "wsaapi.h"#define USERNAME "admin" #define PASSWORD "hik12345"#define SOAP_ASSERT assert #define SOAP_DBGLOG printf #define SOAP_DBGERR printf#define SOAP_TO "urn:schemas-xmlsoap-org:ws:2005:04:discovery" #define SOAP_ACTION "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe"#define SOAP_MCAST_ADDR "soap.udp://239.255.255.250:3702" // onvif規(guī)定的組播地址#define SOAP_ITEM "" // 尋找的設(shè)備范圍 #define SOAP_TYPES "dn:NetworkVideoTransmitter" // 尋找的設(shè)備類型#define SOAP_SOCK_TIMEOUT (10) // socket超時(shí)時(shí)間(單秒秒)void soap_perror(struct soap *soap, const char *str) {if (nullptr == str) {SOAP_DBGERR("[soap] error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));} else {SOAP_DBGERR("[soap] %s error: %d, %s, %s\n", str, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));} }void* ONVIF_soap_malloc(struct soap *soap, unsigned int n) {void *p = nullptr;if (n > 0) {p = soap_malloc(soap, n);SOAP_ASSERT(nullptr != p);memset(p, 0x00 ,n);}return p; }struct soap *ONVIF_soap_new(int timeout) {struct soap *soap = nullptr; // soap環(huán)境變量SOAP_ASSERT(nullptr != (soap = soap_new()));soap_set_namespaces(soap, namespaces); // 設(shè)置soap的namespacessoap->recv_timeout = timeout; // 設(shè)置超時(shí)(超過(guò)指定時(shí)間沒(méi)有數(shù)據(jù)就退出)soap->send_timeout = timeout;soap->connect_timeout = timeout;#if defined(__linux__) || defined(__linux) // 參考https://www.genivia.com/dev.html#client-c的修改:soap->socket_flags = MSG_NOSIGNAL; // To prevent connection reset errors #endifsoap_set_mode(soap, SOAP_C_UTFSTRING); // 設(shè)置為UTF-8編碼,否則疊加中文OSD會(huì)亂碼return soap; }void ONVIF_soap_delete(struct soap *soap) {soap_destroy(soap); // remove deserialized class instances (C++ only)soap_end(soap); // Clean up deserialized data (except class instances) and temporary datasoap_done(soap); // Reset, close communications, and remove callbackssoap_free(soap); // Reset and deallocate the context created with soap_new or soap_copy }/************************************************************************ **函數(shù):ONVIF_init_header **功能:初始化soap描述消息頭 **參數(shù):[in] soap - soap環(huán)境變量 **返回:無(wú) **備注:1). 在本函數(shù)內(nèi)部通過(guò)ONVIF_soap_malloc分配的內(nèi)存,將在ONVIF_soap_delete中被釋放 ************************************************************************/ void ONVIF_init_header(struct soap *soap) {struct SOAP_ENV__Header *header = nullptr;SOAP_ASSERT(nullptr != soap);header = (struct SOAP_ENV__Header *)ONVIF_soap_malloc(soap, sizeof(struct SOAP_ENV__Header));soap_default_SOAP_ENV__Header(soap, header);header->wsa__MessageID = (char*)soap_wsa_rand_uuid(soap);header->wsa__To = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_TO) + 1);header->wsa__Action = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_ACTION) + 1);strcpy(header->wsa__To, SOAP_TO);strcpy(header->wsa__Action, SOAP_ACTION);soap->header = header; }/************************************************************************ **函數(shù):ONVIF_init_ProbeType **功能:初始化探測(cè)設(shè)備的范圍和類型 **參數(shù):[in] soap - soap環(huán)境變量[out] probe - 填充要探測(cè)的設(shè)備范圍和類型 **返回:0表明探測(cè)到,非0表明未探測(cè)到 **備注:1). 在本函數(shù)內(nèi)部通過(guò)ONVIF_soap_malloc分配的內(nèi)存,將在ONVIF_soap_delete中被釋放 ************************************************************************/ void ONVIF_init_ProbeType(struct soap *soap, struct wsdd__ProbeType *probe) {struct wsdd__ScopesType *scope = nullptr; // 用于描述查找哪類的Web服務(wù)SOAP_ASSERT(nullptr != soap);SOAP_ASSERT(nullptr != probe);scope = (struct wsdd__ScopesType *)ONVIF_soap_malloc(soap, sizeof(struct wsdd__ScopesType));soap_default_wsdd__ScopesType(soap, scope); // 設(shè)置尋找設(shè)備的范圍scope->__item = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_ITEM) + 1);strcpy(scope->__item, SOAP_ITEM);memset(probe, 0x00, sizeof(struct wsdd__ProbeType));soap_default_wsdd__ProbeType(soap, probe);probe->Scopes = scope;probe->Types = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_TYPES) + 1); // 設(shè)置尋找設(shè)備的類型strcpy(probe->Types, SOAP_TYPES); }void ONVIF_DetectDevice(void (*cb)(char *DeviceXAddr)) {int i;int result = 0;unsigned int count = 0; // 搜索到的設(shè)備個(gè)數(shù)struct soap *soap = nullptr; // soap環(huán)境變量struct wsdd__ProbeType req; // 用于發(fā)送Probe消息struct __wsdd__ProbeMatches rep; // 用于接收Probe應(yīng)答struct wsdd__ProbeMatchType *probeMatch;SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));ONVIF_init_header(soap); // 設(shè)置消息頭描述ONVIF_init_ProbeType(soap, &req); // 設(shè)置尋找的設(shè)備的范圍和類型result = soap_send___wsdd__Probe(soap, SOAP_MCAST_ADDR, nullptr, &req); // 向組播地址廣播Probe消息while (SOAP_OK == result) // 開始循環(huán)接收設(shè)備發(fā)送過(guò)來(lái)的消息{memset(&rep, 0x00, sizeof(rep));result = soap_recv___wsdd__ProbeMatches(soap, &rep);if (SOAP_OK == result) {if (soap->error) {soap_perror(soap, "ProbeMatches");} else { // 成功接收到設(shè)備的應(yīng)答消息printf("__sizeProbeMatch:%d\n",rep.wsdd__ProbeMatches->__sizeProbeMatch);if (nullptr != rep.wsdd__ProbeMatches) {count += rep.wsdd__ProbeMatches->__sizeProbeMatch;for(i = 0; i < rep.wsdd__ProbeMatches->__sizeProbeMatch; i++) {probeMatch = rep.wsdd__ProbeMatches->ProbeMatch + i;if (nullptr != cb) {cb(probeMatch->XAddrs); // 使用設(shè)備服務(wù)地址執(zhí)行函數(shù)回調(diào)}}}}} else if (soap->error) {break;}}SOAP_DBGLOG("\ndetect end! It has detected %d devices!\n", count);if (nullptr != soap) {ONVIF_soap_delete(soap);}}#define SOAP_CHECK_ERROR(result, soap, str) \do { \if (SOAP_OK != (result) || SOAP_OK != (soap)->error) { \soap_perror((soap), (str)); \if (SOAP_OK == (result)) { \(result) = (soap)->error; \} \goto EXIT; \} \ } while (0)/************************************************************************ **函數(shù):ONVIF_SetAuthInfo **功能:設(shè)置認(rèn)證信息 **參數(shù):[in] soap - soap環(huán)境變量[in] username - 用戶名[in] password - 密碼 **返回:0表明成功,非0表明失敗 **備注: ************************************************************************/ static int ONVIF_SetAuthInfo(struct soap *soap, const char *username, const char *password) {int result = 0;SOAP_ASSERT(nullptr != username);SOAP_ASSERT(nullptr != password);result = soap_wsse_add_UsernameTokenDigest(soap, NULL, username, password);SOAP_CHECK_ERROR(result, soap, "add_UsernameTokenDigest");EXIT:return result; } /************************************************************************ **函數(shù):ONVIF_GetDeviceInformation **功能:獲取設(shè)備基本信息 **參數(shù):[in] DeviceXAddr - 設(shè)備服務(wù)地址 **返回:0表明成功,非0表明失敗 **備注: ************************************************************************/ int ONVIF_GetDeviceInformation(const char *DeviceXAddr) {int result = 0;struct soap *soap = nullptr;_tds__GetDeviceInformation devinfo_req;_tds__GetDeviceInformationResponse devinfo_resp;SOAP_ASSERT(nullptr != DeviceXAddr);SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);result = soap_call___tds__GetDeviceInformation(soap, DeviceXAddr, nullptr, &devinfo_req, devinfo_resp);SOAP_CHECK_ERROR(result, soap, "GetDeviceInformation");std::cout << " Manufacturer:\t" << devinfo_resp.Manufacturer << "\n";std::cout << " Model:\t" << devinfo_resp.Model << "\n";std::cout << " FirmwareVersion:\t" << devinfo_resp.FirmwareVersion << "\n";std::cout << " SerialNumber:\t" << devinfo_resp.SerialNumber << "\n";std::cout << " HardwareId:\t" << devinfo_resp.HardwareId << "\n";EXIT:if (nullptr != soap) {ONVIF_soap_delete(soap);}return result; }/************************************************************************ **函數(shù):ONVIF_GetCapabilities **功能:獲取設(shè)備能力信息 **參數(shù):[in] DeviceXAddr - 設(shè)備服務(wù)地址 **返回:0表明成功,非0表明失敗 **備注:1). 其中最主要的參數(shù)之一是媒體服務(wù)地址 ************************************************************************/ int ONVIF_GetCapabilities(const char *DeviceXAddr) {int result = 0;struct soap *soap = NULL;_tds__GetCapabilities devinfo_req;_tds__GetCapabilitiesResponse devinfo_resp;SOAP_ASSERT(NULL != DeviceXAddr);SOAP_ASSERT(NULL != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));result = soap_call___tds__GetCapabilities(soap, DeviceXAddr, NULL, &devinfo_req, devinfo_resp);SOAP_CHECK_ERROR(result, soap, "GetCapabilities");std::cout << " Device.XAddr: " << devinfo_resp.Capabilities->Device->XAddr << "\n";std::cout << " Analytics.XAddr: " << devinfo_resp.Capabilities->Analytics->XAddr << "\n";std::cout << " Events.XAddr: " << devinfo_resp.Capabilities->Events->XAddr << "\n";std::cout << " Imaging.XAddr: " << devinfo_resp.Capabilities->Imaging->XAddr << "\n";std::cout << " Media.XAddr: " << devinfo_resp.Capabilities->Media->XAddr << "\n";if (devinfo_resp.Capabilities->PTZ != nullptr){std::cout << " PTZ.XAddr: " << devinfo_resp.Capabilities->PTZ->XAddr << "\n";}std::cout << " Extension.DeviceIO.XAddr: " << devinfo_resp.Capabilities->Extension->DeviceIO->XAddr << "\n";EXIT:if (NULL != soap) {ONVIF_soap_delete(soap);}return result; }/************************************************************************ **函數(shù):ONVIF_GetCapabilities **功能:獲取wsdl的地址 **參數(shù):[in] DeviceXAddr - 設(shè)備服務(wù)地址 **返回:0表明成功,非0表明失敗 **備注:1). 其中最主要的參數(shù)之一是媒體服務(wù)地址 ************************************************************************/ int ONVIF_GetWsdlUrl(const char *DeviceXAddr) {int result = 0;struct soap *soap = nullptr;_tds__GetWsdlUrl devinfo_req;_tds__GetWsdlUrlResponse devinfo_resp;SOAP_ASSERT(nullptr != DeviceXAddr);SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));result = soap_call___tds__GetWsdlUrl(soap, DeviceXAddr, nullptr, &devinfo_req, devinfo_resp);SOAP_CHECK_ERROR(result, soap, "ONVIF_GetWsdlUrl");std::cout << " WsdlUrl:\t" << devinfo_resp.WsdlUrl << "\n";EXIT:if (nullptr != soap) {ONVIF_soap_delete(soap);}return result; }void cb_discovery(char *DeviceXAddr) {ONVIF_GetDeviceInformation(DeviceXAddr);ONVIF_GetCapabilities(DeviceXAddr); }int main(int argc, char **argv) {ONVIF_DetectDevice(cb_discovery);return 0; }其他文章
- Onvif協(xié)議:理解什么是Web Services
- Onvif協(xié)議:使用gSOAP創(chuàng)建SOAP調(diào)用實(shí)例
- Onvif協(xié)議:門外漢理解ONVIF協(xié)議
- Onvif協(xié)議:到底什么是ONVIF協(xié)議
- Onvif協(xié)議:實(shí)現(xiàn)Probe命令來(lái)進(jìn)行設(shè)備發(fā)現(xiàn)(discover)
- Onvif協(xié)議:IPC客戶端開發(fā)之獲取設(shè)備基本信息
- Onvif協(xié)議:IPC客戶端開發(fā)之鑒權(quán)
- Onvif協(xié)議:IPC客戶端開發(fā)之獲取設(shè)備能力
- Onvif協(xié)議:IPC客戶端開發(fā)之PTZ控制
- Onvif協(xié)議:IPC客戶端開發(fā)之獲取實(shí)時(shí)預(yù)覽的Url地址
- Onvif協(xié)議:IPC客戶端開發(fā)之圖像抓拍
- ONVIF Device Test Tool測(cè)試工具使用方法
總結(jié)
以上是生活随笔為你收集整理的Onvif协议:IPC客户端开发之获取设备能力的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux设置断网自动关机(蓄电池)
- 下一篇: UG通讯类复杂薄壁产品工厂案例,00多张