この記事でわかること

テスト済みバージョン: 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_size5で、プレイリストには直近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.tssegment_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ラダーは同じコンテンツを複数のビットレート・解像度でエンコードし、各バリアントを参照するマスタープレイリストを作成する必要があります。典型的な手順:

  1. 各ビットレート/解像度を個別のHLSストリームとしてエンコード
  2. #EXT-X-STREAM-INFタグで各バリアントを列挙するマスタープレイリスト(.m3u8)を作成

FFmpegは-mapと複数の-f hls出力を使って1パスで複数出力できますが、コマンドが複雑になります。本番用ABRには、AWS MediaConvertやFFmpegをベースにした専用トランスコーダーの使用が実用的です。


主要オプション一覧

オプションデフォルト説明
-hls_time N2ターゲットセグメント長(秒)
-hls_list_size N5プレイリストの最大セグメント数(0=全保持)
-hls_segment_filename パターン(自動)セグメントファイルの命名パターン
-hls_flags delete_segmentsオフプレイリストから除外されたセグメントを自動削除
-hls_flags append_listオフ既存プレイリストに追記(上書きせず)
-start_number N0セグメントの開始シーケンス番号

よくある問題

セグメントがプレイリストに含まれていない

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タイプを設定しているか確認してください:

一部のサーバーではこれらの設定が必要です。


関連記事


テスト環境: ffmpeg 6.1.1 / Ubuntu 24.04(GitHub Actions)
一次ソース: ffmpeg.org/ffmpeg-formats.html#hls-1 / trac.ffmpeg.org/wiki/StreamingGuide