linux设备上的Onvif 实现21:解决大华摄像头无法使用问题

好长时间没有再写该系列文章了,最近刚好摸索着解决了大华摄像头无法使用问题,记录下来,应该对其他博友有所帮助。之前虽然写了一大堆文章说明了如何使用gsoap连接摄像头,但这是针对一台海康的摄像头开发的,一旦使用了同品牌不同型号摄像头或者其他牌子的摄像头就可能出现兼容性问题,导致无法使用。我就是碰到了这个问题,测试过的多个品牌型号摄像头,有的能直接使用,有的不能使用,问题各部相同。本文就是针对大华摄像头的问题解决过程说明。

摄像头型号:DH-IPC-HDW130S-0600B
MAC:90:02:A9:3D:1A:63
默认IP: 192.168.16.108, 修改使用IP:192.168.0.108
默认用户名密码;admin:admin

软件里面查看版本信息如下:
设备类型 IPC-HDW4105S
软件版本 2.400.0000.0.R, build : 2013-12-31
WEB版本  3.2.4.161826
ONVIF版本 2.3
序列号   TGC4AW158W00019

有意思的一点是摄像头标签上的型号是HDW130s,但是固件中的设备类型却是HDW4105S,不一致的哦。

-------------------------------------------------------------------

问题1:我的分机发出probe命令,但是没有收到大华IPC应答,无法发现 。

问题分析:OnvifTest软件可以正确发现大华IPC,抓包比对OnvifTest报文和我的报文,发现SOAP-ENV不同。百度后明白原因如下:

