架构
本文档提供了 ffmpeg.wasm 架构的技术概述,解释了 JavaScript API 如何与 WebAssembly 核心交互,处理流程如何通过 Web Worker 进行,以及虚拟文件系统如何在浏览器环境中实现媒体处理。
有关特定 FFmpeg Core 实现细节的信息,请参阅 FFmpeg Core Module。有关 JavaScript API 的详细信息,请参阅 JavaScript API Layer。
系统概述
ffmpeg.wasm 被设计为分层架构,通过 WebAssembly 将 FFmpeg 的功能带入 Web 浏览器。该系统将计算密集型视频处理从主线程隔离出来,以确保浏览器的响应性。
该架构由以下关键组件组成:
- FFmpeg Class:应用程序与之交互的 JavaScript API 层。
- Web Worker:通过
worker.ts在独立线程中执行 FFmpeg 操作。 - FFmpeg Core:编译后的 WebAssembly 模块 (
ffmpeg-core.wasm),包含 FFmpeg 及其库。 - Virtual File System:使用 Emscripten 的 FS API 管理 WebAssembly 环境内的文件。
包组织
ffmpeg.wasm 作为一个 monorepo 组织,包含以下包:
| Package | Description |
|---|---|
@ffmpeg/ffmpeg | 暴露 FFmpeg 类的主要 JavaScript API。 |
@ffmpeg/core | 单线程 WebAssembly FFmpeg 实现。 |
@ffmpeg/core-mt | 多线程 WebAssembly FFmpeg 实现。 |
@ffmpeg/util | 工具函数(例如,fetchFile、toBlobURL)。 |
@ffmpeg/types | 核心和 API 的 TypeScript 类型定义。 |
用户主要交互的主包是 @ffmpeg/ffmpeg,它可以根据提供给 load() 的 coreURL 与单线程或多线程核心配合工作。
处理流程
下图说明了使用 ffmpeg.wasm 处理媒体时的典型执行流程:
典型处理流程包括:
- 初始化 (Initialization) - 创建
FFmpeg实例并调用load()以启动 worker 并初始化 WASM 核心 - 输入 (Input) - 通过
writeFile()将输入文件写入虚拟文件系统 - 处理 (Processing) - 通过
exec()执行 FFmpeg 命令 - 输出 (Output) - 通过
readFile()从虚拟文件系统读取处理后的文件 - 清理 (Cleanup) - 使用
terminate()终止 worker
组件详情
FFmpeg Class
FFmpeg 类是应用程序的主要接口。它在 classes.ts 中实现,负责与 web worker 通信并提供基于 Promise 的 API。
关键特性:
- 私有状态管理 (Private state management):使用
#resolves和#rejects跟踪映射到消息 ID 的 Promise 完成状态 - 消息传递 (Message passing):实现私有
#send()方法以向 worker 分发FFMessage对象 - 事件系统 (Event system):提供
on()和off()用于log和progress事件
Web Worker Implementation
web worker 定义在 worker.ts 中,作为 JS API 和 WebAssembly 模块之间的桥梁。它管理 ffmpeg 核心实例并将传入的 FFMessageType 请求转换为核心函数调用。
worker 处理各种消息类型:
LOAD:动态导入核心并调用createFFmpegCoreEXEC/FFPROBE:运行底层 FFmpeg 二进制逻辑FS操作:与ffmpeg.FS接口进行文件管理
FFmpeg Core (WebAssembly)
FFmpeg 核心使用 Emscripten 编译。构建过程(在 Dockerfile 中定义)链接了多个库,包括 x264、x265、libvpx 和 opus,最终生成 WASM 二进制文件。
Virtual File System
虚拟文件系统 (VFS) 由 Emscripten 的 FS API 提供。ffmpeg.wasm 通过 mount 命令支持多种后端,包括 MEMFS(默认)、NODEFS 和 WORKERFS,以实现无需将数据复制到内存的高性能文件访问。
多线程支持
多线程版本(@ffmpeg/core-mt)使用 SharedArrayBuffer 并启动内部工作线程(ffmpeg-core.worker.js)以实现编码/解码的并行处理。
为了处理在工作环境中定位这些资源的复杂性,ffmpeg.wasm 采用了一种 mainScriptUrlOrBlob 技巧,将 wasmURL 和 workerURL 编码到传递给核心工厂的 URL 哈希中。