首页
/ immich 硬件转码实战:NVENC、Quick Sync、VAAPI 与 RKMPP 的 Docker 配置与源码解析

immich 硬件转码实战:NVENC、Quick Sync、VAAPI 与 RKMPP 的 Docker 配置与源码解析

2026-09-06 22:16:10作者:明树来

本篇指南基于 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.ymlnvenc 服务段通过 deploy.resources.reservations.devices 声明 driver: nvidia 并申请 gpucomputevideo 三类能力,这正是依赖 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.ymlimmich-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.ymlvaapi-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。对应服务端枚举 CQModeauto / 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.ymlimmich-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

  1. Unraid > Docker >(停止)Immich 容器 > Edit;
  2. 下滑选择 Add another Path, Port, Variable, Label or Device
  3. 下拉菜单选 Device,任取一个名称,值填 /dev/dri
  4. 继续"基础部署"的步骤四。

NVENC

  1. 在容器应用中添加环境变量:Key=NVIDIA_VISIBLE_DEVICES,Value=all
  2. 将容器从 Basic Mode 切到 Advanced Mode,并在 Extra Parameters 字段添加:--runtime=nvidia
  3. 重启容器应用;
  4. 继续"基础部署"的步骤四。

服务端实现:从配置到 FFmpeg 命令的调用链

理解服务端如何处理硬件转码,有助于排查"改了设置没生效"类问题。

命令构建:按 API 分发

server/src/utils/media.ts 是转码命令的构建核心。其流程为(见约 L70-L130):

  1. config.accel === Disabled,走纯软件编码路径;
  2. 校验 targetVideoCodec 是否在 SUPPORTED_HWA_CODECS[config.accel] 内,否则报错;
  3. 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 rgahwmap=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 decodingwithout 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 编码,只能选 qsvvaapi;NVENC 选 VP9 会在命令构建阶段直接失败(见 server/src/constants.ts)。

小结

immich 的硬件转码通过"compose 层设备挂载 + 配置层 API 选择"两条正交链路实现:前者决定容器能否看到 GPU(docker/hwaccel.transcoding.ymlextends 或内联设备段),后者决定 FFmpeg 走哪条硬件编码/解码管线(accel + accelDecode,见 server/src/utils/media.ts)。按本文的前置条件核对硬件、按对应平台的步骤挂载设备、在管理页面或 immich.json 中选定 API 并可选开启硬解码,即可完成从软件转码到端到端硬件加速的切换,且无需重跑任何历史转码任务。

登录后查看全文
热门项目推荐
相关项目推荐