使用FFmpeg.wasm合并音视频触发Bad Memory错误(Chrome扩展Manifest V2)
问题描述
我正在开发基于Manifest V2的Chrome扩展,功能是获取视频URL与音频URL,通过FFmpeg.wasm(@ffmpeg/ffmpeg v0.9.6、@ffmpeg/core v0.8.5)合并后下载结果。但实际运行时未完成音视频合并,反而抛出Uncaught (in promise) Error: bad memory错误。
相关代码如下:
const onDownloadClickModal = async (event) => { const path = getPathInfo(event); const [videoUrl, audioUrl] = await getVideoUrl(path); let { createFFmpeg, fetchFile } = FFmpeg; let ffmpeg = createFFmpeg(); await ffmpeg.load(); ffmpeg.FS("writeFile", "video.mp4", await fetchFile(videoUrl)); ffmpeg.FS("writeFile", "audio.mp4", await fetchFile(audioUrl)); await ffmpeg.run("-i", "video.mp4", "-i", "audio.mp4", "-c", "copy", "output.mp4"); let _data = await ffmpeg.FS("readFile", "output.mp4"); let data = new Uint8Array(_data.buffer); const a = document.createElement("a"); a.href = URL.createObjectURL(new Blob([data], { type: "video/mp4" })); a.download = "output.mp4" a.click(); a.remove(); }
window.addEventListener("load", function () { if (!crossOriginIsolated) SharedArrayBuffer = ArrayBuffer; afterPageLoad(); });
已尝试的方案:
- 参考使用同版本FFmpeg.wasm的用户代码;
- 通过替换SharedArrayBuffer为ArrayBuffer解决其未定义问题;
- 尝试添加跨域头
Cross-Origin-Embedder-Policy: require-corp和Cross-Origin-Opener-Policy: same-origin,但Chrome扩展场景下无法生效。
解决方案
1. 显式分配足够内存
旧版本FFmpeg.wasm默认内存配额不足以处理较大的音视频文件,创建实例时手动指定更大内存:
let ffmpeg = createFFmpeg({ mem: 4 * 1024 * 1024 * 1024, // 分配4GB内存,可根据文件大小调整 log: true // 开启日志,方便排查执行过程中的问题 });
2. 禁用多线程绕开SharedArrayBuffer依赖
直接替换SharedArrayBuffer为ArrayBuffer会破坏FFmpeg.wasm的内存管理逻辑,改为在创建实例时禁用多线程,同时显式指定本地核心文件路径(避免扩展内跨域加载问题):
let ffmpeg = createFFmpeg({ corePath: chrome.runtime.getURL('ffmpeg-core.js'), // 确保核心文件已打包进扩展,路径自行调整 worker: false, // 禁用多线程,无需依赖SharedArrayBuffer log: true });
3. 优化文件读取逻辑
Chrome扩展环境下直接使用fetchFile可能存在内存溢出或跨域问题,改用原生fetch转为ArrayBuffer后写入:
// 自定义fetch转ArrayBuffer函数 const getFileBuffer = async (url) => { const res = await fetch(url, { mode: 'cors' }); return new Uint8Array(await res.arrayBuffer()); }; // 写入FFmpeg文件系统 ffmpeg.FS("writeFile", "video.mp4", await getFileBuffer(videoUrl)); ffmpeg.FS("writeFile", "audio.mp4", await getFileBuffer(audioUrl));
4. 调整FFmpeg合并命令
添加-y参数自动覆盖输出文件,同时明确映射音视频流,避免流匹配错误:
await ffmpeg.run( "-y", // 自动覆盖已存在的output.mp4 "-i", "video.mp4", "-i", "audio.mp4", "-c:v", "copy", "-c:a", "copy", // 分别指定音视频编码复制 "-map", "0:v:0", "-map", "1:a:0", // 映射第一个输入的视频流和第二个输入的音频流 "output.mp4" );
5. 及时清理内存避免泄漏
合并完成后清理临时文件并退出FFmpeg实例,释放占用的内存:
// 下载完成后执行清理 ffmpeg.FS("unlink", "video.mp4"); ffmpeg.FS("unlink", "audio.mp4"); ffmpeg.FS("unlink", "output.mp4"); ffmpeg.exit();
内容的提问来源于stack exchange,提问作者Ralkey
相关产品推荐
相关产品推荐

