65.9K
CodeProject 正在变化。 阅读更多。
Home

MediaElement 的 DownloadProgress、DownloadProgressOffset 和 BufferProgress

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2009年2月17日

CPOL

4分钟阅读

viewsIcon

43835

downloadIcon

1223

本文介绍 MediaElement 的 DownloadProgress、DownloadProgressOffset 和 BufferProgress。

MediaElementDownloadProgress

引言

本文介绍 MediaElementDownloadProgressDownloadProgressOffsetBufferProgress 属性。

背景

我正在使用 MediaElement,因为我需要从 HTTP URL 播放视频。我遇到了一个奇怪的问题。在正常情况下,MediaElementDownloadProgress 属性会更新 UI 进度条。它在下载时工作正常,DownloadProgress 会增加。但是,当用户单击文件中的另一个位置时,DownloadProgress 值会变为 1.0 (100%),DownloadProgressOffset 也是如此。过一段时间后,它会自行纠正。您可以在以下链接中找到相同的问题:http://silverlight.net/forums/p/69162/167219.aspx

在解释问题之前,我先解释一些我将用来解释显示 DownloadProgressDownloadProgressOffset 问题的定义。

字节范围请求

HTTP 请求有一个选项可以进行部分内容范围请求。为了解释它,让我们举一个场景。假设我想从一个服务请求一个非常大的文件,但在我这样做之前,我想确切地知道它有多大,以及该服务是否支持“范围请求”。为此,我对我要检索的大资源发出一个 HEAD 请求。HEAD 方法是一种标准的 HTTP 方法,其作用就像我发出了一个 GET 请求,但它只返回头信息而不返回主体。这使我能够在不花费时间或带宽下载的情况下了解资源的信息。例如,我可以读取 Content-Length 头并确定资源的大小。

另一个非常重要的头是 Accept-Ranges 头。如果存在,它可能包含值“bytes”。如果是这样,我就知道我可以发出一个 GET 请求并请求一个字节范围来检索这些字节。这是第一个重要的组成部分。

所以,现在我知道我可以向该服务发出范围请求,通过发送一个包含 Range 头(指定我请求的字节范围)的标准 GET 请求来完成,如下所示:Range: bytes=0-999。然后,该服务应该响应一个 206 Partial Content 状态码、一个 Content-Range 头以及请求的字节范围。这是第二个关键组成部分。

我应该注意到,服务不能强制客户端发出范围请求。这完全取决于客户端是否发出此类请求,因此服务应遵守所有不包含 Range 头部的标准 GET 请求,并发送所请求资源的完整表示。如果您的服务允许范围请求,最好通过 Accept-Ranges 头告知客户端。如果您想明确告知客户端您不允许范围请求,请在 Accept-Ranges 头中发送“none”的值。

我从以下文章中获得了此定义,因此如果对您来说不清楚,您可以参考以下文章:http://benramsey.com/archives/206-partial-content-and-range-requests/

DownloadProgress

MediaElementDownloadProgress 属性是一个百分比,表示远程服务器上内容的下载完成量。该值范围从 0 到 1。将其乘以 100 即可获得百分比。默认值为 0。设置此属性时,会发生 DownloadProgressChanged 事件。

DownloadProgressOffset

它获取 MediaElement 下载进度的偏移量。当用户跳转到下载进度中的某个点时(例如,视频的第 30 秒),该点将成为下载进度的偏移量。

BufferingProgress

获取一个指示当前缓冲进度的值。它是为媒体内容完成的缓冲量。该值范围从 0 到 1。乘以 100 即可获得百分比。默认值为 0。每当 BufferingProgress 属性更新 0.05 或更多,或者达到 1.0 时,就会发生 BufferingProgressChanged 事件。在某些情况下,BufferingProgress 值在媒体播放时不会保持为 1。

问题解释

当用户播放 HTTP URL 时,它会下载文件,DowloadProgressDownloadProgressOffest 工作正常,但是当用户更改播放位置或第一次“seek”操作发生时,播放器实际上会触发一个 BRR,下载 WMV 文件的索引(位于文件末尾)。此时,DownloadProgressDownloadProgressOffset 都将非常接近终点,所以过一段时间后,DownloadProgressDownloadProgressOffset 都将达到 100%,这实际上意味着索引文件已完全下载。之后,DownloadProgress 会回退到 seek 点。

Using the Code

代码中没有什么需要解释的。它不言自明。我使用 DownloadProgressChangedBufferingProgressChanged 事件来设置 DownloadProgressDownloadProgressOffsetBufferOffset 进度条。

private void VideoMediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
    //VideoMediaElement.Position = TimeSpan.FromDays(1);
    //VideoMediaElement.Position = TimeSpan.FromSeconds(0);
}

private void Video_BufferingProgressChanged(object sender, RoutedEventArgs e)
{
    BufferProgress.Value = VideoMediaElement.BufferingProgress * 100;
    DownloadProgress.Value = VideoMediaElement.DownloadProgress * 100;
    OffsetValue.Value = VideoMediaElement.DownloadProgressOffset * 100;
}

private void Video_DownloadProgressChanged(object sender, RoutedEventArgs e)
{
    DownloadProgress.Value = VideoMediaElement.DownloadProgress * 100;
    OffsetValue.Value = VideoMediaElement.DownloadProgressOffset * 100;
}

private void Pause_Click(object sender, RoutedEventArgs e)
{
    VideoMediaElement.Pause();
}
private void Play_Click(object sender, RoutedEventArgs e)
{
    if (!Uri.IsWellFormedUriString(URI.Text, UriKind.Absolute))
    {
        MessageBox.Show("Invalid URI");
        return;
    }
    VideoMediaElement.Source = new Uri(URI.Text);
    VideoMediaElement.Play();
}
private void Stop_Click(object sender, RoutedEventArgs e)
{
    VideoMediaElement.Stop();
}
private void Farward_Click(object sender, RoutedEventArgs e)
{
    //if (VideoMediaElement.CurrentState != MediaElementState.Buffering) 
    VideoMediaElement.Position = VideoMediaElement.Position + 
                      TimeSpan.FromSeconds(Int16.Parse(Amount.Text));
}
private void Backward_Click(object sender, RoutedEventArgs e)
{
    //if (VideoMediaElement.CurrentState != MediaElementState.Buffering) 
    VideoMediaElement.Position = VideoMediaElement.Position - 
                      TimeSpan.FromSeconds(Int16.Parse(Amount.Text));
}
© . All rights reserved.