Docker 构建流程

本文档描述了用于将 FFmpeg 及其依赖项编译为 ffmpeg.wasm WebAssembly 模块的基于 Docker 的构建系统。该构建过程创建了可在 Web 浏览器中运行的单线程和多线程版本的 FFmpeg 核心。

概述

ffmpeg.wasm 项目使用 Docker 来提供一致且可重复的构建环境,以便将 FFmpeg 及其相关库编译为 WebAssembly。此过程对于创建 @ffmpeg/core 和 @ffmpeg/core-mt 包至关重要,这些包包含驱动 ffmpeg.wasm 的编译后的 WebAssembly 模块。

该构建被设计为一个多阶段 Dockerfile,将库的编译与最终的链接阶段隔离开来,确保对某一编解码器的修改不需要对整个堆栈进行完全重建。

构建流水线图示

Title: Docker Build Pipeline Flow

Docker 构建流水线流程图

构建环境 (emsdk-base)

构建过程从 emsdk-base 阶段开始,该阶段使用官方的 Emscripten 镜像并配置交叉编译环境。

组件版本 / 值文件引用
基础镜像emscripten/emsdk:3.1.40
FFmpeg 版本n5.1.4
安装前缀/opt
工具链文件$EMSDK/.../Emscripten.cmake

关键环境变量如 CFLAGS 和 LDFLAGS 在此处初始化,以包含 /opt/include 和 /opt/lib 路径,确保后续库阶段能够找到其依赖项

库编译阶段

每个依赖项都在其自己的 FROM emsdk-base AS <lib>-builder 阶段中进行编译。这使得 Docker 可以缓存像 x264 或 libvpx 这样重型库的编译结果。

Title: Code Entity Mapping: Library Builders

代码实体映射:库构建器

依赖链示例

  • libass: 需要 freetype2、fribidi 和 harfbuzz。Dockerfile 使用 COPY --from 将这些依赖聚合到 libass-builder 阶段,然后再运行 build/libass.sh
  • theora/vorbis: 两者都依赖于 ogg,因此它们通过 COPY --from=ogg-builder 访问 libogg 的头文件和二进制文件

FFmpeg 编译 (ffmpeg-builder)

ffmpeg-base 阶段将之前所有已编译的库聚合到 /opt 目录中。ffmpeg-builder 阶段随后运行 build/ffmpeg.sh 来编译实际的 FFmpeg 源代码。

配置标志

build/ffmpeg.sh 脚本使用 emconfigure 来设置 WebAssembly 的构建:

  • --target-os=none 和 --arch=x86_32
  • 禁用硬件功能,如 asm 和 runtime-cpudetect
  • 分配 Emscripten 工具链别名:emcc、emar、emnm
  • 条件化线程支持:如果定义了 FFMPEG_ST,则传递 --disable-pthreads

ffmpeg.wasm 最终链接 (ffmpeg-wasm-builder)

这是最关键的阶段,Emscripten 编译器 (emcc) 在此阶段将 FFmpeg 目标文件与 JavaScript 绑定链接在一起,生成最终的 .js 和 .wasm 文件。

Emscripten 链接标志

脚本 build/ffmpeg-wasm.sh 定义了用于最终 emcc 调用的 CONF_FLAGS :

标志用途引用
-sMODULARIZE将输出包装在工厂函数 (createFFmpegCore) 中
-sEXPORT_NAME设置全局工厂名称
-sENVIRONMENT=worker针对 Web Worker 执行进行优化
-sPTHREAD_POOL_SIZE=32(仅 MT) 预启动 32 个工作线程以处理并行任务
-sALLOW_MEMORY_GROWTH(仅 ST) 允许 WASM 堆动态扩展
--pre-js注入 src/bind/ffmpeg/bind.js,其中包含 JS API 粘合代码

导出的函数

构建过程使用辅助脚本来确定哪些 C 函数对 JavaScript 可见:

  • src/bind/ffmpeg/export.js: 定义核心函数,如 _ffmpeg、_ffprobe、_malloc 和 _abort
  • src/bind/ffmpeg/export-runtime.js: 导出 Emscripten 运行时方法

单线程与多线程逻辑

Dockerfile 通过向构建脚本传递不同的参数来处理两种构建。

Title: Threading Logic in build/ffmpeg-wasm.sh

build/ffmpeg-wasm.sh 中的线程逻辑

请注意,在多线程 (MT) 构建中明确避免了 ALLOW_MEMORY_GROWTH,因为它在某些环境中与 SharedArrayBuffer 不兼容或性能不佳,从而导致巨大的 1024MB 初始分配

工件导出 (exportor)

最后阶段使用 scratch 镜像以最小化输出大小。仅将包含 UMD 和 ESM 格式的编译后 JS 和 WASM 的 /dist 目录复制出来。

要获取这些资源,用户需执行:docker buildx build -o . .