如何发挥需要身份验证的视频流? [英] How to play a video stream that requires authentication?

查看:112
本文介绍了如何发挥需要身份验证的视频流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Windows商店应用(C#/ XAML)与REST服务进行通信。在某些时候,我需要打这个服务提供的视频流。

I have a Windows Store app (C#/XAML) which communicates with a REST service. At some point, I need to play a video stream provided by this service.

如果我刚分配流URI的 MediaElement.Source 属性,这是行不通的,因为该请求需要被验证。我需要自定义的的MediaElement 控制,以增加饼干,凭证和其他一些自定义页眉发送请求,但我找不到任何方法或属性要做到这一点

If I just assign the stream URI to the MediaElement.Source property, it doesn't work, because the request needs to be authenticated. I need to customize the request sent by the MediaElement control in order to add cookies, credentials and some other custom headers, but I can't find any method or property to do this.

我该怎么办呢?它甚至有可能?

How can I do it? Is it even possible?

推荐答案

OK,我得到了它的工作。基本上,该解决方案有两部分:

OK, I got it working. Basically, the solution has 2 parts:


  • 手动进行HTTP请求(具有任何所需的凭据或头)

  • 包的响应流中的自定义的 IRandomAccessStream 实现寻找通过另一个请求到服务器,使用范围头指定我需要的数据流的哪一部分。

  • make the HTTP request manually (with any required credentials or headers)
  • wrap the response stream in a custom IRandomAccessStream that implements Seek by making another request to the server, using the Range header to specify which part of the stream I need.

这里的 RandomAccessStream 实施

delegate Task<Stream> AsyncRangeDownloader(ulong start, ulong? end);

class StreamingRandomAccessStream : IRandomAccessStream
{
    private readonly AsyncRangeDownloader _downloader;
    private readonly ulong _size;

    public StreamingRandomAccessStream(Stream startStream, AsyncRangeDownloader downloader, ulong size)
    {
        if (startStream != null)
            _stream = startStream.AsInputStream();
        _downloader = downloader;
        _size = size;
    }

    private IInputStream _stream;
    private ulong _requestedPosition;

    public void Dispose()
    {
        if (_stream != null)
            _stream.Dispose();
    }

    public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {
        return AsyncInfo.Run<IBuffer, uint>(async (cancellationToken, progress) =>
        {
            progress.Report(0);
            if (_stream == null)
            {
                var netStream = await _downloader(_requestedPosition, null);
                _stream = netStream.AsInputStream();
            }
            var result = await _stream.ReadAsync(buffer, count, options).AsTask(cancellationToken, progress);
            return result;
        });
    }

    public void Seek(ulong position)
    {
        if (_stream != null)
            _stream.Dispose();
        _requestedPosition = position;
        _stream = null;
    }

    public bool CanRead { get { return true; } }
    public bool CanWrite { get { return false; } }
    public ulong Size { get { return _size; } set { throw new NotSupportedException(); } }

    public IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer) { throw new NotSupportedException(); }
    public IAsyncOperation<bool> FlushAsync() { throw new NotSupportedException(); }
    public IInputStream GetInputStreamAt(ulong position) { throw new NotSupportedException(); }
    public IOutputStream GetOutputStreamAt(ulong position) { throw new NotSupportedException(); }
    public IRandomAccessStream CloneStream() { throw new NotSupportedException(); }
    public ulong Position { get { throw new NotSupportedException(); } }
}

它可以像这样使用:

It can be used like this:

private HttpClient _client;
private void InitClient()
{
    _client = new HttpClient();
    // Configure the client as needed with CookieContainer, Credentials, etc
    // ...
}

private async Task StartVideoStreamingAsync(Uri uri)
{
    var request = new HttpRequestMessage(HttpMethod.Get, uri);
    // Add required headers
    // ...

    var response = await _client.SendAsync(request);
    ulong length = (ulong)response.Content.Headers.ContentLength;
    string mimeType = response.Content.Headers.ContentType.MediaType;
    Stream responseStream = await response.Content.ReadAsStreamAsync();

    // Delegate that will fetch a stream for the specified range
    AsyncRangeDownloader downloader = async (start, end) =>
        {
            var request2 = new HttpRequestMessage();
            request2.Headers.Range = new RangeHeaderValue((long?)start, (long?)end);
            // Add other required headers
            // ...
            var response2 = await _client.SendAsync(request2);
            return await response2.Content.ReadAsStreamAsync();
        };

    var videoStream = new StreamingRandomAccessStream(responseStream, downloader, length);
    _mediaElement.SetSource(videoStream, mimeType);
}

用户可以寻求在视频的任意位置,并且流将发出另一请求在指定位置,以获得流

The user can seek to an arbitrary position in the video, and the stream will issue another request to get the stream at the specified position.

这还是比我想应该是比较复杂的,但它的工作原理...

It's still more complex than I think it should be, but it works...

请注意,服务器必须支持请求范围头文件,而且必须出具在的Content-Length 头最初的反应。

Note that the server must support the Range header in requests, and must issue the Content-Length header in the initial response.

这篇关于如何发挥需要身份验证的视频流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