Guide
GPUs, transcoding and local AI: what hardware you actually need
People buy one GPU hoping to cover both jobs and usually get neither right. Transcoding is an Intel integrated graphics problem. Local inference is a VRAM problem. Here is what each one needs, down to the container flags.
Do you need a GPU for a home media server or local AI?
For video transcoding, no: a modern Intel integrated GPU with Quick Sync handles several simultaneous 4K HEVC streams for roughly 10 W and is the right answer for almost everybody. For local language models, yes, and what matters is VRAM capacity, not speed. A model must fit entirely in VRAM or throughput collapses, so an 8 billion parameter model at four-bit quantization needs about 5 GB free and a 70B model needs around 40 GB.
"I want a GPU for my server" is two completely different purchases wearing one sentence. Video transcoding is a fixed-function encoder problem solved by a 6 W integrated graphics block. Local language model inference is a memory capacity problem solved by an expensive card with a lot of VRAM. The hardware that is excellent at one is usually mediocre or useless at the other.
Transcoding: Intel Quick Sync, and then stop reading#
Start by noticing how little transcoding you may need. Direct play, where the client can decode the file as it is, costs the server almost nothing: Jellyfin idles at 280 MB and does essentially no work streaming a file a TV can already play. Transcoding happens when the client cannot handle the codec, the container, the bitrate or the subtitle format. Fix the library and the client first and you may never need the encoder at all.
When you do need it, an Intel iGPU from an N100, N150, i3-12100, i5-12400 or anything newer is the answer. Jellyfin's own hardware guidance recommends Intel on any non-Apple hardware, names the N100 and the i5-11400 as the baseline recommendations, and explicitly removed 7th to 10th generation parts from that list because Intel deprecated their toolkit. AMD is ranked last there, for sub-par H.264 encoder quality. NVIDIA's RTX 50 series has the best encoder quality available, and it is also a 250 W card you do not need in a media server.
The power difference is the point. An N150 has a 6 W processor base power for the entire chip. A transcode session on an iGPU adds roughly 5 to 15 W over idle depending on generation and stream count; a discrete card idles at 8 to 20 W before it does any work at all. Over a year that gap is real money, as What a home server costs to run works through.
QSV, NVENC and VAAPI are not three tiers#
They are two hardware blocks and one API.
| Name | What it is | Runs on |
|---|---|---|
| Quick Sync (QSV) | Intel's media engine, driven through Intel's own oneVPL stack | Intel iGPUs and Arc |
| VAAPI | A Linux video acceleration API, not hardware | Intel and AMD |
| NVENC / NVDEC | NVIDIA's encoder and decoder blocks | NVIDIA GPUs |
| AMF / VCN | AMD's media engine | AMD GPUs |
On an Intel chip, QSV and VAAPI drive the same silicon. QSV usually gives better HDR tone mapping and more format coverage; VAAPI is sometimes more reliable on older kernels. Try QSV first and fall back to VAAPI if a specific transform misbehaves. On AMD, VAAPI is the only path.
The device passthrough, per app#
The device node is /dev/dri, and passing it is only half the job. The container user also needs the host's render group, which is where most "hardware transcoding does not work" threads end.
getent group render # note the GID, often 104 or 993services:
jellyfin:
image: jellyfin/jellyfin
devices:
- /dev/dri:/dev/dri
group_add:
- "993" # the render GID from the host
volumes:
- ./config:/config
- ./cache:/cache
- /srv/media:/media:roThe per-app differences matter more than the similarities:
- Jellyfin:
--device /dev/dri:/dev/driplusgroup_addwith the host render GID. Without the group, ffmpeg cannot open the device and silently falls back to software. Verify in the playback info overlay, which states whether the session is hardware accelerated. NVIDIA instead needs the NVIDIA Container Toolkit, the nvidia runtime andNVIDIA_DRIVER_CAPABILITIES=compute,video,utility. - Emby: same device, different group mechanism. Emby's entrypoint reads a
GIDLISTenvironment variable rather than Compose'sgroup_add, so a Jellyfin snippet copied across will fail. And hardware transcoding requires an active Emby Premiere licence: the options appear in the UI regardless and the transcode still runs on CPU. - Plex Media Server:
--device /dev/dri:/dev/drifor Quick Sync, plus the NVIDIA toolkit for NVENC, plus the toggle in Settings, Transcoder, plus an active Plex Pass. Hardware transcoding has always been a paid feature, so the free tier is a CPU-only server. Run it withnetwork_mode: hostunless you want to fight discovery. - Frigate: pass
/dev/drifor OpenVINO detection and hardware decode. Two other settings decide whether the install survives: raiseshm_sizefrom Docker's 64 MB default using the documented per-camera formula (about 67 MB for one 1280x720 detect stream, 512 MB as a sane starting point), and point the detect role at a low-resolution substream rather than the 4K main stream. Getting the substream right often turns 90 percent CPU into 15. - Immich: has two separate acceleration questions, video transcoding and machine learning. Both are x86-64 only for the good backends: CUDA, OpenVINO and ROCm do not exist on ARM, where you get ARM NN on Mali or RKNN on Rockchip and nothing else.
Local AI: VRAM is the binding constraint#
Everything about local inference follows from one fact: the model has to fit in the memory the compute unit can reach, and if it does not, performance falls off a cliff rather than a slope.
Ollama loads as many model layers into VRAM as fit and runs the remainder on the CPU. Missing the fit by two layers does not cost you a small percentage. Throughput typically drops several times over, because every token now has to cross the PCIe bus. Watch the layer count in the server log; if it is not offloading all of them, drop to a smaller quantization or a shorter context rather than accepting the split.
Orders of magnitude worth memorizing:
| Model | Quantization | Size | Rough speed |
|---|---|---|---|
| 8B | Q4_K_M | ~5 GB | 5 to 15 tokens/sec on a modern desktop CPU |
| 8B | Q4_K_M | ~5 GB | fast and interactive on any 8 GB+ GPU |
| 70B | Q4 | ~40 GB | 1 to 3 tokens/sec CPU-only, not usable interactively |
Those CPU figures scale with memory bandwidth, not core count. This is the single most misunderstood thing about local inference: a 16-core server with dual-channel DDR4 is barely faster than an 8-core one, so buying cores to speed up a local model is money set on fire. The only change that matters is a GPU with enough VRAM to hold the whole model, or Apple Silicon, where unified memory means a 32 GB Mac can run models a 12 GB discrete card cannot.
Quantization is the lever you actually have. The default tags in Ollama's library are typically Q4_K_M, a four-bit compromise at roughly half the memory of Q8. Pulling :latest gets you the compromise rather than the model as published. If you have VRAM headroom, Q6 or Q8 are noticeably better on reasoning and code. Q3 exists and degrades badly.
Three defaults will surprise you. Context length defaults to 4096 tokens regardless of what the model advertises, so a 20,000 token document is silently truncated from the front. Models unload after 5 minutes idle, so the next request pays the full load time again. And OLLAMA_MAX_LOADED_MODELS defaults to 3, so three different models can quietly fill a GPU you thought was free.
# a 128k-capable model still runs at 4096 unless you say otherwise
OLLAMA_CONTEXT_LENGTH=32768 OLLAMA_KEEP_ALIVE=-1 ollama serveWhy one GPU rarely covers both#
| Hardware | Transcoding | Local inference |
|---|---|---|
| Intel iGPU (N150, i5-12400) | Excellent, about 10 W | Poor. No dedicated VRAM, thin stack support |
| Used NVIDIA P400 / T400 (2 to 4 GB) | Good, cheap | Useless. Nothing meaningful fits in 4 GB |
| NVIDIA RTX 3060 12 GB | Good, and 15 W idle you did not need | Good. Comfortable for 8B, tight for 14B |
| NVIDIA RTX 3090 / 4090 (24 GB) | Overkill and hot | Excellent, and the practical home ceiling |
| Google Coral TPU | Nothing. It does not decode video | Nothing. It runs small vision models only |
| Apple Silicon, 32 GB+ | Good via VideoToolbox | Very good, thanks to unified memory |
The two purchases pull in opposite directions. A transcoding GPU should be small, cheap, low-idle and have a modern media engine; VRAM is irrelevant. An inference GPU should have as much VRAM as you can afford; its media engine is irrelevant. The overlap, an RTX 3060 12 GB, is a compromise on both and adds meaningful idle draw to a machine that is idle 95 percent of the time.
The sane setup for most people: an Intel iGPU in the always-on server for transcoding and detection, and, if you genuinely want local models, either a second machine you power on when you use it, or Apple hardware you already own. Running Open WebUI against a model on a desktop that is awake anyway costs nothing extra.
What Immich and Frigate actually want#
Immich wants RAM before it wants a GPU. The docs ask for 6 GB minimum and 8 GB recommended, and the immich-machine-learning container holding CLIP and face models resident is most of that. Raising MACHINE_LEARNING_WORKERS loads a second full copy of the models, which roughly doubles resident memory, and the failure mode is an exit code 137 that looks like broken search rather than an out-of-memory kill. GPU acceleration for ML is a nice-to-have that shortens the initial import; the initial import will peg every core for hours either way.
Frigate wants an Intel iGPU, and specifically not a big GPU. Decoding costs more than detecting, and only the GPU path accelerates decode. The documentation no longer recommends a Coral for new installs outside low-power builds, because OpenVINO on a modern iGPU runs inference in roughly 4 to 15 ms against the Coral's 10 ms and does the decode as well. Version 0.17 also dropped support for NVIDIA GTX 900 series cards, which is another data point on old NVIDIA hardware in this role. Plan the disk before the detector: at roughly 43 GB per camera per day for a 4 Mbit/s continuous stream, six cameras is about 1.8 TB a week.
What to do next#
If you are still choosing a machine, Choosing home server hardware puts the iGPU in the right place in the buying order (second, after RAM). If the media stack is the point, Jellyfin vs Plex settles which server you are passing the device into. And if local models are the real goal, read the Ollama profile and Ollama vs LocalAI before you buy a card, because the VRAM number decides the outcome and nothing else comes close.
Questions#
What is the difference between Quick Sync, NVENC and VAAPI?
Quick Sync is Intel's fixed-function media engine and the software stack that drives it. NVENC and NVDEC are the equivalent blocks on NVIDIA cards. VAAPI is not a hardware feature at all: it is a Linux API that can drive Intel or AMD hardware. On Intel you can usually pick either the QSV path or the VAAPI path for the same silicon, and QSV generally exposes more features and better tone mapping. On AMD, VAAPI is your only option.
Which GPU is best for Plex or Jellyfin transcoding?
An Intel iGPU from an N100, N150, i3-12100, i5-12400 or newer. Jellyfin's hardware guidance recommends Intel on any non-Apple hardware, names the N100 and i5-11400 as baseline recommendations, and ranks AMD last because of its weaker H.264 encoder. A discrete card only makes sense if your CPU has no iGPU at all.
How do I pass a GPU into a Docker container?
For Intel and AMD, add --device /dev/dri:/dev/dri and give the container the host's render group. Find the GID with getent group render and add it with group_add in Compose. Emby is the exception: it uses a GIDLIST environment variable instead. For NVIDIA, install the NVIDIA Container Toolkit, use the nvidia runtime and set NVIDIA_DRIVER_CAPABILITIES=compute,video,utility.
Why is my transcoding still using the CPU?
Almost always a permissions problem, not a configuration one. Passing /dev/dri without adding the render group means ffmpeg cannot open the device, falls back to software, and reports nothing obvious in the UI. Check the playback info overlay in Jellyfin, which states whether the session is hardware accelerated. On Plex Media Server and Emby, also check that you actually hold the licence: hardware transcoding is a paid feature on both.
How much VRAM do I need to run a local LLM?
Enough for the whole model plus its KV cache. An 8B model at Q4_K_M is roughly 5 GB, so 8 GB of VRAM is a workable floor and 12 GB is comfortable. A 70B at Q4 is around 40 GB, which means two 24 GB cards or a large unified-memory Mac. Missing the fit by two layers is not a small penalty: throughput typically drops several times over because every token crosses the PCIe bus.
Can I run a local LLM without a GPU?
Yes, and it is slow in a specific way. CPU inference is bound by memory bandwidth rather than core count, so a 16-core server with dual-channel DDR4 is barely faster than an 8-core one. Expect roughly 5 to 15 tokens per second for an 8B model at Q4 on a modern desktop CPU, and 1 to 3 tokens per second for a 70B, which is not usable interactively. It is fine for overnight batch work.
Do I need a Coral TPU for Frigate?
Not any more, for most builds. Frigate's documentation stopped recommending Coral for new installs outside low-power scenarios. A modern Intel iGPU running OpenVINO does inference in roughly 4 to 15 ms against the Coral's 10 ms, and unlike the Coral it also accelerates video decode, which is where the CPU time actually goes.
Sources#
- Jellyfin hardware selection guidance
- Jellyfin hardware acceleration documentation
- Frigate hardware recommendations and detector inference speeds
- Immich machine learning hardware acceleration
- Ollama GPU support and compute requirements
- Ollama FAQ: context length, keep-alive, concurrency
- Plex, using hardware-accelerated streaming
- Emby Premiere feature list
- TrueNAS 25.10 version notes, NVIDIA driver change
- Intel Processor N150 product specifications
Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.