如何播放需要身份validation的video流?

我有一个Windows应用程序(C#/ XAML),它与REST服务进行通信。 在某些时候,我需要播放此服务提供的video流。

如果我只是将流URI分配给MediaElement.Source属性,则它不起作用,因为需要对请求进行身份validation。 我需要自定义MediaElement控件发送的请求,以便添加cookie,凭据和一些其他自定义标头,但我找不到任何方法或属性来执行此操作。

我该怎么做? 它甚至可能吗?

好的,我搞定了。 基本上,解决方案有两个部分:

  • 手动发出HTTP请求(使用任何所需的凭据或标头)
  • 将响应流包装在自定义IRandomAccessStream ,通过向服务器发出另一个请求来实现Seek ,使用Range标头指定我需要的流的哪个部分。

这是RandomAccessStream实现:

 delegate Task 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 ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) { return AsyncInfo.Run(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 WriteAsync(IBuffer buffer) { throw new NotSupportedException(); } public IAsyncOperation 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(); } } } 

它可以像这样使用:

 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); } 

用户可以寻找video中的任意位置,并且流将发出另一个请求以将流获得到指定位置。

它仍然比我想象的要复杂,但它有效……

请注意,服务器必须支持请求中的Range标头,并且必须在初始响应中发出Content-Length标头。