MP4 轉 M3U8 教學:FFmpeg HLS 切片與 AES-128 加密
HLS(HTTP Live Streaming)是 Apple 開發的串流協定,也是主流影片傳輸方式。YouTube、Netflix、Twitch 都用 HLS 串流。這篇介紹用 FFmpeg 把 MP4 轉成 M3U8 的完整流程,包含切片、加密、多解析度。
HLS 基本原理
HLS 把影片切成小片段(TS 檔案),用 M3U8 播放清單管理。播放器依播放清單順序下載片段播放。
input.mp4 → [切片] → output.m3u8 + segment_001.ts + segment_002.ts + ...HLS 元件
- M3U8 播放清單:記錄片段順序和位置
- TS 片段:實際影片資料(MPEG-TS 容器)
- 主播放清單:多解析度時參照各解析度子播放清單
HLS 優點
- 基於 HTTP,CDN 友善
- 自適應位元率(ABR)
- 跨平台相容(Safari 原生支援)
- 可加密保護
基本 MP4 轉 M3U8
bash
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_filename "segment_%03d.ts" \
output.m3u8參數說明:
-c:v libx264:H.264 視訊編碼-c:a aac:AAC 音訊編碼-f hls:HLS 輸出格式-hls_time 6:每個片段 6 秒-hls_playlist_type vod:VOD(點播)模式-hls_segment_filename "segment_%03d.ts":片段命名模式output.m3u8:播放清單輸出
生成的 M3U8 範例
text
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:6.000000,
segment_000.ts
#EXTINF:6.000000,
segment_001.ts
#EXTINF:6.000000,
segment_002.ts
...
#EXT-X-ENDLIST無重新編碼切片
來源 MP4 已經是 H.264/AAC,可以用串流複製模式避免重新編碼:
bash
ffmpeg -i input.mp4 \
-c copy \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_segment_filename "segment_%03d.ts" \
output.m3u8-c copy 直接複製串流,速度最快、無品質損失。
AES-128 加密
1. 生成密鑰和 IV
bash
# 生成 16 位元組密鑰
openssl rand 16 > enc.key
# 生成 16 位元組 IV
openssl rand 16 > enc.iv
# 確認密鑰內容
xxd enc.key
xxd enc.iv2. 建立 key_info 檔案
建立 key_info 文字檔:
https://example.com/enc.key
/path/to/enc.key
/path/to/enc.iv- 第一行:播放器存取密鑰的 URL
- 第二行:FFmpeg 讀取的本地密鑰檔案路徑
- 第三行:IV 檔案路徑
3. 用 FFmpeg 加密切片
bash
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_key_info_file key_info \
-hls_segment_filename "segment_%03d.ts" \
output.m3u84. 加密 M3U8 範例
text
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="https://example.com/enc.key",IV=0x1234567890abcdef1234567890abcdef
#EXTINF:6.000000,
segment_000.ts
#EXTINF:6.000000,
segment_001.ts
...
#EXT-X-ENDLIST#EXT-X-KEY 標籤告訴播放器用 AES-128 解密,從指定 URI 取得密鑰。
注意: AES-128 是基本保護,播放器仍能取得密鑰。真要防盜用 DRM(Widevine、FairPlay)。詳見常見影片下載問題 Q&A 的 DRM 部分。
多解析度 HLS
1. 生成多解析度串流
bash
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=3[v1][v2][v3]; \
[v1]scale=1920:1080[v1out]; \
[v2]scale=1280:720[v2out]; \
[v3]scale=854:480[v3out]" \
-map "[v1out]" -map 0:a -c:v:0 libx264 -b:v:0 5000k \
-map "[v2out]" -map 0:a -c:v:1 libx264 -b:v:1 2500k \
-map "[v3out]" -map 0:a -c:v:2 libx264 -b:v:2 1000k \
-c:a aac -b:a 128k \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
-hls_segment_filename "v%v/segment_%03d.ts" \
"v%v/out.m3u8"2. 主播放清單 master.m3u8
text
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=5500000,RESOLUTION=1920x1080
v0/out.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720
v1/out.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1200000,RESOLUTION=854x480
v2/out.m3u8播放器依網路狀況選擇最佳解析度。
Web 伺服器設定
Nginx 設定
nginx
server {
listen 80;
server_name example.com;
location /hls/ {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
# CORS 設定(跨網域播放需要)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers 'Range';
# 目錄
root /var/www/hls;
# 啟用 Range 請求
add_header Accept-Ranges bytes;
}
}Apache 設定
apache
<IfModule mod_mime.c>
AddType application/vnd.apple.mpegurl .m3u8
AddType video/mp2t .ts
</IfModule>
<IfModule mod_headers.c>
<Location /hls>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Range"
</Location>
</IfModule>HTML 播放器
Safari 原生播放
html
<video controls>
<source src="https://example.com/hls/output.m3u8" type="application/vnd.apple.mpegurl">
</video>Safari 原生支援 HLS,直接用 <video> 標籤。
其他瀏覽器用 hls.js
html
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="video" controls></video>
<script>
const video = document.getElementById('video');
const url = 'https://example.com/hls/output.m3u8';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(url);
hls.attachMedia(video);
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url;
}
</script>詳見 瀏覽器影片播放原理。
進階設定
1. 片段長度最佳化
bash
# 6 秒片段(一般 VOD)
-hls_time 6
# 2 秒片段(低延遲直播)
-hls_time 2
# 用關鍵幀對齊片段
-hls_time 6 -force_key_frames "expr:gte(t,n_forced*6)"2. 直播串流
bash
# 直播模式(持續更新 M3U8)
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_time 2 \
-hls_list_size 5 \
-hls_flags delete_segments \
-hls_segment_filename "live_%03d.ts" \
output.m3u8-hls_list_size 5:M3U8 只保留最近 5 個片段-hls_flags delete_segments:自動刪除舊片段
3. SegmentTimeline 精確控制
bash
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_time 6 \
-hls_playlist_type vod \
-hls_flags independent_segments \
-hls_segment_type mpegts \
-hls_segment_filename "segment_%03d.ts" \
output.m3u8詳見 H.264 vs H.265 vs AV1 編碼器比較。
常見問題
1. Safari 播放不了
原因: HEVC 編碼或音訊不相容
解決方案: 用 H.264 視訊和 AAC 音訊
2. 跨網域播放失敗
原因: CORS 設定問題
解決方案: 確認伺服器 CORS 設定
3. 片段下載失敗
原因: URL 路徑錯誤
解決方案: 確認 M3U8 中的片段 URL
4. 加密播放失敗
原因: 密鑰 URL 不可存取
解決方案: 確認密鑰 URL 可存取,CORS 設定正確
總結
MP4 轉 M3U8 的核心:
- 基本切片:
ffmpeg -i input.mp4 -c copy -f hls -hls_time 6 output.m3u8 - 無重新編碼: 用
-c copy - 加密: AES-128(
-hls_key_info_file) - 多解析度: 主播放清單 + 子播放清單
- Web 伺服器: 設定 MIME 類型和 CORS
快速參考:
- 基本切片:
ffmpeg -i input.mp4 -c copy -f hls -hls_time 6 -hls_segment_filename "seg_%03d.ts" out.m3u8 - 加密:
-hls_key_info_file key_info - 多解析度:
-var_stream_map+-master_pl_name - 直播:
-hls_list_size+-hls_flags delete_segments