MP4转M3U8教程:HLS切片原理与AES-128加密实战(FFmpeg + 浏览器工具)
要做HLS流媒体测试,需要一个M3U8流;想把MP4放到CDN上做自适应码率分发;学习流媒体原理想自己切片试试。MP4转M3U8这事,看着就是把视频切碎,实际涉及到切片、自适应码率、加密、部署多个环节。今天就把完整流程走一遍。
为什么要MP4转M3U8
直接放MP4文件不行吗?为什么非要切片?三个核心原因:
原因一:自适应码率(ABR)
MP4是单一文件,没法做"网络好播1080p、网络差播480p"的动态切换。HLS把同一视频转成多个不同码率的版本,每个版本切成小片段,播放器按需切换。这是Netflix、YouTube这类平台的核心体验。
原因二:CDN分发效率
一个2GB的1080p MP4文件,CDN缓存成本高、首次加载慢、用户拖进度条要重新请求大块数据。HLS把视频切成2-10秒的小片段,CDN可以按片段缓存,用户起播只需下载第一个切片(几MB),体验更流畅。
原因三:直播场景
直播不可能等到完整视频再分发,必须边录边切边传。HLS就是为这种场景设计的,编码器持续输出TS切片,播放器持续拉取新切片。
HLS切片的工作原理
理解原理有助于你做参数调优:
- MP4输入 → 解码为原始音视频帧
- 重新编码 → 按目标码率/分辨率压缩(可选,也可流复制)
- 切片 → 每6-10秒一个TS文件
- 生成M3U8索引 → 记录所有切片URL和元数据
- 可选加密 → 每个TS切片用AES-128加密
- 输出 → 一个.m3u8文件 + N个.ts文件 + 可选的.key文件
如果你对M3U8文件结构还不熟,建议先看本站 M3U8文件完整指南。
两种切片方案对比
| 方案 | 是否安装 | 处理位置 | 灵活性 | 上手难度 |
|---|---|---|---|---|
| 浏览器在线工具(推荐入门) | 不需要 | 本地 | 中等 | 极简 |
| FFmpeg命令行 | 需要 | 本地 | 最强 | 较高 |
方法一:浏览器端在线工具(最省事)
MP4转M3U8工具 基于FFmpeg.wasm构建:
- 打开 MP4转M3U8工具。
- 上传MP4文件。
- 设置参数:
- 分片时长:默认6秒,点播推荐6-10秒,直播2-4秒
- 是否加密:可选AES-128加密
- 加密密钥:自动生成或自定义16字节HEX
- 点开始切片,下载生成的.m3u8 + .ts文件包。
整个过程浏览器本地处理,文件不上传服务器,适合做HLS学习测试和原型开发。
方法二:FFmpeg命令行(最强大)
基础切片(单码率点播)
ffmpeg -i input.mp4 \
-codec copy \
-start_number 0 \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_filename "segment_%03d.ts" \
playlist.m3u8参数详解:
-codec copy:流复制,不重新编码,最快最无损。-start_number 0:切片从0开始编号。-hls_time 6:每片6秒。-hls_playlist_type vod:点播模式,加#EXT-X-ENDLIST标记。-hls_segment_filename:切片文件名模板,%03d表示3位数字(segment_000.ts、segment_001.ts...)。playlist.m3u8:输出的索引文件。
重新编码切片(改变码率/分辨率)
ffmpeg -i input.mp4 \
-c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_filename "720p/segment_%03d.ts" \
720p/playlist.m3u8多码率自适应(Master Playlist)
这是HLS的精华——同时生成多个清晰度,让播放器自动选择:
# 生成360p
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 800k -s 640x360 \
-c:a aac -b:a 96k \
-hls_time 6 -hls_playlist_type vod \
-hls_segment_filename "360p/segment_%03d.ts" \
360p/playlist.m3u8
# 生成720p
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 2000k -s 1280x720 \
-c:a aac -b:a 128k \
-hls_time 6 -hls_playlist_type vod \
-hls_segment_filename "720p/segment_%03d.ts" \
720p/playlist.m3u8
# 生成1080p
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 5000k -s 1920x1080 \
-c:a aac -b:a 160k \
-hls_time 6 -hls_playlist_type vod \
-hls_segment_filename "1080p/segment_%03d.ts" \
1080p/playlist.m3u8然后手动创建主播放列表 master.m3u8:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2000000,RESOLUTION=1280x720
720p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p/playlist.m3u8FFmpeg也支持一条命令生成多码率(用 var_stream_map),但配置复杂,手动生成更直观。
AES-128加密切片
加密能防止简单盗链和无意泄露:
# 步骤1:生成16字节随机密钥
openssl rand 16 > enc.key
# 步骤2:生成密钥信息文件 enc.keyinfo
echo "https://example.com/enc.key" > enc.keyinfo
echo "enc.key" >> enc.keyinfo
echo "$(openssl rand -hex 16)" >> enc.keyinfo
# 步骤3:执行加密切片
ffmpeg -i input.mp4 \
-codec copy \
-hls_time 6 \
-hls_playlist_type vod \
-hls_key_info_file enc.keyinfo \
-hls_segment_filename "segment_%03d.ts" \
playlist.m3u8enc.keyinfo 文件三行含义:
- 密钥的URL(播放器请求这个URL获取密钥)
- 密钥文件本地路径(FFmpeg读取它加密)
- IV(初始化向量,16字节HEX格式)
加密后的M3U8会包含 #EXT-X-KEY 标签:
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/enc.key",IV=0x1234567890abcdef1234567890abcdef注意: AES-128只是基础保护,不是真正的内容保护。要严格防盗必须用DRM(Widevine、FairPlay、PlayReady)。详见本站 M3U8文件完整指南 中的加密章节。
HLS版本选择
#EXT-X-VERSION 决定了能用的特性:
| 版本 | 关键特性 | 适用场景 |
|---|---|---|
| 3 | 浮点 #EXTINF 时长 | 大部分点播/直播 |
| 4 | BYTERANGE、I-FRAME-ONLY | 拖动条快速预览 |
| 5 | KEYFORMAT(DRM支持) | 多DRM场景 |
| 6 | EXT-X-MAP(fMP4切片) | 现代流媒体,效率更高 |
| 7 | EXT-X-SESSION-DATA | 会话描述 |
FFmpeg默认用版本3。要切fMP4切片(比.ts更高效),加 -hls_segment_type fmp4 和 -hls_fmp4_init_filename init.mp4:
ffmpeg -i input.mp4 \
-codec copy \
-hls_time 6 \
-hls_segment_type fmp4 \
-hls_fmp4_init_filename init.mp4 \
-hls_segment_filename "chunk_%03d.m4s" \
playlist.m3u8部署到服务器(Nginx示例)
切片生成后需要部署到Web服务器才能播放。Nginx配置示例:
server {
listen 80;
server_name stream.example.com;
root /var/www/hls;
# M3U8 MIME类型
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
video/mp4 m4s mp4;
}
# 允许跨域(重要!否则浏览器无法播放)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
# 切片目录
location /hls/ {
alias /var/www/hls/;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# M3U8不缓存(直播流需要实时更新)
location ~ \.m3u8$ {
add_header Cache-Control "no-cache";
}
}配置后访问 https://stream.example.com/hls/playlist.m3u8 即可播放。可以用本站 M3U8在线播放器 测试。
如果想自己搭流媒体服务器,可以看本站 Nginx-RTMP流媒体服务器搭建教程。
常见问题速查
| 问题 | 原因 | 解决 |
|---|---|---|
| 浏览器播放跨域错误 | 服务器没配CORS | Nginx加 Access-Control-Allow-Origin * |
| M3U8无法播放 | MIME类型错误 | 配 .m3u8 为 application/vnd.apple.mpegurl |
| 切片后体积变大 | 重新编码了 | 用 -codec copy 流复制 |
| 加密后播放失败 | 密钥URL不可访问 | 检查密钥URL跨域和可达性 |
| 直播延迟过高 | 切片太长 | 缩短 -hls_time 到2-4秒 |
| 切片数量爆炸 | 切片时长太短 | 长视频用6-10秒,别用1秒 |
| fMP4播放失败 | 浏览器不支持 | 用默认的.ts切片 |
直播场景的切片
直播切片和点播略有不同:
ffmpeg -re -i input.mp4 \
-codec copy \
-hls_time 4 \
-hls_list_size 0 \
-hls_segment_filename "live_%03d.ts" \
live.m3u8关键参数:
-re:按真实时间速度读取输入(直播必须),否则FFmpeg会全速读完文件瞬间切完。-hls_list_size 0:保留所有切片到列表(点播)。直播通常用-hls_list_size 6 -hls_flags delete_segments,只保留最近6个切片,老的自动删除。
总结
MP4转M3U8是HLS流媒体的入口技能。点播切片用 -codec copy 流复制最快最无损,多码率自适应需要分别生成不同分辨率的M3U8再写一个Master Playlist。AES-128加密能挡住简单盗链,但真要保护内容得用DRM。
日常用浏览器工具最省事,做生产环境用FFmpeg命令行最灵活。部署时记得配CORS和MIME类型,不然浏览器死活播不了。
快速回顾:
- 首选工具:MP4转M3U8工具(本地处理,学习测试)
- FFmpeg万能命令:
ffmpeg -i input.mp4 -codec copy -hls_time 6 -hls_playlist_type vod -hls_segment_filename "segment_%03d.ts" playlist.m3u8 - 多码率:分别切片 + 手写Master Playlist
- 加密:AES-128挡简单盗链,DRM保版权
- 部署:Nginx配CORS和MIME