Screen-VLA / utils /videoProcessor.ts
Gemini
VLA Data Generator - Complete TypeScript/React app with backend
256cef9
export function extractFramesFromVideo(
videoFile: File,
maxFrames: number
): Promise<string[]> {
return new Promise((resolve, reject) => {
const video = document.createElement('video');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const frames: string[] = [];
if (!context) {
return reject(new Error('Could not create canvas context.'));
}
video.preload = 'metadata';
video.muted = true;
video.playsInline = true;
video.src = URL.createObjectURL(videoFile);
video.onloadedmetadata = () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const duration = video.duration;
if (duration === 0) {
URL.revokeObjectURL(video.src);
return reject(new Error("Video duration is 0, it might be a still image or invalid file."));
}
const interval = duration / maxFrames;
let currentTime = 0;
let framesExtracted = 0;
const extractFrame = () => {
if (framesExtracted >= maxFrames) {
URL.revokeObjectURL(video.src);
resolve(frames);
return;
}
video.currentTime = currentTime;
};
video.onseeked = () => {
context.drawImage(video, 0, 0, canvas.width, canvas.height);
// Use JPEG for smaller file size compared to PNG
const frameDataUrl = canvas.toDataURL('image/jpeg', 0.8);
frames.push(frameDataUrl);
framesExtracted++;
currentTime += interval;
// Ensure we don't seek beyond the video duration
if (currentTime <= duration) {
extractFrame();
} else {
URL.revokeObjectURL(video.src);
resolve(frames);
}
};
video.onerror = (e) => {
URL.revokeObjectURL(video.src);
let message = "An unknown video error occurred.";
if (video.error) {
switch(video.error.code) {
case video.error.MEDIA_ERR_ABORTED:
message = 'The video playback was aborted.';
break;
case video.error.MEDIA_ERR_NETWORK:
message = 'A network error caused the video download to fail.';
break;
case video.error.MEDIA_ERR_DECODE:
message = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support.';
break;
case video.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
message = 'The video could not be loaded, either because the server or network failed or because the format is not supported.';
break;
default:
message = 'An unknown error occurred.';
}
}
reject(new Error(message));
};
// Start the process
extractFrame();
};
video.onerror = () => {
URL.revokeObjectURL(video.src);
reject(new Error('Failed to load video metadata. The file may be invalid or unsupported.'));
};
});
}