VLC_ADD_LDFLAGS([mkv mp4], [-framework IOKit -framework CoreFoundation])
VLC_ADD_CFLAGS([libvlc vlc],[-x objective-c])
VLC_ADD_LDFLAGS([vlc],[-undefined dynamic_lookup])
+ VLC_ADD_LDFLAGS([motion],[-framework IOKit -framework CoreFoundation])
AC_ARG_ENABLE(macosx-defaults,
[ --enable-macosx-defaults Build the default configuration on Mac OS X (default enabled)])
if test "x${enable_macosx_defaults}" != "xno"
] )
])
-
dnl
dnl A52/AC3 decoder plugin
dnl
SOURCES_hotkeys = hotkeys.c
SOURCES_lirc = lirc.c
SOURCES_rc = rc.c
-SOURCES_motion = motion.c
SOURCES_dbus = dbus.c dbus.h
+if HAVE_DARWIN
+motion_extra = unimotion.c unimotion.h
+else
+motion_extra = $(NULL)
+endif
+SOURCES_motion = \
+ motion.c \
+ $(motion_extra) \
+ $(NULL)
+
/*****************************************************************************
* motion.c: control VLC with laptop built-in motion sensors
*****************************************************************************
- * Copyright (C) 2006 the VideoLAN team
+ * Copyright (C) 2006 - 2007 the VideoLAN team
* $Id$
*
* Author: Sam Hocevar <sam@zoy.org>
+ * Jérôme Decoodt <djc@videolan.org> (unimotion integration)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
+#include <math.h>
#include <vlc/vlc.h>
#include <vlc_interface.h>
# include <unistd.h>
#endif
+#ifdef __APPLE__
+#include "unimotion.h"
+#endif
+
/*****************************************************************************
* intf_sys_t: description and status of interface
*****************************************************************************/
struct intf_sys_t
{
- enum { NO_SENSOR, HDAPS_SENSOR, AMS_SENSOR } sensor;
+ enum { NO_SENSOR, HDAPS_SENSOR, AMS_SENSOR, UNIMOTION_SENSOR } sensor;
+ enum sms_hardware unimotion_hw;
int i_calibrate;
/* Apple Motion Sensor support */
p_intf->p_sys->sensor = AMS_SENSOR;
}
+#ifdef __APPLE__
+ else if( p_intf->p_sys->unimotion_hw = detect_sms() )
+ p_intf->p_sys->sensor = UNIMOTION_SENSOR;
+#endif
else
{
/* No motion sensor support */
/*****************************************************************************
* RunIntf: main loop
*****************************************************************************/
+#define FILTER_LENGTH 16
+#define LOW_THRESHOLD 800
+#define HIGH_THRESHOLD 1000
static void RunIntf( intf_thread_t *p_intf )
{
- int i_x, i_oldx = 0;
+ int i_x, i_oldx = 0, i_sum = 0, i = 0;
+ int p_oldx[FILTER_LENGTH];
+ memset( p_oldx, 0, FILTER_LENGTH * sizeof( int ) );
while( !intf_ShouldDie( p_intf ) )
{
-#define LOW_THRESHOLD 80
-#define HIGH_THRESHOLD 100
vout_thread_t *p_vout;
const char *psz_filter, *psz_type;
vlc_bool_t b_change = VLC_FALSE;
msleep( INTF_IDLE_SLEEP );
i_x = GetOrientation( p_intf );
+ i_sum += i_x - p_oldx[i];
+ p_oldx[i++] = i_x;
+ if( i == FILTER_LENGTH ) i = 0;
+ i_x = i_sum / FILTER_LENGTH;
if( p_intf->p_sys->b_use_rotate )
{
vlc_object_find_name( p_intf->p_libvlc, "rotate", FIND_CHILD );
if( p_obj )
{
- var_SetInteger( p_obj, "rotate-angle",((360+i_x/2)%360) );
+ var_SetInteger( p_obj, "rotate-deciangle",
+ ((3600+i_x/2)%3600) );
i_oldx = i_x;
vlc_object_release( p_obj );
}
i_oldx = i_x;
}
}
+#undef FILTER_LENGTH
+#undef LOW_THRESHOLD
+#undef HIGH_THRESHOLD
/*****************************************************************************
- * GetOrientation: get laptop orientation, range -180 / +180
+ * GetOrientation: get laptop orientation, range -1800 / +1800
*****************************************************************************/
static int GetOrientation( intf_thread_t *p_intf )
{
FILE *f;
- int i_x, i_y;
+ int i_x, i_y, i_z;
switch( p_intf->p_sys->sensor )
{
fscanf( f, "(%d,%d)", &i_x, &i_y );
fclose( f );
- return i_x - p_intf->p_sys->i_calibrate;
+ return ( i_x - p_intf->p_sys->i_calibrate ) * 10;
case AMS_SENSOR:
f = fopen( "/sys/devices/ams/x", "r" );
fscanf( f, "%d", &i_x);
fclose( f );
- return - i_x * 3; /* FIXME: arbitrary */
-
+ return - i_x * 30; /* FIXME: arbitrary */
+#ifdef __APPLE__
+ case UNIMOTION_SENSOR:
+ if( read_sms_raw( p_intf->p_sys->unimotion_hw, &i_x, &i_y, &i_z ) )
+ {
+ double d_norm = sqrt( i_x*i_x+i_z*i_z );
+ if( d_norm < 100 )
+ return 0;
+ double d_x = i_x / d_norm;
+ if( i_z > 0 )
+ return -asin(d_x)*3600/3.141;
+ else
+ return 3600 + asin(d_x)*3600/3.141;
+ }
+#endif
+ else
+ return 0;
default:
return 0;
}
--- /dev/null
+ /*
+ * UniMotion - Unified Motion detection for Apple portables.
+ *
+ * Copyright (c) 2006 Lincoln Ramsay. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation Inc. 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
+ */
+
+/*
+ * HISTORY of Motion
+ * Written by Christian Klein
+ * Modified for iBook compatibility by Pall Thayer
+ * Modified for Hi Res Powerbook compatibility by Pall Thayer
+ * Modified for MacBook Pro compatibility by Randy Green
+ * Disparate forks unified into UniMotion by Lincoln Ramsay
+ */
+
+// This license applies to the portions created by Cristian Klein.
+/* motion.c
+ *
+ * a little program to display the coords returned by
+ * the powerbook motion sensor
+ *
+ * A fine piece of c0de, brought to you by
+ *
+ * ---===---
+ * *** teenage mutant ninja hero coders ***
+ * ---===---
+ *
+ * All of the software included is copyrighted by Christian Klein <chris@5711.org>.
+ *
+ * Copyright 2005 Christian Klein. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author must not be used to endorse or promote
+ * products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifdef __APPLE__
+
+#include "unimotion.h"
+#include <IOKit/IOKitLib.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <string.h>
+#include <stdint.h>
+
+enum data_type {
+ PB_IB,
+ MBP
+};
+
+struct pb_ib_data {
+ int8_t x;
+ int8_t y;
+ int8_t z;
+ int8_t pad[57];
+};
+
+struct mbp_data {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ int8_t pad[34];
+};
+
+union motion_data {
+ struct pb_ib_data pb_ib;
+ struct mbp_data mbp;
+};
+
+
+static int set_values(int type, int *kernFunc, char **servMatch, int *dataType)
+{
+ switch ( type ) {
+ case powerbook:
+ *kernFunc = 21;
+ *servMatch = "IOI2CMotionSensor";
+ *dataType = PB_IB;
+ break;
+ case ibook:
+ *kernFunc = 21;
+ *servMatch = "IOI2CMotionSensor";
+ *dataType = PB_IB;
+ break;
+ case highrespb:
+ *kernFunc = 21;
+ *servMatch = "PMUMotionSensor";
+ *dataType = PB_IB;
+ break;
+ case macbookpro:
+ *kernFunc = 5;
+ *servMatch = "SMCMotionSensor";
+ *dataType = MBP;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int probe_sms(int kernFunc, char *servMatch, int dataType, void *data)
+{
+ kern_return_t result;
+ mach_port_t masterPort;
+ io_iterator_t iterator;
+ io_object_t aDevice;
+ io_connect_t dataPort;
+
+ IOItemCount structureInputSize;
+ IOByteCount structureOutputSize;
+
+ union motion_data inputStructure;
+ union motion_data *outputStructure;
+
+ outputStructure = (union motion_data *)data;
+
+ result = IOMasterPort(MACH_PORT_NULL, &masterPort);
+
+ CFMutableDictionaryRef matchingDictionary = IOServiceMatching(servMatch);
+
+ result = IOServiceGetMatchingServices(masterPort, matchingDictionary, &iterator);
+
+ if (result != KERN_SUCCESS) {
+ //fputs("IOServiceGetMatchingServices returned error.\n", stderr);
+ return 0;
+ }
+
+ aDevice = IOIteratorNext(iterator);
+ IOObjectRelease(iterator);
+
+ if (aDevice == 0) {
+ //fputs("No motion sensor available\n", stderr);
+ return 0;
+ }
+
+ result = IOServiceOpen(aDevice, mach_task_self(), 0, &dataPort);
+ IOObjectRelease(aDevice);
+
+ if (result != KERN_SUCCESS) {
+ //fputs("Could not open motion sensor device\n", stderr);
+ return 0;
+ }
+
+ switch ( dataType ) {
+ case PB_IB:
+ structureInputSize = sizeof(struct pb_ib_data);
+ structureOutputSize = sizeof(struct pb_ib_data);
+ break;
+ case MBP:
+ structureInputSize = sizeof(struct mbp_data);
+ structureOutputSize = sizeof(struct mbp_data);
+ break;
+ default:
+ return 0;
+ }
+
+ memset(&inputStructure, 0, sizeof(union motion_data));
+ memset(outputStructure, 0, sizeof(union motion_data));
+
+ result = IOConnectMethodStructureIStructureO(dataPort, kernFunc, structureInputSize,
+ &structureOutputSize, &inputStructure, outputStructure);
+
+ IOServiceClose(dataPort);
+
+ if (result != KERN_SUCCESS) {
+ //puts("no coords");
+ return 0;
+ }
+ return 1;
+}
+
+int detect_sms()
+{
+ int kernFunc;
+ char *servMatch;
+ int dataType;
+ union motion_data data;
+ int i;
+
+ for ( i = 1; ; i++ ) {
+ if ( !set_values(i, &kernFunc, &servMatch, &dataType) )
+ break;
+ if ( probe_sms(kernFunc, servMatch, dataType, &data) )
+ return i;
+ }
+
+ return unknown;
+}
+
+int read_sms_raw(int type, int *x, int *y, int *z)
+{
+ int kernFunc;
+ char *servMatch;
+ int dataType;
+ union motion_data data;
+
+ if ( !set_values(type, &kernFunc, &servMatch, &dataType) )
+ return 0;
+ if ( probe_sms(kernFunc, servMatch, dataType, &data) ) {
+ switch ( dataType ) {
+ case PB_IB:
+ if ( x ) *x = data.pb_ib.x;
+ if ( y ) *y = data.pb_ib.y;
+ if ( z ) *z = data.pb_ib.z;
+ break;
+ case MBP:
+ if ( x ) *x = data.mbp.x;
+ if ( y ) *y = data.mbp.y;
+ if ( z ) *z = data.mbp.z;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int read_sms(int type, int *x, int *y, int *z)
+{
+ int _x, _y, _z;
+ int xoff, yoff, zoff;
+ Boolean ok;
+ int ret;
+
+ ret = read_sms_raw(type, &_x, &_y, &_z);
+ if ( !ret )
+ return 0;
+
+ static CFStringRef app = CFSTR("com.ramsayl.UniMotion");
+ static CFStringRef xoffstr = CFSTR("x_offset");
+ static CFStringRef yoffstr = CFSTR("y_offset");
+ static CFStringRef zoffstr = CFSTR("z_offset");
+ xoff = CFPreferencesGetAppIntegerValue(xoffstr, app, &ok);
+ if ( ok ) _x += xoff;
+ yoff = CFPreferencesGetAppIntegerValue(yoffstr, app, &ok);
+ if ( ok ) _y += yoff;
+ zoff = CFPreferencesGetAppIntegerValue(zoffstr, app, &ok);
+ if ( ok ) _z += zoff;
+
+ *x = _x;
+ *y = _y;
+ *z = _z;
+
+ return ret;
+}
+
+int read_sms_real(int type, double *x, double *y, double *z)
+{
+ int _x, _y, _z;
+ int xscale, yscale, zscale;
+ int ret;
+ Boolean ok;
+
+ ret = read_sms_raw(type, &_x, &_y, &_z);
+ if ( !ret )
+ return 0;
+
+ static CFStringRef app = CFSTR("com.ramsayl.UniMotion");
+ static CFStringRef xscalestr = CFSTR("x_scale");
+ static CFStringRef yscalestr = CFSTR("y_scale");
+ static CFStringRef zscalestr = CFSTR("z_scale");
+ xscale = CFPreferencesGetAppIntegerValue(xscalestr, app, &ok);
+ if ( !ok ) return 0;
+ yscale = CFPreferencesGetAppIntegerValue(yscalestr, app, &ok);
+ if ( !ok ) return 0;
+ zscale = CFPreferencesGetAppIntegerValue(zscalestr, app, &ok);
+ if ( !ok ) return 0;
+
+ *x = _x / (double)xscale;
+ *y = _y / (double)yscale;
+ *z = _z / (double)zscale;
+
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+ * UniMotion - Unified Motion detection for Apple portables.
+ *
+ * Copyright (c) 2006 Lincoln Ramsay. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation Inc. 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
+ */
+#ifndef UNIMOTION_H
+#define UNIMOTION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The various SMS hardware that unimotion supports
+enum sms_hardware {
+ unknown = 0,
+ powerbook = 1,
+ ibook = 2,
+ highrespb = 3,
+ macbookpro = 4
+};
+
+// prototypes for the functions in unimotion.c
+
+// returns the value of SMS hardware present or unknown if no hardware is detected
+int detect_sms();
+
+// use the value returned from detect_sms as the type
+// these functinos return 1 on success and 0 on failure
+// they modify x, y and z if they are not 0
+
+// raw, unmodified values
+int read_sms_raw(int type, int *x, int *y, int *z);
+// "calibrated" values (same as raw if no calibration data exists)
+int read_sms(int type, int *x, int *y, int *z);
+// real (1.0 = 1G) values (requires calibration data)
+// note that this is the preferred API as it need not change with new machines
+// however, this API does not work if no "scale" calibration data exists
+int read_sms_real(int type, double *x, double *y, double *z);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
vlc_value_t oldval, vlc_value_t newval,
void *p_data );
+static int PreciseRotateCallback( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data );
+
#define ANGLE_TEXT N_("Angle in degrees")
#define ANGLE_LONGTEXT N_("Angle in degrees (0 to 359)")
static inline void cache_trigo( int i_angle, int *i_sin, int *i_cos )
{
- const double f_angle = (((double)i_angle)*M_PI)/180.;
+ const double f_angle = (((double)i_angle)*M_PI)/1800.;
*i_sin = (int)(sin( f_angle )*256.);
*i_cos = (int)(cos( f_angle )*256.);
}
p_filter->p_cfg );
p_sys->i_angle = var_CreateGetIntegerCommand( p_filter,
- FILTER_PREFIX "angle" );
+ FILTER_PREFIX "angle" ) * 10;
+ var_CreateGetIntegerCommand( p_filter, FILTER_PREFIX "deciangle" );
var_AddCallback( p_filter, FILTER_PREFIX "angle", RotateCallback, p_sys );
+ var_AddCallback( p_filter, FILTER_PREFIX "deciangle", PreciseRotateCallback, p_sys );
cache_trigo( p_sys->i_angle, &p_sys->i_sin, &p_sys->i_cos );
filter_sys_t *p_sys = (filter_sys_t *)p_data;
if( !strcmp( psz_var, "rotate-angle" ) )
+ {
+ p_sys->i_angle = newval.i_int*10;
+
+ cache_trigo( p_sys->i_angle, &p_sys->i_sin, &p_sys->i_cos );
+ }
+ return VLC_SUCCESS;
+}
+static int PreciseRotateCallback( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
+{
+ filter_sys_t *p_sys = (filter_sys_t *)p_data;
+
+ if( !strcmp( psz_var, "rotate-deciangle" ) )
{
p_sys->i_angle = newval.i_int;