C# 中的 Onvif 事件订阅

2024-01-03

我正在用 C# 实现 ipCamera/编码器管理系统。该系统将管理来自多个供应商的多个 ipCamera 和/或编码器。使用 Onvif 代替每个 ipcamera 或编码器 sdk 将是一个好处。

管理系统的关键概念之一是监听来自摄像机的事件,例如运动检测事件。 Onvif 通过使用 ws-basenotification 或拉式支持来支持此功能。我不喜欢 pull,所以我将使用 Onvif 中的 ws-basenotification 支持(Onvif 规范 9.1)。

我已成功添加对 Sony SNC-RH164、Bosh VIP X1 XF IVA 和 Acti TCD2100 的订阅。

我的问题是:我没有从任何设备收到任何通知。任何人都可以看到我做错了什么,或者给我一些关于如何从设备获取通知的指导。 我的电脑与设备位于同一子网中。而且我的防火墙是关闭的以进行测试。

我的测试控制台应用程序启动 OnvifManager 类。

using (var manager = new OnvifManager())
        {
            //manager.ScanForDevices();
            var sonyDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.101/onvif/device_service"),

            };
            manager.AddDevice(sonyDevice);
            manager.AddEventSubscription(sonyDevice, "PT1H");

            var boshDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.102/onvif/device_service"),


            };
            manager.AddDevice(boshDevice);
            manager.AddEventSubscription(boshDevice, string.Empty);

            var actiDevice = new OnvifClassLib.OnvifDevice
            {
                OnvifDeviceServiceUri = new Uri(@"http://192.168.0.103/onvif/device_service"),
                UserName = "uid",
                Password = "pwd"

            };
            manager.AddDevice(actiDevice);
            manager.AddEventSubscription(actiDevice);

            Console.WriteLine("Waiting...");
            Console.Read();
        }

我的managerClass将在构造函数中初始化我的NotificationConsumer接口。

private void InitializeNotificationConsumerService()
    {
        _notificationConsumerService = new NotificationConsumerService();
        _notificationConsumerService.NewNotification += NotificationConsumerService_OnNewNotification;
        _notificationConsumerServiceHost = new ServiceHost(_notificationConsumerService);
        _notificationConsumerServiceHost.Open();
    }

我的NotificationConsumer接口实现。

 /// <summary>
/// The client reciever service for WS-BaseNotification
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class NotificationConsumerService : NotificationConsumer
{

    public event EventHandler<EventArgs<Notify1>> NewNotification;

    /// <summary>
    /// Notifies the specified request.
    /// </summary>
    /// <param name="request">The request.</param>
    /// <remarks>A </remarks>
    public void Notify(Notify1 request)
    {
        var threadSafeEventHandler = NewNotification;
        if (threadSafeEventHandler != null)
            threadSafeEventHandler.Invoke(this, new EventArgs<Notify1>(request));
    }
}

public class EventArgs<T> : EventArgs
{

    public EventArgs(T data)
    {
        Data = data;
    }

    public T Data { get; set; }
}

NotificationConsumerService 的配置

<services>
  <service name="OnvifClassLib.NotificationConsumerService">
    <endpoint address="" binding="customBinding" bindingConfiguration="CustomBasicHttpBinding"
      name="CustomHttpBinding" contract="EventService.NotificationConsumer" />
    <host>
      <baseAddresses>
        <add baseAddress="http://192.168.0.10:8080/NotificationConsumerService" />
      </baseAddresses>
    </host>
  </service>
</services>
<bindings>      
  <customBinding>
    <binding name="CustomBasicHttpBinding">
      <textMessageEncoding messageVersion="Soap12">
        <readerQuotas maxStringContentLength="80000" />
      </textMessageEncoding>
      <httpTransport maxReceivedMessageSize="800000" maxBufferSize="800000" />
    </binding>        
  </customBinding>      
</bindings>

添加设备方法

public void AddDevice(OnvifDevice device)
    {
        LoadCapabilities(device);
        OnvifDevices.Add(device);
    }


internal void LoadCapabilities(OnvifDevice onvifDevice)
    {
        if (onvifDevice.OnvifDeviceServiceUri == null)
            return;
        if (onvifDevice.DeviceClient == null)
            LoadDeviceClient(onvifDevice);
        try
        {

            onvifDevice.Capabilities = onvifDevice.DeviceClient.GetCapabilities(new[] { OnvifClassLib.DeviceManagement.CapabilityCategory.All });

        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }


    }
