HTML5 video full preload in javascript

37,022

Solution 1

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.

Solution 2

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

Solution 3

  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");

Solution 4

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 .

Solution 5

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 ).

Share:
37,022
Alex
Author by

Alex

Updated on July 22, 2021

Comments

  • Alex
    Alex almost 3 years

    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))
    
  • Alex
    Alex about 12 years
    is this fully supported though?
  • Simon West
    Simon West about 12 years
    Knowing the half arsed way most of the HTML5 video spec has been implemented by the major vendors, probably not.
  • Placeable
    Placeable over 10 years
    Thanks for this. One note though, Safari browsers doesn't execute the "canplaythrough" event. So you should use "canplay" instead which it does fire. But it seems a bit random the only event that ALWAYS fire is "loadeddata" on Safari.
  • kroe
    kroe almost 10 years
    that should do it! i still didn't test, but that is exactly what i was looking for. thanks a lot.
  • kroe
    kroe almost 10 years
    "canplaythrough" doesn't really solve my issue. and i'm not sure how to put your question as the accepeted
  • Marco Kerwitz
    Marco Kerwitz over 9 years
    @kroe Just click on the tick next to this answer.
  • Volker E.
    Volker E. over 9 years
    The link to areweplayingyet isn't working any more, have you already implemented a working version via load event on iOS devices?
  • Dr.Knowitall
    Dr.Knowitall almost 9 years
    Canplaythrough is a myth. It doesn't work at all, especially in firefox.
  • chadkouse
    chadkouse over 8 years
    Seems like my video player still only takes a certain percentage of the download before pausing it. In my case it preloads about 38-40% and then waits for the video to start playing, then it trickles the rest of the file in. Is there a workaround to download the whole file?
  • jacobsgriffith
    jacobsgriffith over 8 years
    This method for sure downloads the entire video in JavaScript. Check your network traffic using fiddler or the network tab in chrome to make sure. All else fails use some library like jplayer or popcorn.org or videojs
  • Marius
    Marius over 8 years
    This works really well, thanks! I was afraid there would be data url upper limits -- looking around, people say that data urls should be used only with small files. But using your approach, I've been preloading ~100MB videos and it works reliably in chrome.
  • supersan
    supersan almost 5 years
    this should be the accepted answer.. the top answer is wrong because it doesn't really answer the original question
  • plafer
    plafer over 2 years
    This is not preloading. This only fetches it from a remote server to the disk. "Preloading" refers to when a video (or image) is loaded in memory.
  • Enijar
    Enijar over 2 years
    This satisfies the constraints of the author's question. Whilst this is not technically "preloading", it will load the video into a blob (stored on the user's machine for the lifetime of the page), and prevent the issue of video buffering or stopping.
  • alsotang
    alsotang about 2 years
    This method is awesome!! It download the whole video, and nothing would be downloaded while playing or seeking.