Intel Celeron-based Synology NAS devices are popular for home media servers for one key reason: they have an integrated GPU that supports Intel QSV hardware acceleration. This enables them to serve a much higher number of video streams than CPU-based transcoding would allow. That transcoding support is available to any software running on the NAS, though how it is run (i.e., as a native package or within an Docker container) can make it more complex to set up.
While some media server software (e.g., Plex and Emby) have native Synology packages, they’re the exception, and limiting yourself to only those will mean missing out on a lot of great options: Jellyfin, ErsatzTV, etc. Most other software options will be installed and run within a Docker container, and that’s where it becomes difficult because Synology’s Docker GUI does not expose the necessary controls for passing in the hardware transcoding device handle.
Technical Background
Intel QSV hardware acceleration is most easily accessed on Linux via VAAPI, the standard video acceleration API for the platform. It provides a standardized interface that software can use to enable video hardware acceleration in a way that’s agnostic of the actual hardware itself. With it, software doesn’t need to care that it’s using Intel QSV or Nvidia NVENC, though that comes at the expense of possible hardware-specific filters (i.e., anything more than scaling or transcoding may not be supported).
This is exposed to software via the device handles at /dev/dri/renderD128
and /dev/dri/card0
, which must be accessible in order to use the hardware acceleration. Unfortunately, accessing that from a Docker container on Synology is unnecessarily difficult to do correctly. One way, the easiest, is to toggle the option Execute container as high privilege
, but that avoids one of the most significant benefits of using Docker in the first place: complete isolation of the software. The better way is to update the permissions and then pass it in with the initial Docker container creation, something the Synology Docker UI provides no controls to actually do.
The Solution
A variety of posts exist about how to get hardware acceleration working in Jellyfin or any other Docker-based media server software installation. Unfortunately, most do not seem to have actually tested the result and miss one of the key components. There are two things that need done:
- Ensure the Docker user has permissions to access
/dev/dri/renderD128
. By default on the Synology platform, the permissions restrict this to the owner (root
) and the group (videodriver
), neither of which result in Docker containers having permissions. - Pass the device handles
/dev/dri/card0
and/dev/dri/renderD128
into the Docker container at creation.
1. Permissions
There are two options for granting permissions to /dev/dri/renderD128
, one of which is by adding the user to the videodriver
group, and the second by setting the others permission bitfield. I chose the latter because Synology’s UI does not expose management of that system group. Note: this makes a system-level change rather than something configuration-based, so there’s a strong chance it can get reverted on reboot or system update. It’s important to do it in a way that automatically re-applies the change: a triggered task.
Start by opening the Control Panel
Open the Task Scheduler
Create a new Triggered Task (User-defined script)
Name the task and set it to execute as root, boot-up is the default event
Enter the chmod 666 /dev/dri/renderD128
command into the script text area and click OK to save
Select the new task and click Run (in the future it will run at every reboot)
2. Pass Device Handles
Passing device handles into Docker cannot be done within the Synology Docker UI. What needs to be done is to run the literal Docker container creation command:
docker run -d \ --name jellyfin \ --volume /path/to/save/persistent/config:/config \ --volume /path/to/save/cache:/cache \ --volume /path/to/media:/media \ --net=host \ --restart=unless-stopped \ --device /dev/dri/renderD128:/dev/dri/renderD128 \ --device /dev/dri/card0:/dev/dri/card0 \ jellyfin/jellyfin:latest
The resulting effect of the two --device
lines is absolutely necessary for allowing hardware acceleration to work.
For another piece of media server software, ErsatzTV, the command would be:
docker run -d \ --name ersatztv \ -e TZ=America/Los_Angeles \ -p 8409:8409 \ --volume /path/to/save/persistent/config:/root/.local/share/ersatztv \ --volume /path/to/media:/media:ro \ --restart unless-stopped \ --device /dev/dri/renderD128:/dev/dri/renderD128 \ --device /dev/dri/card0:/dev/dri/card0 \ jasongdove/ersatztv:latest-vaapi
There are two ways to run this command. The first is from the command line over an SSH connection as root. The second, and possibly the more simple for most people, is to use the task runner built into the Synology OS.
Start by opening the Control Panel
Open the Task Scheduler
Create a new Scheduled Task (User-defined script)
Name the task and set it to execute as root, uncheck Enabled (we only want to run it manually)
Paste the command into the script text area and click OK to save
Select the new task and click Run
Jellyfin is up and running
Results
With the VAAPI hardware acceleration enabled in Jellyfin, CPU usage is about 1/3 of previous values.