Add Hardware-accelerated transcoding guide (Intel VAAPI)

Alex Shnitman
2026-07-31 09:02:50 +03:00
parent 6a69101bff
commit 86111280c6
2 changed files with 143 additions and 0 deletions
+142
@@ -0,0 +1,142 @@
yt-dlp can re-encode downloads with ffmpeg (via `postprocessor_args`), and on a
machine with an Intel iGPU that encoding can run on the GPU instead of the CPU.
The MeTube image already ships ffmpeg, but not the VAAPI driver, and the
container has no access to the GPU by default. This page covers the three
things you need to add.
Contributed by [@kamaeff](https://github.com/kamaeff) in
[discussion #1045](https://github.com/alexta69/metube/discussions/1045), tested
on Debian 13 with an Intel N150.
### 1. Install the VAAPI driver in the image
The MeTube image is based on `python:3.13-slim` (Debian), so you can layer the
Intel media stack on top of it with a small Dockerfile of your own:
```dockerfile
FROM ghcr.io/alexta69/metube:latest
RUN apt-get update && \
apt-get install -y --no-install-recommends \
intel-media-va-driver \
libvpl2 \
libmfx-gen1.2 && \
rm -rf /var/lib/apt/lists/*
```
Add `vainfo` to that list if you want to be able to check the driver from
inside the container (see [Verifying](#verifying) below).
The host needs the Intel media drivers installed too, and `/dev/dri/card0` and
`/dev/dri/renderD128` must exist there.
### 2. Give the container access to `/dev/dri`
Pass the devices through, and run MeTube with the host's `render` group so it's
allowed to open them. Find the GID first:
```
getent group render | cut -d: -f3
```
Then, in your compose file:
```yaml
metube:
build: ./metube # the Dockerfile from step 1
environment:
- "PGID=993" # <- the render GID from above
devices:
- /dev/dri:/dev/dri
```
Note that `PGID` is also the group MeTube's downloaded files end up owned by,
since the entrypoint chowns the download directories to `PUID:PGID`. If you'd
rather keep your own group for the files, set `user:` in compose instead — that
makes the entrypoint skip its `gosu` step and keep whatever groups Docker gave
the container, so a supplementary group works:
```yaml
user: "1000:1000"
group_add:
- "993" # the render GID
```
### 3. Tell ffmpeg to use the GPU
Encoding options go in `postprocessor_args`. The example below is a preset (via
`YTDL_OPTIONS_PRESETS_FILE`) that decodes on the GPU, scales to 720p, and
encodes to HEVC — all in hardware:
```json
{
"hevc-720p-vaapi": {
"format": "bv*[height<=1440]+ba/b",
"merge_output_format": "mp4",
"postprocessors": [
{ "key": "FFmpegCopyStream" }
],
"postprocessor_args": {
"copystream+ffmpeg_i": [
"-vaapi_device", "/dev/dri/renderD128",
"-hwaccel", "vaapi",
"-hwaccel_output_format", "vaapi"
],
"copystream+ffmpeg_o": [
"-vf", "scale_vaapi=w=-2:h=720,fps=24",
"-vcodec", "hevc_vaapi",
"-qp", "26",
"-tag:v", "hvc1",
"-acodec", "aac",
"-ac", "1",
"-b:a", "64k",
"-f", "mp4",
"-movflags", "+faststart"
]
}
}
}
```
What the pieces do:
* `-hwaccel vaapi` + `-hwaccel_output_format vaapi` — decode on the GPU and
keep the decoded frames in GPU memory, so no copying back and forth.
* `scale_vaapi` — resize on the GPU. Use this rather than `scale`; the regular
filter can't operate on VAAPI surfaces.
* `-vcodec hevc_vaapi` — encode with the hardware HEVC encoder (`h264_vaapi`
for H.264).
* The `copystream+ffmpeg_i` / `copystream+ffmpeg_o` keys attach the arguments
to the `FFmpegCopyStream` postprocessor's ffmpeg invocation, `_i` before the
input and `_o` before the output. Both matter here: `-hwaccel` is an input
option and the filter/encoder settings are output options.
The same setup can be defined globally via `YTDL_OPTIONS` instead of as a
preset, but a preset lets you pick hardware transcoding per download in the UI.
### Verifying
With `vainfo` installed in your image:
```
docker exec metube vainfo --display drm --device /dev/dri/renderD128
```
It should list the driver and a set of `VAProfile...` entries including
`VAEntrypointEncSlice` for the codecs your GPU can encode. Also useful:
```
docker exec metube ffmpeg -hide_banner -encoders | grep vaapi
```
If ffmpeg fails with a permission error on `/dev/dri/renderD128`, the group in
step 2 is wrong or wasn't applied — check with `docker exec metube id`.
### Other GPUs
The device passthrough and group setup in step 2 are the same for AMD; swap the
driver package in step 1 for `mesa-va-drivers`. NVIDIA doesn't use VAAPI — it
needs the NVIDIA Container Toolkit and NVENC encoder names (`hevc_nvenc`,
`h264_nvenc`) instead.
+1
@@ -10,6 +10,7 @@ Welcome to the MeTube wiki — the companion to the [README](https://github.com/
### Guides ### Guides
* [Subscriptions](Subscriptions) — auto-download new uploads from channels and playlists. * [Subscriptions](Subscriptions) — auto-download new uploads from channels and playlists.
* [Hardware-accelerated transcoding](Hardware-accelerated-transcoding) — re-encode downloads on an Intel/AMD GPU.
* [Troubleshooting FAQ](Troubleshooting-FAQ) — common issues and how to diagnose them. * [Troubleshooting FAQ](Troubleshooting-FAQ) — common issues and how to diagnose them.
--- ---