private void LoadDeviceClient(OnvifDevice onvifDevice)
    {

        if (onvifDevice.OnvifDeviceServiceUri == null)
            return;

        var serviceAddress = new EndpointAddress(onvifDevice.OnvifDeviceServiceUri.ToString());
        var binding = GetBindingFactory(onvifDevice);
        onvifDevice.DeviceClient = new OnvifClassLib.DeviceManagement.DeviceClient(binding, serviceAddress);
        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
        {
            onvifDevice.DeviceClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
            onvifDevice.DeviceClient.ClientCredentials.UserName.Password = onvifDevice.Password;
        }

    }

AddEventSubscription 方法

 public void AddEventSubscription(OnvifDevice onvifDevice, string initialTerminationTime = "PT2H")
    {
        if (onvifDevice.Capabilities.Events == null)
            throw new ApplicationException("The streamer info does not support event");
        try
        {


            if (onvifDevice.NotificationProducerClient == null)
                LoadNotificationProducerClient(onvifDevice);

            XmlElement[] filterXml = null;


            var subScribe = new Subscribe()
            {
                ConsumerReference = new EndpointReferenceType
                {
                    Address = new AttributedURIType { Value = _notificationConsumerServiceHost.BaseAddresses.First().ToString() },

                }

            };
            if (!string.IsNullOrWhiteSpace(initialTerminationTime))
                subScribe.InitialTerminationTime = initialTerminationTime;


            onvifDevice.SubscribeResponse = onvifDevice.NotificationProducerClient.Subscribe(subScribe);

            Console.WriteLine("Listening on event from {0}", onvifDevice.NotificationProducerClient.Endpoint.Address.Uri.ToString());
        }

        catch (FaultException ex)
        {
            Console.Write(ex.ToString());
        }
        catch (Exception ex)
        {
            Console.Write(ex.ToString());
        }
    }

private void LoadNotificationProducerClient(OnvifDevice onvifDevice)
    {
        var serviceAddress = new EndpointAddress(onvifDevice.Capabilities.Events.XAddr.ToString());
        var binding = GetBindingFactory(onvifDevice);
        onvifDevice.NotificationProducerClient = new OnvifClassLib.EventService.NotificationProducerClient(binding, serviceAddress);
        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
        {
            onvifDevice.NotificationProducerClient.ClientCredentials.UserName.UserName = onvifDevice.UserName;
            onvifDevice.NotificationProducerClient.ClientCredentials.UserName.Password = onvifDevice.Password;
        }
    }

Soap12 的绑定

private Binding GetBindingFactory(OnvifDevice onvifDevice)
    {            
        return GetCustomBinding(onvifDevice);
    }
private Binding GetCustomBinding(OnvifDevice onvifDevice)
    {
        HttpTransportBindingElement transportElement = new HttpTransportBindingElement();

        if (!string.IsNullOrWhiteSpace(onvifDevice.UserName))
            transportElement.AuthenticationScheme = AuthenticationSchemes.Basic;


        var messegeElement = new TextMessageEncodingBindingElement();
        messegeElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None);

        var binding = new CustomBinding(messegeElement, transportElement);
        binding.SendTimeout = new TimeSpan(0, 10, 0);
        return binding;

    }

我在使用 GrandStream 相机时遇到了这个问题。我必须使用相机 Web UI 添加一个或多个检测区域,以使其检测运动。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的 Onvif 事件订阅 的相关文章

