4.onvif获取设备能力-GetCapabilities

onvif获取设备能力-GetCapabilities

  • 1.函数说明
  • 2.重新构建工程
    • 2.1 生成onvif.h头文件
    • 2.2 生成源文件
  • openssl
  • makefile

我们成功进行probe后,就得到了设备的web server地址,然后就可以根据这个地址来获取设备能力,设备能力包括,

  • Analytics
  • Device
  • Event
  • Imaging
  • Media
  • PTZ

1.函数说明

这里我们的目的是获取RTSP,就是Media能力,代码中提供的函数为

SOAP_FMAC5 int SOAP_FMAC6 soap_call___tds__GetCapabilities(struct soap *soap, 
//设备server地址,就是我们上一步获取到的http://10.0.0.47/onvif/device_service
const char *soap_endpoint, 
//actoin字段,填写NULL会使用默认
const char *soap_action, 
//获取能力请求结构体
struct _tds__GetCapabilities *tds__GetCapabilities, 
//获取能力应答结构体
struct _tds__GetCapabilitiesResponse *tds__GetCapabilitiesResponse)

struct _tds__GetCapabilities
{
	int __sizeCategory;	/* sequence of elements  */
	enum tt__CapabilityCategory *Category;	/* optional element of type tt:CapabilityCategory */
};

enum tt__CapabilityCategory { 
tt__CapabilityCategory__All = 0, 
tt__CapabilityCategory__Analytics = 1, 
tt__CapabilityCategory__Device = 2,
 tt__CapabilityCategory__Events = 3, 
 tt__CapabilityCategory__Imaging = 4, 
 tt__CapabilityCategory__Media = 5, 
 tt__CapabilityCategory__PTZ = 6 };

2.重新构建工程

由于这次要加上新的功能,所以工程代码需要重新生成

2.1 生成onvif.h头文件

还是用脚本来生成代码,一下为脚本内容

 #!/bin/bash

mkdir onvif_head
cd onvif_head

../bin/wsdl2h -o onvif.h -c -s -d -x  -t ../gsoap/WS/typemap.dat \
http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl \
http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl \
http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl \
http://www.onvif.org/onvif/ver10/search.wsdl \
http://www.onvif.org/onvif/ver10/schema/onvif.xsd \
http://www.onvif.org/ver10/pacs/types.xsd

再生成的onvif.h中添加#import "wsse.h"

新添加命令参数说明

  • -d:-d use DOM to populate xs:any, xs:anyType, and xs:anyAttribute,解决SOAP-TYP问题
  • -x:-x don’t generate _XML any/anyAttribute extensibility elements

2.2 生成源文件

脚本如下

#!/bin/bash
DIR=soap
mkdir $DIR
cd $DIR
 ../bin/soapcpp2 -2 -c ../onvif_head/onvif.h  -L -I ../gsoap/import -I ../gsoap/

工程模板已经再前面做过了,就不再重复,接下来的任务就是编写代码,接下来的几篇博客的里的函数都是可以单独调用的,再前面说写的probe成功后,调用该代码

