虚拟文件系统
虚拟文件系统 (VFS) 是 ffmpeg.wasm 的关键组件,它使得在浏览器环境中进行文件操作成为可能。由于 Web 浏览器无法直接访问本地文件系统,ffmpeg.wasm 实现了一个虚拟文件系统,允许在内存中读取、写入和管理文件和目录。该系统充当 FFmpeg 基于文件的操作与浏览器沙盒环境之间的中间层。
概述
ffmpeg.wasm 中的虚拟文件系统构建于 Emscripten 的文件系统实现之上。它提供了一个完整的文件系统 API,支持在浏览器内存空间中执行创建、读取、写入和删除文件和目录等操作。这使得 FFmpeg 能够像处理常规文件系统上的文件一样处理媒体文件,而实际上完全在浏览器内运行。
数据流管道
系统遵循“写入 - 执行 - 读取”的管道流程。文件被写入 VFS,由 WebAssembly 核心处理,然后将结果读回 JavaScript。
标题:VFS 写入 - 执行 - 读取管道
实现细节
VFS 实现为 FFmpeg 类和 FFmpegCoreModule 之间的一层。它在 Web Worker 内部完全运行,以防止阻塞主线程。
标题:代码实体映射
主要组件
- JavaScript API 层:
FFmpeg类提供高级方法,封装复杂的消息传递逻辑 - Web Worker 处理器:
worker.ts文件包含将传入的FFMessageType事件转换为对 EmscriptenFS对象直接调用的逻辑 - Emscripten FS:由编译后的 WebAssembly 核心提供的底层文件系统实现
文件系统后端
ffmpeg.wasm 通过 FFFSType 枚举支持多种文件系统类型
| 文件系统类型 | 描述 | 使用场景 |
|---|---|---|
MEMFS | 内存文件系统。 | 默认选项;速度快但易失且占用内存 |
WORKERFS | 只读访问浏览器的 File 和 Blob 对象。 | 处理大文件而无需将其复制到 WASM 内存 |
IDBFS | 通过 IndexedDB 进行持久化存储。 | 跨页面重新加载缓存文件 |
NODEFS | 直接访问 Node.js fs。 | 当前仅浏览器构建版本不支持 |
WORKERFS 挂载
WORKERFS 的独特之处在于它允许直接将 Blob 或 File 对象挂载到文件系统。这避免了在调用 writeFile 之前需要将文件读取到 Uint8Array 的需求。
// WORKERFS mounting logic in worker.ts
const mount = ({ fsType, options, mountPoint }: FFMessageMountData): OK => {
const str = fsType as keyof typeof ffmpeg.FS.filesystems;
const fs = ffmpeg.FS.filesystems[str];
if (!fs) return false;
ffmpeg.FS.mount(fs, options, mountPoint);
return true;
};API 参考
FFmpeg 类暴露了以下与 VFS 相关的方法:
文件操作
writeFile(path, data):将Uint8Array或string写入 VFSreadFile(path, encoding):读取文件。默认返回Uint8Array,如果指定了编码则返回stringdeleteFile(path):从 VFS 中解除链接文件rename(oldPath, newPath):移动或重命名文件/目录
目录操作
createDir(path):创建新目录listDir(path):返回FSNode对象数组(包含名称和isDir标志)deleteDir(path):删除空目录
挂载操作
mount(fsType, options, mountPoint):将特定后端(例如WORKERFS)挂载到路径unmount(mountPoint):卸载已挂载的文件系统
使用模式
标准内存工作流
这是中小型文件最常见的模式。
// 1. Write input to memory
await ffmpeg.writeFile('input.mp4', data);
// 2. Execute command (reads from and writes to VFS)
await ffmpeg.exec(['-i', 'input.mp4', 'output.mp4']);
// 3. Read result from memory
const output = await ffmpeg.readFile('output.mp4');高效大文件工作流 (WORKERFS)
为了避免在处理大于 1GB 的文件时出现 RangeError: Array buffer allocation failed 错误,请使用 WORKERFS。
await ffmpeg.mount(FFFSType.WORKERFS, {
files: [fileHandle], // 浏览器 File 对象
}, '/mnt');
await ffmpeg.exec(['-i', '/mnt/video.mp4', 'out.gif']);技术实现内部细节
消息序列化
当调用 readFile 时,worker 会检测数据是否为 Uint8Array。如果是,它会将底层的 ArrayBuffer 添加到 postMessage 的 transferables 列表中,以避免内存克隆。
退出与清理
每次 exec 或 ffprobe 调用后,FFmpeg 核心模块都会重置,以确保内部状态(包括文件描述符)被清除,尽管 VFS 文件会保留直到被删除或 worker 终止。