FFmpeg HLS/VOD on Ubuntu — 動画をHLS変換してNginxで配信する

サーバー構築

動画ファイルを HLS(HTTP Live Streaming)に変換して Nginx で配信する手順をまとめました。

「YouTube のような動画配信を自分のサーバーでやってみたい」という相談を受けることがあります。実は Ubuntu 24.04 + FFmpeg + Nginx の3本セットがあれば、ブラウザで再生できる VOD 環境を1時間もかからず構築できます。正直、HLS の仕組みを理解してしまえばコマンドは10行に満たないので、思ったより簡単でした。

この記事では Ubuntu 24.04.4 LTS で実際に FFmpeg 6.1.1 を動かし、テスト動画を HLS に変換した実出力をそのまま載せています。

この記事のポイント

  • apt install ffmpeg nginx だけで HLS 配信に必要なツールが揃う(Ubuntu 24.04 標準リポジトリ)
  • -hls_time 4-hls_playlist_type vod を指定するだけで .m3u8.ts セグメントが生成される
  • 実測では 30秒動画 → 約1.3秒で変換完了(約24倍速)、生成サイズ 984KB
  • アダプティブビットレート(360p+720p 同時出力)は -filter_complex split-var_stream_map で対応できる
  • Nginx 側は m3u8ts の MIME タイプ設定+ CORS ヘッダーが必須

目次

  1. HLS(HTTP Live Streaming)とは
  2. FFmpeg と Nginx のインストール
  3. シングルビットレート HLS への変換
  4. Nginx で HLS コンテンツを配信する
  5. ブラウザで再生する(hls.js)
  6. アダプティブビットレート HLS(360p + 720p)
  7. よくあるエラーと解決策
  8. まとめ

HLS(HTTP Live Streaming)とは

HLS は Apple が開発した動画配信プロトコルで、いまでは YouTube・Netflix・Twitch でも使われています。仕組みはシンプルで、動画を数秒ごとの小さなファイル(.ts セグメント)に分割し、どのファイルをどの順で取得するかを .m3u8(プレイリスト)に記述します。

ブラウザはまず .m3u8 を取得 → そこに書かれた .ts を順番に HTTP でダウンロードして再生します。特別な配信サーバーは必要なく、ただの静的ファイルとして Nginx で配信できるのが最大の利点です。

プロトコル 配信形式 必要なサーバー ブラウザ対応
HLS .m3u8 + .ts 静的ファイルサーバー(Nginx 可) Safari ネイティブ、他は hls.js
RTMP ストリーム RTMP 対応サーバー必須 Flash が必要(現在非推奨)
DASH .mpd + .m4s 静的ファイルサーバー可 dash.js が必要

FFmpeg と Nginx のインストール

Ubuntu 24.04 の標準リポジトリには FFmpeg 6.1.1 が収録されています。apt install 1コマンドで H.264・AAC・HLS 出力が揃います。

Ubuntu 24.04 で FFmpeg + Nginx を apt install した実ログ(実測)
Ubuntu 24.04 で FFmpeg + Nginx を apt install した実ログ(実測)



ubuntu@server: ~
$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Reading package lists… Done
$ sudo apt-get install -y ffmpeg nginx
The following additional packages will be installed:
libavcodec60 libavformat60 libavutil58 libswscale7 …
Setting up ffmpeg (7:6.1.1-3ubuntu5) …
Setting up nginx (1.24.0-2ubuntu7.12) …

インストール後にバージョンを確認します。




ubuntu@server: ~
$ ffmpeg -version | head -2
ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers
built with gcc 13 (Ubuntu 13.2.0-23ubuntu3)
$ nginx -v
nginx version: nginx/1.24.0 (Ubuntu)
$ ffmpeg -formats 2>/dev/null | grep hls
DE hls Apple HTTP Live Streaming

Ubuntu 24.04 に入る FFmpeg は libx264(H.264 エンコーダ)・libx265(H.265)・AAC すべてが有効です。追加ビルドは不要です。

シングルビットレート HLS への変換

まず基本形から始めます。MP4 ファイルを index.m3u8seg000.ts, seg001.ts, … に変換するコマンドです。




ubuntu@server: ~/hls_work
$ mkdir -p hls
$ ffmpeg -i input.mp4 \
-c:v libx264 -preset fast -crf 23 \
-c:a aac -b:a 128k \
-hls_time 4 \
-hls_playlist_type vod \
-hls_segment_filename ‘hls/seg%03d.ts’ \
hls/index.m3u8

主なオプションの意味です。

