Alex
Alex

Reputation: 3791

HTML5 video full preload in javascript

I have a high quality video which I cannot compress too much as it's going to be the base of a lot of image analysis whereby each frame will be redrawn into the canvas and then manipulated.

I'm trying to preload the whole thing before playing it as I can't have the video stop, buffer and continue. Is there an event which I can listen for which signifies that the whole video has preloaded before I commence playback?

Here's how I'm doing it in JS/jQuery:

this.canvas            = this.el.find("canvas")[0];
this.video             = this.el.find("video")[0];
this.ctx               = this.canvas.getContext("2d");
this.video.autoplay    = false;

this.video.addEventListener("play",this.draw)
this.video.addEventListener("timeupdate",this.draw)
this.video.addeventlistener("ended",this.trigger("complete",this))

Upvotes: 20

Views: 50550

Answers (7)

James Craig
James Craig

Reputation: 6864

  1. Download the video using fetch
  2. Convert the response to a blob
  3. Create an object URL from the blob (e.g. blob:http://localhost:8080/df3c4336-2d9f-4ba9-9714-2e9e6b2b8888)
async function preloadVideo(src) {
  const res = await fetch(src);
  const blob = await res.blob();
  return URL.createObjectURL(blob);
}

Usage:

const video = document.createElement("video");
video.src = await preloadVideo("https://example.com/video.mp4");

Upvotes: 12

Simon West
Simon West

Reputation: 3788

canplaythrough is the event that should fire when enough data has downloaded to play without buffering.

From the Opera teams excellent (although maybe very slightly dated now) resource Everything you need to know about HTML5 video and audio

If the load is successful, whether using the src attribute or using source elements, then as data is being downloaded, progress events are fired. When enough data has been loaded to determine the video's dimensions and duration, a loadedmetadata event is fired. When enough data has been loaded to render a frame, the loadeddata event is fired. When enugh data has been loaded to be able to play a little bit of the video, a canplay event is fired. When the browser determines that it can play through the whole video without stopping for downloading more data, a canplaythrough event is fired; this is also when the video starts playing if it has a autoplay attribute.

'canplaythrough' support matrix available here: https://caniuse.com/mdn-api_htmlmediaelement_canplaythrough_event

You can get around the support limitations by binding the load element to the same function, as it will trigger on those.

Upvotes: 12

stackFish
stackFish

Reputation: 607

Hope this could help you

var xhrReq = new XMLHttpRequest();
xhrReq.open('GET', 'yourVideoSrc', true);
xhrReq.responseType = 'blob';

xhrReq.onload = function() {
    if (this.status === 200) {
        var vid = URL.createObjectURL(this.response);
        video.src = vid;
    }
}
xhrReq.onerror = function() {
    console.log('err' ,arguments);
}
xhrReq.onprogress = function(e){
    if(e.lengthComputable) {
        var percentComplete = ((e.loaded/e.total)*100|0) + '%';
        console.log('progress: ', percentComplete);
    }
}
xhrReq.send();

and then , if your video src has another domain ,you have to handle CORS .

Upvotes: 2

Meekohi
Meekohi

Reputation: 10883

Does this work?

video.onloadeddata = function(){
  video.onseeked = function(){
    if(video.seekable.end(0) >= video.duration-0.1){
      alert("Video is all loaded!");
    } else {
      video.currentTime=video.buffered.end(0); // Seek ahead to force more buffering
    }
  };
  video.currentTime=0; // first seek to trigger the event
};

Upvotes: 1

jacobsgriffith
jacobsgriffith

Reputation: 1476

This will load the entire video in JavaScript

var r = new XMLHttpRequest();
r.onload = function() {
    myVid.src = URL.createObjectURL(r.response);
    myVid.play();
};
if (myVid.canPlayType('video/mp4;codecs="avc1.42E01E, mp4a.40.2"')) {
    r.open("GET", "slide.mp4");
}
else {
    r.open("GET", "slide.webm");
}

r.responseType = "blob";
r.send();

Upvotes: 26

Tomer Almog
Tomer Almog

Reputation: 3868

You can use this nice plugin: https://github.com/GianlucaGuarini/jquery.html5loader In its API there is a onComplete event that is triggered when the plugin finishes to load all the sources

Upvotes: 1

kroe
kroe

Reputation: 1126

So far the most trustable solution we found was to play it and wait for the buffer to be fully loaded.

Which means if the video is long, you will have to wait for almost all the video length.

That isn't cool, i know.

Wondering if someone has figured out some other magically reliable way of doing it ( ideally using something like PreloadJS which automatically falls back to flash when HTML5 video isn't supported ).

Upvotes: 1

Related Questions