mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.08k stars 2.88k forks source link

Tone Mapping: target-contrast != inf reduces saturation on dark images #12707

Open FoLLgoTT opened 11 months ago

FoLLgoTT commented 11 months ago

Important Information

Provide following Information:

Reproduction steps

When using a target-contrast != inf dark scenes get desaturated on HDR content. Especially scenes which have no highlights. It seems to affect all tone mapping algorithms.

Example scenes:

"Parasite" (1:30:45)

target-contrast=1000: target-constrast=1000 Screenshot 2023-10-21 182752

target-contrast=inf: target-constrast=inf

Another example is "Jurassic World 2" chapter 3 (begins with a panning over a dark wood). I compared to madVR and tone-mapping 3D LUT created by DisplayCAL and they look more saturated in these scenes (similar to target-contrast=inf).

Expected behavior

Saturation should be preserved.

Actual behavior

Desaturated picture.

Log file

target-contrast=1000 target-contrast=1000.txt

target-contrast=inf target-contrast=inf.txt

haasn commented 11 months ago

Does this patch help?

diff --git a/src/shaders/colorspace.c b/src/shaders/colorspace.c
index 997ffc1f..0b24f50c 100644
--- a/src/shaders/colorspace.c
+++ b/src/shaders/colorspace.c
@@ -1967,9 +1967,9 @@ void pl_shader_color_map_ex(pl_shader sh, const struct pl_color_map_params *para
         // Avoid raising saturation excessively when raising brightness, and
         // also desaturate when reducing brightness greatly to account for the
         // reduction in gamut volume.
-        GLSL("vec2 hull = vec2(i_orig, ipt.x);                  \n"
-             "hull = ((hull - 6.0) * hull + 9.0) * hull;        \n"
-             "ipt.yz *= min(i_orig / ipt.x, hull.y / hull.x);   \n");
+        GLSL("vec2 hull = vec2(i_orig, ipt.x);              \n"
+             "hull = ((hull - 6.0) * hull + 9.0) * hull;    \n"
+             "ipt.yz *= min(1.0, hull.y / hull.x);          \n");
     }

     if (need_gamut_map) {

See also: https://code.videolan.org/videolan/libplacebo/-/issues/280, which this code was originally introduced to fix. It's possible that there may be some subjective disagreement here about how the result should look.

haasn commented 11 months ago

cc @nevcairiel

haasn commented 11 months ago

I made an example screenshot comparing the effects of the above patch on the frame from the original issue. These are designed for an absolute HDR display (e.g. OLED), so viewing them on a typical SDR monitor will produce wrong results.

HDR reference

orient-hdr

1000:1 emulation, linear desaturation (current)

orient-1000

1000:1 emulation, no desaturation (above patch)

orient-1000-saturate

1000:1 emulation, gamut hull desaturation (possible slight refinement)

orient-1000-hull

Let me know what you think. If you can exact the above frame I can throw up a comparison for it as well.

haasn commented 11 months ago

From my own testing, it seems that disabling this desaturation completely produces the best visual match between the HDR and SDR versions, for me.

I also noticed that, for some reason, the spline TM function produces horrible black clipping when you raise the black point significantly above 0.2 nits. I should investigate and fix this.

FoLLgoTT commented 11 months ago

Does this patch help?

I have to check if I get MPV compiled (never did this before). But when I look at the screenshots in your link I think the problem is now the other way around. Maybe saturation is overcompensated on very dark shots now.

It's possible that there may be some subjective disagreement here about how the result should look.

Maybe. But I have a comparison to the SDR Blu-ray. Saturation looks more like the "inf" version (or like madVR or DisplayCAL LUT).

SDR (Blu-ray): mpv-shot0001

If you can exact the above frame I can throw up a comparison for it as well.

Of course. Here it is. :)

https://github.com/mpv-player/mpv/assets/95616074/40b8cf74-2e68-43b9-b10f-c4d0f596de60

FoLLgoTT commented 11 months ago

Here is another sample. Using ST2094-40 converts the picture nearly to black and white.

https://github.com/mpv-player/mpv/assets/95616074/e5a32b26-e8df-465f-a8a1-b111b6fbee7e

FoLLgoTT commented 11 months ago

And here is how the Blu-ray (SDR) looks like:

blu-ray

FoLLgoTT commented 11 months ago

@haasn

Does this patch help?

I reverted that patch and recompiled and saturation looks fine now. This piece of code is responsible for the described effect in dark scenes.

haasn commented 11 months ago

I did some extensive testing with a 'low contrast monitor simulation' mode (in plplay) and came to the conclusion that the current default behavior does reduce saturation too much. However, the reverted behavior doesn't look quite right either, in particular with regards to skin tones. Maybe some middle ground would be the best.

I could also try disabling black point management during tone mapping completely in favor of always doing linear black point stretching, but I'm not a huge fan of this.

FoLLgoTT commented 11 months ago

However, the reverted behavior doesn't look quite right either, in particular with regards to skin tones.

Do you have some examples (movie and timestamp)?

I could also try disabling black point management during tone mapping completely in favor of always doing linear black point stretching, but I'm not a huge fan of this.

Is this equivalent to target-contrast=inf? If yes, I also don't prefer that either. The image looks less contrasty and flat in many cases.

Nevcairiel commented 11 months ago

Check the sample from Murder on the Orient Express in the original ticket (https://code.videolan.org/videolan/libplacebo/-/issues/280), the skin tones seem unnaturally red in that one, which prompted the original adjustment.