我们成功进行probe后,就得到了设备的web server
地址,然后就可以根据这个地址来获取设备能力,设备能力包括,
这里我们的目的是获取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 };
由于这次要加上新的功能,所以工程代码需要重新生成
还是用脚本来生成代码,一下为脚本内容
#!/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"
新添加命令参数说明
脚本如下
#!/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,如果没有安装的话需要安装
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下载地址