0

我正在尝试为 Onvif 投诉设备构建 UI。一段时间以来,我一直在用头撞墙。我相信我已经正确构建了自定义 URI。根据 ONVIF 程序员指南,我们需要 Get Profiles、GetStreamURI、Request Streaming。http://www.openipcam.com/files/ONVIF/ONVIF_WG-APG-Application_Programmer's_Guide.pdf

使用 Wireshark,我相信我看到了正在发送的 HTTP 数据包(显示适当的请求),以及我认为是适当的响应。最终的 GetStreamURI 会从摄像头获得成功的响应。然后,当我尝试调用 _mp.Play 时,我看到一些通过 HTTP 的数据包和一些从相机返回的 TCP 数据包。在此通信停止后。

using System;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LibVLCSharp.Shared;
using LibVLCSharp;
using System.ServiceModel.Channels;
using Lib_vlc_CSharp_Onvif.OnvifDevice;
using System.ServiceModel;
using Lib_vlc_CSharp_Onvif.OnvifMedia;


namespace Lib_vlc_CSharp_Onvif
{

    public partial class Form1 : Form
    {
        public LibVLC _libVLC;
        public LibVLCSharp.Shared.MediaPlayer _mp;
        public LibVLCSharp.Shared.Media media; 


        //ToDO... make screen size adjustable 
        public System.Drawing.Size VidSize;
        public System.Drawing.Size FormSize;
        public System.Drawing.Point OldVidLoc;


        //Create Onvif Media Profiles through service references 
        OnvifMedia.Media2Client Onvif_media;
        OnvifMedia.MediaProfile[] profiles;

        //Custom URI variable 
        UriBuilder deviceUri; 
        public Form1()
        {
            InitializeComponent();

            //LibVLCSharp Specific 
            Core.Initialize();
            this.KeyPreview = true;

            //Just controlling the size. TODO: Imp controls 
            VidSize = videoView.Size;
            FormSize = this.Size;
            OldVidLoc = videoView.Location;

            //Vlc Specific 
            //Set up the Vlc Lib and then connect the Form1 media window player to the media player of the library.
            //videoVew is vlcsharp item in Form1. 
            _libVLC = new LibVLC();
            _mp = new MediaPlayer(_libVLC);
            videoView.MediaPlayer = _mp;             
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //Set up device to get profiles (Onvif Specific) 

            //Required a custom URI and binding. 
            deviceUri = new UriBuilder("Http:/onvif/device_service");
            System.ServiceModel.Channels.Binding binding;
            HttpTransportBindingElement httpTransport = new HttpTransportBindingElement();
            httpTransport.AuthenticationScheme = System.Net.AuthenticationSchemes.Digest;
            binding = new CustomBinding(new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8), httpTransport);

            //Assign IP Address to device URI. TODO: This eventually will be pulled from user entered value in an text box. 
            deviceUri.Host = "xxx.xxx.x.x";
            DeviceClient Onvif_Device = new DeviceClient(binding, new EndpointAddress(deviceUri.ToString()));
            OnvifDevice.Service[] service = Onvif_Device.GetServices(false);

            //Check if they contain media and that we have made contact TODO wrap in a try catch block
            OnvifDevice.Service xmedia = service.FirstOrDefault(s => s.Namespace == "http://www.onvif.org/ver20/media/wsdl");
            if (xmedia != null)
            {
                Onvif_media = new Media2Client(binding, new EndpointAddress(deviceUri.ToString()));
                Onvif_media.ClientCredentials.HttpDigest.ClientCredential.UserName = "admin";
                Onvif_media.ClientCredentials.HttpDigest.ClientCredential.Password = "admin";
                Onvif_media.ClientCredentials.HttpDigest.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

                //Get camera Profiles. 
                profiles = Onvif_media.GetProfiles(null, null);

                if (profiles != null)
                {
                    foreach (var p in profiles)
                    {
                        listBox.Items.Add(p.Name); 
                        //Profiles listed in box match profiles setup on camera. 
                    }
                }
            }

            //Eventually add a selection option on the list box. 
            //listBox.SelectedINdexChanged += OnSelectionChanged

            //If we have profiles build a custom URI to past to the vlc boject 
            if (profiles != null)
            {
                //Building URI to pass to VLCSharp VideoView Item.
                //https://www.onvif.org/ver20/media/wsdl/media.wsdl
                //GetSreamUri and define RtspUnicast. 
                //http://www.openipcam.com/files/ONVIF/ONVIF_WG-APG-Application_Programmer's_Guide.pdf on page 57&58

                UriBuilder local_uri = new UriBuilder(Onvif_media.GetStreamUri("RtspUnicast", profiles[0].token));

                //ToDO: Build list box to allow user to switch between profiles. Just past main profile for now. 

                local_uri.Host = deviceUri.Host;
                local_uri.Port = deviceUri.Port;
                local_uri.Scheme = "rtsp";
                //List full URI info. 
                infoBox.Text = local_uri.Host + local_uri.Port + local_uri.Path; 

                //Past it to VideoView and start playing video. 
                _mp.Play(new Media(_libVLC, local_uri.Uri));
            }
        }
    }
}

更新:我相信我的问题是我构建的 URI 需要验证。当我将此 URI 放入 Web 浏览器时,我收到 401 错误。我不确定为什么我在wire-shark 上看不到这个错误。我将用户名和密码分配给 URI 对象,但是当我检查“IsWellFormedURIString”时,我得到一个“无效端口错误”。

4

2 回答 2

2

您是否尝试过 --rtsp-user 和 --rtsp-pwd ?您还可以使用对话框 API 设置 RTSP 密码。

如果这不起作用,请分享您的完整日志。

您应该能够将 URL 从 Onvif 设备管理器复制/粘贴到 VLC 中并看到它播放(前提是您输入了正确的凭据)。如果没有,这本身就是一个问题。

于 2020-09-06T06:15:33.503 回答
0

您仍然可以分配密码和用户名密码。

MyUri.UserName = MyName
MyUri.Password = password 

当您的密码包含“#”之类的字符时,您会遇到问题虽然我还没有找到解决方法,但暂时保持密码简单,例如“MyPassword”而不是“MyPassword#1234”将允许您使用具有内置在字符串中的名称和密码的 URI。

于 2020-09-07T17:08:15.507 回答