この記事でわかること
- HLSの仕組み:プレイリスト(
.m3u8)とトランスポートストリームセグメント(.ts) - 主要オプション:
-hls_time・-hls_list_size・-hls_segment_filename - 静的HTTPサーバーに配置可能なHLS出力の作成方法
- ライブストリーム向けの
-hls_flags delete_segments - アダプティブビットレートラダーの概要
テスト済みバージョン: FFmpeg 6.1(ubuntu-latest / CI検証済み)
対象 OS: Windows / macOS / Linux
HLSの仕組み
HLS(HTTP Live Streaming)はAppleが開発したアダプティブストリーミングプロトコルで、現在は事実上すべてのプラットフォームでサポートされている業界標準です。FFmpegは-f hlsマルチプレクサーでHLS出力を生成できます。
HLS出力は2種類のファイルで構成されます:
| ファイル種別 | 拡張子 | 説明 |
|---|---|---|
| プレイリスト | .m3u8 | すべてのセグメントURLを列挙したインデックスファイル |
| セグメント | .ts | 短い動画・音声チャンク(通常2〜10秒) |
Webサーバーはこれらの静的ファイルをHTTPで配信するだけでよく、プレーヤー(ブラウザのhls.js、iOS/macOSネイティブ、Android)はプレイリストをダウンロードしてセグメントをオンデマンドで取得します。
最小限のHLS出力
ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f hls /tmp/playlist.m3u8
デフォルト設定で/tmp/playlist.m3u8と番号付きセグメントファイル(/tmp/out000.ts、/tmp/out001.tsなど)が生成されます。
セグメント長の制御
-hls_time Nでターゲットのセグメント長を秒単位で設定します(デフォルト: 2):
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 /tmp/playlist.m3u8
セグメントはキーフレーム境界で分割されるため、実際の長さはわずかに異なる場合があります。一定間隔にするには、強制キーフレーム間隔を追加します:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -g 60 -keyint_min 60 -sc_threshold 0 -c:a aac -f hls -hls_time 6 /tmp/playlist.m3u8
-g 60で60フレームごとにキーフレームを挿入(30fpsで2秒間隔)。-hls_time 6と組み合わせると、各セグメントがちょうど3キーフレーム区間になります。
プレイリストにすべてのセグメントを保持する
デフォルトでは-hls_list_sizeは5で、プレイリストには直近5セグメントだけが含まれます(ライブストリーム向け)。VOD(ビデオオンデマンド)では0に設定してすべてのセグメントを保持します:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 -hls_list_size 0 /tmp/playlist.m3u8
セグメントファイル名のカスタマイズ
-hls_segment_filenameでセグメントファイルのパスと命名パターンを制御します:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "/tmp/segment_%03d.ts" /tmp/playlist.m3u8
%03dはprintf形式でゼロパディングされた連番を生成します(segment_000.ts、segment_001.tsなど)。ディレクトリパスも含められます:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "/tmp/hls/seg_%04d.ts" /tmp/hls/playlist.m3u8
出力ディレクトリは事前に作成しておく必要があります(FFmpegは自動作成しません)。
VOD用の完全な例
オンデマンド再生向けにファイルをHLSに変換する本番向けコマンド:
ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 22 -c:a aac -b:a 128k -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "/tmp/hls_vod/seg_%04d.ts" /tmp/hls_vod/index.m3u8
/tmp/hls_vod/ディレクトリ全体をHTTPサーバーに配置し、プレーヤーをindex.m3u8に向けます。
ライブストリーミング — 古いセグメントの自動削除
ライブストリームでは、プレイリストのウィンドウから外れた古いセグメントは不要です。-hls_flags delete_segmentsで自動削除します:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 -hls_list_size 5 -hls_flags delete_segments /tmp/playlist.m3u8
-hls_list_size 5でプレイリストに5セグメントを保持し、除外されたセグメントはディスクから自動削除されます。
アダプティブビットレートラダー(概要)
フルABRラダーは同じコンテンツを複数のビットレート・解像度でエンコードし、各バリアントを参照するマスタープレイリストを作成する必要があります。典型的な手順:
- 各ビットレート/解像度を個別のHLSストリームとしてエンコード
#EXT-X-STREAM-INFタグで各バリアントを列挙するマスタープレイリスト(.m3u8)を作成
FFmpegは-mapと複数の-f hls出力を使って1パスで複数出力できますが、コマンドが複雑になります。本番用ABRには、AWS MediaConvertやFFmpegをベースにした専用トランスコーダーの使用が実用的です。
主要オプション一覧
| オプション | デフォルト | 説明 |
|---|---|---|
-hls_time N | 2 | ターゲットセグメント長(秒) |
-hls_list_size N | 5 | プレイリストの最大セグメント数(0=全保持) |
-hls_segment_filename パターン | (自動) | セグメントファイルの命名パターン |
-hls_flags delete_segments | オフ | プレイリストから除外されたセグメントを自動削除 |
-hls_flags append_list | オフ | 既存プレイリストに追記(上書きせず) |
-start_number N | 0 | セグメントの開始シーケンス番号 |
よくある問題
セグメントがプレイリストに含まれていない
VODファイルで-hls_list_size 0を忘れると、直近N件のセグメントしかプレイリストに含まれません。ファイルは再生できますが、最後の部分だけになります。
出力ディレクトリが存在しない
セグメントパスの親ディレクトリが存在しない場合、FFmpegは「No such file or directory」エラーで失敗します。事前に作成してください:
mkdir -p /tmp/hls_output
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -c:a aac -f hls -hls_time 6 -hls_list_size 0 -hls_segment_filename "/tmp/hls_output/seg_%04d.ts" /tmp/hls_output/playlist.m3u8
プレーヤーが「再生可能なソースがありません」と表示する
HTTPサーバーが正しいMIMEタイプを設定しているか確認してください:
.m3u8→application/vnd.apple.mpegurlまたはapplication/x-mpegURL.ts→video/mp2t
一部のサーバーではこれらの設定が必要です。
関連記事
テスト環境: ffmpeg 6.1.1 / Ubuntu 24.04(GitHub Actions)
一次ソース: ffmpeg.org/ffmpeg-formats.html#hls-1 / trac.ffmpeg.org/wiki/StreamingGuide