【问题标题】:Using libVLCsharp to stream pw protected IP Camera Video but video not playing使用 libVLCsharp 流式传输受密码保护的 IP 摄像机视频,但视频不播放
【发布时间】:2020-12-24 16:36:20
【问题描述】:

我正在尝试为 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”时,我得到一个“无效端口错误”。

【问题讨论】:

  • 注意:我已确认使用 Onvif 设备管理器正确配置了相机的配置文件。我比较了每个程序引入的配置文件,我相信它们是相同的。

标签: ip-camera libvlcsharp rtcp


【解决方案1】:

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

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

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

【讨论】:

  • 你让我成功了。我没有考虑将 ODM 中的 URL 与我正在做的事情进行比较。原来我有两个问题,而不是一个。首先,我使用了错误的端口。这解释了为什么在发送流 URI 请求时通信会停止。现在使用正确的端口,我看到来回发送 RTSP 数据包,但出现 401 身份验证错误。将我的密码和用户名构建到 URI 中不起作用。即使在查看 RTSP 的有效格式时这似乎是正确的,我也会收到一个无效的格式错误。
  • 使用ONVIF协议认证是不够的,还需要告诉VLC使用RTSP认证。对于您的用例,onvif 协议只是一种发现要使用的 RTSP URL 的编程方式。
  • 要么按照建议使用 --rtsp 选项,要么使用 Dialog API 在 libvlc 要求用户名/密码时做出响应,就像在 VLC 界面中一样。我认为有一个示例。
  • 与你的问题完全无关,是关于 UWP 包的一些问题。 401(摘要质询)然后 200 是 HTTP 摘要身份验证的正确工作流程。我不知道您认为哪里错了,但您可能没有朝着正确的方向寻找。
  • 是的,RTSP 401 表示您未通过身份验证。看我的回答,一切都在里面。谷歌搜索如何将选项传递给 libvlc 实例
【解决方案2】:

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

MyUri.UserName = MyName
MyUri.Password = password 

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

【讨论】:

    猜你喜欢
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多