点击Create Video按钮无响应且FFmpeg加载失败问题排查
问题描述
我用React、FFmpeg及WASM开发了一款简单视频编辑器,功能是将音频叠加至图片生成视频。但点击Create Video按钮无响应,且出现“failed to load ffmpeg”错误。使用的版本为:@ffmpeg/ffmpeg": "^0.12.7、@ffmpeg/util": "^0.12.1、@ffmpeg/core": "^0.12.3。
附上代码:
import React, { useState, useEffect } from 'react'; import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile, toBlobURL } from '@ffmpeg/util'; function App() { const [videosrc, setvideosrc] = useState(''); const [imgfile, setimgfile] = useState(null); const [audiofile, setaudiofile] = useState(null); const [ffmpeg, setFfmpeg] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { const load = async () => { try { const ffmpegInstance = new FFmpeg(); ffmpegInstance.on('log', ({ message }) => console.log(message)); await ffmpegInstance.load({ coreURL: await toBlobURL(`http://localhost:5173/node_modules/@ffmpeg/core/dist/ffmpeg-core.js`, 'text/javascript'), wasmURL: await toBlobURL(`http://localhost:5173/node_modules/@ffmpeg/core/dist/ffmpeg-core.wasm`, 'application/wasm'), }); setFfmpeg(ffmpegInstance); console.log('FFmpeg loaded successfully'); } catch (err) { console.error('Failed to load FFmpeg:', err); setError('Failed to load FFmpeg'); } }; load(); }, []); const createVideo = async () => { console.log('Create Video button clicked'); setLoading(true); setError(null); if (!ffmpeg) { console.error('FFmpeg not loaded'); setError('FFmpeg not loaded'); setLoading(false); return; } if (!imgfile || !audiofile) { console.error('Image or audio file not selected'); setError('Please select both image and audio files'); setLoading(false); return; } try { console.log('Writing files to MEMFS'); await ffmpeg.writeFile('image.png', await fetchFile(imgfile)); await ffmpeg.writeFile('sound.mp3', await fetchFile(audiofile)); console.log('Running FFmpeg command'); await ffmpeg.exec([ "-framerate", "1/10", "-i", "image.png", "-i", "sound.mp3", "-c:v", "libx264", "-t", "10", "-pix_fmt", "yuv420p", "-vf", "scale=1920:1080", "test.mp4" ]); console.log('Reading output file'); const data = await ffmpeg.readFile('test.mp4'); console.log('Creating URL for video'); const url = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' })); setvideosrc(url); console.log('Video created successfully'); } catch (err) { console.error('Error creating video:', err); setError(`Error creating video: ${err.message}`); } finally { setLoading(false); } }; const handlechangeimage = (e) => { setimgfile(e.target.files[0]); }; const handlechangesound = (e) => { setaudiofile(e.target.files[0]); }; return ( <div> <h1>Image</h1> <input type="file" accept='image/*' onChange={handlechangeimage} /> <h1>Audio</h1> <input type="file" accept='audio/*' onChange={handlechangesound} /> <button onClick={createVideo} disabled={loading}> {loading ? 'Creating Video...' : 'Create Video'} </button> {error && <p style={{color: 'red'}}>{error}</p>} {videosrc && ( <div> <h2>Generated Video:</h2> <video controls src={videosrc} /> </div> )} </div> ); } export default App;
解决方案
1. 修复FFmpeg核心文件加载路径问题
硬编码的本地路径http://localhost:5173/node_modules/@ffmpeg/core/dist/...在生产环境或打包后会失效,开发环境也可能因静态资源规则无法访问node_modules文件,推荐两种修复方式:
方案A:使用官方CDN加载
修改useEffect中的load方法,替换为匹配版本的CDN地址:
await ffmpegInstance.load({ coreURL: await toBlobURL('https://unpkg.com/@ffmpeg/core@0.12.3/dist/ffmpeg-core.js', 'text/javascript'), wasmURL: await toBlobURL('https://unpkg.com/@ffmpeg/core@0.12.3/dist/ffmpeg-core.wasm', 'application/wasm'), });
方案B:本地静态资源配置(Vite环境)
- 将
node_modules/@ffmpeg/core/dist/下的ffmpeg-core.js、ffmpeg-core.wasm复制到项目public目录 - 加载路径改为相对路径:
await ffmpegInstance.load({ coreURL: await toBlobURL('/ffmpeg-core.js', 'text/javascript'), wasmURL: await toBlobURL('/ffmpeg-core.wasm', 'application/wasm'), });
2. 统一依赖版本
当前版本组合存在小版本差异,可能引发API不兼容问题,执行命令统一版本:
npm install @ffmpeg/ffmpeg@0.12.7 @ffmpeg/core@0.12.7 @ffmpeg/util@0.12.7
3. 解决跨域与安全限制
- 开发环境下,确保服务器(如Vite)允许跨域访问静态资源,FFmpeg WASM需要正确的
application/wasmMIME类型 - 生产环境部署时,确认服务器配置了正确的CORS头,且WASM文件的Content-Type设置正确
4. 优化FFmpeg命令参数
原命令中-t 10会强制视频时长为10秒,可调整为跟随音频时长,同时显式指定音频编码提升兼容性:
await ffmpeg.exec([ "-loop", "1", "-i", "image.png", "-i", "sound.mp3", "-c:v", "libx264", "-c:a", "aac", "-pix_fmt", "yuv420p", "-vf", "scale=1920:1080", "-shortest", "test.mp4" ]);
5. 添加FFmpeg加载状态反馈
在FFmpeg加载完成前禁用按钮,避免用户过早点击:
<button onClick={createVideo} disabled={loading || !ffmpeg}> {loading ? 'Creating Video...' : !ffmpeg ? 'Loading FFmpeg...' : 'Create Video'} </button>
内容的提问来源于stack exchange,提问作者shashwat bajpai
相关产品推荐
相关产品推荐

