onvif基础框架搭建与简单开发

Onvif基础框架搭建

第一步、下载gsoap

    从gsoap官网(http://www.genivia.com/products.html#notice)下载最新版gsoap(博主用的是gsoap_2.8.46)。gsoap有三个版本:Open Source gSOAP、Commercial gSOAP Edition、Commercial gSOAP Edition。我们下载开源版本即可。

    这是博主分享的gsoap下载链接:链接:http://pan.baidu.com/s/1mi2tWLy 密码: rpms

第二步、下载所有wsdl与xsd

    从onvif官网(https://www.onvif.org/profiles/specifications/)下载所有wsdl与xsd(右键-将链接另存为即可)

    这是博主分享的wsdl与xsd链接:http://pan.baidu.com/s/1o8hrjWe 密码: 9gqm

第三步、解压gsoap并建立文件夹层次

   新建一个文件夹,命名为OnvifFramework,将下载下来的gsoap_x.x.xx.zip解压到该文件夹。在该文件夹下再新建两个文件夹,分别命名为:level1和ver10。在level1文件夹下新建一个文件夹,命名为:level2。在level2文件夹下新建三个文件夹,分别命名为:FrameworkSource、GenerateSource、ver10。在ver10文件夹下建立三个文件夹,分别命名为:device、media、schema。在device和media文件夹下新建一个文件夹,命名为wsdl。在ver10文件夹下新建一个文件夹,命名为schema。文件夹请务必按这个顺序建立。最后将OnvifFramework\gsoap-2.8\gsoap路径下的typemap.dat和OnvifFramework\gsoap-2.8\gsoap\bin\win32路径下的wsdl2h.exe、soapcpp2.exe拷贝到GenerateSource文件夹下。

    具体文件夹层次结构如下图所示:


第四步、下载Onvif相关文件

    从Onvif官网(http://www.onvif.org/Documents/Specifications.aspx)的ONVIF WSDL and XML Schemas Specifications页面中下载wsdl(右键-将链接另存为即可),并将下载下来的wsdl放在GenerateSource文件夹内。拷贝devicemgmt.wsdl到D:\ONVIF\OnvifFramework\level1\level2\ver10\device\wsdl路径下,拷贝media.wsdl到OnvifFramework\level1\level2\ver10\media\wsdl路径下,拷贝所有xsd到OnvifFramework\level1\level2\ver10\schema与OnvifFramework\ver10\schema路径下。

第五步、生成onvif.h

   生成方式分为在线生成和本地生成两种,鉴于在线生成的不稳定性,博主采用本地生成方式。打开控制台,切换到GenerateSource路径下,在控制台中输入wsdl2h -x -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl
;因为我只用到了媒体相关部分,所以只用了这两个wsdl,如果需要其他的,后面加上即可
(各个wsdl间用一个空格隔开)

第六步、通过onvif.h文件生成源代码框架

     修改xsd和wsdl中的schemaLocation为本地路径(仅部分wsdl需要修改),将 OnvifFramework\gsoap-2.8\gsoap\import路径下的wsa5.h中的SOAP_ENV__Fault结构体注释掉或改为其他名字,如 SOAP_ENV__Fault_ex。修改完后在控制台中输入soapcpp2 -c onvif.h -x -d .\ -I..\..\..\gsoap-2.8\gsoap\import -I ..\..\..\gsoap-2.8\gsoap\,看到Compilation successful即为成功。

第七步、整理源代码

   将生成的.h和.cpp、.c文件以及.cnsmap文件拷贝到FrameworkSource中,并拷贝OnvifFramework\gsoap-2.8\gsoap路径下的stdsoap2.h和stdsoap2.cpp到该文件夹。还需要拷贝OnvifFramework\gsoap-2.8\gsoap\custom路径下的duration.h和duration.c到该文件下

总结

   通过以上七个步骤即可完成ONVIF开发框架搭建,以后开发Onvif应用时,直接拷贝FrameworkSource文件夹中的文件即可。Onvif框架文件已上传,请到此处(链接:http://pan.baidu.com/s/1ge2nXRX 密码: 1say)下载。

   onvif开发必备资料链接:

https://www.onvif.org/onvif/ver20/util/operationIndex.html


Onvif简单开发

以下代码还不支持带验证的(需要把代码中的soap_wsse_add_UsernameTokenDigest加上,这部分需要加上gsoap其他源码),后续再补上,现在先上代码

#include "FrameworkSource/MediaBinding.nsmap"
#include "FrameworkSource/soapH.h"
#include "FrameworkSource/stdsoap2.h"

struct OnvifApp {
	char hostAddress[32];
	char xAddr[128];
	unsigned short bindPort;
	char xAddrRoot[128];
	struct soap *soap;
	SOAP_SOCKET masterSocket;
};
static struct OnvifApp *gApp = new struct OnvifApp();

int UserGetCapabilities(struct soap *soap, struct __wsdd__ProbeMatches *resp,
	struct _tds__GetCapabilities *capa_req, struct _tds__GetCapabilitiesResponse *capa_resp)
{
	int result = 0;

	capa_req->Category = (enum tt__CapabilityCategory *)soap_malloc(soap, sizeof(int));
	capa_req->__sizeCategory = 1;
	*(capa_req->Category) = (enum tt__CapabilityCategory)(tt__CapabilityCategory__Media);
	capa_resp->Capabilities = (struct tt__Capabilities*)soap_malloc(soap, sizeof(struct tt__Capabilities));

	//soap_wsse_add_UsernameTokenDigest(soap, "user", ONVIF_USER, ONVIF_PASSWORD);
	printf("\n--------------------Now Gettting Capabilities NOW --------------------\n\n");

	result = soap_call___tds__GetCapabilities(soap, "http://192.168.0.55/onvif/device_service", NULL, capa_req, capa_resp);

	if (soap->error)
	{
		printf("[%s][%d]--->>> soap error: %d, %s, %s\n", __func__, __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
		result = soap->error;
	}
	else
	{
		printf(" \n--------------------GetCapabilities  OK! result=%d--------------\n \n", result);
		if (capa_resp->Capabilities == NULL)
		{
			printf(" GetCapabilities  failed!  result=%d \n", result);
		}
		else
		{
			printf(" Media->XAddr=%s \n", capa_resp->Capabilities->Media->XAddr);
		}
	}
	return result;
}

int UserGetProfiles(struct soap *soap, struct _tds__GetCapabilitiesResponse *capa_resp, 
	struct _trt__GetProfiles *trt__GetProfiles, struct _trt__GetProfilesResponse *trt__GetProfilesResponse)
{
	int result = 0;

	printf("\n-------------------Getting Onvif Devices Profiles--------------\n\n");
	//soap_wsse_add_UsernameTokenDigest(soap, "user", ONVIF_USER, ONVIF_PASSWORD);
	result = soap_call___trt__GetProfiles(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetProfiles, trt__GetProfilesResponse);
	if (soap->error)
		//NOTE: it may be regular if result isn't SOAP_OK.Because some attributes aren't supported by server.
		//any question email leoluopy@gmail.com
	{
		printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
		result = soap->error;
	}
	else {
		printf("\n-------------------Profiles Get OK--------------\n\n");
		if (trt__GetProfilesResponse->Profiles != NULL)
		{
			if (trt__GetProfilesResponse->Profiles->Name != NULL) {
				printf("Profiles Name:%s  \n", trt__GetProfilesResponse->Profiles->Name);

			}
			if (trt__GetProfilesResponse->Profiles->token != NULL) {
				printf("Profiles Taken:%s\n", trt__GetProfilesResponse->Profiles->token);
			}
		}
		else {
			printf("Profiles Get inner Error\n");

		}
	}
	printf("Profiles Get Procedure over\n");
	return result;
}

int UserGetUri(struct soap *soap, struct _tds__GetCapabilitiesResponse *capa_resp, struct _trt__GetProfilesResponse *trt__GetProfilesResponse,
	struct _trt__GetStreamUri *trt__GetStreamUri, struct _trt__GetStreamUriResponse *trt__GetStreamUriResponse)
{
	int result = 0;

	trt__GetStreamUri->StreamSetup = (struct tt__StreamSetup*)soap_malloc(soap, sizeof(struct tt__StreamSetup));//初始化,分配空间
	trt__GetStreamUri->StreamSetup->Stream = tt__StreamType__RTP_Unicast;//stream type

	trt__GetStreamUri->StreamSetup->Transport = (struct tt__Transport *)soap_malloc(soap, sizeof(struct tt__Transport));//初始化,分配空间
	trt__GetStreamUri->StreamSetup->Transport->Protocol = tt__TransportProtocol__UDP;
	trt__GetStreamUri->StreamSetup->Transport->Tunnel = 0;
	//trt__GetStreamUri->StreamSetup->__size = 1;
	//trt__GetStreamUri->StreamSetup->__any = NULL;
	//trt__GetStreamUri->StreamSetup->__anyAttribute = NULL;

	trt__GetStreamUri->ProfileToken = trt__GetProfilesResponse->Profiles->token;

	printf("\n\n---------------Getting Uri----------------\n\n");

	//soap_wsse_add_UsernameTokenDigest(soap, "user", ONVIF_USER, ONVIF_PASSWORD);
	result = soap_call___trt__GetStreamUri(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetStreamUri, trt__GetStreamUriResponse);
	//rtsp://192.168.0.55:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif

	if (soap->error) {
		printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
		result = soap->error;
	}
	else {
		printf("!!!!NOTE: RTSP Addr Get Done is :%s \n", trt__GetStreamUriResponse->MediaUri->Uri);
	}
	return result;
}

int get(struct soap *soap)
{
	struct _tds__GetCapabilities capa_req;
	struct _tds__GetCapabilitiesResponse capa_resp;
	int ret = UserGetCapabilities(soap, NULL, &capa_req, &capa_resp);
	if (ret != 0)
		return ret;

	struct _trt__GetProfiles trt__GetProfile;
	struct _trt__GetProfilesResponse trt__GetProfileResponse;
	trt__GetProfileResponse.Profiles = NULL;
	ret = UserGetProfiles(soap, &capa_resp, &trt__GetProfile, &trt__GetProfileResponse);
	if (ret != 0)
		return ret;

	struct _trt__GetStreamUri trt__GetStreamUri;
	struct _trt__GetStreamUriResponse trt__GetStreamUriResponse;
	ret = UserGetUri(soap, &capa_resp, &trt__GetProfileResponse, &trt__GetStreamUri, &trt__GetStreamUriResponse);
	if (ret != 0)
		return ret;
	return ret;
}
int _gsoapInit(struct OnvifApp* app)
{
	if (!app->bindPort)
		app->bindPort = 80;
	strcpy(app->hostAddress, "192.168.0.55");
	snprintf(app->xAddr, sizeof(app->xAddr), "http://%s:%d/onvif/device_service",
		app->hostAddress, app->bindPort);
	fprintf(stderr, "xAddr:%s\n", app->xAddr);
	snprintf(app->xAddrRoot, sizeof(app->xAddrRoot), "http://%s:%d/onvif",
		app->hostAddress, app->bindPort);

	app->soap = soap_new();
	//soap_init2(app->soap, SOAP_ENC_MTOM | SOAP_ENC_MIME, 0);
	soap_set_namespaces(app->soap, namespaces);
	soap_set_recv_logfile(app->soap, "./log/recv.xml");
	soap_set_sent_logfile(app->soap, "./log/send.xml");
	soap_set_test_logfile(app->soap, "./log/test.log");
	app->soap->bind_flags = SO_REUSEADDR;
	app->soap->accept_timeout = 10;
	app->soap->recv_timeout = 10;
	app->soap->send_timeout = 10;
	app->soap->max_keep_alive = 30;
	app->masterSocket = soap_bind(app->soap, "0.0.0.0", app->bindPort, 100);
	if (app->masterSocket < 0) {
		soap_print_fault(app->soap, stderr);
		return -1;
	}

	get(app->soap);
	return 0;
}
int gsoapInit()
{
	return _gsoapInit(gApp);
}
int main(int argc, char *argv[])
{
	return gsoapInit();
}


在中UserGetUri中获取到rtsp如下:rtsp://192.168.0.55:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif。至此通过ip地址获取rtsp地址成功,接下来剩下rtsp对接,这部分以后再补上。

该地址是否可用可以用VLC验证:

1.打开VLC,在媒体按钮中点击【打开网络串流】。

2.输入获取到rtsp地址即可播放,视频能正确播放就成功了(再次申明目前不支持带验证的)



开发过程中遇到获取设备能力参数时发生错误得到soap->error=4,

解决办法:

1.在stdsoap2.cpp中找到soap_s2byte(struct soap *soap, const char *s, char *p)函数的实现,加上注释改为if (/*s == r || *r ||*/ n < -128 || n > 127)

2.在onvif.h生成时加入-x,这个博主已经在文中讲解过了

以下博客给予博主很大帮助,特此感谢:

http://blog.csdn.net/u011110151/article/details/51115225 ONVIF学习-ONVIF开发框架搭建(C++)
http://blog.csdn.net/bing87496988/article/details/38707829 关于onvif对接海康设备出现soap->error=4的问题
http://blog.csdn.net/gubenpeiyuan/article/details/25618177 ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值