SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor

Docker Jellyfin 开启 NVIDIA 硬件转码配置指南

在 Docker 中为 Jellyfin 配置 NVIDIA GPU 硬件转码的完整步骤。包含安装 NVIDIA Container Toolkit、Docker Compose 挂载配置以及验证 NVENC 与 NVDEC 转码状态的方法,助您解决容器无法识别显卡的问题。

构建目标

在 NVIDIA GPU 上启用 Jellyfin 硬件转码需按固定顺序执行四个步骤,且仅最后一步在 Jellyfin 内部完成。如果宿主机驱动未加载,容器将无法识别 GPU;如果容器无法识别 GPU,Jellyfin 也无法使用它。请按此顺序操作,以便在出现故障时能快速定位问题。

  1. 在宿主机安装 NVIDIA 驱动,并使用 nvidia-smi 进行验证。
  2. 安装 NVIDIA Container Toolkit,以便 Docker 能将 GPU 分配给容器。
  3. docker-compose.yml 中为 Jellyfin 服务预留 GPU,并确认容器已识别到该设备。
  4. 在 Jellyfin 的播放设置中开启 NVENC 和 NVDEC,并确认实际播放时已调用硬件加速。

NVENC(NVIDIA 编码器)和 NVDEC(NVIDIA 解码器)是显卡上的固定功能模块。它们与运行 CUDA(统一计算设备架构)任务的着色器核心在物理上是分离的。这种分离正是硬件转码的价值所在:原本需要消耗多个 CPU 核心的软件转码任务,现在只需占用极少量的 CPU 资源,并由 GPU 上的专用硬件模块完成。

直接播放优于任何转码,请优先检查此项

在进行任何配置之前,请先确认您是否因为某些可以轻易消除的原因而进行转码。当客户端无法直接播放文件时,Jellyfin 会触发转码。原因通常仅限于以下几项:视频编码、音频编码、容器格式、基于图像的字幕,或客户端请求的比特率限制。

打开仪表板(Dashboard),进入播放(Playback),并在播放内容时观察活跃会话。标记为“直接播放”(Direct playing)的会话会直接发送文件,几乎不消耗 CPU。标记为“转码”(Transcoding)的会话会显示 Jellyfin 选择转码的原因。消除该原因后,GPU 将无需运行。

两项更改可消除大部分转码。将客户端应用的质量设置为“自动”(Auto)或最高,因为客户端若请求 4 Mbps,无论文件采用何种编码,都会强制对 20 Mbps 的文件进行重新编码。其次,使用原生客户端应用而非浏览器标签页,因为浏览器是您拥有的功能最受限的播放器,而在同一台电视上使用原生应用通常可以直接播放相同的文件。

基于图像的字幕是无法通过客户端设置解决的例外情况。来自蓝光原盘的 PGS 字幕和来自 DVD 原盘的 VOBSUB 字幕本质上是图片,因此必须将其绘制到视频画面上,这意味着需要对视频流进行完整的重新编码。SRT 格式的文本字幕会作为独立轨道发送给客户端,几乎不产生开销。在可能的情况下,将字幕轨道转换为文本格式比升级 GPU 更有价值。服务器端的其余部分内容请参考 在 VPS 上运行 Jellyfin 媒体服务器的指南

大多数 VPS 套餐不提供 GPU

标准 VPS 套餐不包含 GPU。在进行任何规划前,请先在服务器上运行此命令。

lspci -nn | grep -Ei "3d|display|vga"

在典型的 KVM VPS 上,该命令只会显示来自宿主机的虚拟显示适配器,或者没有任何有效输出。该设备无法进行视频编码。只有当服务商将物理显卡透传给你的实例,或者为你分配了显卡切片时,才会出现真实的 GPU,而此类套餐的价格也相应更高。哪些工作负载值得购买 GPU VPS 一文详细说明了哪些用户需要或不需要 GPU。

如果没有 GPU,请优先选择直接播放,并将软件转码视为极少数情况。单路 1080p H.264 软件转码虽然负载较重,但在几个 CPU 核心上尚可运行。4K HDR 软件转码配合色调映射(tone mapping)无法在小型 VPS 上实时完成,这会导致 CPU 占用率达到 100%,进而引发视频流卡顿。

