Onvif协议:IPC客户端开发之获取实时预览的Url地址

您所在的位置:网站首页 onvif下载 Onvif协议:IPC客户端开发之获取实时预览的Url地址

Onvif协议:IPC客户端开发之获取实时预览的Url地址

2024-01-23 17:10| 来源: 网络整理| 查看: 265

介绍

Onvif协议对前端摄像头的取流是通过标准Rtsp协议,因此我们就需要通过Onvif协议获取到需要预览摄像头的Rtsp的地址,将拿到的RTSP通过VLC或者其他的RTSP客户端取流预览前端摄像头。

编码流程 通过「设备发现」,得到 「设备服务地址」。使用「设备服务地址」调用GetCapabilities接口,得到「媒体服务地址」。使用「媒体服务地址」调用GetProfiles接口,得到主次码流的「媒体配置信息」,其中包含ProfileToken根据获取到的token调用对应的接口获取到RTSP地址

注:获取的token包含了主码流、辅码流的token已经各种配置的token,可以根据自己需要自取;根据主、辅码流的toekn获取到的是对应主、辅码流的RTSP地址。主、辅码流的RTSP地址不同,但是差异可能不大。

获取到uri之后我们就看用opencv或者ffmeg之类的看实时视频了

实践

步骤同此一样

main.cpp改成

