如何发挥需要身份验证的视频流? [英] How to play a video stream that requires authentication?
问题描述
我有一个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 implementsSeek
by making another request to the server, using theRange
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屋!