在宿主机上安装 NVIDIA 驱动

Jellyfin 10.11 文档要求 Linux 上的 NVIDIA 驱动版本至少为 520.56.06。Ubuntu 提供了一个辅助工具,可为您选择匹配的软件包。

sudo ubuntu-drivers list --gpgpu
sudo ubuntu-drivers install --gpgpu
sudo reboot

--gpgpu 会选择驱动的无头服务器版本,这是媒体服务器所需的,因为该设备上没有桌面环境。list 命令会打印出可用的分支,您可以按名称锁定其中一个,例如 sudo ubuntu-drivers install --gpgpu nvidia:570-server。请使用 list 命令实际打印出的分支,不要直接使用此处编写的分支名称。

服务器版本并不总是会自动拉取 nvidia-smi。请为您选择的分支安装对应的 utils 软件包,例如 sudo apt install nvidia-utils-570-server。随后检查驱动程序。

nvidia-smi

正常的结果会打印一个表格,头部包含驱动版本和 CUDA 版本,列出您的显卡名称,且进程列表为空。此处常见的故障有两种。nvidia-smi: command not found 表示缺少 utils 软件包,而非驱动程序缺失。NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver 表示内核模块未加载,在全新安装的情况下,这通常意味着您尚未重启,或者 Secure Boot 拒绝加载未签名的模块。请使用 lsmod | grep nvidia 确认模块是否存在。

安装 NVIDIA Container Toolkit

驱动程序允许宿主机使用 GPU。Docker 默认不会将其传递给容器,因为容器内既没有设备节点,也没有驱动程序库。NVIDIA Container Toolkit 的作用是在容器启动时注入这两者。以下是 NVIDIA 官方提供的 Debian 和 Ubuntu 安装命令。

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit

仅安装软件包是不够的,必须告知 Docker 运行时环境的存在。

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

nvidia-ctk runtime configure 会在 /etc/docker/daemon.json 中写入 nvidia 运行时条目。重启守护进程是人们最容易忽略的步骤,而忽略它会导致整个配置过程中最常见的错误。在操作 Jellyfin 之前,请先测试管道是否通畅。

sudo docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi

该命令应输出与宿主机相同的表格。如果报错提示无法选择具有 gpu 功能的设备驱动程序,说明 Docker 守护进程未识别 nvidia 运行时,请重新运行配置命令并重启守护进程。

在 Docker Compose 中为 Jellyfin 容器分配 GPU

这是符合 Jellyfin 官方发布示例的现代 Compose 写法。

services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    user: 1000:1000
    network_mode: host
    restart: unless-stopped
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    volumes:
      - /srv/jellyfin/config:/config
      - /srv/jellyfin/cache:/cache
      - /srv/media:/media:ro
    runtime: nvidia
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

启动容器并直接查询。

docker compose up -d
docker compose exec jellyfin nvidia-smi

如果该命令在容器内输出了驱动程序表,说明 GPU 已正确透传,其余问题均属于 Jellyfin 设置范畴。

该文件中的四行配置需要说明。capabilities: [gpu] 是 Compose 本身所必需的,若省略此项,Compose 会拒绝启动该服务,而不是在没有 GPU 的情况下启动。NVIDIA_DRIVER_CAPABILITIES=all 很重要,因为只有在请求视频功能时,工具包才会将视频库挂载到容器中,且 Jellyfin 文档将此变量列为官方镜像的必需项。若缺少该变量,CUDA 可以工作但 NVDEC 无法使用,转码日志会报告 Cannot load libnvcuvid.so.1network_mode: host 是 Jellyfin 官方示例所使用的配置,因为 UDP 端口 7359 上的客户端自动发现功能无法在桥接网络(bridge network)中正常工作。

user: 1000:1000 是最后一行,它与 GPU 无关。它决定了 Jellyfin 可以读取媒体挂载点中的哪些文件;如果此处配置不匹配,表现为媒体库为空,而不是权限错误。PUID 和 PGID 如何将容器用户映射到磁盘文件 一文解释了编号规则,如果你在旁边运行了 Docker Compose 部署 Sonarr 和 Radarr 栈,所使用的编号应与此处一致。

为什么大多数教程仍在使用 runtime: nvidia

