この記事の対象読者
- 動画エンコードに時間がかかりすぎて困っている方
- NVIDIA製GPUを持っているがNVENCを使ったことがない方
- FFmpegでハードウェアエンコードを試してみたい方
- Pythonで動画処理を高速化したいエンジニア
この記事で得られること
- NVENCの基本概念: ハードウェアエンコーダーとは何か、CPUエンコードとの違いを理解
- 実践的なFFmpegコマンド: コピペで使えるNVENCエンコードコマンド集
- Python連携: FFmpegをPythonから呼び出してGPUエンコードを自動化
- トラブルシューティング: よくあるエラーと解決方法
この記事で扱わないこと
- NVIDIAドライバーのインストール方法(OSによって異なるため)
- 配信ソフト(OBS等)でのNVENC設定
- AMDやIntelのハードウェアエンコーダー
1. NVENCとの出会い
「4K動画のエンコードに3時間もかかった...」
動画編集をしている人なら、一度はこんな経験があるのではないだろうか。私も以前、iPhone撮影の10分動画をH.265に変換するだけで、コーヒーを3杯飲み干すほど待たされた経験がある。CPUがフル稼働してPCファンが唸りを上げる中、「もっと速くできないのか」と悶々としていた。
そんな時に出会ったのが NVENC(NVIDIA Encoder)だ。
NVENCとは、NVIDIA製GPUに搭載されている専用のハードウェアビデオエンコーダーのこと。料理で例えるなら、CPUエンコードが「万能包丁で野菜も肉も魚も切る」のに対し、NVENCは「野菜専用の超高速スライサー」のようなもの。特定の作業に特化しているからこそ、圧倒的に速い。
ここまでで、NVENCがどんなものか、なんとなくイメージできただろうか。次は、この記事で使う用語を整理しておこう。
2. 前提知識の確認
本題に入る前に、この記事で登場する用語を確認しておく。
2.1 エンコード(Encode)とは
動画データを特定の形式(コーデック)に変換・圧縮すること。生の動画データは膨大なサイズになるため、H.264やH.265といったコーデックで圧縮して保存・配信する。逆に、圧縮されたデータを元に戻すのが「デコード」。
2.2 コーデック(Codec)とは
動画の圧縮・展開方式の規格。主なものとして以下がある。
| コーデック | 別名 | 特徴 |
|---|---|---|
| H.264 | AVC | 互換性最高、広く普及 |
| H.265 | HEVC | H.264の約2倍の圧縮効率 |
| AV1 | - | 次世代規格、ロイヤリティフリー |
2.3 FFmpegとは
動画・音声の変換、編集、配信などを行うオープンソースのコマンドラインツール。世界中で最も使われている動画処理ツールといっても過言ではない。
2.4 CPUエンコードとGPUエンコード
| 種類 | 処理担当 | 代表例 | 特徴 |
|---|---|---|---|
| CPUエンコード(ソフトウェア) | CPU | libx264, libx265 | 高画質だが遅い、CPU負荷高 |
| GPUエンコード(ハードウェア) | GPU専用チップ | NVENC, QSV, VCE | 超高速、CPU負荷ほぼゼロ |
これらの用語が押さえられたら、NVENCの背景を見ていこう。
3. NVENCが生まれた背景
3.1 動画エンコードの課題
2010年代初頭、YouTubeやニコニコ動画の普及により、動画コンテンツが爆発的に増加した。しかし当時のエンコードはすべてCPU任せ。高画質な動画を作ろうとすると、ハイエンドCPUでも数時間〜数十時間かかることが珍しくなかった。
特に問題だったのは以下の点だ。
- 待ち時間: 10分の動画エンコードに30分〜1時間
- PC負荷: エンコード中は他の作業が困難
- 電力消費: CPUフル稼働で消費電力が増大
3.2 NVIDIAの解決策
2012年、NVIDIAはKepler世代のGPU(GeForce 600シリーズ)にNVENCを搭載した。これはGPU内部に設けられたエンコード専用の固定機能ユニットで、CUDAコアとは別の独立したハードウェアだ。
NVENCの登場により、以下が実現した。
- エンコード時間: CPUの5〜10倍高速
- CPU負荷: ほぼゼロ(エンコード中もPCがサクサク動く)
- 消費電力: CUDAコアを使わないため省電力
背景がわかったところで、基本的な仕組みを見ていこう。
4. 基本概念と仕組み
4.1 NVENCのアーキテクチャ
NVENCはGPUダイ上の独立したハードウェアブロックとして実装されている。
┌─────────────────────────────────────────┐
│ GPU │
│ ┌─────────────────────────────────┐ │
│ │ CUDAコア(汎用演算) │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ NVENC │ │ NVDEC │ │
│ │ (エンコード) │ │ (デコード) │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────┘
重要なのは、NVENCがCUDAコアとは完全に独立していること。つまり、機械学習やゲームでCUDAコアを使いながら、同時にNVENCでエンコードができる。
4.2 世代ごとの進化
NVENCは世代を重ねるごとに機能が強化されている。
| 世代 | GPUアーキテクチャ | 主な機能 |
|---|---|---|
| 第1世代 | Kepler (2012) | H.264エンコード |
| 第4世代 | Pascal (2016) | HEVC 10bit、4K対応 |
| 第6世代 | Turing (2018) | HEVC Bフレーム対応 |
| 第8世代 | Ada Lovelace (2022) | AV1エンコード、UHQモード |
| 第9世代 | Blackwell (2024) | AV1 UHQ、H.264 422対応 |
4.3 対応コーデック
2025年現在、NVENCがサポートするコーデックは以下の通り。
| コーデック | FFmpegエンコーダー名 | 対応GPU |
|---|---|---|
| H.264 | h264_nvenc |
Kepler以降(GTX 600〜) |
| H.265/HEVC | hevc_nvenc |
Maxwell 2nd以降(GTX 900〜) |
| AV1 | av1_nvenc |
Ada Lovelace以降(RTX 40〜) |
4.4 同時エンコードセッション数
2025年11月のドライバ更新により、GeForceカードでの同時エンコードセッション数が最大12に拡大された。以前は3〜8セッションだったため、大幅な改善だ。
基本概念が理解できたところで、実際にコードを書いて動かしてみよう。
5. 実践:実際に使ってみよう
5.1 環境構築
必要なもの
- NVIDIA製GPU(Kepler世代以降)
- NVIDIAドライバー(522.25以降推奨)
- FFmpeg(NVENC有効ビルド)
- Python 3.9以降(Python連携する場合)
FFmpegのNVENCサポート確認
まず、お使いのFFmpegがNVENCに対応しているか確認しよう。
# Windows (コマンドプロンプト or PowerShell)
ffmpeg -encoders | findstr nvenc
# Linux / macOS
ffmpeg -encoders | grep nvenc
以下のように表示されればOK。
V..... h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)
V..... hevc_nvenc NVIDIA NVENC hevc encoder (codec hevc)
V..... av1_nvenc NVIDIA NVENC av1 encoder (codec av1)
何も表示されない場合は、NVENC対応ビルドのFFmpegをインストールする必要がある。WindowsならGyan.devのfullビルドがおすすめ。
5.2 環境別の設定ファイル
以下の3種類の設定ファイル(シェルスクリプト)を用意した。用途に応じて選択してほしい。
開発環境用(encode_dev.sh)
#!/bin/bash
# encode_dev.sh - 開発環境用(速度優先、デバッグしやすい設定)
INPUT="$1"
OUTPUT="${2:-output.mp4}"
ffmpeg -y \
-hwaccel cuda \
-hwaccel_output_format cuda \
-i "$INPUT" \
-c:v h264_nvenc \
-preset p1 \
-b:v 5M \
-c:a copy \
"$OUTPUT"
echo "Encoding complete: $OUTPUT"
本番環境用(encode_prod.sh)
#!/bin/bash
# encode_prod.sh - 本番環境用(画質優先、配信・アーカイブ向け)
INPUT="$1"
OUTPUT="${2:-output.mp4}"
ffmpeg -y \
-hwaccel cuda \
-hwaccel_output_format cuda \
-i "$INPUT" \
-c:v hevc_nvenc \
-preset p6 \
-rc vbr \
-cq 23 \
-b:v 8M \
-maxrate 12M \
-bufsize 16M \
-spatial-aq 1 \
-temporal-aq 1 \
-c:a aac \
-b:a 192k \
"$OUTPUT"
echo "Encoding complete: $OUTPUT"
テスト環境用(encode_test.sh)
#!/bin/bash
# encode_test.sh - テスト/CI環境用(最速、品質検証用)
INPUT="$1"
OUTPUT="${2:-output_test.mp4}"
# 最初の10秒だけエンコード
ffmpeg -y \
-hwaccel cuda \
-hwaccel_output_format cuda \
-i "$INPUT" \
-t 10 \
-c:v h264_nvenc \
-preset p1 \
-b:v 2M \
-c:a copy \
"$OUTPUT"
echo "Test encoding complete (first 10 seconds): $OUTPUT"
5.3 基本的な使い方
最もシンプルなNVENCエンコード
ffmpeg -i input.mp4 -c:v h264_nvenc output.mp4
たったこれだけで、GPUエンコードが有効になる。
フルGPUパイプライン(デコード + エンコード)
デコードもGPUで行うことで、さらに高速化できる。
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
-i input.mp4 \
-c:v h264_nvenc \
-preset p4 \
-b:v 5M \
-c:a copy \
output.mp4
H.265(HEVC)でより高圧縮
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
-i input.mp4 \
-c:v hevc_nvenc \
-preset p5 \
-cq 28 \
-c:a copy \
output_hevc.mp4
5.4 Pythonからの利用
Pythonで動画処理を自動化したい場合、subprocessでFFmpegを呼び出すのが最も確実。
#!/usr/bin/env python3
"""
nvenc_encoder.py - NVENCを使った動画エンコードスクリプト
実行方法:
python nvenc_encoder.py input.mp4 output.mp4
python nvenc_encoder.py input.mp4 # 出力ファイル名は自動生成
"""
import subprocess
import sys
from pathlib import Path
def check_nvenc_support() -> bool:
"""NVENCサポートを確認"""
try:
result = subprocess.run(
["ffmpeg", "-encoders"],
capture_output=True,
text=True
)
return "h264_nvenc" in result.stdout
except FileNotFoundError:
return False
def encode_with_nvenc(
input_path: str,
output_path: str,
codec: str = "h264_nvenc",
preset: str = "p4",
bitrate: str = "5M",
cq: int | None = None
) -> bool:
"""
NVENCでエンコードを実行
Args:
input_path: 入力ファイルパス
output_path: 出力ファイルパス
codec: 使用するコーデック (h264_nvenc, hevc_nvenc, av1_nvenc)
preset: エンコードプリセット (p1:最速 〜 p7:最高画質)
bitrate: ビットレート
cq: 固定品質値 (0-51, 低いほど高画質)
Returns:
成功したかどうか
"""
cmd = [
"ffmpeg", "-y",
"-hwaccel", "cuda",
"-hwaccel_output_format", "cuda",
"-i", input_path,
"-c:v", codec,
"-preset", preset,
]
if cq is not None:
cmd.extend(["-cq", str(cq)])
else:
cmd.extend(["-b:v", bitrate])
cmd.extend([
"-c:a", "copy",
output_path
])
print(f"Executing: {' '.join(cmd)}")
result = subprocess.run(cmd)
return result.returncode == 0
def main():
if len(sys.argv) < 2:
print("Usage: python nvenc_encoder.py <input> [output]")
sys.exit(1)
input_path = sys.argv[1]
if len(sys.argv) >= 3:
output_path = sys.argv[2]
else:
# 出力ファイル名を自動生成
p = Path(input_path)
output_path = str(p.with_stem(f"{p.stem}_nvenc"))
# NVENCサポート確認
if not check_nvenc_support():
print("Error: NVENC is not supported in your FFmpeg build")
sys.exit(1)
print(f"Input: {input_path}")
print(f"Output: {output_path}")
print("Starting NVENC encoding...")
success = encode_with_nvenc(
input_path,
output_path,
codec="h264_nvenc",
preset="p4",
bitrate="5M"
)
if success:
print(f"Encoding complete: {output_path}")
else:
print("Encoding failed")
sys.exit(1)
if __name__ == "__main__":
main()
5.5 実行結果
上記のPythonスクリプトを実行すると、以下のような出力が得られる。
$ python nvenc_encoder.py sample_4k.mp4 output.mp4
Input: sample_4k.mp4
Output: output.mp4
Starting NVENC encoding...
Executing: ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i sample_4k.mp4 -c:v h264_nvenc -preset p4 -b:v 5M -c:a copy output.mp4
frame= 3600 fps=450 q=23.0 Lsize= 38542kB time=00:02:00.00 bitrate=2631.0kbits/s speed=15.0x
Encoding complete: output.mp4
注目すべきは speed=15.0x の部分。2分の動画が約8秒でエンコード完了している。CPUエンコード(libx264)では同じ動画に30秒〜1分かかることを考えると、その差は歴然だ。
5.6 よくあるエラーと対処法
| エラー | 原因 | 対処法 |
|---|---|---|
Unknown encoder 'h264_nvenc' |
FFmpegがNVENC非対応ビルド | NVENC対応FFmpegをインストール(Gyan.devのfullビルド推奨) |
Cannot load nvcuda.dll |
NVIDIAドライバー未インストール | 最新のNVIDIAドライバーをインストール |
No NVENC capable devices found |
対応GPUが見つからない | デバイスマネージャーでGPU認識を確認、ドライバー更新 |
OpenEncodeSessionEx failed |
同時セッション数超過 | 他のエンコードプロセスを終了、または待機 |
Invalid option preset |
プリセット名が間違い |
p1〜p7 または fast/medium/slow を使用 |
5.7 環境診断スクリプト
問題が発生した場合は、以下のスクリプトで環境を診断できる。
#!/usr/bin/env python3
"""
check_nvenc_env.py - NVENC環境診断スクリプト
実行方法: python check_nvenc_env.py
"""
import subprocess
import shutil
import sys
def check_environment():
"""環境をチェックして問題を報告"""
issues = []
info = []
# Python バージョン確認
if sys.version_info < (3, 9):
issues.append(f"Python 3.9以上が必要です(現在: {sys.version})")
else:
info.append(f"Python: {sys.version.split()[0]}")
# FFmpeg確認
ffmpeg_path = shutil.which("ffmpeg")
if not ffmpeg_path:
issues.append("FFmpegがインストールされていません")
else:
info.append(f"FFmpeg: {ffmpeg_path}")
# NVENCサポート確認
result = subprocess.run(
["ffmpeg", "-encoders"],
capture_output=True,
text=True
)
nvenc_encoders = []
for line in result.stdout.split("\n"):
if "nvenc" in line.lower():
nvenc_encoders.append(line.strip())
if not nvenc_encoders:
issues.append("FFmpegでNVENCが有効になっていません")
else:
info.append(f"NVENC Encoders: {len(nvenc_encoders)}個検出")
for enc in nvenc_encoders:
info.append(f" - {enc}")
# nvidia-smi確認(GPU情報)
nvidia_smi = shutil.which("nvidia-smi")
if not nvidia_smi:
issues.append("nvidia-smiが見つかりません(NVIDIAドライバー未インストール?)")
else:
result = subprocess.run(
["nvidia-smi", "--query-gpu=name,driver_version", "--format=csv,noheader"],
capture_output=True,
text=True
)
if result.returncode == 0:
gpu_info = result.stdout.strip()
info.append(f"GPU: {gpu_info}")
else:
issues.append("nvidia-smiの実行に失敗しました")
# 結果表示
print("=" * 50)
print("NVENC 環境診断結果")
print("=" * 50)
if info:
print("\n[INFO] 検出された環境:")
for i in info:
print(f" {i}")
if issues:
print("\n[ERROR] 問題が見つかりました:")
for issue in issues:
print(f" - {issue}")
print("\n対処法:")
print(" 1. NVIDIAドライバーを最新版に更新")
print(" 2. NVENC対応FFmpegをインストール")
print(" Windows: https://www.gyan.dev/ffmpeg/builds/")
print(" Linux: apt install ffmpeg または手動ビルド")
else:
print("\n[OK] 環境は正常です。NVENCが使用可能です。")
print("=" * 50)
return len(issues) == 0
if __name__ == "__main__":
success = check_environment()
sys.exit(0 if success else 1)
実装方法がわかったので、次は具体的なユースケースを見ていこう。
6. ユースケース別ガイド
6.1 ユースケース1: ゲーム配信・録画
想定読者: ゲーム実況者、Twitch/YouTube配信者
推奨構成: 低遅延モードで高フレームレート維持
サンプルコード:
#!/usr/bin/env python3
"""
streaming_encoder.py - 配信向け低遅延エンコード
"""
import subprocess
def encode_for_streaming(input_path: str, output_path: str):
"""配信向け低遅延エンコード"""
cmd = [
"ffmpeg", "-y",
"-hwaccel", "cuda",
"-hwaccel_output_format", "cuda",
"-i", input_path,
"-c:v", "h264_nvenc",
"-preset", "p1", # 最速プリセット
"-tune", "ll", # 低遅延チューニング
"-rc", "cbr", # 固定ビットレート(配信向け)
"-b:v", "6M",
"-maxrate", "6M",
"-bufsize", "6M",
"-g", "60", # キーフレーム間隔(2秒 @ 30fps)
"-bf", "0", # Bフレーム無効(遅延削減)
"-c:a", "aac",
"-b:a", "160k",
output_path
]
subprocess.run(cmd)
if __name__ == "__main__":
encode_for_streaming("gameplay.mp4", "stream_ready.mp4")
6.2 ユースケース2: アーカイブ・保存用の高画質エンコード
想定読者: 動画編集者、アーカイブ管理者
推奨構成: 画質優先、HEVC/AV1でファイルサイズ削減
サンプルコード:
#!/usr/bin/env python3
"""
archive_encoder.py - アーカイブ向け高画質エンコード
"""
import subprocess
from pathlib import Path
def encode_for_archive(
input_path: str,
output_path: str,
use_av1: bool = False
):
"""アーカイブ向け高画質エンコード"""
codec = "av1_nvenc" if use_av1 else "hevc_nvenc"
cq = 28 if use_av1 else 23 # AV1は若干高めのCQでも高画質
cmd = [
"ffmpeg", "-y",
"-hwaccel", "cuda",
"-hwaccel_output_format", "cuda",
"-i", input_path,
"-c:v", codec,
"-preset", "p6", # 高画質プリセット
"-rc", "vbr", # 可変ビットレート
"-cq", str(cq), # 固定品質
"-b:v", "0", # CQモードではビットレート指定不要
"-spatial-aq", "1", # 空間適応量子化
"-temporal-aq", "1", # 時間適応量子化
"-rc-lookahead", "32", # 先読みフレーム数
"-c:a", "aac",
"-b:a", "256k",
output_path
]
print(f"Encoding with {codec}...")
subprocess.run(cmd)
if __name__ == "__main__":
# HEVC版
encode_for_archive("raw_footage.mp4", "archive_hevc.mp4", use_av1=False)
# AV1版(RTX 40シリーズ以降)
# encode_for_archive("raw_footage.mp4", "archive_av1.mp4", use_av1=True)
6.3 ユースケース3: バッチ処理(複数ファイルの一括変換)
想定読者: 大量の動画を処理する必要があるエンジニア
推奨構成: 並列処理でNVENCの同時セッションを活用
サンプルコード:
#!/usr/bin/env python3
"""
batch_encoder.py - 複数ファイルのバッチエンコード
実行方法:
python batch_encoder.py /path/to/video/folder
"""
import subprocess
import sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
def encode_single_file(input_path: Path, output_dir: Path) -> tuple[Path, bool]:
"""単一ファイルをエンコード"""
output_path = output_dir / f"{input_path.stem}_nvenc.mp4"
cmd = [
"ffmpeg", "-y",
"-hwaccel", "cuda",
"-hwaccel_output_format", "cuda",
"-i", str(input_path),
"-c:v", "h264_nvenc",
"-preset", "p4",
"-b:v", "5M",
"-c:a", "copy",
str(output_path)
]
result = subprocess.run(cmd, capture_output=True)
return input_path, result.returncode == 0
def batch_encode(
input_dir: str,
output_dir: str | None = None,
max_workers: int = 4 # 同時エンコード数(GPU性能に応じて調整)
):
"""ディレクトリ内の動画を一括エンコード"""
input_path = Path(input_dir)
output_path = Path(output_dir) if output_dir else input_path / "encoded"
output_path.mkdir(exist_ok=True)
# 動画ファイルを検索
video_extensions = {".mp4", ".mkv", ".avi", ".mov", ".wmv"}
video_files = [
f for f in input_path.iterdir()
if f.suffix.lower() in video_extensions
]
if not video_files:
print("No video files found")
return
print(f"Found {len(video_files)} video files")
print(f"Using {max_workers} parallel workers")
# 並列処理
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(encode_single_file, f, output_path): f
for f in video_files
}
completed = 0
for future in as_completed(futures):
input_file, success = future.result()
completed += 1
status = "OK" if success else "FAILED"
print(f"[{completed}/{len(video_files)}] {input_file.name}: {status}")
print(f"\nBatch encoding complete. Output: {output_path}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python batch_encoder.py <input_directory> [output_directory]")
sys.exit(1)
input_dir = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
batch_encode(input_dir, output_dir, max_workers=4)
ユースケースを把握できたところで、この先の学習パスを確認しよう。
7. 学習ロードマップ
この記事を読んだ後、次のステップとして以下をおすすめする。
初級者向け(まずはここから)
- NVIDIA Video Codec SDK 公式ドキュメント - NVENCの公式情報源
- FFmpeg NVIDIA GPU Acceleration - FFmpegとの連携方法
中級者向け(実践に進む)
- Video Encode and Decode GPU Support Matrix - GPUごとの対応状況確認
- NVEncC(rigaya氏作成)の活用 - より細かなパラメータ制御
- PyNvVideoCodecの導入 - Python向け公式ライブラリ
上級者向け(さらに深く)
- NVENC Application Note - 内部実装の詳細
- Split Frame Encoding(SFE)の活用 - 複数NVENCの並列利用
- NVIDIA Video Codec SDKを使ったC++開発
8. まとめ
この記事では、NVENCについて以下を解説した。
- NVENCとは: NVIDIA GPU内蔵のハードウェアエンコーダー。CPUの5〜10倍高速
-
FFmpegでの使い方:
-c:v h264_nvencを指定するだけで有効化 - Python連携: subprocessでFFmpegを呼び出してバッチ処理も可能
私の所感
NVENCを使い始めてから、動画処理のストレスが劇的に減った。特に「待ち時間」がほぼなくなったのが大きい。以前は「エンコード開始」→「コーヒーを淹れに行く」→「戻ってきてもまだ終わってない」だったのが、今では「エンコード開始」→「コーヒーを淹れる前に終わってる」になった。
ただし注意点もある。NVENCは速度に振った設計なので、同じビットレートならCPUエンコード(libx264, libx265)の方が画質は上だ。とはいえ、RTX 40シリーズ以降のNVENCはかなり画質が向上しており、実用上は問題ないレベルになっている。
「速度を取るか、極限の画質を取るか」という選択になるが、多くのユースケースではNVENCの速度メリットが圧倒的だろう。まだ使ったことがない人は、ぜひ一度試してみてほしい。
参考文献
- NVIDIA Video Codec SDK - 公式SDK
- NVENC - Wikipedia - 世代別機能一覧
- Using FFmpeg with NVIDIA GPU Hardware Acceleration - NVIDIA公式FFmpegガイド
- NVEnc by rigaya - 高機能NVENCフロントエンド