immich 硬件转码实战:NVENC、Quick Sync、VAAPI 与 RKMPP 的 Docker 配置与源码解析
本篇指南基于 immich 官方文档 hardware-transcoding.md,讲解如何用 GPU 加速视频转码以降低 CPU 负载,覆盖四种硬件加速 API(NVENC、Quick Sync、RKMPP、VAAPI)的 Docker Compose 配置、immich.json 配置文件写法、各硬件平台的前置条件与限制,并结合 server/src/utils/media.ts 等源码说明服务端实际生成的 FFmpeg 加速参数。读完本文,你可以按硬件型号完成端到端(含硬解码)的转码加速部署,并理解每个配置项在服务端的真实作用。
硬件转码是什么,代价是什么
immich 的硬件转码功能允许服务器使用 GPU 加速视频转码(transcoding),从而显著降低 CPU 占用。需要明确两个官方提示的事实边界:
- 体积与质量:硬件转码在相同设置下产生的视频文件明显大于软件转码,且通常质量更低。使用更慢的 preset、更高效的编码格式(codec)可以缩小这一差距;
- 实验性质:这是相对较新的功能,仍处于实验阶段,可能无法在所有系统上正常工作。
一个重要的免迁移特性:启用硬件加速后不需要重跑已有的转码任务。加速设备只用于启用之后新执行的转码任务,此前软件转码生成的文件会原样保留。
源码视角:加速能力的枚举定义
在服务端 server/src/enum.ts 中,转码硬件加速被定义为如下枚举,即管理页面"Video transcoding settings"下拉框的五个选项来源:
export enum TranscodeHardwareAcceleration {
Nvenc = 'nvenc',
Qsv = 'qsv',
Vaapi = 'vaapi',
Rkmpp = 'rkmpp',
Disabled = 'disabled',
}
与文档"Supported APIs"一节一一对应:NVENC(NVIDIA)、Quick Sync(Intel)、RKMPP(Rockchip)、VAAPI(AMD / NVIDIA / Intel 通用)。
此外,server/src/constants.ts 中的 SUPPORTED_HWA_CODECS 常量给出了每种 API 实际允许的目标视频编码,与文档"Codec support varies"的限制说明相互印证:
| 加速 API | 支持的目标视频编码 |
|---|---|
| nvenc | H.264、HEVC、AV1(不支持 VP9,与文档"NVIDIA 与 AMD 不支持 VP9 编码"一致) |
| qsv | H.264、HEVC、VP9、AV1 |
| vaapi | H.264、HEVC、VP9、AV1 |
| rkmpp | 仅 H.264、HEVC |
| disabled | 全部四种编码 |
当管理员选择的 targetVideoCodec 不在对应列表内时,server/src/utils/media.ts 会在构建 FFmpeg 命令时直接抛出 Nvenc acceleration does not support codec ... 之类的错误,因此选型时必须先对照上表。
功能限制:部署前必读
文档明确列出了以下限制,本文所有配置步骤均以此为前提:
- 文中的指令与配置仅针对 Docker Compose,其他容器引擎可能需要不同的配置方式;
- 仅支持 Linux 服务器以及通过 WSL2 运行的 Windows 服务器;WSL2 下不支持 Quick Sync;
- 目前不支持 Raspberry Pi;
- Two-pass 模式仅 NVENC 有效,其他 API 会忽略该设置。源码层面,server/src/utils/media.ts 中双遍编码的逻辑在
accel !== Disabled时会被整体跳过(见约 L315 处:if (!this.config.twoPass || this.config.accel !== TranscodeHardwareAcceleration.Disabled)),与文档描述吻合; - 默认只有编码(encoding)是硬件加速的,解码(decoding)与 tone-mapping 仍走 CPU。要获得端到端加速,需要在视频转码设置中显式开启硬件解码(下文
accelDecode/ 步骤 5); - 硬件相关限制:
- 编码支持因设备而异,但 H.264 和 HEVC 通常都受支持;
- 较新的设备通常转码质量更高。
各硬件平台前置条件
NVENC
- 服务器必须安装官方 NVIDIA 驱动;
- Linux 上(WSL2 除外)还需安装 NVIDIA Container Toolkit,使容器能访问 GPU。
对应的容器侧配置见 docker/hwaccel.transcoding.yml:nvenc 服务段通过 deploy.resources.reservations.devices 声明 driver: nvidia 并申请 gpu、compute、video 三类能力,这正是依赖 NVIDIA Container Toolkit 的资源预留写法。
QSV(Quick Sync)
文档针对 VP9 编码给出额外要求:
- 需要第 9 代及以后的 Intel CPU;
- 若为 11 代或更早的 CPU,可能需要按 Jellyfin 的"Low-Power 编码"说明修改内核参数(Low-Power 模式是 QSV 编码的前提);
- 若服务器恰好是 11 代 CPU 且运行 5.15 内核(Ubuntu 22.04 LTS 自带版本),需要按 Jellyfin 文档升级内核以规避已知问题。
RKMPP(Rockchip)
- 必须是受支持的 Rockchip ARM SoC;
- 只有 RK3588 支持硬件 tonemapping,其他 SoC 在硬件编码的同时使用较慢的软件 tonemapping;
- Tonemapping 依赖宿主机上的
/usr/lib/aarch64-linux-gnu/libmali.so.1。需要安装与你 Mali GPU 对应的libmali发行版(RK3588 对应libmali-valhall-g610-g13p0-gbm),然后修改 docker/hwaccel.transcoding.yml:在rkmpp段下取消以下三行 OpenCL tonemapping 配置的注释(去掉行首#):
rkmpp:
# ...
devices:
# - /dev/mali0:/dev/mali0
volumes:
# - /etc/OpenCL:/etc/OpenCL:ro
# - /usr/lib/aarch64-linux-gnu/libmali.so.1:/usr/lib/aarch64-linux-gnu/libmali.so.1:ro
仓库中这三行默认即为注释状态(见 docker/hwaccel.transcoding.yml),且注释说明"only required to enable OpenCL-accelerated HDR -> SDR tonemapping"。rkmpp 段还默认挂载了 /dev/rga、/dev/dri、/dev/dma_heap、/dev/mpp_service 四个设备并放宽了 apparmor 限制,这些是 Rockchip 硬件编码链路的基础,无需手动改动。
基础部署:Docker Compose + extends
步骤一:获取 hwaccel.transcoding.yml 并放置
如果尚无该文件,下载仓库中的 docker/hwaccel.transcoding.yml,确保它与 docker-compose.yml 位于同一目录。该文件定义了五个可挂载的后端服务段:
services:
cpu: {}
nvenc: # 通过 deploy.resources 申请 NVIDIA GPU
quicksync: # 挂载 /dev/dri
rkmpp: # 挂载 Rockchip 设备节点 + 可注释的 Mali/OpenCL 卷
vaapi: # 挂载 /dev/dri
vaapi-wsl: # WSL2 专用:额外挂载 /dev/dxg,并设置 LIBVA_DRIVER_NAME=d3d12
步骤二:在 docker-compose.yml 中启用 extends
在 docker-compose.yml 的 immich-server 服务下,取消注释 extends 段,并把 cpu 改成与你的硬件匹配的后端名称。docker/docker-compose.yml 中该段默认即为注释状态:
immich-server:
# extends:
# file: hwaccel.transcoding.yml
# service: cpu
改为例如 service: quicksync 即可。
注意:WSL2 下使用 VAAPI 时,务必用
vaapi-wsl而不是vaapi。两者差异见 docker/hwaccel.transcoding.yml:vaapi-wsl额外挂载/dev/dxg与/usr/lib/wsl,并注入LIBVA_DRIVER_NAME=d3d12环境变量,走 DirectX 12 的 VAAPI 兼容路径。
步骤三:重新部署 immich-server 容器
用更新后的配置重新部署 immich-server 容器,使设备挂载生效。
步骤四:在管理页面选择加速 API
打开 Admin 页面 → Video transcoding settings,把硬件加速设置改为对应选项(nvenc / qsv / vaapi / rkmpp)并保存。
注意:对于 Jasper Lake 与 Elkhart Lake 这类 CPU,需要把
Hardware Acceleration -> Constant quality mode设为CQP。对应服务端枚举CQMode(auto/cqp/icq)定义在 server/src/enum.ts。
步骤五(可选):开启硬件解码
为获得最优性能,建议开启硬件解码,实现端到端加速。这一步对应 FFmpeg 配置中的 accelDecode 字段:server/src/dtos/config.dto.ts 将其定义为 configBool.describe('Accelerated decode'),且 server/src/dtos/config.dto.ts 中的默认值为 accel: Disabled + accelDecode: true——即默认关闭硬编码、默认开启硬解码,与文档"默认只有编码是软件"的说明一致。
开启后,server/src/utils/media.ts 会为各 API 生成不同的硬解码参数,例如 NVENC 路径使用 -hwaccel cuda -hwaccel_output_format cuda(见约 L734),QSV 路径使用 -hwaccel qsv -hwaccel_output_format qsv 并配合 scale_qsv 缩放滤镜(约 L781-L918)。
配置文件方式:immich.json 的 accel 选项
如果你使用 配置文件方式部署,无需改 compose,直接在 immich.json 中用 accel 选择硬件(如 Intel 用 qsv、NVIDIA 用 nvenc),需要硬解码时把 accelDecode 设为 true:
{
"ffmpeg": {
"accel": "qsv",
"accelDecode": true
}
}
转码相关配置项全景
结合 server/src/dtos/config.dto.ts 中的 AdminConfigFFmpegSchema,管理页面"Video transcoding settings"里与硬件转码最相关的字段及其约束为:
| 字段 | 类型/范围 | 说明 |
|---|---|---|
accel |
disabled / nvenc / qsv / vaapi / rkmpp |
硬件加速 API,默认 disabled |
accelDecode |
boolean | 是否硬件解码,默认 true |
twoPass |
boolean | 双遍编码,仅 NVENC 实际生效 |
cqMode |
auto / cqp / icq |
恒质量模式,Jasper Lake / Elkhart Lake 需 cqp |
preset |
string | 转码 preset,硬件转码建议选更慢的 preset |
crf |
整数 0–51 | 恒定质量因子 |
targetVideoCodec |
视频编码 | 必须在 SUPPORTED_HWA_CODECS 对应列表内 |
preferredHwDevice |
string | 偏好使用的硬件设备 |
tonemap |
hable / mobius / reinhard / disabled |
HDR→SDR tone mapping 算法 |
单文件部署:不依赖 extends 的平台
部分平台(如 Unraid、Portainer)截至文档撰写时不支持多个 Compose 文件。替代方案是把 docker/hwaccel.transcoding.yml 中对应后端的配置内联到 docker-compose.yml 的 immich-server 服务里,去掉 extends 段。
以 quicksync 段为例(该段内容仅为 devices: - /dev/dri:/dev/dri):
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# 注意:没有 extends 段
devices:
- /dev/dri:/dev/dri
volumes:
...
nvenc / rkmpp / vaapi 的内联做法同理,直接复制 docker/hwaccel.transcoding.yml 中对应服务段的全部键(deploy / devices / volumes / security_opt / group_add / environment)到 immich-server 服务即可。完成内联后,回到"基础部署"的步骤三继续(重新部署容器并修改管理页面设置)。
All-In-One:Unraid 专属步骤
QSV
- Unraid > Docker >(停止)Immich 容器 > Edit;
- 下滑选择
Add another Path, Port, Variable, Label or Device; - 下拉菜单选
Device,任取一个名称,值填/dev/dri; - 继续"基础部署"的步骤四。
NVENC
- 在容器应用中添加环境变量:Key=
NVIDIA_VISIBLE_DEVICES,Value=all; - 将容器从 Basic Mode 切到 Advanced Mode,并在 Extra Parameters 字段添加:
--runtime=nvidia; - 重启容器应用;
- 继续"基础部署"的步骤四。
服务端实现:从配置到 FFmpeg 命令的调用链
理解服务端如何处理硬件转码,有助于排查"改了设置没生效"类问题。
命令构建:按 API 分发
server/src/utils/media.ts 是转码命令的构建核心。其流程为(见约 L70-L130):
- 若
config.accel === Disabled,走纯软件编码路径; - 校验
targetVideoCodec是否在SUPPORTED_HWA_CODECS[config.accel]内,否则报错; - 按
accel值 switch 分发到NvencHandler/QsvHandler/VaapiHandler/RkmppHandler,并且每个 Handler 内部再根据accelDecode选择"硬解码输入参数"(如 CUDA /scale_qsv/scale_vaapi/hwmap=derive_device=rkmpp)或退化为软件解码 + 硬件编码。
从源码结构看,各 Handler 的硬解码参数即 FFmpeg 的硬件管线,例如 QSV 会构造 -init_hw_device qsv=hw,child_device=${device} 与 hwmap=derive_device=qsv 滤镜链(约 L781、L907),RKMPP 则使用 -hwaccel rkmpp -hwaccel_output_format drm_prime -afbc rga 加 hwmap=derive_device=rkmpp:mode=write:reverse=1(约 L1080-L1092)。
容错回退:失败自动降级
server/src/services/media.service.ts 展示了转码任务的日志与重试策略:
- 每次转码会打印所用模式日志:
Transcoding video ... with QSV-accelerated encoding and software decoding(或...accelerated decoding、without hardware acceleration),这本身就可以作为"设备是否被真正使用"的验证手段; - 若硬件解码路径失败,会以"硬编码 + 软解码"重试(
Retrying with QSV-accelerated encoding and software decoding); - 若仍失败,则彻底关闭硬件加速重试(
Retrying with hardware acceleration disabled),保证转码任务最终完成而不阻塞队列。
这也解释了为什么误配硬件 API 时 immich 不会丢任务——代价只是该次转码退回 CPU 且文件可能更大。
调优与验证技巧
文档 Tips 一节给出的实践建议,结合源码可以进一步落地:
- 选更慢的 preset:硬件转码的 preset 与软件转码的 preset 含义不同,为保持质量与效率,建议选比软件转码更慢(如
slow/slower)的档位; - 优先专用 API 而非 VAAPI:虽然 VAAPI 可用于 NVIDIA 与 Intel 设备,但 NVENC(
nvenc)与 QSV(qsv)分别为自家设备深度优化,应优先选用; - 验证设备确实被使用:转码期间用
nvtop(NVIDIA)、intel_gpu_top(Intel)等工具查看 GPU 利用率;同时检查日志无报错(参考上文media.service.ts的转码日志)也是设备生效的旁证; - 对照 codec 支持表选型:若目标是 VP9 编码,只能选
qsv或vaapi;NVENC 选 VP9 会在命令构建阶段直接失败(见 server/src/constants.ts)。
小结
immich 的硬件转码通过"compose 层设备挂载 + 配置层 API 选择"两条正交链路实现:前者决定容器能否看到 GPU(docker/hwaccel.transcoding.yml 的 extends 或内联设备段),后者决定 FFmpeg 走哪条硬件编码/解码管线(accel + accelDecode,见 server/src/utils/media.ts)。按本文的前置条件核对硬件、按对应平台的步骤挂载设备、在管理页面或 immich.json 中选定 API 并可选开启硬解码,即可完成从软件转码到端到端硬件加速的切换,且无需重跑任何历史转码任务。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00