Docker上のJellyfinでIntel QuickSyncによる4Kハードウェアトランスコーディングを設定する方法

HomeLab tutorial - IT technology blog
HomeLab tutorial - IT technology blog

現場で起こるトラブル:4K再生時のシステム崩壊

Linux HomeLab用に、Intel N100や第8世代Core i5などを搭載した省電力ミニPCを用意したとします。DockerでJellyfinをデプロイし、ライブラリに65 Mbpsの4K HDR映画を追加して、ノートPCのブラウザから再生ボタンを押します。

しかし、動画が始まる代わりに読み込みのスピナーが回り続けます。サーバーの冷却ファンが突如として全開で回転し始め、htopを確認すると全CPUコアが100%に張り付いており、FFmpegは秒間8フレーム程度で低速動作しています。数秒ごとにバッファリングが発生し、静音メディアサーバーが一瞬にして暖房器具と化してしまうのです。

原因の分析:なぜCPUが最新メディアで逼迫するのか

カクつきを解消するには、動画データがストレージから画面へとどのように送られているかを追跡する必要があります。

Direct Playとトランスコーディングの違い

Apple TV 4Kのようなクライアントデバイスが、メディアファイルのコーデック、コンテナ、ビットレートをネイティブでサポートしている場合、JellyfinはDirect Play(直接再生)を使用します。サーバーはディスクから生データを読み取ってネットワーク経由で送信するだけなので、CPU使用率は2%未満に維持されます。

問題は、再生側デバイスがコーデックをネイティブサポートしていない場合に発生します。Webブラウザが10-bit HEVC(H.265)をデコードできることは稀であり、モバイルアプリも高ビットレートのTrueHDオーディオやPGS字幕の処理が苦手な場合があります。こうした不一致が起きると、Jellyfinはストリームをリアルタイムで変換しなければなりません。この処理をトランスコーディングと呼びます。

ソフトウェアエンコードの罠

ハードウェアアクセラレーションがない場合、Jellyfinは純粋なCPU命令によるソフトウェアエンコードに頼ることになります。4K 10-bit HEVCストリームのソフトウェアデコードとH.264への再エンコードを同時に行うと、標準的なプロセッサコアは過負荷に陥ります。6コアのIntel Core i5-12400であっても負荷率は95%に達し、動きの激しいシーンでは24 fpsを下回ってしまいます。その結果、絶え間ないバッファリングとカクつきが発生します。

Dockerの分離の壁

第7世代(Kaby Lake)以降のほとんどのIntel製CPUには、Intel Quick Sync Video(QSV)に対応した内蔵GPU(iGPU)が搭載されています。QSVは、動画のエンコードとデコードに特化して設計された専用のシリコン回路を提供します。しかし、Dockerはデフォルトでコンテナをホストのハードウェアから隔離します。レンダーノード(/dev/dri)をパススルーし、適切なグループ権限を設定しない限り、JellyfinからiGPUを利用することはできません。

解決策の比較:最適な方法を見つける

ターミナルコマンドを実行する前に、HomeLab運用者がトランスコーディングのボトルネックを解消するためによく用いるアプローチを比較してみましょう。

アプローチ メリット デメリット
1. 事前のバッチトランスコード(Tdarr / Handbrake) サーバーのリアルタイム負荷がゼロ。全クライアントで確実にDirect Playが可能。 1作品あたり20〜45分を要する。ストレージを二重に消費。HDR10メタデータが失われるリスク。
2. 多コアCPUへのアップグレード GPUドライバやマッピング、パーミッション管理が不要。 高負荷時に125W以上を消費。ファンの騒音大。小型ミニPCには不向き。
3. ディスクリートGPUの導入(NVIDIA NVENC) 6本以上の4K同時ストリームを容易に処理可能。優れたコーデック対応力。 150〜300ドルの追加コスト。アイドル時でも10W〜25W消費。フルサイズのPCIeスロットが必要。
4. Intel QuickSync iGPUパススルー(推奨) システム全体で15W未満で動作。4K HDRを70+ fpsで変換。既存の内蔵ハードウェアを活用。 ホストのグループIDとデバイスノードをDockerへマッピングする必要がある。

最適なアプローチ:ステップ別セットアップ手順

QSVパススルーを設定することで、サーバーのCPU使用率を5%未満に維持しつつ、ストレスのない4K HDRトランスコーディングを実現できます。

ステップ1:ホスト上でIntel GPUドライバと権限を確認する

LinuxマシンにSSH接続し、カーネルがIntelグラフィックスデバイスを認識しているか確認します:

ls -l /dev/dri

