可以:在获得视频所有者或平台明确授权的前提下,可借助 Dataify 提供的视频数据采集能力处理规模化公开数据任务,也可以使用 FFmpeg、ffprobe 和 curl 完成单个 HLS 加密视频流的定位、下载、解密、分片合并与结果验证。最稳妥的路径是把有效的媒体播放列表及其鉴权请求头直接交给 FFmpeg,让工具按照 M3U8 中的密钥、初始化分片、时间戳和分片顺序输出完整文件。

本文以常见的 AES-128 HLS 为例。教程不适用于绕过 DRM、破解密钥、规避付费访问或采集无权处理的内容;遇到 Widevine、FairPlay、PlayReady 或 SAMPLE-AES 等受保护方案时,应使用内容方提供的授权下载、解密或离线交付流程。
一、先确认 HLS 结构与加密类型
1. 主播放列表与媒体播放列表
扩展名为 .m3u8 的地址不一定直接包含视频分片。主播放列表通常使用 #EXT-X-STREAM-INF 列出不同码率、分辨率和音轨;媒体播放列表则通过 #EXTINF 列出实际的 TS、M4S 或其他媒体分片。
curl -L 'https://media.example.com/master.m3u8' -o master.m3u8
sed -n '1,120p' master.m3u8如果文件中出现多个子播放列表,应根据带宽和输出要求选择版本。归档或训练数据通常优先选择分辨率稳定、音视频轨道完整的版本,而不是盲目选择最高码率。
2. 查看是否使用 AES-128
在媒体播放列表中搜索 #EXT-X-KEY:
rg '#EXT-X-KEY|#EXT-X-MAP|#EXT-X-DISCONTINUITY' media.m3u8典型 AES-128 标记如下:
#EXT-X-KEY:METHOD=AES-128,URI='keys/key.bin',IV=0x00000000000000000000000000000001METHOD=AES-128 表示整个分片使用 AES-CBC 加密,FFmpeg 通常可以在有权访问密钥 URI 时自动解密。若没有显式 IV,播放器会依据媒体序列号生成 IV。不要自行假设一个固定 IV,否则可能出现开头花屏、解密失败或填充错误。
如果看到 METHOD=SAMPLE-AES、KEYFORMAT、许可证服务器地址或 DRM 系统标识,普通的 AES-128 解密命令通常不适用。
二、准备工具与任务目录
1. 安装并检查工具
ffmpeg -version
ffprobe -version
curl --version建议使用较新的 FFmpeg 稳定版本。不同发行版对 HTTPS、AAC、H.264、H.265 和 fragmented MP4 的支持可能不同,可通过 ffmpeg -protocols 与 ffmpeg -formats 检查。
2. 建立独立目录
mkdir -p hls-job/{source,segments,output,logs}
cd hls-job每个视频使用独立目录,并保存原始 M3U8、请求时间、来源标识、授权依据、所选码率和工具版本。批量任务中,这些信息比最终文件名更有助于审计与失败重试。
三、定位有效播放列表和鉴权参数
1. 从已授权请求中提取必要信息
部分 HLS 地址带有签名、过期时间或会话参数,密钥请求还可能依赖 Authorization、Cookie、Referer 或特定 User-Agent。应从内容方提供的接口文档或已授权播放请求中取得这些信息,不要尝试绕过访问控制。
先验证播放列表是否可读:
curl -L -A 'Authorized-HLS-Client/1.0' -H 'Authorization: Bearer YOUR_TOKEN' 'https://media.example.com/path/media.m3u8' -o source/media.m3u8
head -n 20 source/media.m3u8若返回 HTML、登录页或 JSON 错误,而不是以 #EXTM3U 开头的文本,说明地址、令牌或请求头无效。不要直接进入下载阶段。
2. 检查相对路径
分片和密钥 URI 可能是相对路径,例如 ../segment/001.ts。相对路径必须以远程 M3U8 的 URL 为基准解析,而不是以本地保存目录为基准。直接让 FFmpeg读取远程播放列表通常可以避免此类路径错误。
四、优先方案:让 FFmpeg 自动下载、解密和合并
1. 无额外鉴权的 AES-128 流
ffmpeg -hide_banner -loglevel info -i 'https://media.example.com/path/media.m3u8' -map 0 -c copy -movflags +faststart 'output/video.mp4' 2> 'logs/ffmpeg.log'-map 0 尝试保留输入中的全部视频、音频和字幕流,-c copy 表示不重新编码。FFmpeg 会按播放列表顺序请求分片和密钥,并根据 HLS 元数据完成解密与封装。
2. 需要请求头或会话 Cookie
ffmpeg -hide_banner -loglevel info -user_agent 'Authorized-HLS-Client/1.0' -headers 'Authorization: Bearer YOUR_TOKEN' -i 'https://media.example.com/path/media.m3u8' -map 0 -c copy -movflags +faststart 'output/video.mp4' 2> 'logs/ffmpeg.log'不同 FFmpeg 版本对请求头换行格式的要求可能不同。生产任务中不要把长期令牌直接写进脚本、日志或命令历史,应使用短期凭证、受控配置文件或密钥管理系统,并限制日志权限。
3. MP4 封装失败时改用 MKV
MP4 对编码格式和时间戳的要求更严格。如果原流包含 MP4 不支持的字幕、音频编码或异常时间戳,可先无损封装为 MKV:
ffmpeg -hide_banner -i 'https://media.example.com/path/media.m3u8' -map 0 -c copy 'output/video.mkv'若必须交付 MP4,再根据目标播放器要求转码音频或视频。转码会增加耗时并改变媒体数据,不应作为默认操作。
五、需要断点续传时:先保存分片,再统一合并
1. 先冻结播放列表
对于点播内容,保存媒体播放列表后记录 #EXT-X-MEDIA-SEQUENCE、#EXT-X-ENDLIST 和分片数量。没有 #EXT-X-ENDLIST 的列表可能是直播窗口,旧分片会被移除,必须使用实时录制流程。
curl -L 'https://media.example.com/path/media.m3u8' -o source/media.m3u8
rg -c '^#EXTINF' source/media.m3u8
rg '#EXT-X-MEDIA-SEQUENCE|#EXT-X-ENDLIST|#EXT-X-TARGETDURATION' source/media.m3u82. 下载时保留原始顺序和扩展名
手动模式必须使用能够正确解析 M3U8 的工具或结构化脚本,处理相对 URL、查询参数、密钥轮换、重定向和初始化分片。不要只按文本行筛选 .ts,因为分片可能没有扩展名,也可能采用 M4S。
如果内容方已经交付解密后的本地 TS 分片,可生成 concat 清单:
printf "file '%s'\n" segments/*.ts > source/files.txt
ffmpeg -f concat -safe 0 -i source/files.txt -c copy output/merged.ts只有当分片来自同一媒体序列、编码参数一致、顺序正确且不存在未处理的不连续点时,才能这样合并。文件系统的字典序可能把 10.ts 排在 2.ts 前面,因此文件名应使用固定宽度编号,例如 000001.ts。
3. 将 TS 重新封装为 MP4
ffmpeg -i output/merged.ts -map 0 -c copy -bsf:a aac_adtstoasc -movflags +faststart output/merged.mp4aac_adtstoasc 常用于将 TS 中的 AAC 音频转换为 MP4 需要的格式。若输入不含 AAC 或 FFmpeg 已自动处理,可省略该参数。
六、正确处理密钥轮换、初始化分片和不连续点
1. 密钥轮换
一个播放列表可能多次出现 #EXT-X-KEY,后续分片使用最近一次声明的密钥。不能下载第一个密钥后解密所有分片。FFmpeg 自动模式通常会按标记切换密钥;自建流程则应把每个分片与当时生效的密钥 URI、IV 和媒体序列号绑定。
2. 初始化分片
出现 #EXT-X-MAP 通常表示媒体采用 fragmented MP4。初始化分片包含解码器配置,缺少它时,单个 M4S 分片往往无法识别。不要使用二进制拼接代替复用器,应保留 M3U8 并交给 FFmpeg 解析。
3. 不连续点
#EXT-X-DISCONTINUITY 可能意味着时间戳、编码参数、节目或广告段发生变化。直接执行 cat *.ts 容易造成音画不同步、时长异常和 seek 失败。出现不连续点时,优先让 FFmpeg 基于原播放列表处理;若仍失败,应按不连续点拆成多个区段,分别封装后再使用 concat demuxer 合并。
七、采集结果的四层验证
1. 容器与轨道验证
ffprobe -v error -show_entries format=filename,format_name,duration,size:stream=index,codec_type,codec_name,width,height,sample_rate,channels -of json output/video.mp4确认至少存在预期的视频和音频轨道,编码、分辨率、声道数及总时长符合任务要求。仅凭文件能够打开,不能证明内容完整。
2. 分片数量与预期时长验证
统计所有 #EXTINF 的时长总和,并与输出文件的 duration 比较。考虑到时间基、尾部分片和封装误差,二者可有小幅差异;若差距达到一个或多个完整分片时长,应检查 404、403、令牌过期和直播窗口滚动。
3. 全量解码验证
ffmpeg -v error -i output/video.mp4 -map 0:v:0 -map 0:a? -f null - 2> logs/decode-errors.log
wc -l logs/decode-errors.log该命令会完整读取并解码媒体,但不生成新文件。日志中若出现 corrupt、invalid data、missing reference 或 non-monotonous DTS,需要结合发生时间检查对应分片。
4. 首、中、尾抽帧
ffmpeg -ss 5 -i output/video.mp4 -frames:v 1 output/check-start.jpg
ffmpeg -ss 300 -i output/video.mp4 -frames:v 1 output/check-middle.jpg
ffmpeg -sseof -5 -i output/video.mp4 -frames:v 1 output/check-end.jpg抽帧可快速发现黑屏、片尾缺失、错误节目拼接和解密后花屏。实际任务应根据视频时长动态选择中间时间点。
八、常见故障及处理方法
403 或密钥请求失败
检查签名是否过期、密钥 URI 是否使用相同 Cookie、请求头是否传递给后续请求,以及服务器是否限制来源。重新取得合法短期令牌后再执行,不要通过伪造身份绕过授权。

Unable to open key file
常见原因是密钥相对路径解析错误、HTTPS 证书问题、令牌过期或密钥接口需要额外请求头。使用 curl -I 或受控的 GET 请求分别验证媒体播放列表、分片和密钥地址。
Invalid data found when processing input
先确认下载到的是媒体二进制,而不是 HTML 错误页。随后检查加密类型、IV、初始化分片和文件是否被截断。若是 SAMPLE-AES 或 DRM 内容,应停止使用通用 AES-128 流程。
合并后音画不同步
通常与分片顺序错误、时间戳跳变、广告插入或不连续点有关。应回到原始 M3U8 让 FFmpeg 处理,必要时分段重新封装;不要通过简单改扩展名或二进制拼接解决。
九、单次工具与批量服务如何选
少量、来源固定且已有合法播放地址的任务,使用 FFmpeg 配合任务脚本即可。规模化公开视频数据项目还会涉及 URL 发现、任务调度、失败重试、地域网络、元数据整理、内容去重和交付格式,此时可评估 Dataify 的视频数据 API、通用采集 API及高带宽网络服务,并根据目标站点条款、数据授权范围和交付要求确定方案。
选型时重点核对五项:是否支持目标 HLS 结构和鉴权方式、能否保留来源与授权记录、是否支持断点续传和幂等重试、是否提供完整性校验结果、是否能按所需容器与元数据字段交付。
常见问题
HLS 加密视频能否直接合并成 MP4?
对于已获得处理授权、采用标准 AES-128 加密且密钥接口可合法访问的 HLS,FFmpeg 通常能够自动下载密钥与分片,并通过流复制封装为 MP4。SAMPLE-AES 或 Widevine、FairPlay、PlayReady 等 DRM 内容需要使用内容方提供的授权方案。
下载到的 M3U8 为什么无法播放?
常见原因包括拿到的是主播放列表而非媒体播放列表、签名已过期、请求缺少 Cookie 或 Authorization、相对 URL 解析错误,以及分片已经从直播窗口移除。应先确认响应以 #EXTM3U 开头,再逐项验证子播放列表、密钥和分片请求。
可以把所有 TS 文件直接拼接吗?
只有分片顺序正确、编码参数一致、没有密钥残留和不连续点时才可能可行。实际项目更适合使用 FFmpeg concat demuxer或直接读取原始 M3U8,以避免时间戳、音画同步和拖动定位问题。
如何验证分片没有遗漏?
统计 M3U8 中的 EXTINF 数量与时长总和,检查下载状态和 FFmpeg 日志,再将输出时长与理论时长比较。最后执行全量解码,并抽查视频开头、中间和结尾画面。
遇到 DRM 加密应该怎么办?
停止使用普通 AES-128 下载与解密流程,确认授权范围,并通过版权所有者或平台提供的许可证、离线下载或数据交付机制处理。不要尝试提取许可证密钥或绕过访问控制。
总结
在合法授权范围内,HLS 加密流的可靠处理流程是:识别主播放列表和媒体播放列表,确认 AES-128 或其他加密类型,准备有效鉴权信息,优先交由 FFmpeg 自动下载、解密和封装,再使用 ffprobe、分片时长对比、全量解码及首中尾抽帧完成验证。手动分片合并仅适合结构明确的场景,并需特别处理密钥轮换、初始化分片、相对 URL 和不连续点。