旧的写法几乎出现在你找到的每一篇指南中,它并非错误,只是历史遗留。最初的 nvidia-docker2 软件包注册了一个名为 nvidia 的 OCI 运行时,因此将 GPU 接入容器的唯一方法就是使用 --runtime=nvidia 配合 NVIDIA_VISIBLE_DEVICES。Docker 19.03 版本增加了 --gpus 标志和一套规范的设备请求 API。Compose 跟进得较慢,当它支持该功能时,设备请求被归入 deploy.resources.reservations.devices 下,而大多数人因为 deploy 过去常用于 Docker Swarm 而习惯性忽略了这个键。

结果是这两种写法目前均可使用,Jellyfin 发布的示例中也同时包含了两者。保留 runtime: nvidia 不会有任何负面影响,且能确保文件在旧版 Compose 上正常工作。如果你只保留 runtime: nvidia 并删除了 deploy 代码块,则必须保留 NVIDIA_VISIBLE_DEVICES=all,因为该遗留路径通过读取环境变量来决定注入哪些设备,而没有可供读取的设备请求。

在 Jellyfin 中开启 NVIDIA 硬件转码

目前尚未指示 Jellyfin 使用该显卡。请进入 Dashboard(仪表板),选择 Playback(播放),然后进入 Transcoding(转码)。将 Hardware acceleration(硬件加速)设置为 Nvidia NVENC。勾选 Enable hardware encoding(启用硬件编码),否则 Jellyfin 会在 GPU 上解码但使用 CPU 编码,这会导致 GPU 有负载但 CPU 依然高占用的异常状态。

Enable enhanced NVDEC decoder(启用增强型 NVDEC 解码器)用于在当前的 NVDEC 路径和旧版 CUVID 路径之间切换。请保持开启。处理 Dolby Vision 时必须开启此项才能使用 NVDEC。

在 Enable hardware decoding for(启用硬件解码)下方,仅勾选您的显卡实际支持解码的编解码器。这是最容易出错的设置。如果在不支持 AV1 的显卡上勾选 AV1,系统不会报错。Jellyfin 会请求硬件解码,但因无法获取而回退到软件解码,导致 CPU 占用率高且 GPU 几乎空闲,表现与直通未生效完全一致。

整个页面还需遵循一项约束:硬件加速仅在使用捆绑的 jellyfin-ffmpeg 构建版本时生效。如果您将 FFmpeg 路径指向了系统自带的 FFmpeg,则会导致加速功能部分失效或完全无法使用。

您的 GPU 代际支持的编解码器

以下是 Jellyfin 针对 NVENC 和 NVDEC 记录的边界条件。解码和编码是两项独立的功能,显卡可能仅支持其中之一。

  • H.264 8-bit:所有具备 NVENC 和 NVDEC 的 NVIDIA GPU 均支持解码与编码。
  • HEVC 8-bit:Maxwell 第二代 (GM206) 及更新架构支持解码与编码。
  • HEVC 10-bit:Maxwell 第二代及更新架构支持解码,但仅 Pascal 及更新架构支持编码。
  • AV1:Ampere 及更新架构支持解码,Ada Lovelace 及更新架构支持编码。

HEVC 10-bit 的差异在实际应用中最为常见。Maxwell 时代的显卡可以在 GPU 上解码 4K HDR 文件,但无法编码 10-bit 输出,因此 Jellyfin 会转而编码为 8-bit H.264。该格式仍可正常播放,且对大多数客户端而言是更优的选择。无论使用何种显卡,2026 年通常都不建议使用 AV1 编码,因为客户端对 AV1 的解码支持依然有限,且转码本身就是为了兼容那些解码能力不足的客户端。

为什么色调映射会悄悄占满 GPU

HDR(高动态范围)到 SDR(标准动态范围)的色调映射设置会耗尽 GPU 资源,其原因在于架构。解码由 NVDEC 处理,编码由 NVENC 处理。色调映射两者都不使用:它是一个在着色器核心上执行的 CUDA 滤镜,而着色器核心正是 GPU 中负责计算任务的通用部分。因此,需要色调映射的 4K HDR 流不仅会占用解码器和编码器,还会额外负载着色器。