随机推荐

  • Twitter Bootstrap 选项卡:内容窗格中的链接不起作用

    我这里有一个工作选项卡实例 并准备了一个 jsfiddle 不知何故 选项卡在这里无法正常工作 但链接问题仍然存在 http jsfiddle net Gyrga 6 http jsfiddle net Gyrga 6 选项卡窗格中的链接不
  • 二进制序列 x 位长的所有排列

    我想找到一种干净而聪明的方法 在 python 中 来查找 1 和 0 x 字符长的字符串的所有排列 理想情况下 这会很快并且不需要进行太多迭代 所以 对于 x 1 我想要 0 1 x 2 00 01 10 11 etc 现在我有这个 它很
  • 将一列拆分为多行

    谁能告诉我如何实现这个目标 在某些情况下 我的表中的列包含逗号分隔的值 如果是这样 我需要为这些值创建新行 此外 作为一个例子 一个表包含 1 行 4 列第 2 栏 第 3 栏 Col4 具有以下值 A 乙 C 分别为1 2 3 因此 Co
  • 用于重命名文件夹中的文件并再次命名的批处理文件

    恐怕这是一个有点过时的问题 但这里是 我有一个程序可以按顺序生成一些 RAW 文件 例如 示例 1 RAW示例 2 RAW 然后根据需要向数字添加额外的有效数字 例如 示例 10 RAW示例 200 RAW 我需要将这些文件名转换为数字 以
  • 在地图期间获取前一个元素的功能方法

    我有一个数组map超过 我需要将当前元素与前一个元素进行比较 我通过比较当前元素与前一个元素是否相同来检测id并根据这种情况做一些不同的事情 有没有一种纯粹的函数式方法可以在不进行索引数学的情况下做到这一点 items map item i
  • 如何在 SymPy 中创建一个参数本身就是随机变量的随机变量?

    我有一个随机变量 Y 其分布为泊松分布 参数本身就是随机变量 X 其分布为泊松分布 参数为 10 如何使用 SymPy 自动计算 X 和 Y 之间的协方差 代码 from sympy stats import x1 Poisson x1 3
  • 开玩笑:测试 window.location.reload

    我如何编写一个测试来确保该方法reloadFn实际上会重新加载窗口吗 我发现这个资源 https gist github com remarkablemark 5cb571a13a6635ab89cf2bb47dc004a3但我不清楚当窗口
  • 如何处理 JavaScript 中 setTimeout 的错误?

    简单的问题关于try catch对于函数在setTimeout try setTimeout function throw new Error error 300 catch e console log eeee console log e
  • 如何在 ListView 顶部插入小部件?

    简要说明 在我的所有代码示例中 您都会看到类似的内容material Widget而不是仅仅Widget 这是因为我喜欢这样命名我的导入 import package flutter material dart as material 我的
  • Fragment 切换期间 onResume() 的替代方案

    onResume 当我们在片段之间切换多次时 不会调用该方法 那么 有没有更好的方法来处理恢复操作呢 代码如下 Step 1 创建接口 public interface YourFragmentInterface void fragment
  • Angular4中的ActivatedRoute和ActivatedRouteSnapshot有什么区别

    有什么区别ActivatedRouteSnapshot and ActivatedRoute在 Angular 4 中 我的理解是ActivatedRouteSnapshot是一个孩子ActivatedRoute 意思是ActivatedR
  • 扩展中的延迟加载属性 (Swift)

    我知道 swift 不允许在扩展中声明存储的属性 出于同样的原因 延迟加载的属性也是被禁止的 我知道计算属性是一种选择 但我的任务应该只执行一次 是否有任何黑客 替代 被忽视的方法来模仿扩展中的惰性变量 Thanks 如果你不需要参考sel
  • requestWindowFeature(Window.FEATURE_NO_TITLE);给出例外

    import android content pm ActivityInfo import android os Bundle import android preference ListPreference import android
  • 只有我吗?我发现与 XPath 相比,LINQ to XML 有点麻烦

    我是一名 C 程序员 因此我无法利用 VB 中炫酷的 XML 语法 Dim itemList1 From item In rss
  • 如何验证 reCAPTCHA V2 Java (Servlet)

    这是一个问答风格的帖子 我将同时发布问题和答案 主要原因是我花了相当多的时间寻找验证 recaptcha V2 的最简单方法 因此 我将分享我的知识 以避免进一步浪费开发人员的时间 如何做一个服务器端验证谷歌的验证码 V2 or 隐形验证码
  • Docker构建npm安装错误网络超时

    我尝试将映像构建到节点应用程序 但是当我执行 docker build 时显示运行 npm install 时出现错误 npm 错误 网络超时时间 https registry npmjs org cookie cookie 0 4 0 t
  • 如何并行化复杂的 for 循环

    我有一个复杂的for循环 其中包含循环中对多个记录的多个操作 循环看起来像这样 for i j k in zip is js ks declare multiple lists like a b if i for items in i va
  • 正则表达式来匹配和验证互联网媒体类型?

    我想验证通过 API 输入的互联网类型 你能帮忙写一个正则表达式来匹配吗 下面的示例类型来自http en wikipedia org wiki Internet media type http en wikipedia org wiki
  • 出现错误“‘targetFramework’属性当前引用的版本高于已安装的 .NET Framework 版本”

    我在 IIS7 服务器上发布了 ASP NET Web API 当我在本地测试它时 我收到以下框架错误 配置错误 处理过程中发生错误 服务此请求所需的配置文件 请查看 具体错误详情如下并修改你的配置文件 适当地 解析器错误消息 target
  • C# 中的 Onvif 事件订阅

    我正在用 C 实现 ipCamera 编码器管理系统 该系统将管理来自多个供应商的多个 ipCamera 和 或编码器 使用 Onvif 代替每个 ipcamera 或编码器 sdk 将是一个好处 管理系统的关键概念之一是监听来自摄像机的事