C# 如何播放需要身份验证的视频流?
我有一个与REST服务通信的Windows应用商店应用程序(C#/XAML)。在某些时候,我需要播放此服务提供的视频流 如果我只是将流URI分配给C# 如何播放需要身份验证的视频流?,c#,authentication,windows-runtime,video-streaming,windows-store-apps,C#,Authentication,Windows Runtime,Video Streaming,Windows Store Apps,我有一个与REST服务通信的Windows应用商店应用程序(C#/XAML)。在某些时候,我需要播放此服务提供的视频流 如果我只是将流URI分配给MediaElement.Source属性,它就不起作用,因为请求需要进行身份验证。我需要自定义由MediaElement控件发送的请求,以便添加cookie、凭据和一些其他自定义头,但我找不到任何方法或属性来执行此操作 我怎么做?甚至可能吗?好的,我让它工作了。基本上,解决方案有两个部分: 手动发出HTTP请求(使用任何必需的凭据或标头) 将响应流
MediaElement.Source
属性,它就不起作用,因为请求需要进行身份验证。我需要自定义由MediaElement
控件发送的请求,以便添加cookie、凭据和一些其他自定义头,但我找不到任何方法或属性来执行此操作
我怎么做?甚至可能吗?好的,我让它工作了。基本上,解决方案有两个部分:
- 手动发出HTTP请求(使用任何必需的凭据或标头)
- 将响应流包装在自定义
中,该流通过向服务器发出另一个请求来实现irandomaccesstream
,使用Seek
头指定我需要的流的哪一部分Range
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(); } }
}
用户可以搜索视频中的任意位置,流将发出另一个请求,以在指定位置获取流
它仍然比我想象的要复杂,但它是有效的
请注意,服务器必须支持请求中的
范围
标头,并且必须在初始响应中发出内容长度
标头。签出。您可能需要做的是使用HTTP客户端分别验证和创建流(也可以查看Nuget中的MSFT HTTP库),然后将MediaElement
的源设置为该流。@NateDiamond,谢谢,但我没有此方法。。。根据文档,它在Windows 8.0中可用,但它使用IMediaSource参数,该参数仅在8.1中可用。我怀疑该方法存在于本机MediaElement控件中,但没有出现在.NET APIAh中,您是对的!Regular接受一个RandomAccessStream
。@NateDiamond,是的,但我不知道如何实现这个IRandomAccessStream…@NateDiamond,我成功了,我会尽快发布我的解决方案如果你需要一个与Windows.Web.Http.HttpClient
等效的解决方案,请尝试httprandomaccesstream
:@kiewic,很好!但是能够传递HttpRequestMessage会更灵活,而不仅仅是客户端,URII考虑了这个选项,但是在Windows.Web.Http
中,HttpRequestMessage
是不可重用的,因此每次位置改变时都需要一个新实例。此外,可以在HttpClient中取消配置自定义头、身份验证、重定向、压缩等。@kiewic Awesome!!!!回答我的问题,拿到赏金
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);
}