Linux VA-API Driver and Plex

The vtremote-vaapi-linux-x86_64.tar.gz release asset lets a stock Linux VA-API application send H.264 or HEVC encoding to vtremoted. It supports H.264 Baseline/Main/High, HEVC Main, and HEVC Main 10 with NV12/P010 input.

The general-purpose VA-API driver is encode-only. Decode, scaling, deinterlace, subtitle burn-in, and tone mapping must happen before VA-API upload. B-frames and external DMA-BUF surfaces are not supported.

Install

Install your distribution’s liblz4 and libzstd runtime packages, unpack the release asset, and run:

sudo ./vtremote-vaapi/install-binary.sh
sudo modprobe vgem
export LIBVA_DRIVERS_PATH=/opt/vtremote-vaapi/lib/dri
export LIBVA_DRIVER_NAME=vtremote
export VTREMOTE_HOST=<MAC_PRIVATE_IP>:5555
export VTREMOTE_WIRE_COMPRESSION=auto
/opt/vtremote-vaapi/bin/vtremote-probe --host "$VTREMOTE_HOST" --codec h264

VTREMOTE_HOST is required. Wire compression accepts auto, none, lz4, or zstd. Automatic mode chooses Zstandard for raw traffic below 200 Mbit/s and LZ4 for higher-throughput streams.

Plex

The repository provides a Dockerfile pinned to an official amd64 pms-docker bootstrap image digest, plus a Compose merge example under vaapi-driver/docker/. Its narrow Plex Transcoder wrapper recognizes Plex’s ordinary H.264/HEVC software-scale/format/hardware-upload graph and replaces that video chain with the vtremote_transcode packet filter. Compressed input packets go to the Mac; decoded or scaled frames never cross the network or consume Linux CPU.

This Plex path does not use the VA-API driver and needs no render node. Linux continues to demux, process audio and subtitles, and mux the returned video. Unknown graphs pass through unchanged to Plex’s native Transcoder.

The preload module uses FFmpeg private internals and is therefore enabled only for an explicitly tested Plex libavcodec build. Container startup verifies the library fingerprint, and the wrapper checks the full runtime avcodec_version() before changing any arguments. A missing or unrecognized runtime keeps Plex on its native path.

For recognized commands, the wrapper translates bitrate, maximum rate, VBV window, GOP/B-frame settings, profile, H.264 level, entropy mode, and CBR/VBR/CQP selection. Plex’s periodic force_key_frames expression is converted to a keyframe interval and closed-GOP request using the requested output frame rate. VideoToolbox does not expose a fixed HEVC level, so a command requesting one remains on the native path. Other unsupported values, multiple video inputs or outputs, and indirect filter labels also pass through unchanged.

Validate the bundled Plex Transcoder and VA-API stack without claiming the server or creating a library:

PLEX_CONTAINER=plex \
  vaapi-driver/scripts/plex-transcoder-remote-smoke.sh

This deterministic check covers H.264 encode, HEVC Main10 decode to H.264, and HEVC encode. It invokes Plex’s bundled Transcoder with Plex-shaped VA-API commands and verifies several consecutive remotely decoded, scaled, and encoded segments for every case. Every segment must begin with a keyframe and decode independently. The check requires no Plex token, library, or Plex Pass.

Separately, enable hardware acceleration and hardware encoding in a claimed Plex Pass server. Plex requests its normal hardware pipeline and the wrapper converts the supported graph to remote decode, scale, and encode. Validate it through a real playback request:

PLEX_URL=http://127.0.0.1:32400 \
PLEX_TOKEN=... \
PLEX_RATING_KEY=12345 \
PLEX_CONTAINER=plex \
  vaapi-driver/scripts/plex-playback-smoke.sh

The optional claimed-server check requests an HLS playback transcode from PMS, downloads and decodes a media segment, and requires a new wrapper audit entry. It proves PMS selected the remote packet filter and returned playable media; the unclaimed-server check proves the underlying Transcoder integration.

For build, environment, SDK, and architecture details, see vaapi-driver/README.md.