Skip to content

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切片的工作原理

理解原理有助于你做参数调优:

  1. MP4输入 → 解码为原始音视频帧
  2. 重新编码 → 按目标码率/分辨率压缩(可选,也可流复制)
  3. 切片 → 每6-10秒一个TS文件
  4. 生成M3U8索引 → 记录所有切片URL和元数据
  5. 可选加密 → 每个TS切片用AES-128加密
  6. 输出 → 一个.m3u8文件 + N个.ts文件 + 可选的.key文件

如果你对M3U8文件结构还不熟,建议先看本站 M3U8文件完整指南

两种切片方案对比

方案是否安装处理位置灵活性上手难度
浏览器在线工具(推荐入门)不需要本地中等极简
FFmpeg命令行需要本地最强较高

方法一:浏览器端在线工具(最省事)

MP4转M3U8工具 基于FFmpeg.wasm构建:

  1. 打开 MP4转M3U8工具
  2. 上传MP4文件。
  3. 设置参数:
    • 分片时长:默认6秒,点播推荐6-10秒,直播2-4秒
    • 是否加密:可选AES-128加密
    • 加密密钥:自动生成或自定义16字节HEX
  4. 点开始切片,下载生成的.m3u8 + .ts文件包。

整个过程浏览器本地处理,文件不上传服务器,适合做HLS学习测试和原型开发。

方法二:FFmpeg命令行(最强大)

基础切片(单码率点播)

bash
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:输出的索引文件。

重新编码切片(改变码率/分辨率)

bash
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的精华——同时生成多个清晰度,让播放器自动选择:

bash
# 生成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

text
#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.m3u8

FFmpeg也支持一条命令生成多码率(用 var_stream_map),但配置复杂,手动生成更直观。

AES-128加密切片

加密能防止简单盗链和无意泄露:

bash
# 步骤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.m3u8

enc.keyinfo 文件三行含义:

  1. 密钥的URL(播放器请求这个URL获取密钥)
  2. 密钥文件本地路径(FFmpeg读取它加密)
  3. IV(初始化向量,16字节HEX格式)

加密后的M3U8会包含 #EXT-X-KEY 标签:

text
#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 时长大部分点播/直播
4BYTERANGE、I-FRAME-ONLY拖动条快速预览
5KEYFORMAT(DRM支持)多DRM场景
6EXT-X-MAP(fMP4切片)现代流媒体,效率更高
7EXT-X-SESSION-DATA会话描述

FFmpeg默认用版本3。要切fMP4切片(比.ts更高效),加 -hls_segment_type fmp4-hls_fmp4_init_filename init.mp4

bash
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配置示例:

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流媒体服务器搭建教程

常见问题速查

问题原因解决
浏览器播放跨域错误服务器没配CORSNginx加 Access-Control-Allow-Origin *
M3U8无法播放MIME类型错误.m3u8application/vnd.apple.mpegurl
切片后体积变大重新编码了-codec copy 流复制
加密后播放失败密钥URL不可访问检查密钥URL跨域和可达性
直播延迟过高切片太长缩短 -hls_time 到2-4秒
切片数量爆炸切片时长太短长视频用6-10秒,别用1秒
fMP4播放失败浏览器不支持用默认的.ts切片

直播场景的切片

直播切片和点播略有不同:

bash
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

参考资料

Last updated: