Spaces:
Sleeping
Sleeping
| 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.')); | |
| }; | |
| }); | |
| } | |