Jellyfin 的文档指出,所有支持 HEVC 10-bit 解码的 NVIDIA GPU 均可使用 CUDA 色调映射。这意味着在无法支撑 4K 负载的显卡上,该复选框依然会出现并生效。其表现为流媒体启动后不断缓冲,始终无法流畅播放,而 nvidia-smi 显示编码器几乎处于空闲状态。

这就是为什么需要单独监控着色器负载的原因。

nvidia-smi dmon -s u

该命令每秒打印一行,分别显示 sm、enc 和 dec 的列。如果 enc 和 dec 数值较低而 sm 数值较高,说明固定功能模块处于空闲状态,瓶颈在于着色器,即色调映射、缩放或字幕压制占用了资源。CUDA 路径还支持零拷贝(zero copy)处理 Dolby Vision profile 5,这一点至关重要;若无零拷贝,帧数据会在滤镜步骤之间传输到系统内存再传回,这种往返操作会消耗每一帧的带宽。

消费者级 NVENC 会话限制的实际含义

ChartNVENC engines and concurrent encode session cap, NVIDIA published support matrix, August 2026
The data behind this chart
[
  {
    "label": "GeForce RTX 5090",
    "nvenc_engines": 3,
    "max_encode_sessions": 12
  },
  {
    "label": "GeForce RTX 4090",
    "nvenc_engines": 2,
    "max_encode_sessions": 12
  },
  {
    "label": "GeForce RTX 4060",
    "nvenc_engines": 1,
    "max_encode_sessions": 12
  }
]

以上数据为 NVIDIA 截至 2026 年 8 月发布的官方矩阵参数,并非本站实测结果。无论具体型号为何,GeForce 显卡的并发编码会话数上限均被锁定为 12。该限制存在于驱动程序而非硬件底层,且 NVIDIA 多年来已多次上调此上限,因此请查阅最新矩阵,而非参考过时的论坛讨论。显卡的物理引擎数量才是真正的硬件差异:GeForce RTX 5090 搭载 3 个 NVENC 引擎,而 GeForce RTX 4060 则搭载 1 个。引擎数量增加意味着并行编码吞吐量更高,而非会话上限提升。

该限制仅针对编码会话,因此仅统计转码流。直接播放(Direct play)和封装格式转换(Remuxing)不会开启编码会话。在同一矩阵中,L4 等数据中心级显卡被列为无限制,而 GPU VPS 方案通常提供此类显卡,因此该限制主要影响家庭服务器用户。

当达到限制时,转码会失败,且 FFmpeg 日志中会出现 OpenEncodeSessionEx failed: out of memory (10)。尽管该错误信息提及内存,但会话限制导致的拒绝也会报出相同的代码,因此在排查显存泄漏前,请先检查并发流数量。在实际应用中,大多数用户在达到 12 个会话之前,往往会先触及色调映射(Tone-mapping)的性能瓶颈或上行带宽限制。

验证 GPU 转码状态,不要仅依赖配置

保存的设置不能作为证据。播放一个已知会强制转码的文件,然后执行以下三项检查。

  1. 打开 Dashboard,进入 Playback。当前会话应显示 Transcoding,并注明原因。如果显示 Direct playing,则表示未进行转码,请检查测试文件是否正确。
  2. 打开 Dashboard,进入 Logs,打开最新的 FFmpeg.Transcode 日志。硬件转码会在命令行中显示 -hwaccel cuda-hwaccel_output_format cuda,编码器应为 h264_nvenchevc_nvenc。如果看到 libx264,则表示正在进行软件转码,无论设置页面如何显示。
  3. 在播放过程中,在宿主机上运行 nvidia-smi。应出现一个来自 /usr/lib/jellyfin-ffmpeg/ffmpeg 的进程且已分配 GPU 显存,同时 nvidia-smi dmon -s u 的 enc 和 dec 列应显示非零数值。

请在宿主机上执行第三项检查,不要在容器内执行。在容器内运行 nvidia-smi 通常会显示空的进程列表,因为容器无法查看其命名空间之外的进程 ID,但利用率数值仍可正确读取。容器内进程列表为空并非故障。

当系统静默回退至软件解码时

