import { FFmpeg } from '@ffmpeg/ffmpeg'; import { toBlobURL } from '@ffmpeg/util'; let ffmpeg: FFmpeg | null = null; export const initFFmpeg = async (): Promise => { if (ffmpeg) return ffmpeg; ffmpeg = new FFmpeg(); // Use locally hosted files instead of CDN const baseURL = '/ffmpeg'; await ffmpeg.load({ coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'), wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, 'application/wasm'), }); return ffmpeg; }; export const generateThumbnail = async ( videoFile: File, timeInSeconds: number = 1 ): Promise => { const ffmpeg = await initFFmpeg(); const inputName = 'input.mp4'; const outputName = 'thumbnail.jpg'; // Write input file await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer())); // Generate thumbnail at specific time await ffmpeg.exec([ '-i', inputName, '-ss', timeInSeconds.toString(), '-vframes', '1', '-vf', 'scale=320:240', '-q:v', '2', outputName ]); // Read output file const data = await ffmpeg.readFile(outputName); const blob = new Blob([data], { type: 'image/jpeg' }); // Cleanup await ffmpeg.deleteFile(inputName); await ffmpeg.deleteFile(outputName); return URL.createObjectURL(blob); }; export const trimVideo = async ( videoFile: File, startTime: number, endTime: number, onProgress?: (progress: number) => void ): Promise => { const ffmpeg = await initFFmpeg(); const inputName = 'input.mp4'; const outputName = 'output.mp4'; // Set up progress callback if (onProgress) { ffmpeg.on('progress', ({ progress }) => { onProgress(progress * 100); }); } // Write input file await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer())); const duration = endTime - startTime; // Trim video await ffmpeg.exec([ '-i', inputName, '-ss', startTime.toString(), '-t', duration.toString(), '-c', 'copy', // Use stream copy for faster processing outputName ]); // Read output file const data = await ffmpeg.readFile(outputName); const blob = new Blob([data], { type: 'video/mp4' }); // Cleanup await ffmpeg.deleteFile(inputName); await ffmpeg.deleteFile(outputName); return blob; }; export const getVideoInfo = async (videoFile: File): Promise<{ duration: number; width: number; height: number; fps: number; }> => { const ffmpeg = await initFFmpeg(); const inputName = 'input.mp4'; // Write input file await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer())); // Get video info await ffmpeg.exec(['-i', inputName, '-f', 'null', '-']); // Note: In a real implementation, you'd parse the FFmpeg output // For now, we'll return default values and enhance this later // Cleanup await ffmpeg.deleteFile(inputName); return { duration: 10, // Placeholder - would parse from FFmpeg output width: 1920, // Placeholder height: 1080, // Placeholder fps: 30 // Placeholder }; }; export const convertToWebM = async ( videoFile: File, onProgress?: (progress: number) => void ): Promise => { const ffmpeg = await initFFmpeg(); const inputName = 'input.mp4'; const outputName = 'output.webm'; // Set up progress callback if (onProgress) { ffmpeg.on('progress', ({ progress }) => { onProgress(progress * 100); }); } // Write input file await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer())); // Convert to WebM await ffmpeg.exec([ '-i', inputName, '-c:v', 'libvpx-vp9', '-crf', '30', '-b:v', '0', '-c:a', 'libopus', outputName ]); // Read output file const data = await ffmpeg.readFile(outputName); const blob = new Blob([data], { type: 'video/webm' }); // Cleanup await ffmpeg.deleteFile(inputName); await ffmpeg.deleteFile(outputName); return blob; }; export const extractAudio = async ( videoFile: File, format: 'mp3' | 'wav' = 'mp3' ): Promise => { const ffmpeg = await initFFmpeg(); const inputName = 'input.mp4'; const outputName = `output.${format}`; // Write input file await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer())); // Extract audio await ffmpeg.exec([ '-i', inputName, '-vn', // Disable video '-acodec', format === 'mp3' ? 'libmp3lame' : 'pcm_s16le', outputName ]); // Read output file const data = await ffmpeg.readFile(outputName); const blob = new Blob([data], { type: `audio/${format}` }); // Cleanup await ffmpeg.deleteFile(inputName); await ffmpeg.deleteFile(outputName); return blob; };