Skip to content

4K60 Transcode Ceiling and VBR Peaks on Wi-Fi Clients

Why a healthy Plex server with working hardware transcoding still can't serve 4K60 content to a Wi-Fi-only client — and why "enable hardware acceleration" is not the answer.

This case contradicts the usual advice

The standard fix for Apple TV playback problems is "set Quality to Play Original so it direct plays." That does not help when the source file's peak bitrate exceeds what the Wi-Fi link can carry. Direct play and transcode both fail, for different reasons.

Symptom

On an Apple TV 4K (Wi-Fi only, no Ethernet port):

  1. 4K content plays but is choppy, worse during high-motion scenes
  2. Eventually it stops playing entirely
  3. Plex shows "Your server is not powerful enough to convert video"
  4. The Plex dashboard reports playback at an implausibly high bitrate (e.g. 121 Mbps)

1080p content on the same server, client, and network plays perfectly.

Root cause: two independent problems

1. The source files have unconstrained VBR peaks

ffprobe reports an average bitrate, which hides the real problem. Measure the per-second bitrate instead:

F="/plex/plex/yourfile.mp4"
ffprobe -v error -select_streams v:0 -show_entries packet=pts_time,size \
  -of csv=p=0 "$F" \
| awk -F, '{s=int($1); bytes[s]+=$2} END {for (t in bytes) print bytes[t]*8/1000000}' \
| sort -rn > /tmp/br.txt

echo "peak:   $(head -1 /tmp/br.txt)"
echo "p95:    $(awk '{a[NR]=$1} END {print a[int(NR*0.05)]}' /tmp/br.txt)"
echo "median: $(awk '{a[NR]=$1} END {print a[int(NR/2)]}' /tmp/br.txt)"

A real example from this library:

Metric Bitrate
Average (what ffprobe reports) 32 Mbps
Median 24 Mbps
95th percentile 92 Mbps
Peak 149 Mbps

No Wi-Fi link sustains 92–149 Mbps bursts on a contended 5 GHz radio. The file stutters exactly when the bitrate spikes — i.e. during high-motion scenes.

Cause: -rc_mode CQP with no rate ceiling

These files came from a batch re-encode using -c:v hevc_vaapi -rc_mode CQP -qp 28. Constant-QP mode spends whatever bits a frame needs with no upper bound. The result is a modest average and enormous peaks. Always pair an encode with -maxrate and -bufsize if the output will be streamed over a constrained link.

2. The GPU cannot transcode 4K60 HEVC in real time

When the client requests a lower quality, Plex must transcode. Measured on an RX 480 (Polaris, hevc_vaapi), decoding 4K60 HEVC and re-encoding:

Pipeline Speed
4K60 HEVC decode → 4K HEVC encode 0.3–0.4x
4K60 HEVC decode → 1080p H.264 encode 1.1–1.5x

Real-time playback needs speed ≥ 1.0, and roughly 2x+ to build and hold a client-side buffer. Even the 1080p output path only just clears 1.0, because the 4K60 HEVC decode dominates the cost and no output setting reduces it.

Benchmark gotcha

A decode-only test measured slower (1.19x) than decode+encode (1.49x). The decode-only run omitted -hwaccel_output_format vaapi, forcing an expensive GPU→CPU frame readback. Always keep frames on the GPU when benchmarking VAAPI, or you measure PCIe transfer rather than the decoder.

The livelock

These two problems combine into a self-sustaining failure:

  1. Transcode runs at ~1.1x — barely above real time
  2. Client can't accumulate a startup buffer, times out, and retries
  3. Each retry spawns a new transcode session
  4. Stacked sessions contend for the same GPU, making every one slower
  5. → more timeouts → more sessions

Symptoms in the log: multiple session UUIDs within a few minutes, each ending in exit code ... is -9 (signal: Killed), and zero .ts segments produced.

L="/plex/plexdata/Library/Application Support/Plex Media Server/Logs/Plex Media Server.log"

# Live transcode speed — the number that matters
sudo grep -ao "speed=[0-9.]*" "$L" | tail -10

# Session churn
sudo grep -a "signal: Killed" "$L" | tail

# Are segments actually being written?
D="/plex/plexdata/Library/Application Support/Plex Media Server/Cache/Transcode/Sessions"
sudo find "$D" -name '*.ts' -newermt '-60 seconds' | wc -l

SIGKILL here is a symptom, not a cause

Confirm it is not the OOM killer before chasing memory. If dmesg/journalctl show no OOM events and there are no systemd MemoryMax limits, the SIGKILLs are Plex cleaning up sessions the client already abandoned.

Fix

For a Wi-Fi-only client and 4K60 sources, transcoding is not viable on this hardware. Re-encode the sources to 1080p ahead of time so the client direct plays:

ffmpeg -y \
  -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi \
  -i input.mp4 \
  -vf 'scale_vaapi=w=1920:h=1080:format=nv12' \
  -c:v hevc_vaapi -rc_mode VBR -b:v 12M -maxrate 20M -bufsize 40M \
  -c:a copy \
  -movflags +faststart \
  output.mp4

Key points:

  • -rc_mode VBR with -maxrate/-bufsize bounds the peak. This is the part that makes it Wi-Fi-deliverable; the average was never the problem.
  • -c:a copy passes the audio through untouched rather than re-encoding it (Plex's transcode was converting AC3 → Opus). Check your own source first: on this library the audio was already AC3 stereo 320k, so Plex's ochl='stereo' downmix was a no-op — worth verifying with ffprobe -select_streams a before assuming surround is being lost.
  • Encoding to the same path preserves Plex's added_at (see HEVC VAAPI Batch Encode).

Automated in reencode_4k_1080p.sh on majorhome (queue/resume, verify-before-swap, free-space guard).

What does not fix it

Attempted Result
Set client Quality to "Play Original" Avoids transcode, but 149 Mbps peaks still exceed Wi-Fi
Enable hardware acceleration Already enabled and working correctly — still only 0.3x at 4K→4K
Force 1080p output resolution Improves 0.3x → 1.1x, still too marginal to hold a buffer
Lower transcode quality further Minimal gain — the 4K60 decode is the bottleneck, not the encode
Ethernet Would work (gigabit carries 149 Mbps easily) — but Apple TV 4K Wi-Fi models have no port