summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/vo.rst9
-rw-r--r--test/gl_video.c42
-rw-r--r--test/test_helpers.h4
-rw-r--r--video/out/gl_video.c26
-rw-r--r--video/out/gl_video.h5
-rw-r--r--video/out/vo_opengl.c17
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)