mediacodec.dev

Why your video looks washed out

Everybody hits this once: an export that looked right in the editor arrives flat, foggy, or faintly green. Nothing was lost in compression. The file simply described its colour one way and the player read it another. Here is that bug, on demand, with the damage measured.

encoded as BT.709, limited range, the way a camera or encoder writes it. Below is what the player believes.

Decoder's matrix

BT.601

SD, and what old tools assume

Decoder's range

0 to 255

Assumes the levels are already full: blacks lift, whites dull, and the picture goes flat.

As encodedBT.601 · full

the test card · 640×360 · drag the divider · left is the file as encoded

bars and skin tones make the shift obvious

Try your own image: drop one here, or

Files are processed in this tab and never uploaded.

Two separate bugs that look alike

Video does not store RGB. It stores luma and two colour-difference channels, and turning those back into pixels needs two pieces of information the file is supposed to carry: which matrix was used, and which range the numbers occupy. Get either wrong and the picture is still perfectly decodable, just wrong, which is why the bug survives so long unnoticed.

A range mismatch is a contrast problem. Video normally uses studio swing, where black sits at 16 and white at 235, leaving headroom for overshoot. A player that assumes the numbers already fill 0 to 255 does no expansion, so black arrives as dark grey and white as dull grey. That is the classic washed-out look, and the grey ramp on the test card shows it plainly.

A matrix mismatch is a hue problem. BT.601 was built for standard definition and BT.709 for HD, and they weight red, green and blue differently. Decode 709 content as 601 and brightness stays about right while colours skew, greens and reds most of all. Skin tones give it away first, which is why the card puts a row of them next to the bars.

Where it comes from

Almost always, a file that never said. The matrix and range live in metadata that some encoders omit, and when it is missing every player guesses: many assume BT.601 for anything standard-definition-sized and BT.709 above it, so the same file can look different in two applications. Screen recorders, older editing tools and hand-rolled FFmpeg pipelines are the usual sources.

The fix is to be explicit rather than lucky. Tag the output with -colorspace, -color_primaries, -color_trc and -color_range so nothing has to guess, and if a file is already wrong, convert it deliberately instead of reinterpreting it. The colour spaces article works through the flags and the diagnosis in full.