summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2015-02-03 18:16:02 +0100
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2015-03-04 10:06:08 +0100
commit89306818bb3d2f6942e3cb6bb6c0ce01e7f7f65c (patch)
treeab059803ffbc646df379b1e8853f644cf291c7fb
parent9746e71efc36363f0b007fb73d886d5d35b5671a (diff)
downloadmpv-89306818bb3d2f6942e3cb6bb6c0ce01e7f7f65c.tar.bz2
mpv-89306818bb3d2f6942e3cb6bb6c0ce01e7f7f65c.tar.xz
cocoa: add support for querying ambient lighting
This will be pretty useful to let mpv automatically change VO parameters based on ambient lighting conditions. The conversion code and polinomial equation from Apple LMU values to Lux is taken from Firefox: their license, MPL is GPL compatible and allows relicensing to GPL (MPL is more liberal).
-rw-r--r--video/out/cocoa_common.m94
-rw-r--r--video/out/vo.h3
2 files changed, 97 insertions, 0 deletions
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m
index 4e3c461eaa..027fd313e5 100644
--- a/video/out/cocoa_common.m
+++ b/video/out/cocoa_common.m
@@ -20,6 +20,8 @@
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h> // for CGDisplayHideCursor
#import <IOKit/pwr_mgt/IOPMLib.h>
+#import <IOKit/IOKitLib.h>
+#include <mach/mach.h>
#import "cocoa_common.h"
#import "video/out/cocoa/window.h"
@@ -73,6 +75,10 @@ struct vo_cocoa_state {
bool embedded; // wether we are embedding in another GUI
IOPMAssertionID power_mgmt_assertion;
+ io_connect_t light_sensor;
+ uint64_t last_lmuvalue;
+ int last_lux;
+ IONotificationPortRef light_sensor_io_port;
pthread_mutex_t mutex;
struct mp_log *log;
@@ -146,6 +152,87 @@ static void set_application_icon(NSApplication *app)
[pool release];
}
+static int lmuvalue_to_lux(uint64_t v)
+{
+ // the polinomial approximation for apple lmu value -> lux was empirically
+ // derived by firefox developers (Apple provides no documentation).
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=793728
+ double power_c4 = 1/pow((double)10,27);
+ double power_c3 = 1/pow((double)10,19);
+ double power_c2 = 1/pow((double)10,12);
+ double power_c1 = 1/pow((double)10,5);
+
+ double term4 = -3.0 * power_c4 * pow(v,4);
+ double term3 = 2.6 * power_c3 * pow(v,3);
+ double term2 = -3.4 * power_c2 * pow(v,2);
+ double term1 = 3.9 * power_c1 * v;
+
+ int lux = ceil(term4 + term3 + term2 + term1 - 0.19);
+ return lux > 0 ? lux : 0;
+}
+
+static void light_sensor_cb(void *ctx, io_service_t srv, natural_t mtype, void *msg)
+{
+ struct vo *vo = ctx;
+ struct vo_cocoa_state *s = vo->cocoa;
+ uint32_t outputs = 2;
+ uint64_t values[outputs];
+
+ kern_return_t kr = IOConnectCallMethod(
+ s->light_sensor, 0, NULL, 0, NULL, 0, values, &outputs, nil, 0);
+
+ if (kr == KERN_SUCCESS) {
+ uint64_t mean = (values[0] + values[1]) / 2;
+ if (s->last_lmuvalue != mean) {
+ s->last_lmuvalue = mean;
+ s->last_lux = lmuvalue_to_lux(s->last_lmuvalue);
+ s->pending_events |= VO_EVENT_AMBIENT_LIGHTING_CHANGED;
+ vo_wakeup(vo);
+ return;
+ }
+ }
+}
+
+static void cocoa_init_light_sensor(struct vo *vo)
+{
+ with_cocoa_lock_on_main_thread(vo, ^{
+ struct vo_cocoa_state *s = vo->cocoa;
+ io_service_t srv = IOServiceGetMatchingService(
+ kIOMasterPortDefault, IOServiceMatching("AppleLMUController"));
+ if (srv == IO_OBJECT_NULL) {
+ MP_VERBOSE(vo, "can't find an ambient light sensor\n");
+ return;
+ }
+
+ // subscribe to notifications from the light sensor driver
+ s->light_sensor_io_port = IONotificationPortCreate(kIOMasterPortDefault);
+ IONotificationPortSetDispatchQueue(
+ s->light_sensor_io_port, dispatch_get_main_queue());
+
+ io_object_t n;
+ IOServiceAddInterestNotification(
+ s->light_sensor_io_port, srv, kIOGeneralInterest, light_sensor_cb,
+ vo, &n);
+
+ kern_return_t kr = IOServiceOpen(srv, mach_task_self(), 0,
+ &s->light_sensor);
+ IOObjectRelease(srv);
+ if (kr != KERN_SUCCESS) {
+ MP_WARN(vo, "can't start ambient light sensor connection\n");
+ return;
+ }
+
+ light_sensor_cb(vo, 0, 0, NULL);
+ });
+}
+
+static void cocoa_uninit_light_sensor(struct vo *vo)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ IONotificationPortDestroy(s->light_sensor_io_port);
+ IOObjectRelease(s->light_sensor);
+}
+
int vo_cocoa_init(struct vo *vo)
{
struct vo_cocoa_state *s = talloc_zero(vo, struct vo_cocoa_state);
@@ -156,6 +243,7 @@ int vo_cocoa_init(struct vo *vo)
.embedded = vo->opts->WinID >= 0,
};
mpthread_mutex_init_recursive(&s->mutex);
+ cocoa_init_light_sensor(vo);
vo->cocoa = s;
return 1;
}
@@ -199,6 +287,7 @@ void vo_cocoa_uninit(struct vo *vo)
with_cocoa_lock_on_main_thread(vo, ^{
enable_power_management(vo);
+ cocoa_uninit_light_sensor(vo);
cocoa_rm_fs_screen_profile_observer(vo);
[s->gl_ctx release];
@@ -676,6 +765,11 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
*(double *)arg = vo->cocoa->screen_fps;
return VO_TRUE;
}
+ case VOCTRL_GET_AMBIENT_LUX:
+ if (vo->cocoa->light_sensor != IO_OBJECT_NULL) {
+ *(int *)arg = vo->cocoa->last_lux;
+ return VO_TRUE;
+ }
}
return VO_NOTIMPL;
}
diff --git a/video/out/vo.h b/video/out/vo.h
index a531744c49..f1adbc0908 100644
--- a/video/out/vo.h
+++ b/video/out/vo.h
@@ -38,6 +38,8 @@
#define VO_EVENT_ICC_PROFILE_CHANGED 4
// Some other window state changed
#define VO_EVENT_WIN_STATE 8
+// The ambient light conditions changed and need to be reloaded
+#define VO_EVENT_AMBIENT_LIGHTING_CHANGED 16
// Set of events the player core may be interested in.
#define VO_EVENTS_USER (VO_EVENT_RESIZE | VO_EVENT_WIN_STATE)
@@ -103,6 +105,7 @@ enum mp_voctrl {
VOCTRL_SET_COMMAND_LINE, // char**
VOCTRL_GET_ICC_PROFILE, // bstr*
+ VOCTRL_GET_AMBIENT_LUX, // int*
VOCTRL_GET_DISPLAY_FPS, // double*
VOCTRL_GET_RECENT_FLIP_TIME, // int64_t* (using mp_time_us())