ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

M3U8/HLS/DASH视频下载与TS分片合并转MP4完整指南

M3U8/HLS/DASH视频下载与TS分片合并转MP4完整指南 这次我们来看一类很实用的工具M3U8(HLS)、DASH、MP4视频下载器。现在的网页视频尤其是点播平台、网课、电视直播回放绝大多数都不是直接给你一个 MP4 文件而是把视频切成几十上百个 ts 分片再用一个 m3u8 索引文件串起来。想把这些视频完整下载到本地合并成一个 MP4靠浏览器“右键另存为”是行不通的必须用专门的下载器去解析索引、拉取分片、解密、合并。这类工具能解决的实际问题非常明确把网页上只能在线播放的 HLS/DASH 视频转成离线可用的 MP4或者把零散的 ts 分片合并转换。它的核心能力通常包括 m3u8 链接解析、ts 并发下载、AES-128 分片解密、ts 合并、m3u8 转 MP4、视频格式转换以及批量任务处理。硬件门槛不高CPU 加足够磁盘空间就能跑不需要 GPU也不需要特别高的内存。下面我会从原理讲到部署再讲功能测试、接口批量调用和常见失败排查命令都可以直接复制改路径使用。有一点需要先说明本文里提到的 ts 是 MPEG-TS 视频分片格式也就是 HLS 协议里的媒体分片不是 TypeScript 语言的 ts。网上很多初级开发者搜索“ts 合并”一半是视频分片合并一半是 TS 类型编程两者完全不同别搞混。文章里所有涉及命令的操作都以常见的开源命令行工具和 ffmpeg 为例不管你是用现成的一键工具还是自己写脚本思路都一样。1. 核心能力速览能力项说明项目类型M3U8(HLS)、DASH、MP4 视频下载与格式转换工具核心功能m3u8/mpd 索引解析、ts 分片下载、AES-128 解密、ts 合并、m3u8 转 MP4、视频格式转换支持协议HLS(M3U8)、DASH(MPD)、HTTP 直链 MP4输入格式m3u8、mpd、mp4 直链、本地 ts 目录输出格式MP4、TS、MKV 等启动方式命令行工具 / 脚本调用 / 带 WebUI 或 GUI 的整合工具硬件门槛CPU 即可不需要 GPU建议至少 2GB 可用内存磁盘要求需要同时容纳原分片和合并后的文件建议预留原视频体积 1.5 倍以上是否支持 API命令行工具可直接被 Python、Shell、Node 等脚本调用是否支持批量任务支持可通过目录、清单文件或脚本循环处理适合场景个人离线存档、本地剪辑素材整理、网课视频转码、直播回放下载需要注意不同开源下载器在功能细节上有差异有些只负责下载分片不负责转码有些则内嵌 ffmpeg一条命令就能完成“下载 解密 合并 转 MP4”。所以动手之前先确认你手头工具的定位。最稳妥的组合是“一个 m3u8 下载器 ffmpeg”下载器负责拉分片和密钥ffmpeg 负责合并和封装转换。2. 适用场景与使用边界这类工具最典型的适用场景有三个第一把在线课程的 HLS 视频下载到本地方便没有网络时学习第二把直播回放或活动录像转成 MP4方便在剪辑软件里处理第三把已经下载到本地的 ts 分片目录统一合并转换避免几十个小文件散落在硬盘里。但它也有明确的不适用场景。如果是平台明确要求登录后才能观看的付费内容或者平台服务条款明确禁止下载的内容不建议用下载器绕过。这里强调一个原则你只能下载自己有权访问、有权离线保存的内容。比如你自己上传的视频、平台允许离线缓存的内容、无版权限制的开放视频。下载之后也不应该二次传播或商用尤其是电视剧、电影、付费课程这类有明确版权归属的内容。这是技术工具的通用安全边界不是某个具体开源项目的特殊要求。另外要注意很多 HLS 视频是加密的。加密不一定代表非法平台为了保护播放地址或防止直接抓取会使用 AES-128 加密分片。下载器能否处理加密流主要看它是否实现了 EXT-X-KEY 的解析逻辑以及能否自动获取密钥 URI 并解密。如果工具不支持合并后的视频会花屏或只有声音没有画面。这个问题不是网络问题是解密环节缺失。3. M3U8 下载原理与环境准备想排错先懂原理。HLS 协议的基本流程是视频被切成一个个小的 ts 分片每个分片通常 2 到 10 秒服务端生成一个 m3u8 索引文件按顺序记录所有分片的 URL。播放器拿到 m3u8 后不断拉取分片并连续播放。因此下载 m3u8 视频本质上不是下载一个文件而是下载“索引文件里记录的所有分片”然后按顺序拼接。DASH 协议类似区别在于它的索引文件是 MPD 格式分片通常是 m4s、mp4、webm 等并且可能同时包含多码率、多语言音轨。工具需要解析 MPD 中的 Representation 和 SegmentList才能拿到完整的分片列表。MP4 直链就简单很多下载一个文件即可。环境准备分三块下载器、ffmpeg、磁盘空间。下载器这块常见的开源选择有 yt-dlp、N_m3u8DL-RE、ffmpeg 自带 HLS 下载能力以及各种带图形界面的整合工具。如果你不想折腾优先选 yt-dlp 或带 GUI 的下载器如果你要写脚本做批量任务优先选命令行工具。下面以通用命令行为例。ffmpeg 是必须安装的。Windows 用户可以从 ffmpeg 官网下载编译好的 release 版本解压后把bin目录加入系统 PATHmacOS 用户建议用 Homebrew 安装Linux 用户用 apt 或 yum 安装。安装完验证一下ffmpeg -version能输出版本信息就说明安装成功。另外处理 m3u8 时下载器和 ffmpeg 需要能访问同一个临时目录。建议建一个专门的下载工作目录例如D:\video_download输入链接、分片缓存、最终输出分开管理。mkdir -p video_download/{cache,output,logs}磁盘空间这块建议预留原视频体积的 1.5 到 2 倍。因为分片下载和合并转码同时占用空间转 MP4 时需要额外写输出文件。如果磁盘满了下载器会报磁盘写入错误这种问题不是代码 bug是空间规划没做好。4. 安装部署与启动方式4.1 命令行下载器通用启动方式以 yt-dlp 为例安装很简单。Windows 可以直接下载 exe 文件或者用 pip 安装Linux/macOS 用 pip 安装比较方便pip install -U yt-dlp装完后先验证yt-dlp --versionyt-dlp 的优势是支持站点非常多很多 HLS/DASH 流可以直接解析并调用 ffmpeg 合并。启动方式非常简单基本上是“给链接 给参数”yt-dlp -o ./output/%(title)s.%(ext)s https://example.com/video.m3u8如果目标地址是 MPDDASH用法一样yt-dlp 会自己解析分段列表并尽量合并音视频轨。另一类更专一的工具是 N_m3u8DL-RE它特别擅长处理 m3u8/mpd支持 AES-128 解密、多线程下载、自定义请求头还能直接用--auto-select自动选择最佳音视频轨。启动方式一般是命令行传入 m3u8 地址比如N_m3u8DL-RE https://example.com/index.m3u8 --save-dir ./output --save-name course01如果你的系统不方便直接执行 exe把它放到项目目录下用绝对路径调用也行。关键在于先跑通一次最简单的下载再叠加参数。4.2 带 WebUI 或 GUI 的整合工具如果你不想碰命令行可以选择带图形界面的整合工具。这类工具通常提供一个本地 Web 页面浏览器打开后输入 m3u8 地址选择输出格式和线程数点击下载即可。启动方式一般是双击启动脚本或者在项目目录下执行python app.py --host 127.0.0.1 --port 8080然后访问http://127.0.0.1:8080。注意端口冲突问题如果 8080 被占用换一个端口再启动同时检查防火墙是否拦截了本地端口。图形界面工具的底层逻辑和命令行一样只是把操作包成了表单。对于批量下载我仍然建议用命令行或脚本灵活性更高。4.3 用 ffmpeg 直接处理 m3u8实际上 ffmpeg 自己就能完成 m3u8 下载和转 MP4。对于没有加密、分片数量不多的小视频直接用 ffmpeg 最省事ffmpeg -i https://example.com/index.m3u8 -c copy output.mp4这条命令会用 HLS 解复用器读取索引逐个下载分片然后按顺序封装成 MP4。-c copy表示直接复制音视频流不重新编码速度很快画质也保持不变。不过 ffmpeg 官方也提醒某些非标准 HLS 源可能解析异常遇到这种源还是先用专用下载器拉分片再用 ffmpeg 合并。5. 功能测试与效果验证5.1 测试用 M3U8 下载第一个要验证的功能当然是 m3u8 下载。准备一个测试用 m3u8 地址建议用自己生成的或者公开测试流。先把链接存到一个文本里避免反复粘贴出错cat url.txt EOF https://example.com/test/index.m3u8 EOF然后执行下载yt-dlp -o ./output/test_video.%(ext)s -a url.txt判断成功的标准很简单输出目录里出现完整的 MP4/MKV 文件播放器能正常拖动进度条视频和音频同步。如果产物只有一堆 ts 文件没有合并说明下载器和 ffmpeg 的联动没配置好检查 ffmpeg 是否在 PATH 中。这里要特别提醒如果视频本身有加密下载过程中会看到下载了 key 文件的日志。不要手动把 key 删掉合并时还需要它。没有 key 的情况下解密会失败合并出来的视频大概率花屏。5.2 DASH 视频下载测试DASH 视频最常见的表现是视频没有声音或者只有视频没有声音。这是因为 DASH 协议把视频轨和音频轨分成不同的分片序列需要用工具把它们同时下载再合并。用 yt-dlp 处理 DASH 流时默认会做音视频合并前提是安装了 ffmpeg。测试命令和 m3u8 基本一致yt-dlp -o ./output/dash_test.%(ext)s https://example.com/manifest.mpd下载完成后检查文件里是否同时包含视频轨和音频轨ffprobe -v error -show_streams -select_streams v:0 ./output/dash_test.mp4 ffprobe -v error -show_streams -select_streams a:0 ./output/dash_test.mp4两条命令分别能看到视频流和音频流信息。如果只有一条有输出说明音视频合并失败优先检查 ffmpeg 版本和输出格式参数。5.3 TS 分片合并与 m3u8 转 MP4本地已经有一堆 ts 分片时可以用 ffmpeg 将它们合并。最稳妥的方法是先写一个分片清单文件再交给 ffmpeg 处理。分片文件名要按播放顺序排列而不是按名称字典序排列否则会出现画面乱序。生成播放列表for f in $(ls segment_*.ts | sort -V); do echo file $f concat_list.txt; done合并转 MP4ffmpeg -f concat -safe 0 -i concat_list.txt -c copy merged.mp4判断成功的标准是 merged.mp4 播放时间与源视频一致画面顺序正确。如果合并出来的文件只有第一片能播放大概率是 concat 列表里文件顺序错误如果播放时报解码错误可能是分片本身有编码参数变化比如不同分片分辨率不一致这种情况需要转码而不是直接 copyffmpeg -f concat -safe 0 -i concat_list.txt -c:v libx264 -c:a aac merged.mp4转码会慢一些但兼容性更好。5.4 加密分片 AES-128 解密测试HLS 加密分片的 m3u8 文件里通常会有 EXT-X-KEY 标签类似这样#EXT-X-KEY:METHODAES-128,URIhttps://example.com/key.key,IV0x1234567890abcdef支持自动解密的下载器会读取这个标签获取密钥 URI 并下载密钥再在合并时解密。如果你用 ffmpeg 直接下载加密流ffmpeg 也会自动处理密钥前提是密钥 URL 可以匿名访问或者你通过-headers参数提供 cookie/referer。测试加密流时判断成功的标准很简单最终 MP4 能正常播放画面不花屏。如果下载后画面花屏或绿屏先确认下载器是否开启了解密支持再看日志里有没有成功下载 key 的记录。很多合并失败不是网络问题是密钥没拿到。5.5 视频格式转换测试视频格式转换是这类的附加功能。比如把下载好的 mkv 转成 mp4或者把 mov 转成 mp4 方便在安卓机播放。用途不同命令也不同。只改变封装格式不重新编码ffmpeg -i input.mkv -c copy output.mp4同时把 H.265 视频转成兼容性更好的 H.264ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac output.mp4判断成功的标准是输出文件能被手机、电视、剪辑软件直接打开。如果播放器只放声音不放画面说明输出文件的编码格式不在播放器支持范围内改用 libx264 重新编码就好。6. 接口 API 与批量任务6.1 把命令行工具当作接口来调很多下载器本身没有 HTTP API但命令行接口就是最稳定的“API”。你可以在 Python、Node、Java 里通过子进程调用下载命令实现批量下载、失败重试、结果回调。以 Python 为例核心是subprocess.runimport subprocess import sys def download_m3u8(url: str, output_path: str, tool: str yt-dlp) - bool: cmd [tool, -o, output_path, url] try: result subprocess.run( cmd, capture_outputTrue, textTrue, timeout600 ) if result.returncode 0: print(f下载成功: {url}) return True else: print(f下载失败: {url}) print(result.stderr) return False except subprocess.TimeoutExpired: print(f下载超时: {url}) return False download_m3u8( https://example.com/index.m3u8, ./output/python_test.%(ext)s )这种写法的好处是你不用关心下载器内部逻辑只要拿返回值判断成功或失败再决定是否重试。6.2 批量任务脚本批量下载是这类工具最常见的工程化需求。建议把链接放进一个纯文本文件一行一个链接然后写脚本逐行处理。示例脚本包含失败重试和日志记录import subprocess import time links [] with open(links.txt, encodingutf-8) as f: links [line.strip() for line in f if line.strip()] success_count 0 fail_list [] for idx, url in enumerate(links, start1): print(f[{idx}/{len(links)}] 处理: {url}) ok False for attempt in range(3): result subprocess.run( [yt-dlp, -o, ./output/%(title)s.%(ext)s, url], capture_outputTrue, textTrue, timeout300 ) if result.returncode 0: ok True break print(f第 {attempt 1} 次失败等待后重试) time.sleep(5) if ok: success_count 1 else: fail_list.append(url) print(f完成成功 {success_count} 个失败 {len(fail_list)} 个) with open(failed_links.txt, w, encodingutf-8) as f: f.write(\n.join(fail_list))批量任务要特别注意日志和失败重试矩阵。失败原因可能是网络抖动、服务器限流、链接过期。建议对每个链接先做 HEAD 请求检查可达性再开始下载失败的链接统一写入一个失败列表文件方便二次重跑。不要在同一时间启动太多并发下载否则容易被目标服务器限流IP 被封。6.3 使用 yt-dlp 的 Python 嵌入方式yt-dlp 本身提供了 Python 接口比 subprocess 更好用适合做更精细的视频信息提取。下面是一个简单示例import yt_dlp def download(url: str): opts { outtmpl: ./output/%(title)s.%(ext)s, noplaylist: True, merge_output_format: mp4, } with yt_dlp.YoutubeDL(opts) as ydl: info ydl.extract_info(url, downloadTrue) print(f标题: {info.get(title)}) print(f时长: {info.get(duration)} 秒) download(https://example.com/index.m3u8)这种方式适合后面接自己的自动化流程比如下载完成后再调 ffmpeg 做切片、做字幕、提取音频。接口调用的核心思路是一样的先用小样本跑通参数再放到批处理环境里。7. 资源占用与性能观察这类工具的资源占用和 AI 模型完全不同主要瓶颈不在显卡而在磁盘、内存和网络。下载过程中内存占用主要来自分片队列和多线程缓存。线程数设置过高会导致内存暴涨尤其是在 DASH 音视频轨同时下载时。一般建议把并发线程控制在 8 到 16 之间具体数值要看目标服务器和带宽。合并转 MP4 时CPU 占用会明显上升。使用-c copy直接复制流时CPU 占用很低瓶颈在磁盘读写使用-c:v libx264重新编码时CPU 会跑满一个 1 小时的 1080p 视频可能需要十几分钟到几十分钟不等。如果想控制 CPU 占用可以限制编码线程数ffmpeg -i input.mkv -c:v libx264 -threads 4 -crf 23 -c:a aac output.mp4显存占用为 0这类任务完全不需要 GPU 加速。有人可能会问“我的显卡是 NVIDIA 的能不能加速转码”从材料看这类纯 HLS 下载合并任务的主要时间开销在下载和解密转码用 libx264 就已经够用。如果你有 NVIDIA 显卡可以考虑用 NVENC 硬件编码加速比如ffmpeg -i input.mkv -c:v h264_nvenc -preset p4 -c:a aac output.mp4但需要注意NVENC 转码速度虽然快同码率下画质一般不如软件编码追求高质量本地存档时建议用 libx264。观察资源占用Windows 下打开任务管理器Linux 下用top或htop。重点看三个指标磁盘读写速率、内存占用、CPU 占用。如果磁盘一直 100%说明分片下载太快导致写入瓶颈可以降低线程数如果内存一直涨说明分片队列积压可以限制最大并发。日志里如果出现大量重试先看是不是带宽跑满再决定要不要调低线程。8. 常见问题与排查方法m3u8视频转换失败是搜索热度很高的问题下面把最常见的失败场景整理成排查表按顺序排除基本都能解决。问题现象可能原因排查方式解决方案m3u8 转 MP4 失败提示 404索引里的分片 URL 是相对路径或分片已过期查看日志中具体失败的分片 URL自定义请求头 referer/cookie或重新抓取新的 m3u8 地址下载后视频花屏、绿屏AES-128 加密分片未正确解密检查 m3u8 中是否有 EXT-X-KEY 标签使用支持解密的下载器确保能访问密钥 URL分片下载慢或一直重试服务器限流或本地网络不稳定观察日志中的 HTTP 状态码降低并发线程数增加下载间隔开启断点重试合并后画面顺序乱concat 列表文件顺序错误检查列表文件里的文件名顺序用sort -V按版本号排序而不是字典序合并后只有第一段能播放分片编码参数不一致ffprobe 查看分片参数使用-c:v libx264 -c:a aac重新编码合并下载完成后只有 ts 文件没有 MP4下载器没有调用 ffmpeg 合并检查 PATH 中是否有 ffmpeg安装 ffmpeg或将 ffmpeg 目录加入 PATH提示磁盘空间不足分片缓存加输出文件超出磁盘容量查看磁盘剩余空间和缓存目录大小清理缓存或换更大空间目录请求返回 403 Forbidden目标服务器校验 referer/cookie/UA在下载器参数中携带浏览器请求头添加--add-header Referer: xxx等参数后重试DASH 下载后没有声音音视频轨未自动合并用 ffprobe 检查输出流确保安装 ffmpeg并设置merge_output_format视频转 MP4 后无法在手机播放编码格式是 H.265 或音频格式不兼容检查编码器信息用-c:v libx264 -c:a aac转码Vue 等前端播放 m3u8 时只能播几十秒服务端按时间切片播放器请求部分分片被限流查看浏览器 Network 中分片请求状态这类是播放端问题和下载器无关优先检查跨域和鉴权第一个问题值得展开m3u8视频转换失败最常见的原因不是工具不行而是链接过期。很多平台的 m3u8 地址带有时间戳或 token几小时就失效。如果你使用一个几小时前抓取的地址下载器拿到的分片 URL 可能已经 404。此时刷新播放页面重新抓取新的 m3u8再下载。还有一种情况是 m3u8 里的分片 URL 是相对路径比如/20240101/abc_0001.ts下载器需要正确拼接完整域名。如果日志里合并失败先手动下载一个分片 URL 在浏览器里看看能否访问。遇到 403 时重点是补请求头。很多服务器会校验Referer或User-Agent下载器如果默认 UA 被拒绝模仿浏览器的请求头即可。以 yt-dlp 为例可以通过--add-header指定yt-dlp --add-header Referer:https://example.com --add-header User-Agent:Mozilla/5.0 -o ./output/test.%(ext)s https://example.com/index.m3u8如果目标视频是直播回放且下载到一半中断先确认工具是否支持断点续传。-c或--continue参数通常用于控制是否跳过已下载的分片。如果工具不支持断点续传换用支持重试的脚本方案更稳妥。9. 最佳实践与使用建议第一第一次测试永远用小文件。找一个几 MB 的测试视频先跑通完整链路下载、合并、转 MP4、播放验证。不要一上来就下载 2 小时的课程否则排错成本很高。第二建立清晰目录结构。输入链接、分片缓存、输出文件、日志分开存放。推荐结构是video_download/ ├── input/ │ └── links.txt ├── cache/ │ └── [临时分片文件] ├── output/ │ └── [最终视频] └── logs/ └── download.log第三保留 m3u8 索引文件。下载完成后不要把原始的 m3u8 文件删掉。如果后续发现合并异常翻原始索引能快速定位问题。一些工具会在输出目录里保留副本建议不要清理。第四批量任务必须加日志和失败重试。简单下载可能不需要日志但批量任务如果跑了一半失败没有日志就只能重新开始。脚本里至少要记录每个链接的下载结果、失败原因和重试次数。失败链接单独存放方便二次重跑。第五接口服务要限制访问范围。如果你启动了带 WebUI 的下载服务不要随意暴露到公网。这类服务能指定下载地址和输出路径如果被外部访问可能被别人利用下载大量内容也会消耗你服务器的带宽和磁盘。建议绑定127.0.0.1只在本地访问。第六涉及版权和隐私资源时必须谨慎。下载他人上传的未授权视频、付费课程、影视剧或把录播课、含个人信息的视频用于二次传播都存在法律和隐私风险。技术本身没有倾向性但使用工具的边界需要自己把握。如果你的工作涉及人脸、声音、个人数据更要在授权范围内处理。第七商用前做完整效果复核。不是所有下载转换后的视频都能直接商用。mp4 只是封装格式不代表编码规范。如果要把视频发布到平台建议用 ffprobe 检查编码参数、分辨率、帧率、音频码率是否满足平台要求。10. 总结与下一步这类 M3U8(HLS)、DASH、MP4 视频下载器最值得尝试的点是把无法直接保存的在线分片视频变成一个本地可用的普通 MP4 文件。从技术角度看解析 m3u8、并发下载分片、解密 AES-128、合并封装每一步都有成熟的命令行工具支撑门槛不高但坑也不少。建议第一次试验时先拿一个公开测试流跑通“下载 ffmpeg 合并 播放验证”的最小链路确认你的工具组合没问题再去处理 DASH 多音轨、AES-128 加密分片、批量下载这些更复杂的场景。最容易踩的坑就是链接过期、请求头校验失败、分片顺序错误、解密失败这四类排查顺序可以固定为链接是否有效 - 请求头是否完整 - 工具是否支持解密 - 合并参数是否正确。后续可以继续扩展的方向包括把下载脚本封装成一个本地 Web 工具给批量任务加一个任务队列和失败重试机制把最终视频接入自己的剪辑流程或媒体库再往深一点可以研究下载后的视频如何自动匹配字幕、提取音频、生成章节信息。对于大多数个人和自动化场景把“下载 - 合并 - 转格式”这条链路打磨顺手就已经能覆盖 90% 的需求了。建议收藏备用等真正需要下载 m3u8 视频时按这篇流程一步步走就行。
返回列表