TS 切片合并后卡顿、跳帧?聊聊无缝拼接的那点事
从 m3u8 下回来的视频,本质是一堆 .ts 小切片。很多人合并时图省事直接 cat 拼起来,结果播到切片的接缝处就卡一下、画面跳一下,或者声画不同步。这不是文件坏了,是 TS 合并有前置条件。这篇文章把坑讲清楚。
TS 为什么能直接 cat
TS(Transport Stream)设计上就是为"拼接"而生的:每个包固定 188 字节,自带同步字节 0x47,理论上把多个 TS 文件首尾相接就能播。但前提是:相邻切片的第一帧都得是关键帧(I 帧),并且时间戳连续。
最省事也最脆:二进制拼接
cat 1.ts 2.ts 3.ts > all.ts
ffmpeg -i all.ts -c copy all.mp4
只要源切片本身就是"每个都从 I 帧开始、PTS 连续",这招又快又好。但现实往往不是:
- 有的 m3u8 只在开头有一个 I 帧,后面切片第一帧是 P/B 帧 → 拼完后面切片开头解码不出来,卡顿;
- 各切片 PTS 从 0 开始算 → 拼起来时间轴重叠或跳变 → 声画不同步。
稳妥做法:让 ffmpeg 重新排时间戳
与其手动 cat,不如直接交给 ffmpeg 的 concat demuxer,它会帮你理顺:
# 先建个列表
cat > list.txt <<'EOF'
file '1.ts'
file '2.ts'
file '3.ts'
EOF
ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4
如果还是跳,说明切片缺 I 帧,那就只能重新编码(损失一点画质换稳定):
ffmpeg -f concat -safe 0 -i list.txt -c:v libx264 -c:a aac out.mp4
进阶:先插关键帧再合并
对付"非 I 帧开头"的切片,可以先用 ffmpeg 在每个切片前强制一个关键帧:
ffmpeg -i seg.ts -force_key_frames "expr:gte(t,0)" -c copy seg_kf.ts
或者下载时直接让工具按 GOP 对齐切,从源头避免。
对比
| 方式 | 速度 | 画质 | 稳定性 |
|---|---|---|---|
| 二进制 cat | 最快 | 无损 | 容易卡 |
| concat demuxer + copy | 快 | 无损 | 较好 |
| 重新编码 | 慢 | 有损 | 最稳 |
常见问题
Q:合并后时长对不上? 时间戳不连续,用 ffmpeg -i out.mp4 -c copy -fflags +genpts 重新生成 PTS。
Q:声画不同步怎么救? 重新编码时加 -async 1 或 -vsync 相关参数让音视频对齐。
Q:能不能边下边合并? 可以,但建议下完再合并,避免半个切片导致整段错位。