我使用的gsoap版本生成 RemoteDiscoveryBinding.nsmap,内容是有版本区别的。

    //SOAP 1.1版本

    {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
    {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, //1.1

    //SOAP 1.2版本
    {"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},
    {"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2
1.1版本的可以发现海康IPC,1.2版本才能发现大华IPC。使用1.2版本内容,收到大华Probe应答,解析成功。

-------------------------------------------------------------------

问题2:我的分机发出GetCapabilities命令,无应答。

问题分析:

    还是对比OnvifTest软件和分机发出的GetCapabilities命令,发现主要是域名空间不同。

这是使用ONVIF TEST软件发送的GetCapabilities

POST /onvif/device_service HTTP/1.1
Host: 192.168.0.108
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 335
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope 
  xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Body 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl">
    <Category>All</Category>
  </GetCapabilities>
  </s:Body>
</s:Envelope>

一共使用了4个命名,

 xmlns s="http://www.w3.org/2003/05/soap-envelope"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 xmlns="http://www.onvif.org/ver10/device/wsdl">

而gsoap生成的RemoteDiscoveryBinding.nsmap,完整的命令空间如下,密密麻麻好多啊!

SOAP_NMAC struct Namespace namespaces[] ={ 
    {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL}, 
    {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, 
    {"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},   
    {"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL}, 
    {"wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing", NULL, NULL},    
    {"wsdd", "http://schemas.xmlsoap.org/ws/2005/04/discovery", NULL, NULL},    
    {"chan", "http://schemas.microsoft.com/ws/2005/02/duplex", NULL, NULL}, 
    {"wsa5", "http://www.w3.org/2005/08/addressing", "http://schemas.xmlsoap.org/ws/2004/08/addressing", NULL}, 
    {"c14n", "http://www.w3.org/2001/10/xml-exc-c14n#", NULL, NULL},   
    {"wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", NULL, NULL},  
    {"xenc", "http://www.w3.org/2001/04/xmlenc#", NULL, NULL},  
    {"wsc", "http://schemas.xmlsoap.org/ws/2005/02/sc", NULL, NULL},    
    {"ds", "http://www.w3.org/2000/09/xmldsig#", NULL, NULL},  
    {"wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd", NULL},  
    {"xmime", "http://www.w3.org/2005/05/xmlmime", NULL, NULL}, 
    {"ns5", "http://www.w3.org/2004/08/xop/include", NULL, NULL},   
    {"ns6", "http://docs.oasis-open.org/wsrf/bf-2", NULL, NULL},    
    {"ns3", "http://www.onvif.org/ver10/schema", NULL, NULL},   
    {"ns4", "http://docs.oasis-open.org/wsn/b-2", NULL, NULL},  
    {"ns7", "http://docs.oasis-open.org/wsn/t-1", NULL, NULL},  
    {"wsdd10", "http://tempuri.org/wsdd10.xsd", NULL, NULL},    
    {"ns1", "http://www.onvif.org/ver10/network/wsdl", NULL, NULL}, 
    {"ns2", "http://www.onvif.org/ver10/device/wsdl", NULL, NULL},  
    {"ns8", "http://www.onvif.org/ver10/media/wsdl", NULL, NULL},  
    {NULL, NULL, NULL, NULL}
};
尝试只保留上述4个命名空间,就收到了大华IPC应答。由此确定是分机中的命令空间太多了,大华摄像头不支持某些命名空间,直接无视了,却不会发出任何错误应答。有了这个教训,后面的过程都是小心翼翼的试验只添加命令报文中使用的命名空间,这样就不会出现无应答错误了。最终各种命令汇总后的必须命名空间如下:

  xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" ‘
  xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
  xmlns:xsd="http://www.w3.org/2001/XMLSchema
  xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing
  xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery
  xmlns:ns1="http://www.onvif.org/ver10/network/wsdl
  xmlns:ns2="http://www.onvif.org/ver10/device/wsdl
  xmlns:ns3="http://www.onvif.org/ver10/schema
  xmlns:ns8="http://www.onvif.org/ver10/media/wsdl">

------------------------------------------------------------------

问题3:  我的分机设备发出Probe命令成功,发现了大华IPC,然后发送命令GetCapabilities,收到了大华IPC应答报文,但是分机却返回error=SOAP_TYPE,导致失败。使用OnvifTest软甲测试GetCapabilities,IPC发送了同样的报文,就可以正确解析。

问题分析过程:

    SOAP_TYPE: 标准解释是An XML Schema type mismatch, 到底是个什么意思我也说不出来,猜测是一些字段或域名空间关键字错误。

(1)首先怀疑报文解析过程中的每个字段项解析是否出现了错误,确定是哪个字段项错误。

  方法:编译分机程序时天机编译开关-DDEBUG,这样运行分机程序会自动生成调试文件:RECV.log、SENT.log、TEST.log。打开TEST.log文件,查找error没有发现。观察报文解析过程,发现出现在这一段:

   <tt:Extension>
          <tt:DeviceIO>
            <tt:XAddr>http://192.168.0.108/onvif/deviceIO_service</tt:XAddr>
            <tt:VideoSources>1</tt:VideoSources>
            <tt:VideoOutputs>0</tt:VideoOutputs>
            <tt:AudioSources>0</tt:AudioSources>
            <tt:AudioOutputs>0</tt:AudioOutputs>
            <tt:RelayOutputs>0</tt:RelayOutputs>
          </tt:DeviceIO>
          <tt:Extensions>
            <tt:TelexCapabilities>
              <tt:XAddr>http://192.168.0.108/onvif/telecom_service</tt:XAddr>
              <tt:TimeOSDSupport>true</tt:TimeOSDSupport>
              <tt:TitleOSDSupport>true</tt:TitleOSDSupport>
              <tt:PTZ3DZoomSupport>true</tt:PTZ3DZoomSupport>
              <tt:PTZAuxSwitchSupport>true</tt:PTZAuxSwitchSupport>
              <tt:MotionDetectorSupport>true</tt:MotionDetectorSupport>
              <tt:TamperDetectorSupport>true</tt:TamperDetectorSupport>
            </tt:TelexCapabilities>
          </tt:Extensions>
        </tt:Extension>

遇到Extension段中包含Extensions段,内部的Extensions段都未能识别出来,后面的log中都没有出现该段内容的解析过程。这种TelexCapabilities是海康IPC报文中没有的,在gsoap代码中也找不到该字段。由此确定是该段解析出错。

(2)确定代码中的错误位置

从GetCapabilities命令的调用关系一层层的跟踪下去,

soap_call___ns2__GetCapabilities()  soapClient.c
  soap_get__ns2__GetCapabilitiesResponse()  该函数执行后出现error=SOAP_TYPE
    soap_in__ns2__GetCapabilitiesResponse()
      soap_in_PointerTons3__Capabilities()
        soap_in_ns3__Capabilities()
          soap_in_PointerTons3__CapabilitiesExtension()
            soap_in_ns3__CapabilitiesExtension()
              soap_in_PointerTons3__CapabilitiesExtension2()
                soap_in_ns3__CapabilitiesExtension2()

最后的CapabilitiesExtension2()返回error=SOAP_TYPE,通过添加打印信息确定是if (soap_in_byte(soap, "-any", a->__any, "xsd:byte"))出现失败。 仔细观察soap_in_byte()函数,内部调用 stdsoap2.c soap_s2byte()函数,目的是把输入字符串转换成10进制的整数。

soap_s2byte(struct soap *soap, const char *s, char *p)
{ if (s)
  { long n;
    char *r;

    n = soap_strtol(s, &r, 10);   
    if (s == r || *r || n < -128 || n > 127)
    {         
        soap->error = SOAP_TYPE;
    }
    *p = (char)n;
  }
  return soap->error;
}

soap_s2byte这个函数调用soap_strtol进行转换,s是输入字符串,p指向转换后的单字节。但是对于s=“”空字符串无法转换成功,引起s==r成立,导致错误返回SOAP_TYPE。  看起来好像是gsoap的一个bug。修改方法是去除s==r的判断条件,避免报告错误。

if ( n < -128 || n > 127)
    {         
        soap->error = SOAP_TYPE;
    }

这样修改后就不会出现错误了,soap_call___ns2__GetCapabilities()  解析成功,TEST.log文件中也可以看到相关字段的解析了,下列内容是发现了字段,但是无法识别,予以忽略。

Tags and (default) namespaces match: 'tt:Extensions' 'ns3:Extensions'
Begin element found (level=6) 'tt:Extensions'='ns3:Extensions'
Reverting to last element 'tt:Extensions' (level=5)
Tags and (default) namespaces match: 'tt:Extensions' 'ns3:Extensions'
Begin element found (level=6) 'tt:Extensions'='ns3:Extensions'
Enter id='' type=781 loc=(nil) size=8 level=0
stdsoap2.c(7512): malloc(20) = 0x410d98
New block sequence (prev=(nil))
stdsoap2.c(2187): malloc(12) = 0x410dc8
Push block of 1 bytes (1 bytes total)
stdsoap2.c(2209): malloc(9) = 0x410df0
Enter id='' type=3 loc=0x410df8 size=1 level=0
Element content value=''
Push block of 1 bytes (2 bytes total)
stdsoap2.c(2209): malloc(9) = 0x410e18
Enter id='' type=3 loc=0x410e20 size=1 level=0
Element content value=''
Unexpected element 'tt:TelexCapabilities' in input (level=6, 1)
Tags 'tt:TelexCapabilities' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:TelexCapabilities'
Unexpected element 'tt:XAddr' in input (level=7, 1)
Tags 'tt:XAddr' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:XAddr'
End element found (level=8) 'tt:XAddr'=''
Unexpected element 'tt:TimeOSDSupport' in input (level=7, 1)
Tags 'tt:TimeOSDSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:TimeOSDSupport'
End element found (level=8) 'tt:TimeOSDSupport'=''
Unexpected element 'tt:TitleOSDSupport' in input (level=7, 1)
Tags 'tt:TitleOSDSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:TitleOSDSupport'
End element found (level=8) 'tt:TitleOSDSupport'=''
Unexpected element 'tt:PTZ3DZoomSupport' in input (level=7, 1)
Tags 'tt:PTZ3DZoomSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:PTZ3DZoomSupport'
End element found (level=8) 'tt:PTZ3DZoomSupport'=''
Unexpected element 'tt:PTZAuxSwitchSupport' in input (level=7, 1)
Tags 'tt:PTZAuxSwitchSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:PTZAuxSwitchSupport'
End element found (level=8) 'tt:PTZAuxSwitchSupport'=''
Unexpected element 'tt:MotionDetectorSupport' in input (level=7, 1)
Tags 'tt:MotionDetectorSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:MotionDetectorSupport'
End element found (level=8) 'tt:MotionDetectorSupport'=''
Unexpected element 'tt:TamperDetectorSupport' in input (level=7, 1)
Tags 'tt:TamperDetectorSupport' and 'SOAP-ENV:' match but namespaces differ
IGNORING element 'tt:TamperDetectorSupport'
End element found (level=8) 'tt:TamperDetectorSupport'=''
End element found (level=7) 'tt:TelexCapabilities'=''
Pop block
stdsoap2.c(2236): free(0x410e18)
stdsoap2.c(7512): malloc(12) = 0x410e18
Save all blocks in contiguous memory space of 1 bytes (0x410df0->0x410e18)

 

总结: 通过上述修改,解决了大华IPC无法使用问题,分机可以发现设备、查询设备能力、修改媒体配置、获取流媒体地址。最后,分机能通过rtsp连接摄像头,显示出了视频画面。

 

致谢:最近才在优快云发现一篇博文,简直就是黑夜中指路明灯啊,一下子解决困扰我大半年的问题,太谢谢这位小兵_小白大神了!

原文:关于onvif对接海康设备出现soap->error=4的问题

http://blog.youkuaiyun.com/bing87496988/article/details/38707829

### 使用Java对接海康和大华摄像头设备 #### 实现视频播放、历史回放及云台控制的方法概述 对于海康威视与大华品牌的摄像头,在Java应用程序中实现其功能主要依赖于厂商提供的SDK或API服务。通常情况下,这些操作可以通过HTTP/HTTPS协议访问RESTful API来完成,也可以利用RTSP协议直接获取视频流并解码显示。 #### 海康威视摄像头的操作方法 针对海康威视产品线,官方提供了适用于Windows/Linux平台下的C++ SDK以及.NET SDK用于二次开发;而对于跨平台需求,则推荐采用ONVIF标准协议或者通过调用开放平台所提供的Web Service接口来进行交互[^1]。 为了简化集成过程,可以考虑使用第三方库如`ffmpeg`处理音视频编解码工作,并借助开源框架如`JAVE(Java Audio Video Encoder)`封装FFmpeg命令行工具以便更好地融入到Java项目当中去。 下面给出一段简单的基于HttpURLConnection发起GET请求至指定URL从而获得实时视频流的例子: ```java import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HikvisionCamera { private static final String USER_AGENT = "Mozilla/5.0"; public void getLiveStream(String url){ try{ URL obj = new URL(url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); // 设置请求头信息 con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", USER_AGENT); int responseCode = con.getResponseCode(); System.out.println("\nSending 'GET' request to URL : " + url); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); // 打印结果 System.out.println(response.toString()); }catch(Exception e){ e.printStackTrace(); } } } ``` 这段代码展示了如何向特定的URL发送GET请求以取得当前时刻的画面数据。实际应用时还需要加入身份验证机制(比如Basic Auth)、错误重试逻辑等增强健壮性的措施[^4]。 #### 大华摄像头的具体做法 同样地,对于大华的产品系列而言,除了可以直接运用原生SDK之外,也能够参照上述方式构建自定义客户端连接服务器端口80/443并通过JSON格式传递参数执行相应指令[^2]。 值得注意的是,当涉及到云台转动这类物理动作时,往往需要额外配置权限并且遵循一定的安全策略才能成功触发远程操控事件。因此建议开发者仔细阅读相关文档说明,确保按照规定流程编写代码。 另外关于多路并发读取的问题,考虑到资源消耗较大可能导致性能瓶颈的情况发生,应当合理规划硬件环境并优化软件算法设计,例如采取异步I/O模型减少阻塞等待时间提高吞吐量效率[^3]。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

快活林高老大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值