Jellyfin 倾向于保持播放。当硬件路径不可用时,它会回退至软件解码而非中断流,因此判断依据应是 CPU 负载和 FFmpeg 日志,而非错误提示横幅。

转码日志中出现 Cannot load libnvcuvid.so.1 意味着解码库未挂载至容器内。请设置 NVIDIA_DRIVER_CAPABILITIES=all 并重建容器,因为环境变量的变更需要 docker compose up -d 才能生效,仅重启容器会保留旧配置。

来自 h264_nvencNo capable devices found 意味着 FFmpeg 已调用编码库,但未找到可用显卡。请再次检查 docker compose exec jellyfin nvidia-smi,因为这通常意味着设备预留已被移除,或容器是基于过期的文件重建的。

若 CPU 占用率高但 GPU 处于空闲,说明解码端已静默失败。请取消勾选当前代际硬件不支持的编解码器,重新播放同一文件并查看 FFmpeg 日志,确认是否出现 -hwaccel cuda

如果转码在处理 4K HDR 时启动后卡顿,而 1080p 正常,这通常是色调映射(tone-mapping)达到了性能上限,而非安装损坏。请在 nvidia-smi dmon -s u 的 sm 列中确认这一点,随后要么降低客户端请求的分辨率,要么仅在支持直接播放的客户端上使用 4K HDR 文件。

FAQ

为什么启用 NVENC 后 Jellyfin 仍在使用 CPU?

请查看仪表板(Dashboard)下“日志”(Logs)中的最新 FFmpeg.Transcode 日志。如果日志显示 libx264,说明完全未使用硬件路径,这通常意味着容器无法识别 GPU,请运行 docker compose exec jellyfin nvidia-smi 进行确认。如果显示 h264_nvenc 但 CPU 占用率依然很高,说明解码部分仍在通过软件运行;这通常是因为勾选了显卡不支持的编解码器,或者未开启“启用硬件编码”(Enable hardware encoding),导致只有一半的流水线迁移到了 GPU。

我还需要在 Docker Compose 中保留 runtime: nvidia 这一行吗?

如果你已经配置了 deploy.resources.reservations.devices 代码块且使用的是较新版本的 Docker Compose,则不再需要。该代码块是现代的设备请求方式,功能相同。runtime: nvidia 是来自 nvidia-docker2 时代的旧路径,目前依然有效,Jellyfin 官方提供的示例也同时保留了两者。同时保留不会产生负面影响。如果仅保留 runtime: nvidia,则必须同时保留 NVIDIA_VISIBLE_DEVICES=all,因为前者没有设备请求功能,需要通过环境变量来读取设备列表。

一张 NVIDIA 显卡同时能转码多少路流?

截至 2026 年 8 月,NVIDIA 官方矩阵将 GeForce 系列显卡的并发编码会话限制为 12 路,数据中心级显卡则无此限制。但通常限制你的并非这一上限。HDR 转 SDR 的色调映射(tone mapping)运行在着色器核心(shader cores)而非 NVENC 上,因此几路 4K HDR 流就会耗尽着色器资源,远早于达到会话计数上限。请使用 nvidia-smi dmon -s u 测量你的实际负载,并关注 sm 列,而不是会话计数。

我可以在没有 GPU 的 VPS 上使用硬件转码吗?

不能。编码需要物理 NVENC 模块,而标准 VPS 上的 lspci -nn | grep -Ei "3d|display|vga" 仅能看到来自虚拟化管理程序的虚拟显示适配器。在没有 GPU 的方案中,更现实的做法是消除转码需求:将客户端质量设置调至“自动”(Auto),使用原生客户端应用而非浏览器,并将基于图像的字幕轨道转换为文本格式,以避免强制触发视频重新编码。

为什么 1080p 转码正常,但 4K HDR 会卡顿?

这两种工作负载使用了显卡的不同部分。1080p SDR 转码仅涉及解码和编码,均由固定功能硬件完成。4K HDR 流增加了色调映射,这是一个运行在着色器核心上的 CUDA 滤镜,此外还需要处理更大的缩放帧。如果 nvidia-smi dmon -s u 显示 enc 和 dec 占用率较低但 sm 占用率很高,即可确认瓶颈所在,因为该模式意味着固定功能模块处于空闲状态,而通用计算核心已达到极限。