オプション 意味
-c:v libx264 映像を H.264 でエンコード
-preset fast エンコード速度優先(品質と速度のバランス)
-crf 23 品質固定モード(0〜51、低いほど高品質。23 が標準)
-c:a aac -b:a 128k 音声を AAC 128kbps でエンコード
-hls_time 4 セグメント長の目安(秒)。実際はキーフレームに合わせてカット
-hls_playlist_type vod VOD 用プレイリスト(末尾に #EXT-X-ENDLIST を追記)
-hls_segment_filename セグメントファイル名のパターン

hls_time の注意点

-hls_time 4 は「4秒ごとに切る」ではなく「最低でも4秒、キーフレームが来たら切る」という意味です。入力動画のキーフレーム間隔が長い場合(デフォルト2秒周期でエンコードされた動画でも GOP 設定次第では変わる)、実際のセグメント長はそれより長くなります。実測では 30秒動画 → 4本(各〜8秒)になりました。

変換すると以下の出力が得られます。実際に Ubuntu 24.04 コンテナで計測した結果です。

FFmpeg HLS 変換コマンドの実ログと生成 m3u8(実測)
FFmpeg HLS 変換コマンドの実ログと生成 m3u8(実測)

30秒の動画(H.264 CRF23)を変換した実測値です。

  • 変換速度:約 24倍速(1.3秒で完了)
  • セグメント数:4本(各〜8秒)
  • 合計サイズ:984KB

Nginx で HLS コンテンツを配信する

変換したファイルを Nginx で公開します。ここで詰まりやすいのが MIME タイプの設定です。.m3u8.ts は Nginx のデフォルト設定に含まれていないため、明示的に指定しないと ブラウザが正しく認識できません。




ubuntu@server: /etc/nginx/sites-available/default
server {
listen 80;
server_name example.com; # ← 自分のドメインに変更
root /var/www/html;

location /hls/ {
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers *;
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
}
}
Nginx CORS 設定と nginx -t でのテスト確認(実測)
Nginx CORS 設定と nginx -t でのテスト確認(実測)

設定を反映させます。




ubuntu@server: ~
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx

HLS ディレクトリへコンテンツを配置します。




ubuntu@server: ~
$ sudo mkdir -p /var/www/html/hls
$ sudo cp hls/*.m3u8 hls/*.ts /var/www/html/hls/
$ curl -I http://localhost/hls/index.m3u8
HTTP/1.1 200 OK
Content-Type: application/vnd.apple.mpegurl
Access-Control-Allow-Origin: *

Content-Type: application/vnd.apple.mpegurl が返れば正しく設定できています。

ブラウザで再生する(hls.js)

Safari はネイティブで HLS を再生できますが、Chrome や Firefox は HLS を直接再生できません。hls.js を使うことで MSE(Media Source Extensions)対応のすべてのブラウザで再生できます。

hls.js を使った HLS プレーヤーのブラウザ画面(Ubuntu 24.04 + FFmpeg 生成コンテンツ)
hls.js を使った HLS プレーヤーのブラウザ画面(Ubuntu 24.04 + FFmpeg 生成コンテンツ)

シンプルなプレーヤー HTML の例です。CDN 経由で hls.js を読み込むだけなので、フレームワーク不要です。




player.html
<!DOCTYPE html>
<script src=”https://cdn.jsdelivr.net/npm/hls.js@latest”></script>
<video id=”video” controls></video>
<script>
var video = document.getElementById(‘video’);
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(‘/hls/index.m3u8’);
hls.attachMedia(video);
} else if (video.canPlayType(‘application/vnd.apple.mpegurl’)) {
video.src = ‘/hls/index.m3u8’; // Safari
}
</script>

ブラウザは index.m3u8 を取得し、記載されたセグメントを順に HTTP リクエストで取得して再生します。

ブラウザで /hls/index.m3u8 を直接開いた画面
ブラウザで /hls/index.m3u8 を直接開いた画面

アダプティブビットレート HLS(360p + 720p)

回線速度に応じて品質を自動切り替えするアダプティブビットレート(ABR)を設定します。FFmpeg の -filter_complex-var_stream_map を使って、1コマンドで複数品質のセグメントと master.m3u8 を同時に出力できます。




ubuntu@server: ~/hls_work
$ mkdir -p hls_multi/360p hls_multi/720p
$ ffmpeg -i input.mp4 \
-filter_complex ‘[v:0]split=2[v360][v720]’ \
-map ‘[v360]’ -map ‘[v720]’ -map 0:a -map 0:a \
-c:v libx264 -preset fast \
-c:a aac \
-b:v:0 500k -s:v:0 640×360 \
-b:v:1 1500k -s:v:1 1280×720 \
-b:a:0 64k -b:a:1 128k \
-hls_time 4 \
-hls_playlist_type vod \
-hls_segment_filename ‘hls_multi/%v/seg%03d.ts’ \
-master_pl_name master.m3u8 \
-var_stream_map ‘v:0,a:0,name:360p v:1,a:1,name:720p’ \
‘hls_multi/%v/index.m3u8’
real 0m1.861s (30秒動画を約1.9秒で変換 ≈ 16倍速)

実測結果です。30秒の動画(1280×720 入力)を 2品質同時変換した場合の数値です。

アダプティブビットレート HLS 変換結果(実測)
アダプティブビットレート HLS 変換結果(実測)
生成された master.m3u8 の実内容(実測)
生成された master.m3u8 の実内容(実測)

生成された master.m3u8 は次の形式になります。hls.js はこのファイルを読んで、接続速度に合わせて 360p と 720p を自動で切り替えます。




hls_multi/master.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=620400,RESOLUTION=640×360,CODECS=”avc1.f4001e,mp4a.40.2″
360p/index.m3u8

#EXT-X-STREAM-INF:BANDWIDTH=1790800,RESOLUTION=1280×720,CODECS=”avc1.f4001f,mp4a.40.2″
720p/index.m3u8

-hls_segment_filename のパスに %v を入れると「ストリーム番号(0, 1…)」に展開されます。-var_stream_mapname:360p を指定するとそのまま 360p/ というディレクトリ名で出力されるので、ファイル構成がわかりやすくなります。

アダプティブ配信の場合、プレーヤー側の loadSource には master.m3u8 を渡します。




player.html(ABR版)
hls.loadSource(‘/hls_multi/master.m3u8’); // ← master を指定
hls.attachMedia(video);

よくあるエラーと解決策

エラー1:動画がブラウザで再生されない(CORS エラー)

Chrome の開発者ツールのコンソールに has been blocked by CORS policy と表示される場合、Nginx の CORS ヘッダーが抜けています。/hls/ のブロックに add_header Access-Control-Allow-Origin *; を追加して nginx -t && systemctl reload nginx を実行してください。

エラー2:m3u8 を開くと 404 になる

HLS ファイルを /var/www/html/hls/ にコピーしたか確認します。また ls -la /var/www/html/hls/ でパーミッションを見てください。Nginx は www-data ユーザーで動くため、ファイルのオーナーが root のままだと読めないことがあります。chmod 644 で読み取り権限を付与してください。

エラー3:変換中に「Unknown encoder ‘libx264’」

FFmpeg を自前ビルドしたか、Ubuntu の場合は ffmpeg パッケージ(universe リポジトリ)でなく libav* 系の別パッケージが入っている可能性があります。apt-get install ffmpeg で入れ直し、ffmpeg -codecs | grep libx264 で確認してください。Ubuntu 24.04 の標準 ffmpeg は libx264 有効状態でビルドされています。

エラー4:セグメント長が指定より長い

前述のとおり、-hls_time はキーフレームに合わせてカットするため、実際のセグメント長は指定より長くなります。精密に区切りたい場合は -force_key_frames "expr:gte(t,n_forced*2)" を追加して入力に強制的にキーフレームを打ち込む方法があります。ただし再エンコード時間が増えます。

まとめ

Ubuntu 24.04 上で FFmpeg + Nginx を使った HLS/VOD 配信の手順をまとめました。

  • Ubuntu 24.04 標準の ffmpeg 6.1.1 は libx264・AAC・HLS フォーマットをすべてサポート済み
  • 基本コマンドは -hls_time 4 -hls_playlist_type vod -hls_segment_filename の3オプション
  • 実測では 30秒動画 → 約1.3秒(24倍速)で変換、合計 984KB
  • Nginx 側は m3u8 の MIME タイプと CORS ヘッダーが必須
  • アダプティブビットレートは -filter_complex split + -var_stream_map で対応できる
  • ブラウザ再生には hls.js(CDN 経由でロード可)を使う

自分の VPS でこの構成を動かすには、外部アクセス可能なサーバーが必要です。コスト感を比較したい場合は VPS 比較記事も参考にしてください。

Ubuntuサーバー構築の手順 VPSで実際に立てて解説
「VPS を借りたけど、Ubuntu サーバーをどう設定すればいいか分からない」——そんな疑問に、実際に Ubuntu 24.04 LTS 上でコマンドを動かして確認した手順でお答えします。

コメント

タイトルとURLをコピーしました