The same movie plays perfectly on the TV and buffers in a browser. The file didn't change; what the server had to do with it did. For the TV it sent the file as it is. For the browser it had to rebuild the video, every frame, while you watched, and the server couldn't keep up.
That rebuilding is transcoding. It's what lets any device play anything, and it's also the most expensive thing a media server does. Plex and Jellyfin both do it, in much the same way. This is what happens when you press play, and how to keep the server doing as little as possible.
What's inside a video file
A video file is a box with several things packed inside:
- The container is the box: MKV, MP4, AVI. It says what's inside and keeps it in sync.
- The video stream is the picture, compressed with a codec such as H.264, HEVC (also called H.265) or AV1. Newer codecs make smaller files for the same quality, but take more work to decode.
- One or more audio streams, each in its own codec: AAC, AC-3, DTS, TrueHD (with Atmos).
- Subtitles, either text (SRT) or pictures of text (PGS from Blu-rays, VobSub from DVDs).
To play a file, a device has to understand the container and decode every stream in it. A TV
might handle MKV and HEVC but not DTS audio. A browser might handle H.264 but not HEVC. Whether a
file plays as it is depends on what's inside it, not on its name: two .mkv files can need
completely different treatment.
What the server does when you press play
Before it sends anything, the server compares the file with what the device says it can play, and the speed of the connection. Then it picks the cheapest option that works:
flowchart TB
Start["You press play"]
Q1{"Device plays<br/>everything in it?"}
DP["Direct play<br/>sends the file as it is"]
Q2{"Video plays,<br/>at this bitrate?"}
DS["Direct stream<br/>repackages, converts<br/>audio if needed"]
TC["Transcode<br/>decodes and re-encodes<br/>every frame"]
Start --> Q1
Q1 -- yes --> DP
Q1 -- no --> Q2
Q2 -- yes --> DS
Q2 -- no --> TC
- Direct play: the device can play everything in the file, and the connection is fast enough, so the server just sends the bytes. Almost no work, and you see exactly what's in the file.
- Direct stream: the video is fine, but the container or the audio isn't. The server copies the video as it is, converts the audio if it has to, and packs it all into a container the device accepts. Light work, and the picture is untouched. Moving streams from one container to another without changing them is called remuxing ("mux" is short for multiplex: weaving several streams into one file).
- Transcode: the device can't decode the video, or the connection is too slow for it, so the server decodes every frame and encodes a new video, in real time, while you watch.
Jellyfin splits the middle step in two: remux when only the container changes, and direct stream when the audio is converted too. Plex calls both direct stream.
A video has to be transcoded at least as fast as it plays: 24 frames a second for most movies. When the server falls below that, the player runs out of video and buffers, however fast the network is.
What transcoding is good for
Transcoding is expensive, but it's also what makes a media server work everywhere:
- Any device can play anything. An old smart TV, a browser or a phone that can't decode HEVC still gets a picture, because the server sends it something it can.
- Remote streaming fits a slow connection. A 4K Blu-ray copy can run at 50 Mbps or more, more than most home connections can upload. Transcoding to a lower bitrate fits it through, and keeps a phone from burning through its data plan.
- Subtitles show up on devices that can't draw them. Picture-based subtitles from Blu-rays and DVDs get painted onto the video ("burned in") when the player can't show them itself.
- HDR can look right on an ordinary screen. HDR video shown as-is on a non-HDR screen looks grey and washed out. Tone mapping converts it while transcoding, so the colours come out right.
What it costs
- A lot of processing power. Decoding and re-encoding video is one of the heaviest jobs a computer does. Without help from graphics hardware (next section), one stream can keep every core of a CPU busy, and a 4K stream can be more than a CPU can manage at all.
- Some quality. Every encode throws detail away to make the stream smaller. A transcode is a copy of a copy, at a lower bitrate than the original.
- A slower start and slower seeking. The server has to produce video before it can send it, so it takes a few seconds to start, and again after skipping ahead.
- Washed-out HDR without tone mapping. Tone mapping is heavy work of its own, and slow without hardware that can do it.
Hardware vs software transcoding
Software transcoding runs on the CPU's general-purpose cores. Hardware transcoding uses the media engine on a graphics chip: circuits built only to decode and encode video, which do it far faster for far less power. Many desktop CPUs have one in their integrated graphics (Intel calls it Quick Sync), so you don't need a graphics card to get it. Nvidia and AMD graphics cards have their own.
Both servers support it. Jellyfin includes it for free; Plex makes it part of Plex Pass, its paid subscription.
The catch: hardware only helps with the codecs it supports. An older chip without HEVC support still has to decode an HEVC file on the CPU, and decoding is a large part of the work. Newer Intel integrated graphics, or a cheap Intel Arc card, handle HEVC and AV1 and can tone-map HDR, which is why they're the usual advice for a Plex or Jellyfin server. On older hardware, the answer is to avoid transcoding 4K at all.
Why something transcodes when you didn't expect it
When a file you expected to direct play transcodes, it's usually one of these:
- The browser can't play HEVC. Browser support depends on the browser, the operating system and the graphics hardware. Safari plays it; others often can't. Most 4K files are HEVC.
- The audio is DTS or TrueHD. No major browser plays DTS, and many TVs and phones can't either. This is usually a direct stream (just the audio converted), which is cheap.
- Picture-based subtitles. If the player can't draw them, the server burns them in, which means a full video transcode, and one of the heaviest kinds. Text subtitles (SRT) don't have this problem.
- A quality limit in the app. Most apps have a maximum streaming quality or bitrate. If it's set below the file's bitrate, the server transcodes down to fit, even at home on a fast network.
Aim for direct play
Transcoding is for when nothing else works. At home, the goal is direct play:
- Use the right app. A native app on the TV or streaming box plays far more than a browser does.
- Set the quality to the maximum or "original" in the app at home, so a bitrate limit doesn't force a transcode.
- Prefer text subtitles when there's a choice.
- Keep transcoding for remote viewing and odd devices, where a smaller stream is the point.
To see what's happening, start the video and open the server's dashboard. Both Plex and Jellyfin show each active stream and whether it's direct playing, direct streaming or transcoding.