2021-04-01

ONVIF使用总结

提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

ONVIF总结

设备发现

onvif的设备发现功能,做了好久,写了改,改了写,c语言版本,C++版本,它的核心接口:
1)发送组播消息:SOAP_FMAC5 int SOAP_FMAC6 soap_send___wsdd__Probe(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct wsdd__ProbeType *wsdd__Probe)。

2) 接收组播消息:SOAP_FMAC5 int SOAP_FMAC6 soap_recv___wsdd__ProbeMatches(struct soap *soap, struct __wsdd__ProbeMatches *_param_1)。

通过其参数不难看出,它的调用实际上也很简单;但是真正的难点是该接口涉及到的***UDP组播通信原理***;
通过gsoap生成的ONVIF源码,从某种程度上简化了,这个过程;因此在应用的过程中,经常会出现设备无法找到;尤其是本地网卡比较多的时候;
真正的想做好设备发现接口,一定好掌握UDP组播的工作原理;在实现本接口时,建议用传统的socket通信的实现,在接收的时候绑定本机IP;

建议:通过本方式获取IPC的返回信息,需要解析接收到的内容(xml),如果不依赖于开发工具,其解析有点麻烦;特备不同的厂家,xml在子节点上的定义也是一样的;因此,建议先用抓包工具,仔细分析下接收到的内容。

其核心代码如下:
int ret;
    SOAP_SOCKET s;
    SOAP_SOCKLEN_T len;
    char recv_buff[4096] = { 0 };
    sockaddr_in multi_addr;
    sockaddr_in client_addr;
    sockaddr_in bind_addr;
#ifdef WIN32
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {                             // 初始化Windows Sockets DLL
        printf("Could not open Windows connection.\n");
        return obj_ArrayList;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        printf("the version of WinSock DLL is not 2.2.\n");
        return obj_ArrayList;
    }
#endif
    s = socket(AF_INET, SOCK_DGRAM, 0);
    // 建立数据报套接字
    if (s < 0) {
        printf("socket init failed\n");
    }
    memset(&bind_addr,0,sizeof(bind_addr));
    char local_ip4[INET_ADDRSTRLEN] = {0};
    get_local_ip_using_create_socket(local_ip4);
    printf("local_ip4 ===================%s\n",local_ip4);

    bind_addr.sin_addr.s_addr = inet_addr(local_ip4);
    bind_addr.sin_family = AF_INET;
    bind_addr.sin_port = htons(0);

    if(bind(s,(struct sockaddr*)&bind_addr,sizeof(bind_addr))<0)
        printf("bind fail\n");
    multi_addr.sin_addr.s_addr = inet_addr(CAST_ADDR);
    multi_addr.sin_family = AF_INET;
    multi_addr.sin_port = htons(CAST_PORT);

    if(UDPsendMessage(multi_addr, s, probe) < 0)
    {
        SLEEP(1);
        UDPsendMessage(multi_addr, s, probe);
    }//发送UDP广播
    printf("Send Probe message to [%s:%d]\n\n", CAST_ADDR, CAST_PORT);
    unsigned long on = 1;
#if defined(__linux__) || defined(__linux)
    int flag = fcntl(s, F_GETFL, 0);
    if (flag < 0)
    {
        printf("fcntl failed.\n");
        exit(1);
    }
    flag |= O_NONBLOCK;
    if (fcntl(s, F_SETFL, flag) < 0)
    {
        printf("fcntl failed.\n");
        exit(1);
    }
#else
    int ReValue =ioctlsocket(s, FIONBIO, &on);
    printf("ioctlsocket === %d\n",ReValue);
#endif

    fd_set read_fdset;
    FD_ZERO(&read_fdset);
    FD_SET(s,&read_fdset);
    struct timeval timeout;
    timeout.tv_sec=5;
    timeout.tv_usec=0;
    for(;;)
    {
        ret=select(s+1,&read_fdset,NULL,NULL,&timeout);
        printf("select result is %d\n",ret);
        if(ret<=0)
            break;
        // 接收IPC的应答消息(ProbeMatch)
        len = sizeof(client_addr);
        memset(recv_buff, 0, sizeof(recv_buff));
        memset(&client_addr, 0, sizeof(sockaddr));
        ret = recvfrom(s, recv_buff, sizeof(recv_buff) - 1, 0, (struct sockaddr*)&client_addr, &len);
        printf("recvfrom ====%d\n",ret);
        if(ret < 0)
        {
            break;
        }else
        {
            printf("===Recv ProbeMatch from [%s:%d]===\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
            printf("===recv_buff===%s\n\n", recv_buff);
        }

设备属性相关

设备发现接口相当重要,通过它可以获得设备服务地址(deviceAddr),这个地址是实现ONVIF其他功能的基础。
设备能力接口:SOAP_FMAC5 int SOAP_FMAC6 soap_call___tds__GetCapabilities(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _tds__GetCapabilities *tds__GetCapabilities, struct _tds__GetCapabilitiesResponse *tds__GetCapabilitiesResponse)
配置信息:SOAP_FMAC5 int SOAP_FMAC6 soap_call___trt__GetProfiles(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _trt__GetProfiles *trt__GetProfiles, struct _trt__GetProfilesResponse *trt__GetProfilesResponse)
通过以上2个接口,基本上可以获取IPC的基本信息;

鉴权

ONVIF有点恶心,除了设备搜索不需要鉴权,其他的任何功能在调用前都的需要鉴权;说实在的没有鉴权,IPC对于有些人来说是裸着的,可以随便访问,甚至想干嘛就干嘛。
soap_wsse_add_UsernameTokenDigest(struct soap *soap, const char *id, const char *username, const char *password)。

音视频配置

相同的接口在不同的IPC上返回的结果也是不同的,不知道ONVIF协议是完整支持,还是部分支持。
其获取配置信息的流程如下:
1)获取设备服务地址;
2)调用获取设备能力接口,获取media地址;
3)  调用获取设备配置信息接口(mediaAddr作为参数)获取设备信息,记录token。此处设备信息,相当于总体上的概述;
4)视频配置接口:SOAP_FMAC5 int SOAP_FMAC6 soap_call___trt__GetVideoEncoderConfiguration(struct soap *soap, const char *soap_endpoint, const char *soap_action, _trt__GetVideoEncoderConfiguration *trt__GetVideoEncoderConfiguration, _trt__GetVideoEncoderConfigurationResponse &trt__GetVideoEncoderConfigurationResponse);
5)调用音频接口:SOAP_FMAC5 int SOAP_FMAC6 soap_call___trt__GetAudioEncoderConfiguration(struct soap *soap, const char *soap_endpoint, const char *soap_action, _trt__GetAudioEncoderConfiguration *trt__GetAudioEncoderConfiguration, _trt__GetAudioEncoderConfigurationResponse &trt__GetAudioEncoderConfigurationResponse);

修改音视频配置也是这些接口;
唯一要注意的是在实现某些功能时,需要多测试,不同厂家的IPC,接口返回是有差异的;

总结

《ONVIF2.0协议珍藏版》是值得仔细琢磨的,其中包含了接口的定义及功能说明;在做实际的应用时,做好接口的组合调用即可。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值