#include #include "soapH.h" #include "wsdd.nsmap" #include "soapStub.h" #include "wsseapi.h" #include "wsaapi.h" #include #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规定的组播地址 #define SOAP_ITEM "" // 寻找的设备范围 #define SOAP_TYPES "dn:NetworkVideoTransmitter" // 寻找的设备类型 #define SOAP_SOCK_TIMEOUT (10) // socket超时时间(单秒秒) 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环境变量 SOAP_ASSERT(nullptr != (soap = soap_new())); soap_set_namespaces(soap, namespaces); // 设置soap的namespaces soap->recv_timeout = timeout; // 设置超时(超过指定时间没有数据就退出) 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 #endif soap_set_mode(soap, SOAP_C_UTFSTRING); // 设置为UTF-8编码,否则叠加中文OSD会乱码 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 data soap_done(soap); // Reset, close communications, and remove callbacks soap_free(soap); // Reset and deallocate the context created with soap_new or soap_copy } /************************************************************************ **函数:ONVIF_init_header **功能:初始化soap描述消息头 **参数: [in] soap - soap环境变量 **返回:无 **备注: 1). 在本函数内部通过ONVIF_soap_malloc分配的内存,将在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; } /************************************************************************ **函数:ONVIF_init_ProbeType **功能:初始化探测设备的范围和类型 **参数: [in] soap - soap环境变量 [out] probe - 填充要探测的设备范围和类型 **返回: 0表明探测到,非0表明未探测到 **备注: 1). 在本函数内部通过ONVIF_soap_malloc分配的内存,将在ONVIF_soap_delete中被释放 ************************************************************************/ void ONVIF_init_ProbeType(struct soap *soap, struct wsdd__ProbeType *probe) { struct wsdd__ScopesType *scope = nullptr; // 用于描述查找哪类的Web服务 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); // 设置寻找设备的范围 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); // 设置寻找设备的类型 strcpy(probe->Types, SOAP_TYPES); } void ONVIF_DetectDevice(void (*cb)(char *DeviceXAddr)) { int i; int result = 0; unsigned int count = 0; // 搜索到的设备个数 struct soap *soap = nullptr; // soap环境变量 struct wsdd__ProbeType req; // 用于发送Probe消息 struct __wsdd__ProbeMatches rep; // 用于接收Probe应答 struct wsdd__ProbeMatchType *probeMatch; SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT))); ONVIF_init_header(soap); // 设置消息头描述 ONVIF_init_ProbeType(soap, &req); // 设置寻找的设备的范围和类型 result = soap_send___wsdd__Probe(soap, SOAP_MCAST_ADDR, nullptr, &req); // 向组播地址广播Probe消息 while (SOAP_OK == result) // 开始循环接收设备发送过来的消息 { memset(&rep, 0x00, sizeof(rep)); result = soap_recv___wsdd__ProbeMatches(soap, &rep); if (SOAP_OK == result) { if (soap->error) { soap_perror(soap, "ProbeMatches"); } else { // 成功接收到设备的应答消息 // printf("__sizeProbeMatch:%d\n",rep.wsdd__ProbeMatches->__sizeProbeMatch); if (nullptr != rep.wsdd__ProbeMatches) { count += rep.wsdd__ProbeMatches->__sizeProbeMatch; for(i = 0; i __sizeProbeMatch; i++) { probeMatch = rep.wsdd__ProbeMatches->ProbeMatch + i; if (nullptr != cb ) { std::string url = probeMatch->XAddrs; if(url == "http://192.168.0.116/onvif/device_service"){ cb(probeMatch->XAddrs); // 使用设备服务地址执行函数回调 } } } } } } 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) /************************************************************************ **函数:ONVIF_SetAuthInfo **功能:设置认证信息 **参数: [in] soap - soap环境变量 [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; } #define USERNAME "admin" #define PASSWORD "hik12345" /************************************************************************ **函数:ONVIF_GetDeviceInformation **功能:获取设备基本信息 **参数: [in] DeviceXAddr - 设备服务地址 **返回: 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 int result = 0; struct soap *soap = nullptr; _trt__GetSnapshotUri req; _trt__GetSnapshotUriResponse rep; SOAP_ASSERT(!MediaXAddr.empty() && !ProfileToken.empty()); SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT))); ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD); req.ProfileToken = const_cast(ProfileToken.c_str()); result = soap_call___trt__GetSnapshotUri(soap, MediaXAddr.c_str(), NULL, &req, rep); SOAP_CHECK_ERROR(result, soap, "GetSnapshotUri"); if (nullptr != rep.MediaUri && nullptr != rep.MediaUri->Uri) { *snapUri = rep.MediaUri->Uri; } EXIT: if (NULL != soap) { ONVIF_soap_delete(soap); } return result; } bool ONVIF_GetProfiles(const std::string& mediaXAddr, std::string * profilesToken) { int result = 0; struct soap *soap = nullptr; _trt__GetProfiles devinfo_req; _trt__GetProfilesResponse devinfo_resp; SOAP_ASSERT(!mediaXAddr.empty()); SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT))); ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD); result = soap_call___trt__GetProfiles(soap, mediaXAddr.c_str(), nullptr, &devinfo_req, devinfo_resp); SOAP_CHECK_ERROR(result, soap, "ONVIF_GetProfiles"); SOAP_ASSERT(devinfo_resp.__sizeProfiles > 0); *profilesToken = (*devinfo_resp.Profiles)->token; EXIT: if (nullptr != soap) { ONVIF_soap_delete(soap); } return result; } /************************************************************************ **函数:ONVIF_GetCapabilities **功能:获取设备能力信息 **参数: [in] DeviceXAddr - 设备服务地址 [in] **返回: 0表明成功,非0表明失败 **备注: 1). 其中最主要的参数之一是媒体服务地址 ************************************************************************/ int ONVIF_GetCapabilities(const std::string& deviceXAddr, std::string * mediaXAddr) { int result = 0; struct soap *soap = nullptr; _tds__GetCapabilities devinfo_req; _tds__GetCapabilitiesResponse devinfo_resp; SOAP_ASSERT(!deviceXAddr.empty()); SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT))); result = soap_call___tds__GetCapabilities(soap, deviceXAddr.c_str(), NULL, &devinfo_req, devinfo_resp); SOAP_CHECK_ERROR(result, soap, "GetCapabilities"); if(devinfo_resp.Capabilities->Media != nullptr){ *mediaXAddr = devinfo_resp.Capabilities->Media->XAddr; } EXIT: if (nullptr != soap) { ONVIF_soap_delete(soap); } return result; } /************************************************************************ **函数:make_uri_withauth **功能:构造带有认证信息的URI地址 **参数: [in] src_uri - 未带认证信息的URI地址 [in] username - 用户名 [in] password - 密码 [out] dest_uri - 返回的带认证信息的URI地址 [in] size_dest_uri - dest_uri缓存大小 **返回: 0成功,非0失败 **备注: 1). 例子: 无认证信息的uri:rtsp://100.100.100.140:554/av0_0 带认证信息的uri:rtsp://username:[email protected]:554/av0_0 ************************************************************************/ static int make_uri_withauth(const std::string& src_uri, const std::string&username, const std::string&password, std::string *dest_uri) { int result = 0; SOAP_ASSERT(!src_uri.empty()); if (username.empty() &&password.empty()) { // 生成新的uri地址 *dest_uri = src_uri; } else { std::string::size_type position = src_uri.find("//"); if (std::string::npos == position) { SOAP_DBGERR("can't found '//', src uri is: %s.\n", src_uri.c_str()); result = -1; return result; } position += 2; dest_uri->append(src_uri,0, position) ; dest_uri->append(username + ":" + password + "@"); dest_uri->append(src_uri,position, std::string::npos) ; } return result; } /************************************************************************ **函数:ONVIF_GetStreamUri **功能:获取设备码流地址(RTSP) **参数: [in] MediaXAddr - 媒体服务地址 [in] ProfileToken - the media profile token **返回: 0表明成功,非0表明失败 **备注: ************************************************************************/ int ONVIF_GetStreamUri(const std::string&MediaXAddr, const std::string&ProfileToken) { int result = 0; struct soap *soap = nullptr; tt__StreamSetup ttStreamSetup; tt__Transport ttTransport; _trt__GetStreamUri req; _trt__GetStreamUriResponse rep; SOAP_ASSERT(!MediaXAddr.empty()); SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT))); ttStreamSetup.Stream = tt__StreamType__RTP_Unicast; ttStreamSetup.Transport = &ttTransport; ttStreamSetup.Transport->Protocol = tt__TransportProtocol__RTSP; ttStreamSetup.Transport->Tunnel = nullptr; req.StreamSetup = &ttStreamSetup; req.ProfileToken = const_cast(ProfileToken.c_str()); ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD); result = soap_call___trt__GetStreamUri(soap, MediaXAddr.c_str(), nullptr, &req, rep); SOAP_CHECK_ERROR(result, soap, "GetServices"); if (nullptr != rep.MediaUri) { if (nullptr != rep.MediaUri->Uri) { std::cout std::string mediaXAddr, profilesToken, snapUri, snapAuthUri; ONVIF_GetCapabilities(deviceXAddr, &mediaXAddr); ONVIF_GetProfiles(mediaXAddr, &profilesToken); ONVIF_GetStreamUri(mediaXAddr, profilesToken); /* ONVIF_GetSnapshotUri(mediaXAddr, profilesToken, &snapUri); make_uri_withauth(snapUri, USERNAME, PASSWORD, &snapAuthUri); char cmd[256]; sprintf(cmd, "wget -O %s '%s'", "out.jpeg", snapAuthUri.c_str()); // 使用wget下载图片 system(cmd);*/ } int main(int argc, char **argv) { ONVIF_DetectDevice(cb_discovery); return 0; }

opencv代码打开请参考 在这里插入图片描述

其他文章 Onvif协议:理解什么是Web ServicesOnvif协议:使用gSOAP创建SOAP调用实例Onvif协议:门外汉理解ONVIF协议Onvif协议:到底什么是ONVIF协议Onvif协议:实现Probe命令来进行设备发现(discover)Onvif协议:IPC客户端开发之获取设备基本信息Onvif协议:IPC客户端开发之鉴权Onvif协议:IPC客户端开发之获取设备能力Onvif协议:IPC客户端开发之PTZ控制Onvif协议:IPC客户端开发之获取实时预览的Url地址Onvif协议:IPC客户端开发之图像抓拍ONVIF Device Test Tool测试工具使用方法


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3