Another: Force Chrome to fully buffer mp4 video

Solution 1:

Sadly Chrome - like other HTML5 browsers - tries to be smart about what it's downloading and avoids unnecessary bandwidth usage... this means that sometimes we're left with a sub-optimal experience (ironically YouTube suffers from this so much that there are extensions to force more pre-buffering!)

That said, I've not found this to be required too often with a good server and a good connection - but if you need something the only solution I have found is a bit of a sledgehammer... use Ajax to download the file that you want to play and then load that into the source for the video element.

The sample below assumes your browser supports m4v/mp4 - you'll probably want to use the canPlayType test to select the most appropriate video format for your users if you can't guarantee (eg) Chrome. You'll also want to test to see how well it handles videos of the size you want (I've tried some fairly large ones but not sure what upper limit this will reliably handle)

The sample is also pretty simple... it kicks off the request and doesn't communicate anything to the user while it's loading - with your size video you're probably going to want to show a progress bar just to keep them interested...

the other downside of this process is that it's not going to start playing until you've fully downloaded the file - if you want to go deeper into displaying the video dynamically from your buffer then you'll need to start delving into the bleeding edge (at the moment) world of MediaSource as described in posts like 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>

Solution 2:

My solution is for a much smaller video than the OP described, however the desired behaviour is the same: Prevent the video from beginning playback until the video is fully buffered. Video should play for returning users if the video is already cached.

Below answer was heavily influenced by this answer and has been tested on Chrome, Safari and Firefox.

Javascript file:

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

Above javascript updates the source of a video element such as this one:

    <video id="home_video_element" loop="" poster="/assets/home/video_poster_name.jpg" preload="auto">
      <source id="mp4Source" type="video/mp4">
    </video>