import { FFmpeg } from '@ffmpeg/ffmpeg' import { toBlobURL } from '@ffmpeg/util' let ffmpegInstance: FFmpeg | null = null let loadPromise: Promise | null = null /** * 获取或初始化 FFmpeg 实例(单例模式) */ export const useFFmpeg = async () => { // 如果已经加载过,直接返回 if (ffmpegInstance && ffmpegInstance.loaded) { return ffmpegInstance } // 如果正在加载中,等待加载完成 if (loadPromise) { return loadPromise } loadPromise = initializeFFmpeg() return loadPromise } async function initializeFFmpeg(enableMT: boolean = false): Promise { try { const ffmpeg = new FFmpeg() ffmpeg.on('log', ({ message, type }) => { console.log(`[ffmpeg - ${type}]`, message) }) ffmpeg.on('progress', ({ progress, time }) => { console.log(`[ffmpeg] P: ${(progress * 100).toFixed(2)}%, T: ${time}ms`) }) const baseURL = enableMT ? 'https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm' : 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.10/dist/esm' const coreURL = await toBlobURL( `${baseURL}/ffmpeg-core.js`, 'text/javascript' ) const wasmURL = await toBlobURL( `${baseURL}/ffmpeg-core.wasm`, 'application/wasm' ) let loadPayload = { coreURL, wasmURL, } if (enableMT) { const workerURL = await toBlobURL( `${baseURL}/ffmpeg-core.worker.js`, 'text/javascript' ) Object.assign(loadPayload, { workerURL }) } const isLoaded = await ffmpeg.load(loadPayload) console.log('[FFmpeg] FFmpeg 加载完成,isLoaded:', isLoaded) ffmpegInstance = ffmpeg loadPromise = null return ffmpeg } catch (error) { console.error('[FFmpeg] 初始化失败:', error) loadPromise = null throw error } } /** * 清理 FFmpeg 资源 */ export const cleanupFFmpeg = () => { if (ffmpegInstance && ffmpegInstance.loaded) { console.log('[FFmpeg] 清理 FFmpeg 资源...') ffmpegInstance.terminate() ffmpegInstance = null loadPromise = null } } /** * 将 Blob/File 转换为 Uint8Array */ export const fileToUint8Array = async ( file: File | Blob ): Promise => { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = (e) => { const arrayBuffer = e.target?.result as ArrayBuffer resolve(new Uint8Array(arrayBuffer)) } reader.onerror = reject reader.readAsArrayBuffer(file) }) }