Updated 22/02/23 to include required /dev/dri permissions for non-root users
There is an overwhelming amount of information regarding this topic, with the vast majority being outdated. As such, I am writing this post to provide an up to date method of installing Jellyfin on a Synology NAS (in my case, a DS920+) with the required configuration to support hardware transcoding. This assumes you have a compatible NAS, since CPUs used in Synology’s latest offerings do not have an iGPU and as a result, do not support hardware transcoding.
Prerequisites
- Basic Docker and Docker Compose knowledge.
- A compatible Synology NAS.
- Docker installed (the Package Center version is fine to use).
- Docker Compose installed (if you’re not using the Package Centre version of Docker).
- Set /dev/dri/ permissions (if running as non-root) as documented below.
Setting /dev/dri permissions (if running as non-root user)
Unlike other OSs, Synology DSM does not permit non-root users from accessing /dev/dri which will prevent hardware transcoding from working within your Jellyfin instance if you plan on running this as a non-root user:
[AVHWDeviceContext @ 0x561260cc5a80] No VA display found for any default device. Device creation failed: -22. Failed to set value 'vaapi=va:,driver=iHD,kernel_driver=i915' for option 'init_hw_device': Invalid argument Error parsing global options: Invalid argument
To resolve this issue, you simply need to run the command “chmod 777 /dev/dri/*”, however this permission is not persistant so rebooting your device will result in hardware transcoding breaking again. To get around this, create a triggered task within your DSM Control Panel with the following options:
- Task: Jellyfin driver permissions (this part really doesn’t matter)
- User: root
- Event: Boot-up
- Enabled: Checked
- User-defined script: chmod 777 /dev/dri/*
Click “OK” to create the task, then manually run the task once.
Creating the container
In order to create the container, we are going to use a Docker Compose YAML file which will define its properties and other configurations. On Synology DSM, you have a few options for using Docker Compose, none of which are available from the Docker app’s UI.
- Portainer – My preferred method, since it provides you with a GUI and only requires SSH for the initial install (guide here).
- SSH (here’s a good guide on this method).
- Task scheduler – I’d avoid this method as it makes management messy.
You can find my Compose YAML for Jellyfin below:
version: "3.8" services: jellyfin: image: jellyfin/jellyfin:latest container_name: jellyfin user: xxx:xxx #your UID:GID environment: - TZ=Europe/London #your time zone - JELLYFIN_PublishedServerUrl=x.x.x.x #your NAS IP volumes: - /volume1/docker/jellyfin:/config - /volume1/docker/jellyfin/cache:/cache - /volume1/video:/data/media devices: - /dev/dri:/dev/dri ports: - 8096:8096 #required web port - 8920:8920 #optional https port - 7359:7359/udp #optional discovery port restart: unless-stopped
A few notes about my configuration compared to others I’ve seen:
- I’m using the official Jellyfin image rather than linuxserver.io, since this now supports Intel QSV
- As I’m not using the linuxserver.io image, I do not need to include the Opencl-Intel Docker Mod.
- I’m mapping /dev/dri (for HW transcoding support).
- I’m using the same media volume as Video Station.
- I’ve specified a cache directory to ensure it’s actually where you want it, rather than in the default, hidden location.
- An additional port (1900/udp) used for DLNA is not included as this conflicts with default Synology ports. You can work around this by using a MacVLAN network, however, as this port is optional, I have skipped it in this guide.
Key changes you must make before deploying your container:
- Set the UID and GID values. If you’re using what these should be set to, I’d recommend creating a new “docker” standard user and checking its values using SSH command “id username“. There is no requirement to run this container as root (either by removing the PUID/PGID or setting them to 0/0) and doing so decreases security unnecessarily.
- Set your time zone using the TZ database name
- Set your NAS IP (PublishedServerUrl)
- Review the configured volumes and tweak as required
- Manually create a “jellyfin” folder and “cache” subfolder within your Docker shared folder. This won’t happen automatically and will cause deployment to fail if it’s missing.
Enabling hardware transcoding
Once Jellyfin has been deployed and configured, you must manually enable hardware transcoding. Start by opening the admin dashboard, then select Playback:
Once here, change the Hardware acceleration drop down from None to Intel QuickSync (QSV).
Select your file types (AV1 is not supported so leave it unchecked), as well as the following:
- Enable Enable hardware transcoding.
- Ensure both low-power options are disabled (enabling either of these options breaks transcoding).
- Enable both tone mapping options.
After scrolling to the bottom of the page and clicking Save, you should now have a working Jellyfin container with hardware transcoding support. If you’re facing issues, please leave a comment and I will do my best to help.
Thank you for posting! I’m doing right now on a DS720+ since the hardware is the same. Did you noticed good performances ?
No issues with performance at all, I’ve been really impressed considering the CPU is a few years old at this point.
I also noticed some other way to accelerate:
https://www.reddit.com/r/jellyfin/comments/r5pur8/best_transcoding_settings_for_synology_ds920/
do you have any issues transcoding 4k HEVC HDR files? My 1019+ doesn’t transcode at all for those
Indeed I do – thanks for pointing this out. SDR is fine but HDR is giving me issues at 4K; I’ll look into it.
Hi, Thanks for your guide. I tried it with this on my 720+ but still running in the following error. I also add the puid and pgid to the local dsm user.
Do you have any idea to solve this?
ffmpeg version 5.1.3-Jellyfin Copyright (c) 2000-2022 the FFmpeg developers
built with gcc 10 (Debian 10.2.1-6)
configuration: –prefix=/usr/lib/jellyfin-ffmpeg –target-os=linux –extra-libs=-lfftw3f –extra-version=Jellyfin –disable-doc –disable-ffplay –disable-ptx-compression –disable-static –disable-libxcb –disable-sdl2 –disable-xlib –enable-lto –enable-gpl –enable-version3 –enable-shared –enable-gmp –enable-gnutls –enable-chromaprint –enable-libdrm –enable-libass –enable-libfreetype –enable-libfribidi –enable-libfontconfig –enable-libbluray –enable-libmp3lame –enable-libopus –enable-libtheora –enable-libvorbis –enable-libopenmpt –enable-libdav1d –enable-libwebp –enable-libvpx –enable-libx264 –enable-libx265 –enable-libzvbi –enable-libzimg –enable-libfdk-aac –arch=amd64 –enable-libsvtav1 –enable-libshaderc –enable-libplacebo –enable-vulkan –enable-opencl –enable-vaapi –enable-amf –enable-libmfx –enable-ffnvcodec –enable-cuda –enable-cuda-llvm –enable-cuvid –enable-nvdec –enable-nvenc
libavutil 57. 28.100 / 57. 28.100
libavcodec 59. 37.100 / 59. 37.100
libavformat 59. 27.100 / 59. 27.100
libavdevice 59. 7.100 / 59. 7.100
libavfilter 8. 44.100 / 8. 44.100
libswscale 6. 7.100 / 6. 7.100
libswresample 4. 7.100 / 4. 7.100
libpostproc 56. 6.100 / 56. 6.100
[AVHWDeviceContext @ 0x56256f7c47c0] No VA display found for any default device.
Device creation failed: -22.
Failed to set value ‘vaapi=va:,driver=iHD,kernel_driver=i915’ for option ‘init_hw_device’: Invalid argument
Error parsing global options: Invalid argument
Do you get this error with the “user” environment variable removed?
Thanks for the fast response und support 🙂
Yes, I get the same error when I remove the user variable. I tried it also with the root user. Same ids in the docker and on synology dsm.
That’s very strange! It sounds like the permissions are wonky. Is it a recent DSM installation?
If you’re able to SSH onto the NAS, run “ls -la /dev/dri” and post the output here so we can see the device permissions.
Yes it is a normal DSM installation. I checked the permission on dev/dri
drwxr-xr-x 2 root root 80 May 15 22:05 .
drwxr-xr-x 16 root root 14400 May 18 11:37 ..
crwxrwxrwx 1 root root 226, 0 May 15 22:05 card0
crwxrwxrwx 1 root videodriver 226, 128 May 15 22:05 renderD128
root user id on DSM
id root
uid=0(root) gid=0(root) groups=0(root),2(daemon),19(log)
root user id from jellyfin docker
id root
uid=0(root) gid=0(root) groups=0(root),2(daemon),19(log)