Manatee

10-bit, HDR and the video that looks washed out after converting

You convert a video and the copy looks wrong. Not broken, just flat: greys where blacks should be, muted colour, sometimes a green or magenta cast. The source looked fine.

Nothing is damaged. The conversion carried the picture across and lost the instructions for interpreting it.

What colour information a video carries

A video file stores numbers describing each pixel, and separately stores metadata saying how those numbers should be interpreted: which primaries define the colours, what transfer curve maps stored values to brightness, and what range the values occupy.

Get the same picture data with different metadata and it renders differently. That is the whole problem.

Look at what your files claim:

ffprobe -v error -select_streams v:0 \
  -show_entries stream=pix_fmt,color_space,color_transfer,color_primaries,color_range \
  -of default=noprint_wrappers=1 source.mov

Run it on the source and on the washed-out output, and compare. The fields that matter:

  • color_transfer=smpte2084 or arib-std-b67 means HDR. bt709 means standard.
  • color_primaries=bt2020 means a wide gamut. bt709 means standard.
  • color_range=tv means limited range (16 to 235). pc means full range (0 to 255).

A difference between source and output in any of these explains the appearance.

The most common cause: HDR converted as if it were not

Phone and camera footage is increasingly HDR, recorded with a transfer curve designed for displays that can show a much wider brightness range.

Convert that to a standard format without telling the encoder what the source was, and the HDR values get treated as standard ones. The result looks desaturated and flat, because the picture was encoded expecting a display that would expand it, and nothing does.

Converting properly means tone mapping: deliberately compressing the wide brightness range into the narrow one, rather than reinterpreting the numbers and hoping.

ffmpeg -i hdr-source.mov \
  -vf "zscale=t=linear:npl=100,format=gbrpf32le,\
zscale=p=bt709,tonemap=hable:desat=0,\
zscale=t=bt709:m=bt709:r=tv,format=yuv420p" \
  -c:v libx264 -crf 20 -preset medium -c:a copy sdr-output.mp4

That is a mouthful, and each stage matters: convert to linear light, tone map with an algorithm that handles highlights gracefully, then convert back into standard colour space and range. hable is a good general choice; reinhard is an alternative that behaves differently in the highlights.

If your ffmpeg lacks zscale, a simpler approximation:

ffmpeg -i hdr-source.mov -vf "format=yuv420p,colorspace=all=bt709:iall=bt2020nc:fast=1" \
  -c:v libx264 -crf 20 -c:a copy sdr-output.mp4

Less refined, and much better than no conversion at all.

The second cause: range mismatch

Video traditionally uses limited range, where black is 16 and white is 235 rather than 0 and 255. Computer graphics use full range.

Mislabel one as the other and you get one of two symptoms. Full-range content interpreted as limited looks washed out, with grey blacks. Limited-range content interpreted as full looks crushed, with clipped shadows and blown highlights.

Force the interpretation to match the source:

ffmpeg -i source.mov -vf "scale=in_range=full:out_range=tv" \
  -c:v libx264 -crf 20 -c:a copy output.mp4

Screen recordings are the usual source of this, since they capture computer graphics in full range and then get encoded as video.

The third cause: metadata dropped in a stream copy

A copy that does not re-encode can still lose colour metadata, because the tags live in the container rather than the stream:

ffmpeg -i source.mov -c copy output.mp4                                    # may drop tags
ffmpeg -i source.mov -c copy -movflags use_metadata_tags -map_metadata 0 output.mp4   # keeps them

If your file looks wrong after a conversion that should not have touched the picture at all, this is why. The pixels are identical and the instructions went missing.

You can also write the tags back explicitly without re-encoding:

ffmpeg -i output.mp4 -c copy -color_primaries bt2020 -color_trc smpte2084 \
  -colorspace bt2020nc fixed.mp4

That is the right fix when you know what the source was and the output simply failed to record it.

Deciding what you actually want

Worth being deliberate, because “keep the HDR” and “make it look right everywhere” are different goals.

Keeping HDR means staying in HEVC with the metadata intact, and accepting that displays and players without HDR support will show it incorrectly.

Converting to standard means tone mapping once, properly, and getting a file that looks right on everything. For anything being shared, this is usually the correct choice.

The failure mode people hit is doing neither: converting to a standard format while carrying HDR values across unchanged, which produces a file that looks wrong everywhere.

Manatee handles the colour metadata when converting, so the common version of this problem does not arise, and it does the work on the Mac rather than uploading footage. It works from a duplicate, so the original stays exactly as it is while you check whether the converted version looks right. Why compressing a video twice makes it look worse is worth reading before converting an already-converted file, since each pass compounds.

Questions

It looks fine on my Mac and wrong on a phone. Different displays and players interpret missing metadata differently. A file with correct tags looks consistent; a file relying on a player’s guess does not.

The video looks too dark rather than washed out. Usually the reverse range mismatch: limited-range content interpreted as full. Swap the in_range and out_range values in the command above.

Should I record in HDR at all? If you are delivering to somewhere that supports it, yes. For everyday recording that ends up in messages and documents, standard recording avoids this entire category of problem.

Can I fix a washed-out file without the original? Partly. You can grade it back towards where it should be, and you cannot recover the highlight information the bad conversion discarded. Converting again from the original is always better if you still have it.