吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 8587|回复: 26
收起左侧

[其他转载] C#接入ONVIF操控摄像头

  [复制链接]
liuyuntianxia12 发表于 2020-11-4 11:55
本帖最后由 liuyuntianxia12 于 2020-11-4 11:55 编辑

ONVIF(开放式网络视频接口论坛)是一个全球性的开放式行业论坛,其目标是促进开发和使用基于物理IP的安全产品接口的全球开放标准。ONVIF创建了一个视频监控和其他物理安全领域的IP产品如何进行相互通信的标准。所以说ONVIF接口是市面上所有摄像头的公用接口,而不是厂商提供的独特接口,这就为实现各种厂家、型号、新旧的摄像头的操控(虽然效果差强人意)

网上绝对有相关教程,但是可能就差在某个点,导致学习使用困难,我就是这么过来的,所以直接就把我整理号的接入代码拿出来秀一秀
image.png
直接给东西: ONVIF.rar (8.49 KB, 下载次数: 429)

相关工具类就不多说了,就是些会用的的公用方法和接收对象实体类,主要的内容还是在ONVIFHelper.cs,在说这个类之前,我先介绍一个工具:ONVIF Device Test Tool(下载地址),安装后打开的界面如下

image.png
使用方法,参考:ONVIF Device Test Tool测试工具使用方法,我们开发的话主要用到的是Request内容 如下图所示:

微信图片_20201104113814.png

任何接入都是先获取指定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很有意思的一个东西,分享给大家

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
LowerAI + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| liuyuntianxia12 发表于 2020-11-19 11:15
sweet_love 发表于 2020-11-18 16:25
我有个突发奇想。IP地址段扫描摄像头设备端口。然后写循环,用ONVIF去尝试链接......然后你 ...

是可以的,不能干坏事儿呀
我之前搞测试的时候能直接打开我们公司的监控摄像头(主要是没有设置密码或者是默认密码)
但是后面新出的摄像头都支持ONVIF,但是需要手动去开启,所以。。。
sweet_love 发表于 2020-11-18 16:25
liuyuntianxia12 发表于 2020-11-18 15:49
基本所有摄像头都支持,我就是因为老摄像头没有开发SDK,才关注使用ONVIF的

我有个突发奇想。IP地址段扫描摄像头设备端口。然后写循环,用ONVIF去尝试链接......然后你懂。
QingYi. 发表于 2020-11-4 12:11
dongdiyu789 发表于 2020-11-4 13:05
很不错啊,感谢分享···
背着家旅行 发表于 2020-11-4 13:45

很不错啊,感谢分享···
Jerry86 发表于 2020-11-18 10:16
谢谢LZ分享
sweet_love 发表于 2020-11-18 14:42
如果这个协议,相关的摄像头厂商都支持了,那就好多了。相信应用会很多。
 楼主| liuyuntianxia12 发表于 2020-11-18 15:49
sweet_love 发表于 2020-11-18 14:42
如果这个协议,相关的摄像头厂商都支持了,那就好多了。相信应用会很多。

基本所有摄像头都支持,我就是因为老摄像头没有开发SDK,才关注使用ONVIF的
powerxing 发表于 2021-1-4 13:25
太好了,可以学习下,感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-28 21:54

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表