架构

本文档提供了 ffmpeg.wasm 架构的技术概述,解释了 JavaScript API 如何与 WebAssembly 核心交互,处理流程如何通过 Web Worker 进行,以及虚拟文件系统如何在浏览器环境中实现媒体处理。

有关特定 FFmpeg Core 实现细节的信息,请参阅 FFmpeg Core Module。有关 JavaScript API 的详细信息,请参阅 JavaScript API Layer。

系统概述

ffmpeg.wasm 被设计为分层架构,通过 WebAssembly 将 FFmpeg 的功能带入 Web 浏览器。该系统将计算密集型视频处理从主线程隔离出来,以确保浏览器的响应性。

架构

该架构由以下关键组件组成:

  1. FFmpeg Class:应用程序与之交互的 JavaScript API 层。
  2. Web Worker:通过 worker.ts 在独立线程中执行 FFmpeg 操作。
  3. FFmpeg Core:编译后的 WebAssembly 模块 (ffmpeg-core.wasm),包含 FFmpeg 及其库。
  4. Virtual File System:使用 Emscripten 的 FS API 管理 WebAssembly 环境内的文件。

包组织

ffmpeg.wasm 作为一个 monorepo 组织,包含以下包:

PackageDescription
@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 处理媒体时的典型执行流程:

架构

典型处理流程包括:

  1. 初始化 (Initialization) - 创建 FFmpeg 实例并调用 load() 以启动 worker 并初始化 WASM 核心
  2. 输入 (Input) - 通过 writeFile() 将输入文件写入虚拟文件系统
  3. 处理 (Processing) - 通过 exec() 执行 FFmpeg 命令
  4. 输出 (Output) - 通过 readFile() 从虚拟文件系统读取处理后的文件
  5. 清理 (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:动态导入核心并调用 createFFmpegCore
  • EXEC / 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 哈希中。