Onvif协议:IPC客户端开发之PTZ控制

分手后的思念是犯贱 2022-11-21 04:05 1332阅读 0赞

介绍

在安防摄像头中,不仅仅涉及到固定摄像头的枪击,同样还包含可以360°转动的球机。因此对球机的云台方向控制是Onvif协议开发过程中必不可少的过程

球机的云台控制主要包含:八个方向(上、下、左、右、左上、左下、右上、右下),放大、缩小等,这在个过程中还包含对转动速度的控制或者放大缩小的速度控制。对应的方向及正负值如下图:

在这里插入图片描述

编码流程

1、通过设备服务地址(形如http://xx/onvif/device\_service),调用GetCapabilities函数接口,获取到Ptz的URL;

2、通过Ptz的URL,调用GetProfiles函数接口,获取到ProfileToken;

3、对_tptz__AbsoluteMove结构体进行填充;

4、调用soap_call___tptz__AbsoluteMove函数接口实现摄像头转动功能;

实践

具体请参见

除了onvif_head.sh修改为:

  1. #!/bin/bash
  2. mkdir onvif_head
  3. cd onvif_head
  4. ../bin/wsdl2h -o onvif.h -s -d -x -t ../gsoap/WS/typemap.dat \
  5. http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl \
  6. https://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl \
  7. http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl \
  8. http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl

main.cpp修改为:

  1. #include <assert.h>
  2. #include "soapH.h"
  3. #include "wsdd.nsmap"
  4. #include "soapStub.h"
  5. #include "wsseapi.h"
  6. #include "wsaapi.h"
  7. #include <map>
  8. #define SOAP_ASSERT assert
  9. #define SOAP_DBGLOG printf
  10. #define SOAP_DBGERR printf
  11. #define SOAP_TO "urn:schemas-xmlsoap-org:ws:2005:04:discovery"
  12. #define SOAP_ACTION "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe"
  13. #define SOAP_MCAST_ADDR "soap.udp://239.255.255.250:3702" // onvif规定的组播地址
  14. #define SOAP_ITEM "" // 寻找的设备范围
  15. #define SOAP_TYPES "dn:NetworkVideoTransmitter" // 寻找的设备类型
  16. #define SOAP_SOCK_TIMEOUT (10) // socket超时时间(单秒秒)
  17. void soap_perror(struct soap *soap, const char *str)
  18. {
  19. if (nullptr == str) {
  20. SOAP_DBGERR("[soap] error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  21. } else {
  22. SOAP_DBGERR("[soap] %s error: %d, %s, %s\n", str, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  23. }
  24. }
  25. void* ONVIF_soap_malloc(struct soap *soap, unsigned int n)
  26. {
  27. void *p = nullptr;
  28. if (n > 0) {
  29. p = soap_malloc(soap, n);
  30. SOAP_ASSERT(nullptr != p);
  31. memset(p, 0x00 ,n);
  32. }
  33. return p;
  34. }
  35. struct soap *ONVIF_soap_new(int timeout)
  36. {
  37. struct soap *soap = nullptr; // soap环境变量
  38. SOAP_ASSERT(nullptr != (soap = soap_new()));
  39. soap_set_namespaces(soap, namespaces); // 设置soap的namespaces
  40. soap->recv_timeout = timeout; // 设置超时(超过指定时间没有数据就退出)
  41. soap->send_timeout = timeout;
  42. soap->connect_timeout = timeout;
  43. #if defined(__linux__) || defined(__linux) // 参考https://www.genivia.com/dev.html#client-c的修改:
  44. soap->socket_flags = MSG_NOSIGNAL; // To prevent connection reset errors
  45. #endif
  46. soap_set_mode(soap, SOAP_C_UTFSTRING); // 设置为UTF-8编码,否则叠加中文OSD会乱码
  47. return soap;
  48. }
  49. void ONVIF_soap_delete(struct soap *soap)
  50. {
  51. soap_destroy(soap); // remove deserialized class instances (C++ only)
  52. soap_end(soap); // Clean up deserialized data (except class instances) and temporary data
  53. soap_done(soap); // Reset, close communications, and remove callbacks
  54. soap_free(soap); // Reset and deallocate the context created with soap_new or soap_copy
  55. }
  56. /************************************************************************
  57. **函数:ONVIF_init_header
  58. **功能:初始化soap描述消息头
  59. **参数:
  60. [in] soap - soap环境变量
  61. **返回:无
  62. **备注:
  63. 1). 在本函数内部通过ONVIF_soap_malloc分配的内存,将在ONVIF_soap_delete中被释放
  64. ************************************************************************/
  65. void ONVIF_init_header(struct soap *soap)
  66. {
  67. struct SOAP_ENV__Header *header = nullptr;
  68. SOAP_ASSERT(nullptr != soap);
  69. header = (struct SOAP_ENV__Header *)ONVIF_soap_malloc(soap, sizeof(struct SOAP_ENV__Header));
  70. soap_default_SOAP_ENV__Header(soap, header);
  71. header->wsa__MessageID = (char*)soap_wsa_rand_uuid(soap);
  72. header->wsa__To = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_TO) + 1);
  73. header->wsa__Action = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_ACTION) + 1);
  74. strcpy(header->wsa__To, SOAP_TO);
  75. strcpy(header->wsa__Action, SOAP_ACTION);
  76. soap->header = header;
  77. }
  78. /************************************************************************
  79. **函数:ONVIF_init_ProbeType
  80. **功能:初始化探测设备的范围和类型
  81. **参数:
  82. [in] soap - soap环境变量
  83. [out] probe - 填充要探测的设备范围和类型
  84. **返回:
  85. 0表明探测到,非0表明未探测到
  86. **备注:
  87. 1). 在本函数内部通过ONVIF_soap_malloc分配的内存,将在ONVIF_soap_delete中被释放
  88. ************************************************************************/
  89. void ONVIF_init_ProbeType(struct soap *soap, struct wsdd__ProbeType *probe)
  90. {
  91. struct wsdd__ScopesType *scope = nullptr; // 用于描述查找哪类的Web服务
  92. SOAP_ASSERT(nullptr != soap);
  93. SOAP_ASSERT(nullptr != probe);
  94. scope = (struct wsdd__ScopesType *)ONVIF_soap_malloc(soap, sizeof(struct wsdd__ScopesType));
  95. soap_default_wsdd__ScopesType(soap, scope); // 设置寻找设备的范围
  96. scope->__item = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_ITEM) + 1);
  97. strcpy(scope->__item, SOAP_ITEM);
  98. memset(probe, 0x00, sizeof(struct wsdd__ProbeType));
  99. soap_default_wsdd__ProbeType(soap, probe);
  100. probe->Scopes = scope;
  101. probe->Types = (char*)ONVIF_soap_malloc(soap, strlen(SOAP_TYPES) + 1); // 设置寻找设备的类型
  102. strcpy(probe->Types, SOAP_TYPES);
  103. }
  104. void ONVIF_DetectDevice(void (*cb)(char *DeviceXAddr))
  105. {
  106. int i;
  107. int result = 0;
  108. unsigned int count = 0; // 搜索到的设备个数
  109. struct soap *soap = nullptr; // soap环境变量
  110. struct wsdd__ProbeType req; // 用于发送Probe消息
  111. struct __wsdd__ProbeMatches rep; // 用于接收Probe应答
  112. struct wsdd__ProbeMatchType *probeMatch;
  113. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  114. ONVIF_init_header(soap); // 设置消息头描述
  115. ONVIF_init_ProbeType(soap, &req); // 设置寻找的设备的范围和类型
  116. result = soap_send___wsdd__Probe(soap, SOAP_MCAST_ADDR, nullptr, &req); // 向组播地址广播Probe消息
  117. while (SOAP_OK == result) // 开始循环接收设备发送过来的消息
  118. {
  119. memset(&rep, 0x00, sizeof(rep));
  120. result = soap_recv___wsdd__ProbeMatches(soap, &rep);
  121. if (SOAP_OK == result) {
  122. if (soap->error) {
  123. soap_perror(soap, "ProbeMatches");
  124. } else {
  125. // 成功接收到设备的应答消息
  126. if (nullptr != rep.wsdd__ProbeMatches) {
  127. count += rep.wsdd__ProbeMatches->__sizeProbeMatch;
  128. for(i = 0; i < rep.wsdd__ProbeMatches->__sizeProbeMatch; i++) {
  129. probeMatch = rep.wsdd__ProbeMatches->ProbeMatch + i;
  130. if (nullptr != cb ) {
  131. std::string url = probeMatch->XAddrs;
  132. if(url == "http://192.168.0.116/onvif/device_service"){
  133. cb(probeMatch->XAddrs); // 使用设备服务地址执行函数回调
  134. }
  135. }
  136. }
  137. }
  138. }
  139. } else if (soap->error) {
  140. break;
  141. }
  142. }
  143. SOAP_DBGLOG("\ndetect end! It has detected %d devices!\n", count);
  144. if (nullptr != soap) {
  145. ONVIF_soap_delete(soap);
  146. }
  147. }
  148. #define SOAP_CHECK_ERROR(result, soap, str) \
  149. do { \
  150. if (SOAP_OK != (result) || SOAP_OK != (soap)->error) { \
  151. soap_perror((soap), (str)); \
  152. if (SOAP_OK == (result)) { \
  153. (result) = (soap)->error; \
  154. } \
  155. goto EXIT; \
  156. } \
  157. } while (0)
  158. /************************************************************************
  159. **函数:ONVIF_SetAuthInfo
  160. **功能:设置认证信息
  161. **参数:
  162. [in] soap - soap环境变量
  163. [in] username - 用户名
  164. [in] password - 密码
  165. **返回:
  166. 0表明成功,非0表明失败
  167. **备注:
  168. ************************************************************************/
  169. static int ONVIF_SetAuthInfo(struct soap *soap, const char *username, const char *password)
  170. {
  171. int result = 0;
  172. SOAP_ASSERT(nullptr != username);
  173. SOAP_ASSERT(nullptr != password);
  174. result = soap_wsse_add_UsernameTokenDigest(soap, nullptr, username, password);
  175. SOAP_CHECK_ERROR(result, soap, "add_UsernameTokenDigest");
  176. EXIT:
  177. return result;
  178. }
  179. /************************************************************************
  180. **函数:make_uri_withauth
  181. **功能:构造带有认证信息的URI地址
  182. **参数:
  183. [in] src_uri - 未带认证信息的URI地址
  184. [in] username - 用户名
  185. [in] password - 密码
  186. [out] dest_uri - 返回的带认证信息的URI地址
  187. [in] size_dest_uri - dest_uri缓存大小
  188. **返回:
  189. 0成功,非0失败
  190. **备注:
  191. 1). 例子:
  192. 无认证信息的uri:rtsp://100.100.100.140:554/av0_0
  193. 带认证信息的uri:rtsp://username:password@100.100.100.140:554/av0_0
  194. ************************************************************************/
  195. static int make_uri_withauth(const std::string& src_uri, const std::string&username, const std::string&password, std::string *dest_uri)
  196. {
  197. int result = 0;
  198. SOAP_ASSERT(!src_uri.empty());
  199. if (username.empty() &&password.empty()) {
  200. // 生成新的uri地址
  201. *dest_uri = src_uri;
  202. } else {
  203. std::string::size_type position = src_uri.find("//");
  204. if (std::string::npos == position) {
  205. SOAP_DBGERR("can't found '//', src uri is: %s.\n", src_uri.c_str());
  206. result = -1;
  207. return result;
  208. }
  209. position += 2;
  210. dest_uri->append(src_uri,0, position) ;
  211. dest_uri->append(username + ":" + password + "@");
  212. dest_uri->append(src_uri,position, std::string::npos) ;
  213. }
  214. return result;
  215. }
  216. #define USERNAME "admin"
  217. #define PASSWORD "hik12345"
  218. /************************************************************************
  219. **函数:ONVIF_GetDeviceInformation
  220. **功能:获取设备基本信息
  221. **参数:
  222. [in] DeviceXAddr - 设备服务地址
  223. **返回:
  224. 0表明成功,非0表明失败
  225. **备注:
  226. ************************************************************************/
  227. int ONVIF_GetDeviceInformation(const char *DeviceXAddr)
  228. {
  229. int result = 0;
  230. struct soap *soap = nullptr;
  231. _tds__GetDeviceInformation devinfo_req;
  232. _tds__GetDeviceInformationResponse devinfo_resp;
  233. SOAP_ASSERT(nullptr != DeviceXAddr);
  234. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  235. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  236. result = soap_call___tds__GetDeviceInformation(soap, DeviceXAddr, nullptr, &devinfo_req, devinfo_resp);
  237. SOAP_CHECK_ERROR(result, soap, "GetDeviceInformation");
  238. std::cout << " Manufacturer:\t" << devinfo_resp.Manufacturer << "\n";
  239. std::cout << " Model:\t" << devinfo_resp.Model << "\n";
  240. std::cout << " FirmwareVersion:\t" << devinfo_resp.FirmwareVersion << "\n";
  241. std::cout << " SerialNumber:\t" << devinfo_resp.SerialNumber << "\n";
  242. std::cout << " HardwareId:\t" << devinfo_resp.HardwareId << "\n";
  243. EXIT:
  244. if (nullptr != soap) {
  245. ONVIF_soap_delete(soap);
  246. }
  247. return result;
  248. }
  249. /************************************************************************
  250. **函数:ONVIF_GetCapabilities
  251. **功能:获取设备能力信息
  252. **参数:
  253. [in] DeviceXAddr - 设备服务地址
  254. [in]
  255. **返回:
  256. 0表明成功,非0表明失败
  257. **备注:
  258. 1). 其中最主要的参数之一是媒体服务地址
  259. ************************************************************************/
  260. int ONVIF_GetCapabilities(const std::string& deviceXAddr, std::string * ptzXAddr)
  261. {
  262. int result = 0;
  263. struct soap *soap = nullptr;
  264. _tds__GetCapabilities devinfo_req;
  265. _tds__GetCapabilitiesResponse devinfo_resp;
  266. SOAP_ASSERT(!deviceXAddr.empty());
  267. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  268. result = soap_call___tds__GetCapabilities(soap, deviceXAddr.c_str(), nullptr, &devinfo_req, devinfo_resp);
  269. SOAP_CHECK_ERROR(result, soap, "GetCapabilities");
  270. if(devinfo_resp.Capabilities->PTZ != nullptr){
  271. *ptzXAddr = devinfo_resp.Capabilities->PTZ->XAddr;
  272. }
  273. EXIT:
  274. if (nullptr != soap) {
  275. ONVIF_soap_delete(soap);
  276. }
  277. return result;
  278. }
  279. int ONVIF_GetProfiles(const std::string& ptzXAddr, std::string * profilesToken)
  280. {
  281. int result = 0;
  282. struct soap *soap = nullptr;
  283. _trt__GetProfiles devinfo_req;
  284. _trt__GetProfilesResponse devinfo_resp;
  285. SOAP_ASSERT(!ptzXAddr.empty());
  286. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  287. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  288. result = soap_call___trt__GetProfiles(soap, ptzXAddr.c_str(), nullptr, &devinfo_req, devinfo_resp);
  289. SOAP_CHECK_ERROR(result, soap, "ONVIF_GetProfiles");
  290. SOAP_ASSERT(devinfo_resp.__sizeProfiles > 0);
  291. *profilesToken = devinfo_resp.Profiles[0]->token;
  292. EXIT:
  293. if (nullptr != soap) {
  294. ONVIF_soap_delete(soap);
  295. }
  296. return result;
  297. }
  298. /************************************************************************
  299. **函数:ONVIF_GetSnapshotUri
  300. **功能:获取设备图像抓拍地址(HTTP)
  301. **参数:
  302. [in] MediaXAddr - 媒体服务地址
  303. [in] ProfileToken - the media profile token
  304. [out] uri - 返回的地址
  305. [in] sizeuri - 地址缓存大小
  306. **返回:
  307. 0表明成功,非0表明失败
  308. **备注:
  309. 1). 并非所有的ProfileToken都支持图像抓拍地址。举例:XXX品牌的IPC有如下三个配置profile0/profile1/TestMediaProfile,其中TestMediaProfile返回的图像抓拍地址就是空指针。
  310. ************************************************************************/
  311. int ONVIF_GetSnapshotUri(const std::string& MediaXAddr, const std::string& ProfileToken, std::string * snapUri)
  312. {
  313. int result = 0;
  314. struct soap *soap = nullptr;
  315. _trt__GetSnapshotUri req;
  316. _trt__GetSnapshotUriResponse rep;
  317. SOAP_ASSERT(!MediaXAddr.empty() && !ProfileToken.empty());
  318. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  319. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  320. req.ProfileToken = const_cast<char *>(ProfileToken.c_str());
  321. result = soap_call___trt__GetSnapshotUri(soap, MediaXAddr.c_str(), nullptr, &req, rep);
  322. SOAP_CHECK_ERROR(result, soap, "GetSnapshotUri");
  323. if (nullptr != rep.MediaUri && nullptr != rep.MediaUri->Uri) {
  324. *snapUri = rep.MediaUri->Uri;
  325. }
  326. EXIT:
  327. if (NULL != soap) {
  328. ONVIF_soap_delete(soap);
  329. }
  330. return result;
  331. }
  332. // 获取当前ptz的位置以及状态
  333. int ONVIF_PTZ_GetStatus(const std::string& ptzXAddr, const std::string& ProfileToken){
  334. int result = 0;
  335. struct soap *soap = nullptr;
  336. _tptz__GetStatus getStatus;
  337. _tptz__GetStatusResponse getStatusResponse;
  338. SOAP_ASSERT(!ptzXAddr.empty());
  339. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  340. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  341. getStatus.ProfileToken = const_cast<char *>(ProfileToken.c_str());
  342. result = soap_call___tptz__GetStatus(soap, ptzXAddr.c_str(), nullptr, &getStatus, getStatusResponse);
  343. SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZ_GetStatus");
  344. if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__IDLE){
  345. std::cout << " 空闲 ... " << std::endl;
  346. }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__MOVING){
  347. std::cout << " 移动中 ... " << std::endl;
  348. }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__UNKNOWN){
  349. std::cout << " 未知 ... " << std::endl;
  350. }
  351. std::cout << "当前p: " <<getStatusResponse.PTZStatus->Position->PanTilt->x << "\n";
  352. std::cout << "当前t: " << getStatusResponse.PTZStatus->Position->PanTilt->y << "\n";
  353. std::cout << "当前z: " << getStatusResponse.PTZStatus->Position->Zoom->x << "\n";
  354. EXIT:
  355. if (nullptr != soap) {
  356. ONVIF_soap_delete(soap);
  357. }
  358. return 0;
  359. }
  360. // 以指定速度移动到指定位置的ptz
  361. // p : -1 ~ 1 []
  362. // t : -1 ~ 1
  363. // z : 0 ~ 1
  364. int ONVIF_PTZAbsoluteMove(const std::string& ptzXAddr, const std::string& ProfileToken){
  365. int result = 0;
  366. struct soap *soap = nullptr;
  367. _tptz__AbsoluteMove absoluteMove;
  368. _tptz__AbsoluteMoveResponse absoluteMoveResponse;
  369. SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
  370. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  371. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  372. absoluteMove.ProfileToken = const_cast<char *>(ProfileToken.c_str());
  373. absoluteMove.Position = soap_new_tt__PTZVector(soap);
  374. absoluteMove.Position->PanTilt = soap_new_tt__Vector2D(soap);
  375. absoluteMove.Position->Zoom = soap_new_tt__Vector1D(soap);
  376. absoluteMove.Speed = soap_new_tt__PTZSpeed(soap);
  377. absoluteMove.Speed->PanTilt = soap_new_tt__Vector2D(soap);
  378. absoluteMove.Speed->Zoom = soap_new_tt__Vector1D(soap);
  379. absoluteMove.Position->PanTilt->x = 0.440833; // p
  380. absoluteMove.Position->PanTilt->y = 0.583455; // t
  381. absoluteMove.Position->Zoom->x = 0.0333333; // z
  382. // x 和y的绝对值越接近1,表示云台的速度越快
  383. absoluteMove.Speed->PanTilt->x = 0.5;
  384. absoluteMove.Speed->PanTilt->y = 0.5;
  385. absoluteMove.Speed->Zoom->x = 0.5;
  386. result = soap_call___tptz__AbsoluteMove(soap,ptzXAddr.c_str(), nullptr,&absoluteMove,absoluteMoveResponse);
  387. SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZAbsoluteMove");
  388. EXIT:
  389. if (nullptr != soap) {
  390. ONVIF_soap_delete(soap);
  391. }
  392. return 0;
  393. }
  394. int ONVIF_PTZStopMove(const std::string& ptzXAddr, const std::string& ProfileToken){
  395. int result = 0;
  396. struct soap *soap = nullptr;
  397. _tptz__Stop tptzStop;
  398. _tptz__StopResponse tptzStopResponse;
  399. SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
  400. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  401. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  402. tptzStop.ProfileToken = const_cast<char *>(ProfileToken.c_str());
  403. result = soap_call___tptz__Stop(soap, ptzXAddr.c_str(), nullptr, &tptzStop, tptzStopResponse);
  404. SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZStopMove");
  405. EXIT:
  406. if (nullptr != soap) {
  407. ONVIF_soap_delete(soap);
  408. }
  409. return result;
  410. }
  411. enum PTZCMD
  412. {
  413. PTZ_CMD_LEFT,
  414. PTZ_CMD_RIGHT,
  415. PTZ_CMD_UP,
  416. PTZ_CMD_DOWN,
  417. PTZ_CMD_LEFTUP,
  418. PTZ_CMD_LEFTDOWN,
  419. PTZ_CMD_RIGHTUP,
  420. PTZ_CMD_RIGHTDOWN,
  421. PTZ_CMD_ZOOM_IN,
  422. PTZ_CMD_ZOOM_OUT,
  423. };
  424. // speed --> (0, 1]
  425. int ONVIF_PTZContinuousMove(const std::string& ptzXAddr, const std::string& ProfileToken, enum PTZCMD cmd, float speed){
  426. int result = 0;
  427. struct soap *soap = nullptr;
  428. _tptz__ContinuousMove continuousMove;
  429. _tptz__ContinuousMoveResponse continuousMoveResponse;
  430. SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
  431. SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));
  432. ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
  433. continuousMove.ProfileToken = const_cast<char *>(ProfileToken.c_str());
  434. continuousMove.Velocity = soap_new_tt__PTZSpeed(soap);
  435. continuousMove.Velocity->PanTilt = soap_new_tt__Vector2D(soap);
  436. continuousMove.Velocity->Zoom = soap_new_tt__Vector1D(soap);
  437. switch (cmd)
  438. {
  439. case PTZ_CMD_LEFT:
  440. continuousMove.Velocity->PanTilt->x = -speed;
  441. continuousMove.Velocity->PanTilt->y = 0;
  442. break;
  443. case PTZ_CMD_RIGHT:
  444. continuousMove.Velocity->PanTilt->x = speed;
  445. continuousMove.Velocity->PanTilt->y = 0;
  446. break;
  447. case PTZ_CMD_UP:
  448. continuousMove.Velocity->PanTilt->x = 0;
  449. continuousMove.Velocity->PanTilt->y = speed;
  450. break;
  451. case PTZ_CMD_DOWN:
  452. continuousMove.Velocity->PanTilt->x = 0;
  453. continuousMove.Velocity->PanTilt->y = -speed;
  454. break;
  455. case PTZ_CMD_LEFTUP:
  456. continuousMove.Velocity->PanTilt->x = -speed;
  457. continuousMove.Velocity->PanTilt->y = speed;
  458. break;
  459. case PTZ_CMD_LEFTDOWN:
  460. continuousMove.Velocity->PanTilt->x = -speed;
  461. continuousMove.Velocity->PanTilt->y = -speed;
  462. break;
  463. case PTZ_CMD_RIGHTUP:
  464. continuousMove.Velocity->PanTilt->x = speed;
  465. continuousMove.Velocity->PanTilt->y = speed;
  466. break;
  467. case PTZ_CMD_RIGHTDOWN:
  468. continuousMove.Velocity->PanTilt->x = speed;
  469. continuousMove.Velocity->PanTilt->y = -speed;
  470. break;
  471. case PTZ_CMD_ZOOM_IN:
  472. continuousMove.Velocity->PanTilt->x = 0;
  473. continuousMove.Velocity->PanTilt->y = 0;
  474. continuousMove.Velocity->Zoom->x = speed;
  475. break;
  476. case PTZ_CMD_ZOOM_OUT:
  477. continuousMove.Velocity->PanTilt->x = 0;
  478. continuousMove.Velocity->PanTilt->y = 0;
  479. continuousMove.Velocity->Zoom->x = -speed;
  480. break;
  481. default:
  482. break;
  483. }
  484. // 也可以使用soap_call___tptz__RelativeMove实现
  485. result = soap_call___tptz__ContinuousMove(soap,ptzXAddr.c_str(), nullptr,&continuousMove,continuousMoveResponse);
  486. SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZAbsoluteMove");
  487. /* sleep(1); //如果当前soap被删除(或者发送stop指令),就会停止移动
  488. ONVIF_PTZStopMove(ptzXAddr, ProfileToken);*/
  489. EXIT:
  490. if (nullptr != soap) {
  491. ONVIF_soap_delete(soap);
  492. }
  493. return result;
  494. }
  495. void cb_discovery(char *deviceXAddr)
  496. {
  497. std::string ptzXAddr, profilesToken, snapUri, snapAuthUri;
  498. ONVIF_GetCapabilities(deviceXAddr, &ptzXAddr);
  499. ONVIF_GetProfiles(ptzXAddr, &profilesToken);
  500. // ONVIF_PTZ_GetStatus(ptzXAddr, profilesToken);
  501. // ONVIF_PTZAbsoluteMove(ptzXAddr, profilesToken);
  502. ONVIF_PTZContinuousMove(ptzXAddr, profilesToken, PTZ_CMD_LEFTUP, 0.3);
  503. }
  504. int main(int argc, char **argv)
  505. {
  506. ONVIF_DetectDevice(cb_discovery);
  507. return 0;
  508. }

Onvif协议客户端开发(8)–球机云台的控制
ONVIF PTZ云台控制–RelativeMove
初学小结使用Onvif协议进行PTZ控制
Onvif PTZ简介
使用Onvif协议进行设备PTZ云台控制
ONVIF PTZ控制

发表评论

表情:
评论列表 (有 0 条评论,1332人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Onvif协议:什么是Onvif

    0.为什么要搞ONVIF 最近在做一个视频推流的项目,其中去要获取摄像头的视频流,开始什么也不懂,在网上查资料,原来是使用ffmpeg通过一个叫url的东东来拉去视频流,