使用 FFmpeg 即可完成 HLS 直播流采集、TS 分片保存与合并;在需要批量获取公开音视频数据或稳定网络资源时,也可以结合 Dataify 提供的视频数据 API、通用采集 API 与网络服务,但无论采用哪种方式,都应确保对目标内容拥有采集、存储和使用权限。

Dataify 实操指南:HLS 直播流采集与 TS 分片合并教程

一、开始前需要了解的 HLS 与 TS

HLS 直播流是什么

HLS 通常由一个扩展名为 .m3u8 的播放列表和若干媒体分片组成。播放列表可能分为两层:

  • Master Playlist:记录多个清晰度、码率或音轨对应的子播放列表。
  • Media Playlist:记录实际的 TS、fMP4 等媒体分片地址及播放顺序。

传统 HLS 常使用 MPEG-TS 分片,文件扩展名一般为 .ts。直播列表会持续更新,因此采集程序需要不断读取新增分片,直到达到指定时长、主播结束直播或人工停止。

为什么不能只下载一次 M3U8

直播 M3U8 通常只保留最近一段时间的滑动窗口。只请求一次播放列表,往往只能获得窗口内的少量分片。要完整记录后续直播,应使用 FFmpeg 等支持自动刷新播放列表的工具持续采集。

二、准备工具与目录

安装并检查 FFmpeg

本教程以 FFmpeg 和 ffprobe 为主。安装后执行以下命令确认工具可用:

ffmpeg -version
ffprobe -version

建议使用较新的稳定版本,以减少对加密 HLS、重定向、fMP4 和时间戳处理的兼容问题。

建立工作目录

mkdir -p hls-work/segments
cd hls-work

后续生成的播放列表、TS 分片、合并文件和检测日志均可放在该目录中。正式任务还应预留足够磁盘空间:例如 4 Mbit/s 的视频流每小时大约产生 1.8 GB 数据,实际占用还包括音频和封装开销。

三、识别并检查 HLS 播放列表

第一步:获取合法的 M3U8 地址

在自有系统中,可以直接从播放器配置、接口响应或服务端日志获取 M3U8 地址。采集第三方公开内容时,应遵守网站条款、版权规则、访问频率限制和适用法律,不应绕过登录、付费、数字版权管理或访问控制。

第二步:判断播放列表类型

在地址无需特殊鉴权时,可先查看列表内容:

curl -L 'https://example.com/live/master.m3u8'

如果内容包含 #EXT-X-STREAM-INF,它通常是 Master Playlist;如果包含连续的 #EXTINF 和媒体分片地址,则通常是 Media Playlist。

第三步:选择合适清晰度

Master Playlist 中的 BANDWIDTH、RESOLUTION 和 CODECS 可用于判断码率、分辨率与编码格式。批量任务不应默认选择最高码率,应根据用途、存储成本和后续模型处理要求确定档位。用于语音识别时,低分辨率视频或独立音频轨通常已经足够;用于动作分析、OCR 或画面质量评估时,则应保留更高分辨率。

四、使用 FFmpeg 直接采集 HLS 直播流

方法一:限定时间并保存为单个 TS 文件

以下命令采集 30 分钟,并尽量直接复制原始音视频编码:

ffmpeg -hide_banner -loglevel warning \
  -i 'https://example.com/live/index.m3u8' \
  -map 0:v:0 -map 0:a:0? \
  -c copy -t 00:30:00 \
  capture.ts

-c copy 表示不重新编码,CPU 占用低且不会引入二次压缩损失;-map 0:a:0? 中的问号表示音轨不存在时不让任务直接失败。采集结束后,FFmpeg 会写入 capture.ts。

方法二:持续采集直到人工停止

ffmpeg -hide_banner -loglevel warning \
  -i 'https://example.com/live/index.m3u8' \
  -map 0:v:0 -map 0:a:0? \
  -c copy capture.ts

需要结束时按一次 q,让 FFmpeg正常写完输出。尽量不要直接终止进程或断电,否则最后一段数据可能不完整。

方法三:采集并切成规则的本地 TS 分片

ffmpeg -hide_banner -loglevel warning \
  -i 'https://example.com/live/index.m3u8' \
  -map 0:v:0 -map 0:a:0? -c copy \
  -f segment -segment_time 10 \
  -reset_timestamps 0 \
  -segment_list local.m3u8 \
  -segment_format mpegts \
  'segments/%06d.ts'

该命令按约 10 秒切分文件,并生成本地播放列表。由于复制编码时切分点通常受关键帧位置影响,每个分片的实际时长可能不是严格的 10 秒。使用六位数字命名可以保证按文件名排序时顺序正确。

需要请求头或自有鉴权令牌时

如果自有直播服务要求 Referer、Cookie 或短期令牌,应使用合法获得且仍有效的凭据。Bash 环境下可以这样传递请求头:

ffmpeg -headers $'Referer: https://example.com/\r\nAuthorization: Bearer YOUR_TOKEN\r\n' \
  -i 'https://example.com/live/index.m3u8' \
  -c copy -t 00:30:00 capture.ts

不要把长期密钥直接写进脚本仓库、日志或任务名称。生产环境应通过密钥管理系统或受限环境变量注入,并在日志中隐藏敏感字段。

五、合并已有 TS 分片

第一步:确认文件顺序

TS 合并必须遵循播放列表中的顺序。若文件名为连续补零编号,可以生成 FFmpeg concat 清单:

printf "file '%s'\n" segments/*.ts > list.txt

打开 list.txt抽查开头和结尾,确认没有把 1.ts、10.ts、2.ts按错误顺序排列。对于非连续命名、带查询参数或存在重复序列号的来源,应根据 M3U8 中的排列顺序生成清单,而不是仅依赖文件名。

第二步:使用 concat demuxer 合并

ffmpeg -hide_banner -f concat -safe 0 \
  -i list.txt -c copy merged.ts

这种方式会由 FFmpeg 解析各分片,比简单的二进制拼接更便于发现损坏文件、编码变化或时间戳异常。执行期间应关注 Non-monotonous DTS、Invalid data、Packet corrupt 等警告。

什么时候可以使用 cat

当所有文件都是标准 MPEG-TS、编码参数一致、顺序可靠且不存在明显不连续点时,可以使用:

cat segments/*.ts > merged.ts

MPEG-TS 允许连续拼接,但 cat 不会修复时间戳,也无法识别混入的 HTML 错误页、空文件或编码切换。对需要交付或长期保存的结果,优先使用 FFmpeg 合并并执行完整验证。

六、处理常见复杂情况

AES-128 加密分片

如果播放列表包含 #EXT-X-KEY:METHOD=AES-128,且 FFmpeg 有权访问播放列表声明的密钥地址,通常可以自动获取密钥并解密。密钥请求若需要合法鉴权,应让播放列表、分片和密钥请求使用一致的授权上下文。

如果使用 SAMPLE-AES、DRM 或硬件安全模块保护,普通 TS 拼接流程通常不适用。此时应使用内容方提供的授权下载或解密方案,不应尝试绕过保护措施。

EXT-X-DISCONTINUITY 不连续点

#EXT-X-DISCONTINUITY 可能表示时间戳、编码参数、节目源或加密信息发生变化。把不连续点前后的分片强行无损合并,可能导致音画不同步或播放器跳转。稳妥做法是按不连续点分别输出文件,再检查各段编码参数;如果参数不同,则统一转码后再合并。

音视频编码参数发生变化

先分别检查异常点两侧的分片:

ffprobe -v error -show_entries \
  stream=index,codec_type,codec_name,width,height,sample_rate,channels \
  -of json segments/000100.ts

如果分辨率、编码器、音频采样率或声道数发生变化,-c copy 合并可能失败。可以将各段统一转码为相同规格,例如 H.264 与 AAC,再通过 concat demuxer 合并。转码会增加耗时并产生质量损失,因此应只在参数不一致或原始时间戳无法修复时使用。

网络抖动与短暂断流

长时间直播采集应记录 FFmpeg 退出码、开始时间、结束时间和错误日志。可根据 FFmpeg 版本和协议能力配置读写超时、重连参数,但不能只依赖无限重试:任务还需要设置总时长、最大重试次数和磁盘容量上限,避免失控运行。重新连接后产生的文件应单独编号,并在合并前检查时间轴是否连续。

七、将 TS 无损封装为 MP4

如果视频为 H.264 或 H.265、音频为 AAC 等 MP4 支持的编码,可在不重新编码的情况下更换容器:

ffmpeg -hide_banner -i merged.ts \
  -map 0:v:0 -map 0:a:0? \
  -c copy -bsf:a aac_adtstoasc \
  -movflags +faststart output.mp4

aac_adtstoasc 用于将 TS 中常见的 AAC ADTS 格式转换为 MP4 所需格式;+faststart 将 MP4 索引移到文件前部,便于网络播放。若源编码不受 MP4 支持,则需要选择其他容器或重新编码。

八、验证采集与合并结果

验证一:检查文件和流信息

ffprobe -v error \
  -show_entries format=filename,duration,size,bit_rate \
  -show_entries stream=index,codec_type,codec_name,width,height,sample_rate,channels \
  -of json output.mp4

重点确认文件大小不为零、时长接近计划采集时长、音视频轨存在、编码和分辨率符合预期。直播开始或结束时的空白段、广告切换和断流可能造成少量时长偏差。

验证二:执行全量解码测试

ffmpeg -v error -i output.mp4 -f null -

该命令会读取并解码完整文件,但不生成新视频。没有输出通常表示未发现明显解码错误;如果出现损坏包、解码失败或时间戳异常,应定位对应时间点和原始分片。

验证三:检查预期时长与分片总时长

对于固定窗口采集,可以将目标时长与最终文件时长比较。对于手动下载分片,可以累加 M3U8 中每个 #EXTINF 的时长,再与 ffprobe 检测到的总时长比较。差异明显时,应检查是否存在漏片、重复分片、错误排序或中途重新连接。

验证四:人工抽查关键时间点

至少检查开头、四分之一、二分之一、四分之三和结尾位置,确认画面可解码、声音存在且口型同步。批量任务可以自动生成固定间隔截图和短音频样本,以便快速发现黑屏、静音、花屏或内容错位。

验证五:记录哈希用于交付核验

sha256sum output.mp4 > output.mp4.sha256
sha256sum -c output.mp4.sha256

SHA-256 可以验证文件在传输或归档后是否发生变化,但不能证明内容完整、音画同步或来源合法,因此仍需结合 ffprobe 和解码测试。

九、批量任务的选型与落地建议

单个或少量公开直播源可以直接使用 FFmpeg 和任务调度器。若项目涉及跨地区公开视频数据采集、较大带宽需求、多源任务管理或训练数据交付,可以评估 Dataify 的视频数据 API、通用采集 API、网络服务及定制数据集能力。选型时仍应重点核对目标平台授权、数据字段、地域覆盖、成功率口径、交付格式、去重规则、失败重试策略和实际计费方式。

生产流程建议把任务拆成“地址发现、采集、分片校验、合并、转封装、质量检查、归档”几个阶段。每个阶段保存任务 ID、源地址摘要、开始与结束时间、FFmpeg 版本、命令参数、输出哈希和错误原因,便于审计、重跑及问题定位。

十、可直接执行的标准流程

  1. 确认内容授权、采集边界和保存期限。
  2. 安装 FFmpeg,并为采集目录预留足够空间。
  3. 获取 M3U8 地址,识别 Master Playlist 与 Media Playlist。
  4. 根据用途选择分辨率、码率、音轨和字幕轨。
  5. 使用 FFmpeg 按指定时长采集,优先采用 -c copy。
  6. 需要独立分片时,使用 segment muxer 和补零编号保存。
  7. 依据播放列表顺序生成 list.txt,使用 concat demuxer 合并。
  8. 存在不连续标签或编码变化时,先分段检查,必要时统一转码。
  9. 根据交付要求保留 TS,或无损封装为 MP4。
  10. 使用 ffprobe、全量解码、时长对比、人工抽查和 SHA-256 完成验证。
十、可直接执行的标准流程

常见问题

直接把所有 TS 文件拼接起来为什么会音画不同步?

常见原因包括分片顺序错误、时间戳跳变、重复或缺失分片、EXT-X-DISCONTINUITY,以及中途切换了编码参数。应先按 M3U8 顺序生成 concat 清单,再检查异常点两侧的编码和时间戳;参数不一致时,需要分段处理或统一转码。

FFmpeg 下载 M3U8 后只有几分钟内容怎么办?

可能拿到的是直播滑动窗口,或者采集任务在网络异常、鉴权过期后提前退出。应让 FFmpeg 持续运行并刷新列表,同时检查退出码和日志;如果播放列表已经下线且服务端不保留历史分片,通常无法仅凭最后一次 M3U8 恢复更早内容。

TS 合并后一定要转换成 MP4 吗?

不一定。TS 对直播中断和局部损坏的容忍度较高,适合保留原始采集结果;MP4 的兼容性和随机定位体验通常更好,适合播放、标注或交付。如果现有编码受 MP4 支持,可以使用 -c copy 只更换容器。

如何判断某个 TS 分片下载到了错误内容?

先检查文件大小和 Content-Type,再用 ffprobe 读取流信息。部分服务器在鉴权失效时会返回 HTML、JSON 错误信息或零字节文件,却仍被保存为 .ts。全量解码测试中的 Invalid data 或 Packet corrupt 也可以帮助定位异常分片。

加密 HLS 是否可以直接采集和合并?

AES-128 HLS 在拥有合法密钥访问权限时通常可由 FFmpeg自动处理。对于 SAMPLE-AES、DRM 或其他访问控制,应使用内容提供方授权的下载和解密流程,普通 TS 拼接命令不能替代授权,也不应被用于绕过保护措施。

总结

HLS 直播流采集的关键不是简单下载一次 M3U8,而是持续刷新播放列表、按序保存分片并处理鉴权、断流和不连续点。小规模任务可用 FFmpeg 直接采集或输出本地 TS 分片,再通过 concat demuxer 合并;需要播放和交付时,可在编码兼容的前提下无损封装为 MP4。最终应通过 ffprobe、全量解码、时长比对、关键点抽查和文件哈希验证结果,并始终确保采集行为具有合法授权。