ターミナルに以下のような出力が表示されるはずです:

total 0
drwxr-xr-x  2 root root         80 Oct 15 10:00 by-path
crw-rw----+ 1 root video      226,   0 Oct 15 10:00 card0
crw-rw----+ 1 root render     226, 128 Oct 15 10:00 renderD128

card0デバイスは映像出力を制御し、renderD128は演算処理とハードウェアデコードを担当します。次に、これらのノードを制御しているホストグループの数値グループID(GID)を調べます:

getent group render | cut -d: -f3
getent group video | cut -d: -f3

これらの数値をメモしておきます。Debian 12やUbuntu 22.04/24.04では、renderは通常107、108、または110であり、videoは通常44です。

ステップ2:ホストにGPU監視ツールをインストールする

ハードウェアエンコーダの動作状況をリアルタイムで監視するために、intel-gpu-toolsをインストールします:

sudo apt update && sudo apt install -y intel-gpu-tools

ステップ3:Docker ComposeでJellyfinをデプロイする

Jellyfin用のディレクトリ構成を準備します:

mkdir -p ~/homelab/jellyfin/{config,cache}
cd ~/homelab/jellyfin
nano docker-compose.yml

以下のComposeファイルの内容を貼り付けます。group_add内のGIDの値を更新し、メディアのボリュームマウントをお使いのファイルシステムに合わせて調整してください:

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: 1000:1000
    network_mode: "host"
    group_add:
      - "107"  # ホストの 'render' GID に置き換え
      - "44"   # ホストの 'video' GID に置き換え
    devices:
      - /dev/dri/renderD128:/dev/dri/renderD128
      - /dev/dri/card0:/dev/dri/card0
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/storage/media/movies:/data/movies:ro
      - /mnt/storage/media/shows:/data/shows:ro
    restart: unless-stopped
    environment:
      - TZ=UTC
      - JELLYFIN_PublishedServerUrl=http://192.168.1.100:8096

バックグラウンドでコンテナを起動します:

docker compose up -d

ステップ4:JellyfinのダッシュボードでIntel QuickSyncを有効化する

  1. ブラウザを開き、http://192.168.1.100:8096(サーバーのIPアドレスに適宜置き換え)にアクセスします。
  2. 管理者アカウントの作成とメディアライブラリフォルダの設定を行い、初期セットアップウィザードを完了します。
  3. サイドバーを開き、ダッシュボード > 再生に移動します。
  4. トランスコーディングの項目で、ハードウェアアクセラレーションをIntel QuickSync (QSV)に変更します。
  5. ハードウェアデコードの有効化で、H.264、HEVC、MPEG2、VC1、VP9にチェックを入れます。お使いのシステムが第11世代CoreプロセッサやIntel N100以降である場合のみ、AV1にもチェックを入れます。
  6. ハードウェアエンコードを有効にするにチェックを入れます。
  7. VPPトーンマッピングとトーンマッピングの両方を有効にします。これにより、標準のSDRディスプレイ上で4K HDR10やDolby Visionのコンテンツが白飛びしたり、白く霞んだような映像になったりするのを防ぎます。
  8. 下にスクロールして保存をクリックします。

ステップ5:負荷テストでハードウェアトランスコーディングを確認する

処理フローが正常に機能しているか検証するため、WebブラウザでJellyfinを開き、4K HEVC映画を再生して、動画プレーヤーの設定から画質を手動で1080p - 10Mbpsに変更します。これにより、強制的にトランスコード処理が発生します。

SSHのターミナルに戻り、GPUモニターを起動します:

sudo intel_gpu_top

Videoエンジンの行を確認します。35%〜65%の使用率でアクティブに稼働しているはずです。その間、ホストのCPU使用率は10%未満に抑えられ、トランスコード速度は60 fps以上を維持し、サーバーのファンも静かなままです。

よくある落とし穴とトラブルシューティング

  • /dev/dri/renderD128でのPermission Denied(権限拒否): コンテナのログ(docker compose logs -f)にDevice creation failed: -13 (Permission denied)と出力される場合、root以外のコンテナユーザーがデバイスノードにアクセスできていません。getent group renderを使ってホストのグループIDを再確認し、YAMLファイルのgroup_addの値を更新してください。
  • 映像の白飛びやOpenCLトランスコードのクラッシュ: トーンマッピングが失敗したり、ログにOpenCLの初期化エラーが表示されたりする場合は、公式のjellyfin/jellyfin Dockerイメージを使用しているか確認してください。公式イメージには、必要なintel-opencl-icdパッケージとIntelの商用・非フリー計算ランタイムがあらかじめバンドルされています。
Share: