限时福利领取


为什么选择ONVIF+VLC?

ONVIF协议作为安防监控领域的通用语言,能统一不同厂商设备的控制接口。但实际开发中常遇到两个头疼问题:

  • WS-Security鉴权复杂:需要手动处理XML签名和加密头
  • 跨平台播放器缺失:Windows的MediaFoundation在Linux上水土不服

ONVIF协议架构示意图

技术选型对比

| 方案 | 跨平台性 | 解码能力 | 开发复杂度 | |---------------|----------|----------|------------| | FFmpeg | 优秀 | 极强 | 高 | | MediaFoundation| 仅Windows| 中等 | 低 | | LibVLCSharp | 优秀 | 强 | 中 |

VLC凭借其开箱即用的RTSP支持和硬件加速能力,成为我们的首选。

实战三步走

1. 设备发现

// 发送WS-Discovery探测包
var probe = new XElement("Probe",
    new XAttribute(XNamespace.Xmlns + "d", "http://schemas.xmlsoap.org/ws/2005/04/discovery"),
    new XAttribute(XNamespace.Xmlns + "dn", "http://www.onvif.org/ver10/network/wsdl"));

using var udpClient = new UdpClient(3702);
udpClient.Send(Encoding.UTF8.GetBytes(probe.ToString()), 
    IPAddress.Parse("239.255.255.250"));

2. WSSE鉴权

string GetWsseHeader(string username, string password)
{
    var nonce = Guid.NewGuid().ToString("N");
    var created = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
    var nonceBytes = Encoding.UTF8.GetBytes(nonce);
    var passwordDigest = SHA1.Create().ComputeHash(
        nonceBytes.Concat(Encoding.UTF8.GetBytes(created))
                 .Concat(Encoding.UTF8.GetBytes(password))
                 .ToArray());

    return $"""
        <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <UsernameToken>
                <Username>{username}</Username>
                <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
                    {Convert.ToBase64String(passwordDigest)}
                </Password>
                <Nonce>{Convert.ToBase64String(nonceBytes)}</Nonce>
                <Created>{created}</Created>
            </UsernameToken>
        </Security>
    """;
}

3. VLC集成

var libVLC = new LibVLC("--no-xlib", "--avcodec-hw=dxva2");
var mediaPlayer = new MediaPlayer(libVLC);

// RTSP地址格式:rtsp://user:pass@ip:port/path
using var media = new Media(libVLC, new Uri(rtspUrl));
media.AddOption(":network-caching=300");

videoView.MediaPlayer = mediaPlayer;
mediaPlayer.Play(media);

VLC视频流渲染效果

性能优化技巧

  1. 内存管理
  2. 释放资源时先调用mediaPlayer.Stop()再Dispose
  3. 限制同时播放的流数量(建议不超过4路1080P)

  4. 线程策略

    Task.Run(() => {
        // 每个播放器独占线程
        mediaPlayer.Play(media);
    }).ConfigureAwait(false);

常见坑点

  • TLS 1.2问题:在应用启动时添加
    System.Net.ServicePointManager.SecurityProtocol |= 
        SecurityProtocolType.Tls12;
  • 内存泄漏:定期检查libVLC日志中的avformat警告

项目结构建议

ONVIFClient/
├── Services/
│   ├── DeviceDiscoverService.cs
│   ├── CameraControlService.cs
├── Models/
│   ├── CameraDevice.cs
│   ├── Config.cs
├── Views/
│   └── VideoViewWrapper.axaml

思考延伸

如何实现有人闯入时自动截图并推送告警?可以结合ONVIF的事件订阅服务: 1. 创建PullPoint订阅 2. 解析tns1:RuleEngine/CellMotionDetector/Motion事件 3. 触发MediaPlayer.TakeSnapshot()方法

完整示例代码已上传Github:https://github.com/example/onvif-vlc-demo (注:此为示意链接)

Logo

音视频技术社区,一个全球开发者共同探讨、分享、学习音视频技术的平台,加入我们,与全球开发者一起创造更加优秀的音视频产品!

更多推荐