diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 4a36041595..a3539c156e 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -37,6 +37,9 @@ Interface changes - add an additional optional `albumart` argument to the `video-add` command, which tells mpv to load the given video as album art. - undeprecate `--cache-secs` option + - remove `--icc-contrast` and introduce `--icc-force-contrast`. The latter + defaults to the equivalent of the old `--icc-contrast=inf`, and can + instead be used to specifically set the contrast to any value. --- mpv 0.33.0 --- - add `--d3d11-exclusive-fs` flag to enable D3D11 exclusive fullscreen mode when the player enters fullscreen. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index e07f7a7851..f8f20d6e32 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6358,14 +6358,15 @@ The following video options are currently all specific to ``--vo=gpu`` and Size of the 3D LUT generated from the ICC profile in each dimension. Default is 64x64x64. Sizes may range from 2 to 512. -``--icc-contrast=<0-1000000|inf>`` - Specifies an upper limit on the target device's contrast ratio. This is - detected automatically from the profile if possible, but for some profiles - it might be missing, causing the contrast to be assumed as infinite. As a - result, video may appear darker than intended. This only affects BT.1886 - content. The default of 0 means no limit if the detected contrast is less - than 100000, and limits to 1000 otherwise. Use ``--icc-contrast=inf`` to - preserve the infinite contrast (most likely when using OLED displays). +``--icc-force-contrast=`` + Override the target device's detected contrast ratio by a specific value. + This is detected automatically from the profile if possible, but for some + profiles it might be missing, causing the contrast to be assumed as + infinite. As a result, video may appear darker than intended. If this is + the case, setting this option might help. This only affects BT.1886 + content. The default of ``no`` means to use the profile values. The special + value ``inf`` causes the BT.1886 curve to be treated as a pure power gamma + 2.4 function. ``--blend-subtitles=`` Blend subtitles directly onto upscaled video frames, before interpolation diff --git a/video/out/gpu/lcms.c b/video/out/gpu/lcms.c index 894506973b..704f1fbf1d 100644 --- a/video/out/gpu/lcms.c +++ b/video/out/gpu/lcms.c @@ -84,11 +84,12 @@ const struct m_sub_options mp_icc_conf = { {"icc-profile-auto", OPT_FLAG(profile_auto)}, {"icc-cache-dir", OPT_STRING(cache_dir), .flags = M_OPT_FILE}, {"icc-intent", OPT_INT(intent)}, - {"icc-contrast", OPT_CHOICE(contrast, {"inf", -1}), + {"icc-force-contrast", OPT_CHOICE(contrast, {"no", 0}, {"inf", -1}), M_RANGE(0, 1000000)}, {"icc-3dlut-size", OPT_STRING_VALIDATE(size_str, validate_3dlut_size_opt)}, {"3dlut-size", OPT_REPLACED("icc-3dlut-size")}, {"icc-cache", OPT_REMOVED("see icc-cache-dir")}, + {"icc-contrast", OPT_REMOVED("see icc-force-contrast")}, {0} }, .size = sizeof(struct mp_icc_opts), @@ -272,48 +273,46 @@ static cmsHPROFILE get_vid_profile(struct gl_lcms *p, cmsContext cms, break; case MP_CSP_TRC_BT_1886: { - // To build an appropriate BT.1886 transformation we need access to - // the display's black point, so we LittleCMS' detection function. - // Relative colorimetric is used since we want to approximate the - // BT.1886 to the target device's actual black point even in e.g. - // perceptual mode - const int intent = MP_INTENT_RELATIVE_COLORIMETRIC; - cmsCIEXYZ bp_XYZ; - if (!cmsDetectBlackPoint(&bp_XYZ, disp_profile, intent, 0)) - return false; - - // Map this XYZ value back into the (linear) source space - cmsToneCurve *linear = cmsBuildGamma(cms, 1.0); - cmsHPROFILE rev_profile = cmsCreateRGBProfileTHR(cms, &wp_xyY, &prim_xyY, - (cmsToneCurve*[3]){linear, linear, linear}); - cmsHPROFILE xyz_profile = cmsCreateXYZProfile(); - cmsHTRANSFORM xyz2src = cmsCreateTransformTHR(cms, - xyz_profile, TYPE_XYZ_DBL, rev_profile, TYPE_RGB_DBL, - intent, 0); - cmsFreeToneCurve(linear); - cmsCloseProfile(rev_profile); - cmsCloseProfile(xyz_profile); - if (!xyz2src) - return false; - double src_black[3]; - cmsDoTransform(xyz2src, &bp_XYZ, src_black, 1); - cmsDeleteTransform(xyz2src); - - // Contrast limiting - if (p->opts->contrast > 0) { + if (p->opts->contrast < 0) { + // User requested infinite contrast, return 2.4 profile + tonecurve[0] = cmsBuildGamma(cms, 2.4); + break; + } else if (p->opts->contrast > 0) { + MP_VERBOSE(p, "Using specified contrast: %d\n", p->opts->contrast); for (int i = 0; i < 3; i++) - src_black[i] = MPMAX(src_black[i], 1.0 / p->opts->contrast); - } + src_black[i] = 1.0 / p->opts->contrast; + } else { + // To build an appropriate BT.1886 transformation we need access to + // the display's black point, so we use LittleCMS' detection + // function. Relative colorimetric is used since we want to + // approximate the BT.1886 to the target device's actual black + // point even in e.g. perceptual mode + const int intent = MP_INTENT_RELATIVE_COLORIMETRIC; + cmsCIEXYZ bp_XYZ; + if (!cmsDetectBlackPoint(&bp_XYZ, disp_profile, intent, 0)) + return false; - // Built-in contrast failsafe - double contrast = 3.0 / (src_black[0] + src_black[1] + src_black[2]); - MP_VERBOSE(p, "Detected ICC profile contrast: %f\n", contrast); - if (contrast > 100000 && !p->opts->contrast) { - MP_WARN(p, "ICC profile detected contrast very high (>100000)," - " falling back to contrast 1000 for sanity. Set the" - " icc-contrast option to silence this warning.\n"); - src_black[0] = src_black[1] = src_black[2] = 1.0 / 1000; + // Map this XYZ value back into the (linear) source space + cmsHPROFILE rev_profile; + cmsToneCurve *linear = cmsBuildGamma(cms, 1.0); + rev_profile = cmsCreateRGBProfileTHR(cms, &wp_xyY, &prim_xyY, + (cmsToneCurve*[3]){linear, linear, linear}); + cmsHPROFILE xyz_profile = cmsCreateXYZProfile(); + cmsHTRANSFORM xyz2src = cmsCreateTransformTHR(cms, + xyz_profile, TYPE_XYZ_DBL, rev_profile, TYPE_RGB_DBL, + intent, 0); + cmsFreeToneCurve(linear); + cmsCloseProfile(rev_profile); + cmsCloseProfile(xyz_profile); + if (!xyz2src) + return false; + + cmsDoTransform(xyz2src, &bp_XYZ, src_black, 1); + cmsDeleteTransform(xyz2src); + + double contrast = 3.0 / (src_black[0] + src_black[1] + src_black[2]); + MP_VERBOSE(p, "Detected ICC profile contrast: %f\n", contrast); } // Build the parametric BT.1886 transfer curve, one per channel