//soap_endpoint:probe后获得的http://10.0.0.47/onvif/device_service
 bool  get_capabilities(struct soap * soap, const char * soap_endpoint)
 {
	 bool bret = false;
	 int ret = 0;
	 struct _tds__GetCapabilities get_cap_req;
	 struct _tds__GetCapabilitiesResponse get_cap_resp;
	 //选择获取media能力
	 enum tt__CapabilityCategory temp_category = tt__CapabilityCategory__Media;
	 get_cap_req.__sizeCategory = 1;
	 get_cap_req.Category = &temp_category;
 
	 ret = soap_call___tds__GetCapabilities(soap, soap_endpoint, NULL, &get_cap_req, &get_cap_resp);
	 if(ret == -1)
	 {
		 printf("get capabilities error: %d, %s, %s \n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
		 ret = soap->error;
		 bret = false;
	 }
	 else
	 {
		 if(get_cap_resp.Capabilities == NULL)
		 {
			 printf("Capabilities is NULL: %d, %s, %s \n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
			 bret = false;
		 }
		 else
		 {
			 printf("get capabilities ok! result = %d \n", ret);
			 //获得Media地址http://10.0.0.47/onvif/Media,各个厂家的地址不同
			 printf("Media XAddr = %s \n", get_cap_resp.Capabilities->Media->XAddr);
			 bret = true;
		 }
	 }
	 soap_end(soap);
	 return bret;
 }

注意,这里需要鉴权
调用函数为

soap_wsse_add_UsernameTokenDigest(soap, NULL, "admin", "admin");

一下为main函数

int main(int argc, char *argv[])
{
	struct soap * soap;

	//发送消息描述
	struct wsdd__ProbeType req;
	//消息应答
	struct __wsdd__ProbeMatches resp;

	//描述查找哪类的web消息
	struct wsdd__ScopesType sScope;

	//soap 消息头
	struct SOAP_ENV__Header header;
	//搜索到的设备个数
	int count = 0;
	int ret;
	char *uuid_string;

	soap = soap_new();
	if(soap == NULL)
	{
		printf("malloc soap error \n");

		return -1;
	}

	//设置命名空间,就是xml文件的头
	soap_set_namespaces(soap, namespaces);
	//超出5s没数据就推出,超时时间
	soap->recv_timeout = 5;
	soap->accept_timeout = 5;
	//将header设置为soap消息,头属性,暂且认为是soap和header绑定
	soap_default_SOAP_ENV__Header(soap, &header);

	
	uuid_string = soap_wsa_rand_uuid(soap);
	if(uuid_string == NULL)
	{
		printf("uuid error \n");

		return -1;
	}
	
	
	printf("uuid = %s \n", uuid_string);
	header.wsa__MessageID = uuid_string;
	header.wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
	//header.wsa__Action = "http://schemas.xmllocal_soap.org/ws/2005/04/discovery/Probe";
	header.wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
	soap->header = &header;

	//设置soap消息的请求服务属性
	soap_default_wsdd__ScopesType(soap, &sScope);
	sScope.__item = "onvif://www.onvif.org";
	soap_default_wsdd__ProbeType(soap, &req);
	req.Scopes = &sScope;
	req.Types = "ns1:NetworkVideoTransmitter";

	ret = soap_send___wsdd__Probe(soap,	"soap.udp://239.255.255.250:3702/", NULL, &req);
	printf("ret = %d \n", ret);
	if(ret == -1)
	{
		printf("soap error: %d, %s, %s \n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
		ret = soap->error;
	}
	else
	{
		do
		{
			
			printf("%s: %d, begin receive probematch... \n", __FUNCTION__, __LINE__);
			printf("count = %d \n", count);

			ret = soap_recv___wsdd__ProbeMatches(soap, &resp);
			printf("ret = %d \n", ret);

			if(ret == -1)
			{
				printf("find %d devcies ! \n", count);
				break;
			}
			else
			{
				//读取服务器回应的Probematch消息
				if(resp.wsdd__ProbeMatches->__sizeProbeMatch == 0)
					break;
				printf("soap_recv___wsdd__Probe: __sizeProbeMatch = %d \n", resp.wsdd__ProbeMatches->__sizeProbeMatch);
				printf("Target EP Address : %s \n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
				printf("Target Type : %s \n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
				printf("Target Service Address : %s \n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
				printf("Target Metadata Version: %d \n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
				printf("Target Scope Address : %s \n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item);	
				count++;
				
				soap_wsse_add_UsernameTokenDigest(soap, NULL, "admin", "Xf900411");
				get_capabilities(soap, "http://10.0.0.47/onvif/device_service");	
			}
		}while(1);
	}
	// clean up and remove deserialized data
	soap_end(soap);
	//detach and free runtime context
	soap_free(soap);
	return ret;
}

openssl

使用鉴权,就得使用openssl,如果没有安装的话需要安装

  • sudo apt-get install openssl
  • sudo apt-get install libssl-dev

makefile

CC = gcc 
CFLAGS := -Wall  -O2 -g -DWITH_NONAMESPACES -DWITH_DOM -DWITH_OPENSSL -lcrypto -lssl
CFLAGS += -I ./
#LDFLAGS := -lcrypto -lssl

#-DWITH_OPENSSL
CLIENT_OBJS = soapC.o \
duration.o \
stdsoap2.o \
soapClient.o \
dom.o \
wsseapi.o \
smdevp.o \
mecevp.o \
threads.o \
wsaapi.o \
main.o

client:$(CLIENT_OBJS)
	$(CC) -o client $(CLIENT_OBJS) $(CFLAGS)
	
clean:
	rm -f client *.o
	

码云地址
CSDN下载地址

你可能感兴趣的:(ONVIF)