多线程

ffmpeg.wasm 中的多线程功能使 FFmpeg 能够通过 Web Worker 利用多个 CPU 核心进行并行处理,显著提高了资源密集型视频和音频处理任务的性能。本指南介绍了如何使用 ffmpeg.wasm 的多线程版本、其要求以及重要注意事项。

有关 ffmpeg.wasm 基本用法的详细信息,请参阅 基本用法。有关 FFmpeg Core Module 架构的详细信息,请参阅 FFmpeg Core Module。

ffmpeg.wasm 中的多线程概述

ffmpeg.wasm 提供了两种不同的核心实现:

  1. 单线程核心 (@ffmpeg/core):在单个 worker 线程中运行的默认核心
  2. 多线程核心 (@ffmpeg/core-mt):利用多个 Web Worker 进行并行处理的增强型核心

使用多线程版本 (@ffmpeg/core-mt) 时,FFmpeg 核心会启动额外的 web workers 来处理并行处理任务。这是通过 Emscripten 的 pthreads 实现实现的,使其能够同时利用多个 CPU 核心。

多线程的要求

使用多线程版本需要特定的浏览器特性和安全配置:

  1. SharedArrayBuffer 支持:浏览器必须支持 SharedArrayBuffer,它实现了线程间的高效内存共享。
  2. 跨源隔离 (Cross-Origin Isolation):您的应用程序必须是跨源隔离的。这需要特定的 HTTP 头:
    • Cross-Origin-Opener-Policy: same-origin
    • Cross-Origin-Embedder-Policy: require-corp
  3. workerURL 参数:与单线程版本不同,调用 load() 时必须提供 workerURL 以指向多线程 worker 脚本

如果未满足这些要求,多线程版本将无法工作,因为 SharedArrayBuffer 仅在跨源隔离上下文中可用。

服务器配置

为了启用多线程所需的跨源隔离,您的服务器必须发送适当的 HTTP 头。以下是 vanilla-app 示例中使用的配置:

app.use((_, res, next) => {
 res.set({
 "Cross-Origin-Opener-Policy": "same-origin",
 "Cross-Origin-Embedder-Policy": "require-corp",
 "Cross-Origin-Resource-Policy": "cross-origin",
 "Origin-Agent-Cluster": "?1",
 "Access-Control-Allow-Origin": "*",
 });
 next();
});

这些头信息告诉浏览器您的页面需要跨源隔离,这对于 SharedArrayBuffer 正常运行是必要的。

架构

ffmpeg.wasm 的多线程架构由几个协同工作的组件组成:

多线程系统架构

多线程

多线程数据流

多线程

使用多线程版本

要使用多线程版本,您必须将 load() 方法指向 @ffmpeg/core-mt 资源。请注意,如果您使用的是 Vite 等构建工具,应使用 esm 分发版。

import { FFmpeg } from "@ffmpeg/ffmpeg";
import { toBlobURL } from "@ffmpeg/util";
 
const ffmpeg = new FFmpeg();
 
const load = async () => {
 const baseURL = "https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.10/dist/esm";

 await ffmpeg.load({
 coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
 wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"),
 // 多线程必需
 workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"),
 });
};

性能和限制

PTHREAD_POOL_SIZE

多线程核心通常以固定的线程池大小编译(例如 PTHREAD_POOL_SIZE=32)。这决定了核心可以启动用于处理并行 FFmpeg 任务的 Web Workers 的最大数量。

性能优势

操作优势
x264/x265 编码高(多线程帧/宏块编码)
视频解码中等至高(取决于编解码器支持)
复杂滤镜高(并行滤镜图执行)

权衡

  1. 初始化时间:启动 worker 池比初始化单线程核心花费更多时间。
  2. 内存使用:SharedArrayBuffer 需要预先分配固定内存,且每个 worker 都有自己的栈。
  3. 复杂性:需要严格的 COOP/COEP 头,如果处理不当,可能会破坏第三方集成(如某些 OAuth 流程或 CDN)。

测试多线程

该仓库包含针对多线程的自动化测试。这些测试在headless Chrome环境中执行,并带有特定标志以启用隔离功能。

# Example CI test execution for MT
npx mocha-headless-chrome \
 --args="--headless --disable-gpu --no-sandbox --enable-features=SharedArrayBuffer,CrossOriginIsolation" \
 -a no-sandbox \
 -f http://localhost:3000/tests/ffmpeg-core-mt.test.html

您可以编程验证环境:

console.log('SharedArrayBuffer available:', typeof SharedArrayBuffer !== 'undefined');
console.log('crossOriginIsolated:', window.crossOriginIsolated);