Skip to content

Instantly share code, notes, and snippets.

@atwong
Last active August 16, 2023 10:08
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save atwong/49b9e7d911dca0663e23c50c60f28784 to your computer and use it in GitHub Desktop.
Save atwong/49b9e7d911dca0663e23c50c60f28784 to your computer and use it in GitHub Desktop.
Extract Multiple Screenshots Video
/*
* Extract multiple screenshots/frames from a video URL
* Params
* - vidURL : video URL
* - frOffsets : array of timestamps
* - frameWidth : screenshot width (default: video width)
* Returns
* - frames: object with offset => {imgUrl, blob}
*
* An multiple-frame extension of http://cwestblog.com/2017/05/03/javascript-snippet-get-video-frame-as-an-image/
* In this version, video & canvas elements are reused to extract multiple screenshots. Note, video seeks must
* occur serially, hence use of async/await.
*/
function extractVideoFrames(vidUrl, frOffsets, frameWidth) {
function extractFrame(video, canvas, offset) {
return new Promise((resolve, reject) => {
video.onseeked = event => {
var ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
canvas.toBlob(blob => {
resolve({offset: offset, imgUrl: canvas.toDataURL() , blob: blob});
}, "image/png");
};
video.currentTime = offset;
});
};
async function serialExtractFrames(video, canvas, offsets) {
var frames = {};
var lastP = null;
for (var offset of offsets) {
if (offset < video.duration) {
if (lastP) {
var f = await lastP
frames[f.offset] = f;
}
lastP = extractFrame(video, canvas, offset);
}
}
if (lastP) {
var f = await lastP;
frames[f.offset] = f;
lastP = null;
}
return frames;
};
return new Promise((resolve, reject) => {
var vvid = document.createElement("video");
var vcnv = document.createElement("canvas");
vvid.onloadedmetadata = event => {
var aspect_ratio = vvid.videoWidth/vvid.videoHeight;
vcnv.width = frameWidth !== undefined ? frameWidth : vvid.videoWidth;
vcnv.height = vcnv.width/aspect_ratio;
if (vvid.duration) {
serialExtractFrames(vvid, vcnv, frOffsets).then(resp => {
resolve(resp);
})
}
}
vvid.src = vidUrl;
});
};
export default extractVideoFrames;
@gnanet
Copy link

gnanet commented Nov 9, 2019

I will do my rounds, to check following:

  1. Switch to OffscreenCanvas because i would need the videoframe content, but will not interfere with a video player onthe same page
  2. My goal is a bit different, because i need the frames for analysing, which makes saving them unnecessary, so i will get the frame as data with getImageData

lets see

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment