diff options
-rw-r--r-- | DOCS/man/vo.rst | 9 | ||||
-rw-r--r-- | test/gl_video.c | 42 | ||||
-rw-r--r-- | test/test_helpers.h | 4 | ||||
-rw-r--r-- | video/out/gl_video.c | 26 | ||||
-rw-r--r-- | video/out/gl_video.h | 5 | ||||
-rw-r--r-- | video/out/vo_opengl.c | 17 |
6 files changed, 103 insertions, 0 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index 317aea14aa..1778577d64 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -543,6 +543,15 @@ Available video output drivers are: 0.8 Pitch black room + ``gamma-auto`` + Automatically corrects the gamma value depending on ambient lighting + conditions (adding a gamma boost for dark rooms). + + With ambient illuminance of 64lux, mpv will pick the 1.0 gamma value + (no boost), and slightly increase the boost up until 0.8 for 16lux. + + NOTE: Only implemented on OS X. + ``icc-profile=<file>`` Load an ICC profile and use it to transform linear RGB to screen output. Needs LittleCMS 2 support compiled in. This option overrides the ``srgb`` diff --git a/test/gl_video.c b/test/gl_video.c new file mode 100644 index 0000000000..543ff2e295 --- /dev/null +++ b/test/gl_video.c @@ -0,0 +1,42 @@ +#include "test_helpers.h" +#include "video/out/gl_video.h" + +static void test_scale_ambient_lux_limits(void **state) { + float x; + x = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, 16.0); + assert_double_equal(x, 2.40f); + + x = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, 64.0); + assert_double_equal(x, 1.961f); +} + +static void test_scale_ambient_lux_sign(void **state) { + float x; + x = gl_video_scale_ambient_lux(16.0, 64.0, 1.961, 2.40, 64.0); + assert_double_equal(x, 2.40f); +} + +static void test_scale_ambient_lux_clamping(void **state) { + float x; + x = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, 0.0); + assert_double_equal(x, 2.40f); +} + +static void test_scale_ambient_lux_log10_midpoint(void **state) { + float x; + // 32 corresponds to the the midpoint after converting lux to the log10 scale + x = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, 32.0); + float mid_gamma = (2.40 - 1.961) / 2 + 1.961; + assert_double_equal(x, mid_gamma); +} + +int main(void) { + const UnitTest tests[] = { + unit_test(test_scale_ambient_lux_limits), + unit_test(test_scale_ambient_lux_sign), + unit_test(test_scale_ambient_lux_clamping), + unit_test(test_scale_ambient_lux_log10_midpoint), + }; + return run_tests(tests); +} + diff --git a/test/test_helpers.h b/test/test_helpers.h index 3dfe08fdbe..7a61da82ea 100644 --- a/test/test_helpers.h +++ b/test/test_helpers.h @@ -7,5 +7,9 @@ #include <cmocka.h> #include <stdio.h> +#include <math.h> +#include <float.h> + +#define assert_double_equal(a, b) assert_true(fabs(a - b) <= DBL_EPSILON) #endif diff --git a/video/out/gl_video.c b/video/out/gl_video.c index f1ea03ed80..7420d9d4d1 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -355,6 +355,7 @@ static int validate_scaler_opt(struct mp_log *log, const m_option_t *opt, const struct m_sub_options gl_video_conf = { .opts = (const m_option_t[]) { OPT_FLOATRANGE("gamma", gamma, 0, 0.1, 2.0), + OPT_FLAG("gamma-auto", gamma_auto, 0), OPT_FLAG("srgb", srgb, 0), OPT_FLAG("npot", npot, 0), OPT_FLAG("pbo", pbo, 0), @@ -2564,6 +2565,31 @@ void gl_video_resize_redraw(struct gl_video *p, int w, int h) gl_video_render_frame(p, 0, NULL); } +float gl_video_scale_ambient_lux(float lmin, float lmax, + float rmin, float rmax, float lux) +{ + assert(lmax > lmin); + + float num = (rmax - rmin) * (log10(lux) - log10(lmin)); + float den = log10(lmax) - log10(lmin); + float result = num / den + rmin; + + // clamp the result + float max = MPMAX(rmax, rmin); + float min = MPMIN(rmax, rmin); + return MPMAX(MPMIN(result, max), min); +} + +void gl_video_set_ambient_lux(struct gl_video *p, int lux) +{ + if (p->opts.gamma_auto) { + float gamma = gl_video_scale_ambient_lux(16.0, 64.0, 2.40, 1.961, lux); + MP_INFO(p, "ambient light changed: %dlux (gamma: %f)\n", lux, gamma); + p->opts.gamma = MPMIN(1.0, 1.961 / gamma); + gl_video_eq_update(p); + } +} + void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec) { p->hwdec = hwdec; diff --git a/video/out/gl_video.h b/video/out/gl_video.h index 74a8b7fd93..8c273faa9e 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -35,6 +35,7 @@ struct gl_video_opts { float scaler_radius[2]; float scaler_antiring[2]; float gamma; + int gamma_auto; int srgb; int linear_scaling; int fancy_downscaling; @@ -83,6 +84,10 @@ void gl_video_eq_update(struct gl_video *p); void gl_video_set_debug(struct gl_video *p, bool enable); void gl_video_resize_redraw(struct gl_video *p, int w, int h); +float gl_video_scale_ambient_lux(float lmin, float lmax, + float rmin, float rmax, float lux); +void gl_video_set_ambient_lux(struct gl_video *p, int lux); + void gl_video_set_gl_state(struct gl_video *p); void gl_video_unset_gl_state(struct gl_video *p); void gl_video_reset(struct gl_video *p); diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index a9435eeac2..9318914dbd 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -276,6 +276,19 @@ static bool get_and_update_icc_profile(struct gl_priv *p, int *events) return true; } +static void get_and_update_ambient_lighting(struct gl_priv *p, int *events) +{ + int lux; + int r = p->glctx->vo_control(p->vo, events, VOCTRL_GET_AMBIENT_LUX, &lux); + if (r == VO_TRUE) { + gl_video_set_ambient_lux(p->renderer, lux); + } + if (r != VO_TRUE && p->renderer_opts->gamma_auto) { + MP_ERR(p, "gamma_auto option provided, but querying for ambient" + " lighting is not supported on this platform\n"); + } +} + static bool reparse_cmdline(struct gl_priv *p, char *args) { struct m_config *cfg = NULL; @@ -390,6 +403,10 @@ static int control(struct vo *vo, uint32_t request, void *data) get_and_update_icc_profile(p, &events); vo->want_redraw = true; } + if (events & VO_EVENT_AMBIENT_LIGHTING_CHANGED) { + get_and_update_ambient_lighting(p, &events); + vo->want_redraw = true; + } if (events & VO_EVENT_RESIZE) resize(p); if (events & VO_EVENT_EXPOSE) |