You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击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/wasm MIME类型
  • 生产环境部署时,确认服务器配置了正确的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 08:50:02