mirror of
https://github.com/mpv-player/mpv
synced 2024-11-03 03:19:24 +01:00
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).
This commit is contained in:
parent
9746e71efc
commit
89306818bb
@ -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;
|
||||
}
|
||||
|
@ -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())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user