如何基于ONVIF WSDL用C#开发无第三方SDK的IP摄像头流媒体服务器
嘿,我正好折腾过类似的需求——纯原生C#搞ONVIF设备对接,完全不用第三方SDK/工具是可行的,咱们一步步来解决你的问题:
第一步:用.NET原生工具生成ONVIF代理类
ONVIF的WSDL本质是Web服务定义,.NET自带的工具就能直接把它转成可调用的C#类,完全不需要第三方依赖:
- 方法1:用
svcutil.exe命令行工具(适合不想开Visual Studio的场景)
打开.NET命令行工具(比如Developer Command Prompt for Visual Studio),输入类似命令:
这个命令会把ONVIF设备管理、媒体服务的WSDL直接生成对应的C#代理类,你把生成的.cs文件加到项目里就能用。svcutil.exe http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl /language:C# /out:OnvifDevice.cs svcutil.exe http://www.onvif.org/ver10/media/wsdl/media.wsdl /language:C# /out:OnvifMedia.cs - 方法2:Visual Studio图形化操作
右键你的C#项目 → 「添加」→「服务引用」,在地址栏输入ONVIF的WSDL地址(比如设备管理的http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl),点击「转到」,给服务起个名字(比如OnvifDeviceService),确认后VS会自动生成代理类到你的项目里。
第二步:实现ONVIF设备搜索(SSDP协议)
设备搜索是ONVIF的基础,用的是SSDP简单服务发现协议,纯UDP广播就能实现,不用任何库:
using System; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; public async Task SearchOnvifDevices() { using var udpClient = new UdpClient(); udpClient.EnableBroadcast = true; udpClient.Client.ReceiveTimeout = 5000; // 搜索超时时间设为5秒 // 构造ONVIF标准的M-SEARCH请求 var searchRequest = @"M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: ""ssdp:discover"" MX: 3 ST: urn:schemas-onvif-org:device:NetworkVideoTransmitter:1 "; var requestBytes = Encoding.ASCII.GetBytes(searchRequest); await udpClient.SendAsync(requestBytes, requestBytes.Length, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900)); try { while (true) { var response = await udpClient.ReceiveAsync(); var responseStr = Encoding.ASCII.GetString(response.Buffer); // 从响应里提取设备的ONVIF服务地址(LOCATION字段) var locationLine = responseStr.Split('\n') .FirstOrDefault(line => line.TrimStart().StartsWith("LOCATION:")); if (!string.IsNullOrEmpty(locationLine)) { var deviceServiceUrl = locationLine.Substring("LOCATION:".Length).Trim(); Console.WriteLine($"找到ONVIF设备:{deviceServiceUrl}"); // 拿到这个地址后,就能调用设备管理、媒体服务接口了 } } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut) { Console.WriteLine("搜索超时,结束设备查找"); } }
这段代码的逻辑很简单:发送广播请求,监听设备的响应,提取出设备的服务地址——这是后续所有操作的基础。
第三步:获取摄像头流媒体地址(RTSP)
有了设备服务地址后,就能用之前生成的代理类调用ONVIF媒体服务,拿到RTSP流地址:
using System; using System.Linq; using System.Threading.Tasks; // 这里引用你生成的媒体服务代理类命名空间,比如你之前命名的OnvifMediaService public async Task<string> GetCameraRtspUrl(string deviceMediaUrl, string username, string password) { // 实例化媒体服务客户端 var mediaClient = new MediaClient(new BasicHttpBinding(), new EndpointAddress(deviceMediaUrl)); // 设置设备的认证信息(大部分ONVIF摄像头需要用户名密码) mediaClient.ClientCredentials.UserName.UserName = username; mediaClient.ClientCredentials.UserName.Password = password; // 获取设备的媒体配置文件(每个配置对应一个流) var profilesResponse = await mediaClient.GetProfilesAsync(); if (!profilesResponse.Any()) { throw new Exception("设备未返回任何媒体配置"); } // 取第一个配置文件(一般主流都在第一个) var targetProfile = profilesResponse.First(); // 请求RTSP流地址 var streamRequest = new GetStreamUriRequest { ProfileToken = targetProfile.Token, StreamSetup = new StreamSetup { Stream = StreamType.RTPUnicast, // 单播流,适合客户端直接拉取 Transport = new Transport { Protocol = TransportProtocol.RTSP } } }; var streamResponse = await mediaClient.GetStreamUriAsync(streamRequest); return streamResponse.Uri; // 拿到的就是摄像头的RTSP流地址 }
拿到RTSP地址后,你就可以做后续的转发了——如果要推流到网站/移动端,纯原生C#的话需要自己处理RTP解包、转成HTTP-FLV/HLS这类Web支持的格式(这部分比较复杂,但先搞定流地址是核心第一步)。
一些踩坑提醒
- 设备认证:有些老设备用的是Digest认证,.NET的WCF客户端会自动处理,不用额外写代码;
- WSDL版本:ONVIF有ver10、ver20等多个版本,尽量选设备支持的版本(可以从SSDP响应里的
SERVER字段判断); - 防火墙:搜索设备时要确保UDP 1900端口没被防火墙挡住,不然搜不到设备。
我当初也是查了一堆资料才摸透原生实现的路子,完全不用依赖那些第三方SDK,先从设备搜索和获取RTSP地址开始,一步步来就好。
内容的提问来源于stack exchange,提问作者Yogesh Jangir
相关产品推荐
相关产品推荐

