浏览器也能跑 FFmpeg?我用 ffmpeg.wasm 做了个 TS 在线合并工具

0 阅读4分钟

浏览器也能跑 FFmpeg?我用 ffmpeg.wasm 做了个 TS 在线合并工具

在做视频处理相关工具时,经常会遇到一个很常见的需求:

把一堆 .ts 分片视频合并成一个 MP4 文件。

这种情况在很多场景都会出现,例如:

  • HLS 视频流下载
  • 课程平台视频缓存
  • 直播流录制
  • M3U8 视频下载

通常你会得到一堆文件:

0001.ts
0002.ts
0003.ts
...

如果你用过视频处理工具,大概率知道这件事可以用 FFmpeg 一条命令完成。但对于大多数用户来说,命令行始终是个门槛。

于是我尝试用 ffmpeg.wasm 做了一个浏览器端 TS 合并工具,让整个流程变成:

拖入 TS 文件 → 点击合并 → 下载 MP4

不需要安装软件,也不需要上传视频到服务器。


一、为什么 TS 文件经常需要合并

TS(Transport Stream)是 MPEG‑TS 格式,常见于 HTTP Live Streaming(HLS) 视频流。

HLS 的工作方式是:

  1. 视频被切成很多 .ts 小片段
  2. .m3u8 文件记录播放顺序
  3. 播放器按顺序加载这些 TS

例如:

index.m3u8
segment0001.ts
segment0002.ts
segment0003.ts

如果你通过工具下载视频,往往就只会得到这些 .ts 文件。这时候最常见的需求就是:

把这些 TS 文件重新拼成一个完整视频。


二、传统解决方案的问题

传统做法一般有三种。

1 使用 FFmpeg 命令

最标准的方法是:

ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

但问题是:

  • 要安装 FFmpeg
  • 要写文件列表
  • 要使用命令行

对于非技术用户来说并不友好。


2 使用桌面软件

例如:

  • 格式工厂
  • 剪映
  • Premiere

但这些工具存在几个问题:

  • 安装体积大
  • 打开速度慢
  • 操作复杂

3 使用在线网站

很多在线工具要求:

  • 上传视频到服务器

但 TS 文件往往:

  • 几百 MB
  • 几 GB

上传速度慢,而且很多人也不希望视频离开本地设备。


三、ffmpeg.wasm:让浏览器运行 FFmpeg

为了解决这个问题,我选择了 ffmpeg.wasm。简单来说,它做了一件很有意思的事情:

把 FFmpeg 编译成 WebAssembly。

也就是说:

浏览器可以直接运行 FFmpeg

整个流程变成:

浏览器
   ↓
WebAssemblyFFmpeg
   ↓
本地视频处理

优点非常明显:

  • 不需要安装软件
  • 不需要上传视频
  • 数据完全在本地处理
  • 跨平台(Windows / Mac / Linux / 手机)

四、实现一个 TS 在线合并工具的思路

我在实现这个工具时,整体流程大致是这样的。

第一步:加载 FFmpeg wasm

浏览器启动时加载 FFmpeg wasm 核心。

示例代码:

import { createFFmpeg } from "@ffmpeg/ffmpeg"

const ffmpeg = createFFmpeg({
  log: true
})

await ffmpeg.load()

第一次加载会稍慢,因为需要下载 wasm 文件。

第二步:上传 TS 文件

用户可以:

  • 拖拽文件
  • 或选择多个 TS 文件

示例:

for (const file of files) {
  ffmpeg.FS("writeFile", file.name, await fetchFile(file))
}

这些文件会被写入 FFmpeg 的虚拟文件系统

ts-merge

第三步:生成 concat 列表

FFmpeg 合并 TS 的标准方法是使用 concat demuxer

例如:

file '0001.ts'
file '0002.ts'
file '0003.ts'

浏览器中动态生成:

let list = files
  .map(f => `file '${f.name}'`)
  .join("\n")

ffmpeg.FS("writeFile", "list.txt", list)

第四步:执行合并命令

核心命令:

ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

在 wasm 中运行:

await ffmpeg.run(
  "-f","concat",
  "-safe","0",
  "-i","list.txt",
  "-c","copy",
  "output.mp4"
)

这里的关键点是:

-c copy

表示:

不重新编码,只做封装转换

因此速度非常快。

process-ts

第五步:导出 MP4 文件

最后从虚拟文件系统读取结果:

const data = ffmpeg.FS("readFile", "output.mp4")

然后触发浏览器下载。

process-finish

五、最终实现效果

整个用户体验变成:

1️⃣ 打开网页 2️⃣ 拖入 TS 文件 3️⃣ 点击合并 4️⃣ 下载 MP4

整个过程:

  • 不上传视频
  • 不安装软件
  • 不需要命令行

浏览器直接完成视频处理。

如果你想体验类似的工具,可以参考这个在线 TS 合并工具:

ezwebtools.net/ts-merge

它的交互流程和设计思路与我实现的版本比较接近。

六、浏览器端视频处理的优势

使用 ffmpeg.wasm 做视频工具,其实有几个非常明显的优势。

1 隐私安全

视频始终在本地处理:

  • 不上传服务器
  • 不经过第三方存储

2 几乎零运维成本

服务器只需要:

  • 静态文件
  • CDN

不需要:

  • GPU
  • 编码服务器
  • 视频存储

3 跨平台

只要有浏览器:

  • Windows
  • macOS
  • Linux
  • Android
  • iOS

都可以使用。

七、开发过程中的一些坑

在实现这个工具时,也遇到了一些实际问题。

1 浏览器内存限制

TS 文件如果:

  • 几 GB

浏览器可能会出现内存压力。


2 wasm 首次加载较慢

首次加载 ffmpeg.wasm:

  • 需要下载十几 MB

可以通过:

  • CDN
  • 缓存

优化体验。

八、总结

以前做视频处理:

需要安装软件、写命令、配置环境。

现在通过 ffmpeg.wasm,浏览器本身就可以成为一个轻量级的视频处理平台。

像 TS 合并这种常见需求,其实只需要:

  • 文件上传
  • concat 列表
  • FFmpeg 执行

三步就能完成。

而用户体验也从:

复杂命令行操作

变成:

拖文件 → 点击 → 下载

这也是 WebAssembly 在前端工具领域一个非常典型的应用场景。