Skip to content

Instantly share code, notes, and snippets.

@schmidtsonian
Created August 20, 2019 08:40
Show Gist options
  • Save schmidtsonian/a2da2a60912a09009235fa7ea3660084 to your computer and use it in GitHub Desktop.
Save schmidtsonian/a2da2a60912a09009235fa7ea3660084 to your computer and use it in GitHub Desktop.
//https://stackoverflow.com/a/52357595/2690846
// usage: let frames = await extractFramesFromVideo("https://example.com/video.webm");
async extractFramesFromVideo(videoUrl: string, fps=3) {
return new Promise(async (resolve) => {
// fully download it first (no buffering):
let videoBlob = await fetch(videoUrl).then(r => r.blob());
let videoObjectUrl = URL.createObjectURL(videoBlob);
let video = document.createElement('video');
let seekResolve;
video.addEventListener('seeked', async function() {
if(seekResolve) seekResolve();
});
video.src = videoObjectUrl;
// workaround chromium metadata bug (https://stackoverflow.com/q/38062864/993683)
while((video.duration === Infinity || isNaN(video.duration)) && video.readyState < 2) {
await new Promise(r => setTimeout(r, 1000));
video.currentTime = 10000000*Math.random();
}
let duration = video.duration;
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
let [w, h] = [video.videoWidth, video.videoHeight]
canvas.width = w;
canvas.height = h;
let theFrames: string[] = [];
let interval = 1 / fps;
let currentTime = 0;
while(currentTime < duration) {
video.currentTime = currentTime;
await new Promise(r => seekResolve=r);
if (context) {
context.drawImage(video, 0, 0, w, h);
let base64ImageData = canvas.toDataURL();
theFrames.push(base64ImageData);
}
currentTime += interval;
}
resolve(theFrames);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment