浏览器里也能转码?WebAssembly 版 FFmpeg 原理(小白版)
你有没有想过:不用装任何软件,打开网页就能把 mp4 转成 mp3,这背后到底是什么在干活?
不少人默认是"网站后台的服务器在偷偷转"。其实不是。在 tools.beer 网页端,转码是在你自己的浏览器里完成的——靠的是把 ffmpeg 这个老牌转码器,编译成了一种能在浏览器跑的格式,叫 WebAssembly。
今天用最直白的方式,讲清它怎么跑、为什么有时"起不来"、为什么比桌面软件慢、以及到底能处理多大文件。
1. 一句话定义
WebAssembly(简称 wasm) 是一种能在浏览器里以接近原生速度运行的二进制指令格式。而 FFmpeg.wasm,就是把原本用 C 语言写的 ffmpeg,整套编译成 wasm,然后丢进浏览器去跑。
类比一下:把一家用 C 语言"盖"起来的老牌工厂(ffmpeg),整体"折叠"成一套能塞进浏览器沙盒里的便携图纸(wasm)。浏览器拿到图纸,就在自己的地盘上现场搭厂、开工。工厂还是那家工厂,只是从"建在工业区(操作系统)"搬到了"搭在浏览器里"。
所以网页转码的第一hand事实是:引擎是同一个 ffmpeg,只是运行环境换了。
2. 它在浏览器里到底怎么跑
一步步看:
- 你选一个 mp4,浏览器先用 JS 把整个文件读进内存(变成一段字节);
- 这段字节被写进 wasm 的"虚拟文件系统"(叫 MEMFS),ffmpeg 以为自己在读本地磁盘,其实读的是内存;
- 转码在 Web Worker 里跑,不会卡住页面;
- 转完,输出文件再从虚拟文件系统读出来,交给你下载或预览。
这一步里最关键的一点:文件全程驻留浏览器内存,不落地你的磁盘。它带来两个后果——好处是"不用上传、隐私好";代价是文件大小受内存限制(第 5 节细说)。
3. 我们踩过的真实坑:它为什么"起不来"
在 tools.beer 网页端用 FFmpeg.wasm,我们栽过最久的一个坑,正好讲给你听。
FFmpeg.wasm 为了跑得快,有多线程版本,依赖浏览器的一个能力叫 SharedArrayBuffer(多线程之间共享内存)。但浏览器有个规矩:只在页面处于 crossOriginIsolated 状态时才给这个能力。而要让页面 crossOriginIsolated,服务器必须同时返回两个响应头:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
少一个,crossOriginIsolated 就是 false,ffmpeg core 一加载就报错。我们当时排查了很久,最后定位到就是这两个头没配对。
坑中坑:COEP 这个头是对整页生效的。它会拒绝加载任何没带跨源响应头的外部资源——包括外链图片。结果是:用 curl 能下到的图,在页面里却显示不出来(DevTools 标 blocked by COEP)。所以我们站点的配图,一律本地化放 public/ 或内联 SVG,绝不直接外链裸图。
4. 为什么浏览器版比桌面版慢(物理原因)
回头看FFmpeg 是怎么干活的那篇的流水线:解码 → 编码是 CPU 最重的两段。浏览器里的 wasm 跑同一条线,却少了桌面端的两样东西:
- 多核:桌面原生 ffmpeg 能开十几个线程并行;浏览器里的 wasm 即便多线程版也受 SharedArrayBuffer 牵制。我们在 tools.beer 为了首屏加载速度,用的是单线程 core,更慢一些但加载快。
- 硬件加速:桌面端能调 Intel QSV、NVIDIA NVENC 这类硬件编码器;wasm 跑在通用 CPU 上,用不上。
所以同样把 mp4 转成 mp3,桌面原生可能几秒搞定,浏览器里要更久——不是玄学,是硬件差距。
5. 文件大小上限:为什么大文件该用桌面端
因为第 2 节说的"文件全程在内存",而 wasm 是 32 位地址空间,堆内存上限约 2GB;输入和输出还要同时驻留,所以:
- 网页版:理论上限约 2GB,实际几百 MB 到 1GB 最稳;
- 桌面原生:文件从磁盘流式读写,上限≈磁盘剩余空间,几十 GB 也轻松。
所以一个 5GB 的会议录像想抽音轨,网页端转不动,只有桌面端(调原生 ffmpeg)能本地搞定。
6. 我们怎么选:网页 vs 桌面
tools.beer 的答案很直接,两套都做、各管一段:
- 网页端(FFmpeg.wasm):免安装、即开即用,适合小文件随手转;
- 桌面端(Tauri 调原生 ffmpeg):本地、隐私、超大文件、硬件加速,适合重度需求。
技术上我们用同一套 UI,isTauri() 判断环境分流——网页走 wasm,桌面走原生二进制。这正好构成我们"本地 / 隐私 / 超大文件"的差异化卖点,也是上传式在线转换器做不到的。
小结
- FFmpeg.wasm = 把 ffmpeg 编译成 WebAssembly,在浏览器沙盒里跑同一套引擎;
- 文件读进内存虚拟文件系统,全程不落地磁盘(隐私好,但受内存限制);
- 多线程版依赖 SharedArrayBuffer → 需要 COOP/COEP 两个头,缺一则加载失败;
- 比桌面原生慢,是少了多核与硬件加速;
- 网页版文件上限约 2GB,大文件交给桌面端。
延伸阅读
- FFmpeg 是怎么干活的?原理图解
- 容器和编码到底有什么区别?
- 重编码 vs 流复制:为什么转换有时变慢变糊
- 常见音视频格式怎么选?
- 无损与有损,到底差在哪?
- 音视频转换完全指南:从容器到编码一篇搞懂
想立刻上手,可以直接在浏览器里把 MP4 转成 MP3。
参考资料(权威来源)
FFmpeg 官网Emscripten 官方文档(C→WebAssembly 编译工具链)
MDN: SharedArrayBuffer
MDN: Cross-Origin-Opener-Policy
本文由 tools.beer 团队撰写,基于我们在浏览器端 FFmpeg.wasm 与桌面端原生 ffmpeg 转码中的真实踩坑经验整理。最后更新于 2026-08-20。