本帖最后由 liuyuntianxia12 于 2020-11-4 11:55 编辑
ONVIF(开放式网络视频接口论坛)是一个全球性的开放式行业论坛,其目标是促进开发和使用基于物理IP的安全产品接口的全球开放标准。ONVIF创建了一个视频监控和其他物理安全领域的IP产品如何进行相互通信的标准。所以说ONVIF接口是市面上所有摄像头的公用接口,而不是厂商提供的独特接口,这就为实现各种厂家、型号、新旧的摄像头的操控(虽然效果差强人意)
网上绝对有相关教程,但是可能就差在某个点,导致学习使用困难,我就是这么过来的,所以直接就把我整理号的接入代码拿出来秀一秀
直接给东西:
ONVIF.rar
(8.49 KB, 下载次数: 480)
相关工具类就不多说了,就是些会用的的公用方法和接收对象实体类,主要的内容还是在ONVIFHelper.cs,在说这个类之前,我先介绍一个工具:ONVIF Device Test Tool(下载地址),安装后打开的界面如下
使用方法,参考:ONVIF Device Test Tool测试工具使用方法,我们开发的话主要用到的是Request内容 如下图所示:
任何接入都是先获取指定IP摄像头的相关信息,使用:GetSystemDateAndTime
[C#] 纯文本查看 复制代码 /// <summary>
/// 同步服务器与客户端时间(无需授权)
/// </summary>
public string ONVIF_GetSystemDateAndTime()
{
String reqMessageStr = "<?xml version=\"1.0\" encoding=\"utf - 8\"?> "+
"<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tds=\"http://www.onvif.org/ver10/device/wsdl\" xmlns:tt=\"http://www.onvif.org/ver10/schema\">"+
" <s:Body> " +
" <tds:GetSystemDateAndTime/> " +
" </s:Body > " +
"</s:Envelope> ";
byte[] reqMessageBinary = EncodingHelper.String2Byte(reqMessageStr);
string Url = deviceURL;
_http.Connect(Url);
_http.setONVIFHeader("\"http://www.onvif.org/ver10/device/wsdl/GetSystemDateAndTime\"");
_http.Write(reqMessageBinary);
try
{
string paramStr = _http.Read();
//序列化返回内容
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(paramStr.ToString());
XmlNamespaceManager xnamespace = XMLControl.getAllNamespaces(xdoc);
onvifdev.schemaPrefix = xnamespace.LookupPrefix(ONVIFNameSpace.schema);
XmlNodeList xnode_list = xdoc.GetElementsByTagName(onvifdev.schemaPrefix + ":UTCDateTime");
XmlNode time_node = xnode_list[0].FirstChild;
XmlNode date_node = xnode_list[0].LastChild;
string _hour = time_node[onvifdev.schemaPrefix + ":Hour"].InnerText;
string _min = time_node[onvifdev.schemaPrefix + ":Minute"].InnerText;
string _sec = time_node[onvifdev.schemaPrefix + ":Second"].InnerText;
string _year = date_node[onvifdev.schemaPrefix + ":Year"].InnerText;
string _month = date_node[onvifdev.schemaPrefix + ":Month"].InnerText;
string _day = date_node[onvifdev.schemaPrefix + ":Day"].InnerText;
System.DateTime currentTime = new System.DateTime(Int32.Parse(_year), Int32.Parse(_month), Int32.Parse(_day)
, Int32.Parse(_hour), Int32.Parse(_min), Int32.Parse(_sec));
//更新设置相关时间
baseDateTime = currentTime;
onvifdev.timeoffset = baseDateTime;
startDate = System.DateTime.Now;
}
catch (Exception ex)
{
return ex.ToString();
}
return "";
}
然后获取设备支持的接口列表:GetCapabilities
[C#] 纯文本查看 复制代码 /// <summary>
/// 初始化摄像头服务配置(无需授权)
/// </summary>
/// <returns></returns>
public string ONVIF_GetCapabilities()
{
String reqMessageStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tds=\"http://www.onvif.org/ver10/device/wsdl\" xmlns:tt=\"http://www.onvif.org/ver10/schema\">" +
" <s:Body>" +
" <tds:GetCapabilities> "+
" <tds:Category>All</tds:Category>"+
" </tds:GetCapabilities> " +
" </s:Body>" +
"</s:Envelope> ";
byte[] reqMessageBinary = EncodingHelper.String2Byte(reqMessageStr.ToString());
string paramStr = string.Empty;
string Url = deviceURL;
try
{
_http.Connect(Url);
_http.setONVIFHeader(ONVIFHeader.GetCapabilities);
_http.Write(reqMessageBinary);
paramStr = _http.Read();
//序列化返回内容
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(paramStr.ToString());
XmlNamespaceManager xnamespace = XMLControl.getAllNamespaces(xdoc);
onvifdev.schemaPrefix = xnamespace.LookupPrefix(ONVIFNameSpace.schema);
onvifdev.devicePrefix = xnamespace.LookupPrefix(ONVIFNameSpace.device_service);
//保存服务器配置信息
onvifdev = XMLControl.findAllXAddr(xdoc, onvifdev);
}
catch (XmlException xe)
{
return xe.ToString();
}
catch (WebException we)
{
return we.ToString();
}
return "";
}
获取设备配置信息:GetProfiles
[C#] 纯文本查看 复制代码 /// <summary>
/// 获取设备配置信息
/// </summary>
/// <returns>返回Token</returns>
public string ONVIF_GetProfiles(bool IsOAuth = false)
{
string reqMessageStr = "";
if (IsOAuth)
{
//生成客户端随机码
setNonce();
//基准时间
baseDateTime = DigestPassword.getCurrentTime(startDate, baseDateTime);
//UtcTime时间
_wsdUsernameToken.Create = DigestPassword.getCreatedTimeString(baseDateTime);
//Digest摘要
_wsdUsernameToken.Password = DigestPassword.getPasswordDigest(_wsdUsernameToken.Nonce,
_wsdUsernameToken.Create,
_wsdUsernameToken.plainPassword);
/* set packet */
reqMessageStr = "<?xml version=\"1.0\" encoding=\"utf - 8\"?>" +
"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:trt=\"http://www.onvif.org/ver10/media/wsdl\" xmlns:tt=\"http://www.onvif.org/ver10/schema\">" +
" <s:Header xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" +
" <wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
" <wsse:UsernameToken>" +
" <wsse:Username>" + _wsdUsernameToken.Username + "</wsse:Username>" +
" <wsse:Password Type = \"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + _wsdUsernameToken.Password + "</wsse:Password>" +
" <wsse:Nonce>" + _wsdUsernameToken.Nonce + "</wsse:Nonce>" +
" <wsu:Created>" + _wsdUsernameToken.Create + "</wsu:Created>" +
" </wsse:UsernameToken>" +
" </wsse:Security>" +
" </s:Header>" +
" <soap:Body>" +
" <trt:GetProfiles />" +
" </soap:Body>" +
"</soap:Envelope> ";
}
else
{
reqMessageStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap = \"http://www.w3.org/2003/05/soap-envelope\" xmlns:trt = \"http://www.onvif.org/ver10/media/wsdl\" xmlns:tt = \"http://www.onvif.org/ver10/schema\" > " +
"<soap:Body> " +
"<trt:GetProfiles /> " +
"</soap:Body> " +
"</soap:Envelope> ";
}
byte[] reqMessageBinary = EncodingHelper.String2Byte(reqMessageStr);
string paramStr = string.Empty;
string Url = onvifdev.mediaxaddr;
try
{
_http.Connect(Url);
_http.setONVIFHeader(ONVIFHeader.GetProfiles);
_http.Write(reqMessageBinary);
paramStr = _http.Read();
//序列化返回内容
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(paramStr.ToString());
//解析出Token
XmlElement root = xdoc.DocumentElement;
string nameSpace = root.NamespaceURI;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
//设置命名空间前缀
nsmgr.AddNamespace("SOAP-ENV", nameSpace);
nsmgr.AddNamespace("trt", root.Attributes["xmlns:trt"].InnerText);
//默认值为第一个
string value = xdoc.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/trt:GetProfilesResponse", nsmgr).ChildNodes[0].Attributes["token"].InnerText.Trim();
return value;
}
catch (XmlException xe)
{
return "";
}
catch (WebException we)
{
return "";
}
}
指定通道接口获取视频流地址:GetStreamUri
[C#] 纯文本查看 复制代码 /// <summary>
/// 获取视频流地址
/// </summary>
/// <param name="token">Token</param>
/// <returns>视频流地址</returns>
public string ONVIF_GetStreamUri(bool IsOAuth=false)
{
string token = ONVIF_GetProfiles(IsOAuth);
string reqMessageStr = "";
if (IsOAuth)
{
//生成客户端随机码
setNonce();
//基准时间
baseDateTime = DigestPassword.getCurrentTime(startDate, baseDateTime);
//UtcTime时间
_wsdUsernameToken.Create = DigestPassword.getCreatedTimeString(baseDateTime);
//Digest摘要
_wsdUsernameToken.Password = DigestPassword.getPasswordDigest(_wsdUsernameToken.Nonce,
_wsdUsernameToken.Create,
_wsdUsernameToken.plainPassword);
//设置发送消息体
reqMessageStr = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:trt=\"http://www.onvif.org/ver10/media/wsdl\" xmlns:tt=\"http://www.onvif.org/ver10/schema\" >" +
" <s:Header xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">" +
" <wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
" <wsse:UsernameToken>" +
" <wsse:Username>" + _wsdUsernameToken.Username + "</wsse:Username>" +
" <wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + _wsdUsernameToken.Password + "</wsse:Password>" +
" <wsse:Nonce>" + _wsdUsernameToken.Nonce + "</wsse:Nonce>" +
" <wsu:Created>" + _wsdUsernameToken.Create + "</wsu:Created>" +
" </wsse:UsernameToken>" +
" </wsse:Security>" +
" </s:Header>" +
" <soap:Body>" +
" <GetStreamUri xmlns=\"http://www.onvif.org/ver10/media/wsdl\">" +
" <StreamSetup>" +
" <Stream xmlns=\"http://www.onvif.org/ver10/schema\">RTP-Unicast</Stream>" +
" <Transport xmlns=\"http://www.onvif.org/ver10/schema\">" +
" <Protocol>UDP</Protocol>" +
" </Transport>" +
" </StreamSetup>" +
" <ProfileToken>" + token + "</ProfileToken>" +
" </GetStreamUri>" +
" </soap:Body>" +
"</soap:Envelope>";
}
else
{
reqMessageStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:trt=\"http://www.onvif.org/ver10/media/wsdl\" xmlns:tt=\"http://www.onvif.org/ver10/schema\">" +
"<soap:Body>" +
"<GetStreamUri xmlns = \"http://www.onvif.org/ver10/media/wsdl\">" +
"<StreamSetup>" +
"<Stream xmlns = \"http://www.onvif.org/ver10/schema\">RTP-Unicast</Stream>" +
"<Transport xmlns = \"http://www.onvif.org/ver10/schema\">" +
"<Protocol>UDP</Protocol>" +
"</Transport>" +
"</StreamSetup>" +
"<ProfileToken>mainStream</ProfileToken>" +
"</GetStreamUri>" +
"</soap:Body>" +
"</soap:Envelope>";
}
byte[] reqMessageBinary = EncodingHelper.String2Byte(reqMessageStr);
string paramStr = string.Empty;
string Url = onvifdev.mediaxaddr;
try
{
_http.Connect(Url);
_http.setONVIFHeader("\"http://www.onvif.org/ver10/media/wsdl/GetStreamUri\"");
_http.Write(reqMessageBinary);
paramStr = _http.Read();
//序列化返回内容
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(paramStr.ToString());
//解析出Token
XmlElement root = xdoc.DocumentElement;
string nameSpace = root.NamespaceURI;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
//设置命名空间前缀
nsmgr.AddNamespace("SOAP-ENV", nameSpace);
nsmgr.AddNamespace("trt", root.Attributes["xmlns:trt"].InnerText);
//默认值为第一个
string value = xdoc.SelectSingleNode("/SOAP-ENV:Envelope/SOAP-ENV:Body/trt:GetStreamUriResponse/trt:MediaUri", nsmgr).ChildNodes[0].InnerText.Trim();
return value;
}
catch (XmlException xe)
{
return "";
}
catch (WebException we)
{
return "";
}
finally
{
}
}
代码部分就是这样,很简单的逻辑,拼接请求参数获取信息
开发过程中可以用工具先测试相关接口,配置好摄像头的账号密码权限,同时要摄像头启用支持ONVIF,部分接口不用传递账号密码(传递有可能还报错),部分就需要传递账号密码,具体看代码
觉得ONVIF很有意思的一个东西,分享给大家
|