I'm trying to extract the frames from a video that is uploaded to my Vue application. Here's the function I'm working with at the moment:
async extractFramesFromVideo(video, duration) {
return new Promise(async (resolve) => {
await video.play();
let seekResolve;
video.addEventListener("seeked", async function() {
if (seekResolve) seekResolve();
});
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d");
let [w, h] = [video.videoWidth, video.videoHeight];
canvas.width = w;
canvas.height = h;
let frames = [];
let interval = 0.1;
let currentTime = 0;
while (currentTime < duration) {
video.currentTime = currentTime;
await new Promise((r) => (seekResolve = r));
context.drawImage(this, 0, 0, w, h);
frames = [...frames, canvas.toDataURL("image/png")];
currentTime += interval;
}
resolve(frames);
});
}
extractFrames
is called from within loadMedia
:
async loadMedia(media) {
// Create URL for uploaded video
const newVideoSrc = URL.createObjectURL(media[0]);
const duration = await getBlobDuration(media[0]);
this.currentVideo.videoSrc = newVideoSrc;
this.currentVideo.name = media[0].name;
this.currentVideo.mimeType = media[0].type;
this.currentVideo.duration = duration;
// Grab video element from main workspace
const baseVideo = document.getElementById("baseVideo");
// Extract frames from video
this.currentVideo.frames = this.extractFrames(baseVideo, duration);
// Add video to Vuex store
this.addVideoToStudio(this.currentVideo);
// Reset currentVideo
this.currentVideo = {
videoSrc: "",
mimeType: "",
name: "",
duration: 0,
frames: [],
};
this.videoLoaded = true;
}
With this configuration I can see the frames being added to the array, but nothing is returned. This is true if I call the method using:
this.currentVideo.frames = await this.extractFrames(baseVideo, duration);
Or using .then()
:
await this.extractFrames(baseVideo, duration)
.then((frames) => {
this.currentVideo.frames = frames;
})
.catch((err) => {
console.log(err);
});
I've logged the value of frames both inside and outside of the loadeddata
event listener and frames is correct inside the event listener. However if I move resolve()
inside the event listener the method doesn't run. I've tried to also define frames inside the loadeddata
event listener, but that hasn't seemed to make a difference.
However, this.currentVideo.frames
is not being updated properly. I have a Vuex action to add the video to my Vuex store, and it seems that I have a timing issue. I think the action is being dispatched before the frames are returned.
6/30/22 Edit: I was looking through the question @Kaiido linked in the comments, but I haven't been able to resolve my issue.
How can I get the extractFrames
function to work in the way that I expect?