强制Chrome完全缓冲mp4视频

26

我看到了一些关于这个问题的讨论,但都没有给出答案,所以我想在这个已经被污染的与YouTube相关的页面上再添加一个。

我有一个100MB的mp4视频需要被浏览器完全下载,

然而当视频被完全下载时,不会触发任何事件,Chrome似乎停止缓冲视频,并等待当前视频时间接近缓冲区末端时才请求更多的数据。

我该如何让浏览器完全下载视频并将其缓冲到100%?

谢谢。

3个回答

47

可悲的是,Chrome - 像其他HTML5浏览器一样 - 试图聪明地下载并避免不必要的带宽使用...这意味着有时我们会得到次优的体验(具有讽刺意味的是,YouTube受此影响如此之大,以至于有扩展程序强制进行更多的预缓冲!)

尽管如此,在具有良好服务器和良好连接的情况下,我发现这并不经常需要 - 但是如果您需要一些东西,我发现唯一的解决方案是使用Ajax下载要播放的文件,然后将其加载到视频元素的源中。

下面的示例假定您的浏览器支持m4v/mp4格式 - 如果无法保证(例如)Chrome,则可能需要使用canPlayType测试来选择最适合您用户的视频格式。您还需要测试以查看它对所需大小的视频处理得有多好(我尝试了一些相当大的视频,但不确定这将可靠地处理什么上限)

该示例也非常简单...它启动请求并在加载过程中不向用户传达任何信息 - 对于您的大小视频,您可能需要显示进度条以保持他们的兴趣...

这个过程的另一个缺点是,在完全下载文件之前,它不会开始播放 - 如果您想更深入地从缓冲区动态显示视频,则需要开始深入探讨(目前)MediaSource等帖子中描述的领先技术世界,例如http://francisshanahan.com/index.php/2013/build-an-mpeg-dash-player-from-scratch/

<!DOCTYPE html>
<html>
<head>
<title>Preload video via AJAX</title>
</head>
<body>
<script>
console.log("Downloading video...hellip;Please wait...")
var xhr = new XMLHttpRequest();
xhr.open('GET', 'BigBuck.m4v', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
  if (this.status == 200) {
    console.log("got it");
    var myBlob = this.response;
    var vid = (window.webkitURL || window.URL).createObjectURL(myBlob);
    // myBlob is now the blob that the object URL pointed to.
    var video = document.getElementById("video");
    console.log("Loading video into element");
    video.src = vid;
    // not needed if autoplay is set for the video element
    // video.play()
   }
  }

xhr.send();
</script>

<video id="video" controls autoplay></video>

</body>
</html>

1
Blob在三星Internet(三星的默认浏览器)8.2版本中无法正常工作。 - Antonios Tsimourtos
1
我可以问一下,作为一个终端用户视频观看者,我该如何做到这一点,而不是作为网站开发人员? - Hon

4
我的解决方案是针对比OP描述的视频要小得多,但期望的行为是相同的:在视频完全缓冲之前防止视频开始播放。如果视频已经被缓存,视频应该可以播放给返回用户。
下面的答案受到此answer的很大影响,并已在Chrome、Safari和Firefox上进行了测试。
Javascript文件:
    $(document).ready(function(){
      // The video_length_round variable is video specific.
      // In this example the video is 10.88 seconds long, rounded up to 11.
      var video_length_round = 11;

      var video = document.getElementById('home_video_element');
      var mp4Source = document.getElementById('mp4Source');

      // Ensure home_video_element present on page
      if(typeof video !== 'undefined'){

        // Ensure video element has an mp4Source, if so then update video src
        if(typeof mp4Source !== 'undefined'){
          $(mp4Source).attr('src', '/assets/homepage_video.mp4');
        }

        video.load();

        // Ensure video is fully buffered before playing
        video.addEventListener("canplay", function() {
          this.removeEventListener("canplay", arguments.callee, false);

          if(Math.round(video.buffered.end(0)) >= video_length_round){
            // Video is already loaded
            this.play();

          } else {
            // Monitor video buffer progress before playing
            video.addEventListener("progress", function() {
              if(Math.round(video.buffered.end(0)) == video_length_round){
                this.removeEventListener("progress", arguments.callee, false);
                video.play();
              }
            }, false);
          }
        }, false);
      }
    });

上面的 JavaScript 更新了视频元素的源,例如这个:
    <video id="home_video_element" loop="" poster="/assets/home/video_poster_name.jpg" preload="auto">
      <source id="mp4Source" type="video/mp4">
    </video>

0

我曾经遇到一个类似的问题,我想要在桌面端不计量的连接上更积极地加载视频。我尝试研究了上面某个答案提到的MediaSource,但那样做需要我把我的mp4编码为分段mp4,这看起来太麻烦了。

最终,我选择了以下行为:

<!DOCTYPE html>
<html>
<head>
  <title>Test</title>
</head>

<script>
  function load(){
    const url = document.getElementById('url').value
    const vid = document.getElementById('video')
    vid.src = url;
    const progressElem = document.getElementById('progress')

    const xhr = new XMLHttpRequest();
    xhr.onload = function() {
        const wasPaused = vid.paused
        const time =  vid.currentTime;
        vid.src = URL.createObjectURL(xhr.response);
        vid.currentTime = time;
        if(!wasPaused)
          vid.play();
    };
    xhr.onprogress = onprogress = function (event) {
      progressElem.innerText = 'Download Progress: ' + (event.loaded / event.total);
    };

    xhr.responseType = "blob";
    xhr.open("GET", url)
    xhr.send();
  }
</script>


<body style="padding-left: 30px">
    <h1>Testing video loading</h1>
    <input type="text" id="url" value="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" size="200">
    <br>
    <button onclick="load()">Load Video</button>
    <br>
    <h3 id="progress"></h3>
    <br>
    <video id="video" style="max-width:min(800px, 100vw)" controls></video>
</body>
</html>

基本上,我会让用户从浏览器本地流式传输视频,但同时也会开始下载整个文件,一旦完成下载,我就会将已下载的数据替换到 vid.src 中,并确保播放器处于正确的状态。请注意,这会在视频中创建轻微的卡顿/缓冲效果。

这种解决方案肯定不是带宽效率最高的,但对于桌面上的 1-2GB 视频文件似乎运行得相当不错。

我还应该提到的是,我认为你只应该在 Chrome 中这样做,因为其他浏览器可能有更好的解决方案。例如,在 Firefox 中,用户可以访问 设置,以控制视频缓冲的大小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接