Add rotate-deciangle for more precision in rotate
authorJérome Decoodt <djc@videolan.org>
Wed, 20 Jun 2007 20:19:24 +0000 (20:19 +0000)
committerJérome Decoodt <djc@videolan.org>
Wed, 20 Jun 2007 20:19:24 +0000 (20:19 +0000)
Add unimotion (http://members.optusnet.com.au/lbramsay/programs/unimotion.html)
to motion interface
Add a low band filter to the motion

configure.ac
modules/control/Modules.am
modules/control/motion.c
modules/control/unimotion.c [new file with mode: 0644]
modules/control/unimotion.h [new file with mode: 0644]
modules/video_filter/rotate.c

index 1f0ebc4..4171971 100644 (file)
@@ -173,6 +173,7 @@ case "${host_os}" in
     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"
@@ -3330,7 +3331,6 @@ AS_IF([test "${enable_libtar}" != "no"],[
   ] )
 ])
 
-
 dnl
 dnl A52/AC3 decoder plugin
 dnl
index bc50699..c982b05 100644 (file)
@@ -6,5 +6,14 @@ SOURCES_ntservice = ntservice.c
 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)
+
index 4541551..783af9f 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * 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
@@ -26,6 +27,7 @@
  *****************************************************************************/
 #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;
 
@@ -110,6 +117,10 @@ int Open ( vlc_object_t *p_this )
         /* 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 */
@@ -136,14 +147,17 @@ void Close ( vlc_object_t *p_this )
 /*****************************************************************************
  * 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;
@@ -152,6 +166,10 @@ static void RunIntf( intf_thread_t *p_intf )
         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 )
         {
@@ -162,7 +180,8 @@ static void RunIntf( intf_thread_t *p_intf )
                 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 );
                 }
@@ -209,14 +228,17 @@ static void RunIntf( intf_thread_t *p_intf )
         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 )
     {
@@ -231,7 +253,7 @@ static int GetOrientation( intf_thread_t *p_intf )
         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" );
@@ -243,8 +265,23 @@ static int GetOrientation( intf_thread_t *p_intf )
         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;
     }
diff --git a/modules/control/unimotion.c b/modules/control/unimotion.c
new file mode 100644 (file)
index 0000000..331f7fc
--- /dev/null
@@ -0,0 +1,310 @@
+ /*
+ *  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
diff --git a/modules/control/unimotion.h b/modules/control/unimotion.h
new file mode 100644 (file)
index 0000000..4c7118a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  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
+
index ec32815..ac9cddf 100644 (file)
@@ -46,6 +46,10 @@ static int RotateCallback( vlc_object_t *p_this, char const *psz_var,
                            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)")
 
@@ -84,7 +88,7 @@ struct filter_sys_t
 
 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.);
 }
@@ -110,8 +114,10 @@ static int Create( vlc_object_t *p_this )
                        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 );
 
@@ -219,6 +225,20 @@ static int RotateCallback( vlc_object_t *p_this, char const *psz_var,
     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;