Use Case Description#
Originally, Jellyfin was deployed in a server's k8s environment without a dedicated graphics card. Relying solely on the CPU made it difficult to achieve server-side hardware decoding, resulting in a message during media playback on any platform via the browser stating "This client is not compatible with the media, and the server did not send a compatible media format."
After installing Ubuntu on my home desktop, I had the idea to use it as a server, completely separating it from the work and entertainment environment. After installing Docker and deploying Jellyfin through Docker, I wanted to enable Jellyfin to achieve hardware decoding capabilities through PCI hardware.
I never expected that I hadn't installed the graphics card driver yet, nor had I allocated the graphics card to the container. This led to this article documenting the troubleshooting process.
Situation Analysis#
The client prompts "This client is not compatible with the media, and the server did not send a compatible media format." The reason is speculated to be the server's own limitations, requiring the client to perform hardware decoding to support video playback. If the browser lacks the decoding capability for the corresponding video format, this message will appear.
Perhaps one could try installing a browser extension to support client-side decoding (feasibility unverified).
Based on personal experience, Jellyfin in the original k8s environment displayed the above message when playing any video on the PC's browser. However, decoding through apps like PotPlayer, Jellyfin Client, and iOS's Fileball worked normally. This situation also occurred with Emby.
Thus, it is inferred that the reason for the browser's inability to play is ultimately due to the server's lack of decoding capability.
Solution#
Applicable scenarios: Linux server (I used Ubuntu 22.04), k8s environment (not Unraid or Synology).
Graphics Card Driver Installation — Taking NVIDIA GTX 1660 Ti as an Example#
For AMD solutions, please Google or Baidu how to install drivers. The methods are similar.
Method 1 (Offline Installation):
Download the driver installation package from the official website, upload it to the server, and install it using dpkg -i
. A pure command-line installation is required. If the lightdm desktop environment is enabled, it needs to be manually closed.
# Note: Log in as root user
> systemctl stop lightdm
# Enter pure command-line mode
> init 3
> dpkg -i <downloaded NVIDIA driver package, .deb suffix>
# After installation, restart to recover. If it does not recover, execute the following command and then restart
> init 5
> systemctl set-default graphical.target
Method 2 (Online Installation, Recommended):
- Driver
# First, check if the computer can recognize the PCI graphics card
> lspci | grep -i nvidia
26:00.0 VGA compatible controller: NVIDIA Corporation TU116 [GeForce GTX 1660 Ti] (rev a1)
26:00.1 Audio device: NVIDIA Corporation TU116 High Definition Audio Controller (rev a1)
26:00.2 USB controller: NVIDIA Corporation TU116 USB 3.1 Host Controller (rev a1)
26:00.3 Serial bus controller: NVIDIA Corporation TU116 USB Type-C UCSI Controller (rev a1)
# Check the current system-supported drivers
> ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:03.1/0000:26:00.0 ==
modalias : pci:v000010DEd00002182sv000019DAsd00003539bc03sc00i00
vendor : NVIDIA Corporation
model : TU116 [GeForce GTX 1660 Ti]
driver : nvidia-driver-525 - distro non-free
driver : nvidia-driver-470-server - distro non-free
driver : nvidia-driver-535-open - distro non-free
driver : nvidia-driver-418-server - distro non-free
driver : nvidia-driver-525-open - distro non-free
driver : nvidia-driver-525-server - distro non-free
driver : nvidia-driver-450-server - distro non-free
driver : nvidia-driver-535 - distro non-free recommended
driver : nvidia-driver-470 - distro non-free
driver : xserver-xorg-video-nouveau - distro free builtin
## Install the latest driver support
> apt-get install nvidia-driver-535.54.03
## After reboot, execute to check graphics card information
> nvidia-smi
Mon Jul 3 00:05:19 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.54.03 Driver Version: 535.54.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce GTX 1660 Ti Off | 00000000:26:00.0 Off | N/A |
| 46% 41C P8 13W / 120W | 29MiB / 6144MiB | 0% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 3283 G /usr/lib/xorg/Xorg 25MiB |
| 0 N/A N/A 26860 G xfwm4 1MiB |
+---------------------------------------------------------------------------------------+
- CUDA
The above CUDA Version indicates the installable version information, not that it has been installed. The installation method is as follows (commands from NVIDIA official):
> wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
> dpkg -i cuda-keyring_1.1-1_all.deb
> apt-get update
> apt-get -y install cuda
After execution, set the environment variable by adding the following at the end of the ~/.bashrc
file:
> vim ~/.bashrc
# Add the following content, note the version number
export PATH=/usr/local/cuda-12.2/bin${PATH:+:${PATH}}
# Confirm whether the nvidia-persistenced daemon is enabled
> systemctl status nvidia-persistenced
● nvidia-persistenced.service - NVIDIA Persistence Daemon
Loaded: loaded (/lib/systemd/system/nvidia-persistenced.service; static)
Active: active (running) since Sun 2023-07-02 05:43:54 CST; 18h ago
Process: 1937 ExecStart=/usr/bin/nvidia-persistenced --user nvidia-persistenced --no-persistence-mode --verbose (code=exited, status=0/SUCCESS)
Main PID: 1947 (nvidia-persiste)
Tasks: 1 (limit: 47904)
Memory: 568.0K
CPU: 3ms
CGroup: /system.slice/nvidia-persistenced.service
└─1947 /usr/bin/nvidia-persistenced --user nvidia-persistenced --no-persistence-mode --verbose
Regardless of the method used to install the graphics card driver, a restart is required afterward.
Docker Pass-Through#
- Install nvidia-docker2 and nvidia-container-runtime
When mounting the graphics card to Docker, an error occurs, causing the container to remain in the create state.
# Add apt source
> distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
&& 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/$distribution/libnvidia-container.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
> apt update
> apt-get install -y nvidia-docker2 nvidia-container-runtime
- Run the container to mount the graphics card driver
Using docker-compose as an example:
version: "3.7"
services:
jellyfin:
container_name: jellyfin
image: "jellyfin/jellyfin:latest"
environment:
- PUID=0
- GUID=0
- NVIDIA_DRIVER_CAPABILITIES=all
- NVIDIA_VISIBLE_DEVICES=all
ports:
- "10029:8096"
volumes:
- "/root/jellyfin/config:/config"
- "/mnt/media:/media"
restart: always
user: root
devices:
- "/dev/dri:/dev/dri"
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"]
Jellyfin Hardware Decoding Settings#
There's not much to say here; just check all the boxes if conditions allow.
Conclusion#
At this point, hardware pass-through for Jellyfin is considered complete. It has been tested that browsers that originally did not support video playback can now play media. Furthermore, when a user is playing media, the actual memory usage of the graphics card can be clearly observed.
Mon Jul 3 00:47:21 2023
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.54.03 Driver Version: 535.54.03 CUDA Version: 12.2 |
|-----------------------------------------+----------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+======================+======================|
| 0 NVIDIA GeForce GTX 1660 Ti Off | 00000000:26:00.0 Off | N/A |
| 46% 44C P2 31W / 120W | 257MiB / 6144MiB | 3% Default |
| | | N/A |
+-----------------------------------------+----------------------+----------------------+
+---------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=======================================================================================|
| 0 N/A N/A 3725 G /usr/lib/xorg/Xorg 13MiB |
| 0 N/A N/A 6735 C /usr/lib/jellyfin-ffmpeg/ffmpeg 238MiB |
+---------------------------------------------------------------------------------------+
It was found that when a user plays through the web client, the Jellyfin server is using the graphics card for decoding, with the graphics card memory usage increasing from 29MiB to 257MiB, where the running process is ffmpeg.
Thus, it can be concluded that the inference in this article is relatively correct. The use of hardware decoding can eliminate the prompt "This client is not compatible with the media, and the server did not send a compatible media format" that appears on the Jellyfin client.
It also indirectly indicates that without a graphics card, the Jellyfin server cannot perform decoding, and video decoding occurs locally on the client, which explains why playback is not possible on the web but works on client apps. It can also be inferred that in this case, whether or not a third-party ffmpeg client is set on Jellyfin does not affect local decoding on the client; the error message appears solely due to the server's insufficient decoding capability.
Aside
NVIDIA-docker2 is NVIDIA's support component for Docker containers. If you do not deploy services using Docker, you can skip this installation. The same method can be applied to stable diffusion Docker projects to achieve remote processing 🫠