face detection resets idle time and deactivates ss
authorozzloy <ozzloy@zero7.(none)>
Thu, 18 Feb 2010 08:55:31 +0000 (00:55 -0800)
committerozzloy <ozzloy@zero7.(none)>
Thu, 18 Feb 2010 08:55:31 +0000 (00:55 -0800)
Makefile
NOTES
TODO
idle_x11.cpp [new file with mode: 0644]
idle_x11.h [new file with mode: 0644]
oble.cpp

index 7391fbda35eb0d6adb7ec3a76561b59eba955f3d..e268f883d5e26a6593248a821b97d2be70591650 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,23 @@
 
 all: oble
 
-oble: oble.cpp oble.h
-       gcc `pkg-config --cflags opencv` -o oble oble.cpp `pkg-config --libs opencv`
+PKGS = opencv x11 xext xscrnsaver
+CXXFLAGS += $(shell pkg-config --cflags $(PKGS))
+LDFLAGS += $(shell pkg-config --libs $(PKGS))
+
+OBJS = idle_x11.o oble.o
+
+idle_x11.o: idle_x11.h
+oble.o: oble.h
+
+oble: $(OBJS)
+       gcc $(LDFLAGS) -o $@ $(OBJS)
 
 test: all
        ./oble /usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml
 
 clean:
-       rm -rf oble
+       rm -rf oble *.o
 
 new: clean all
 
diff --git a/NOTES b/NOTES
index 7554836adbc9260393209501ecefb80401e8e15b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -1,10 +0,0 @@
-(screensaver activation and deactivation) has 2 managers right now.  oble and
-gnome-screensaver have independent criteria for activation and deactivation.
-oble relies only on time since face detected, gss relies on time since keyboard
-or mouse state change.  this causes annoying problems.
-       * example: gss activates screensaver on timeout even though face is clearly
-       detected the whole time.
-       * workaround: make gss timeout be as long as possible
-there are other problems.
-the real fix is to combine the two.  user activity should be any of {keyboard,
-mouse, face detection}.
diff --git a/TODO b/TODO
index 6dae6432bd9d736d79ebc9e2d82fc42f933a47ed..646efd4bb64bf3b5fb60dd3d30e5a4e3bf978d6c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,18 +1,5 @@
 FOR SCREENSAVER:
-* use [Un]Inhibit together as a SimulateUserActivity workalike
-       * disablegss.py from http://ubuntuforums.org/showthread.php?t=284804
-       * this method doesn't work either.  tried in gss-poke.py
-* xdg-screensaver suspend / resume to SimulateUserActivity
-       * http://tronche.com/gui/x/xlib-tutorial/2nd-program-anatomy.html
-       * http://portland.freedesktop.org/xdg-utils-1.0beta3/xdg-screensaver.html
-* SimulateUserActivity
-       * does it work on other people's machines?
-               * find if other people have their gnome-screensaver run even if they set
-               screensaver timeout to 1 minute and run:
-               for ((i = 0; i < 999; i++)); do
-                       sleep 50;
-                       gnome-screensaver-command --poke;
-               done;
+* gnome-screensaver-command --poke
        * find irc channel to ask if my understanding is correct
        * file bug
        * track down bug
@@ -22,12 +9,14 @@ FOR SCREENSAVER:
                * no display window
                * no text printed to terminal
 * fire up the face detector only just before going to inactive mode.
+       * possibly this is how kreed's version works.  read kreed's code to find out
        * that way the camera isn't running all the time
-       * maybe start 10 seconds before going inactive, then run until activity
+       * maybe start 10 seconds before going inactive, then run until activity, or 10
+       seconds, whichever's first.
 * be more aggressive with turning off the screen.  dim the screen as soon as
 it's not being looked at.  turn it off soon thereafter.
        * could be enough to save battery.  would need to power the camera sometimes,
-       but would save on backlight.  need to test.
+       but would save on backlight.  need to profile.
 * don't prevent sleep when face is detected, but user isn't actually looking at
 screen.
        * requires pose estimation.
diff --git a/idle_x11.cpp b/idle_x11.cpp
new file mode 100644 (file)
index 0000000..1b5e6e4
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2009 Christopher Eby <kreed@kreed.org>
+ *
+ * This file is part of Inertia.
+ *
+ * Inertia is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * Inertia 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 <http://www.gnu.org/licenses/> for the full license text.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/sync.h>
+#include <X11/extensions/scrnsaver.h>
+
+static Display *dpy = NULL;
+
+static void get_alarm(XSyncAlarm *alarm, XSyncCounter counter, XSyncTestType type, XSyncValue value)
+{
+       XSyncAlarmAttributes attrs;
+
+       XSyncValue delta;
+       XSyncIntToValue(&delta, 0);
+
+       static const unsigned long flags = XSyncCACounter | XSyncCATestType | XSyncCAValue | XSyncCADelta;
+
+       attrs.trigger.counter = counter;
+       attrs.trigger.test_type = type;
+       attrs.trigger.wait_value = value;
+       attrs.delta = delta;
+
+       if (*alarm)
+               XSyncChangeAlarm(dpy, *alarm, flags, &attrs);
+       else
+               *alarm = XSyncCreateAlarm(dpy, flags, &attrs);
+}
+
+static void die(const char *errstr)
+{
+       fputs(errstr, stderr);
+       fflush(stderr);
+       exit(EXIT_FAILURE);
+}
+
+bool wait_for_idle_time(int idle_time)
+{
+       static int xsync_event_base;
+       static XSyncAlarm idle_alarm = None;
+       static XSyncAlarm reset_alarm = None;
+       static XSyncCounter idle = None;
+       static XSyncValue idle_timeout;
+
+       if (idle == None) {
+               if (!(dpy = XOpenDisplay(NULL)))
+                       die("Could not open X11 display; exiting.\n");
+
+               int dummy;
+               if (!XQueryExtension(dpy, "XTEST", &dummy, &dummy, &dummy))
+                       die("XTEST extension not available; cannot reset idle time\n");
+
+               int xsync_error_base;
+               int xsync_major = SYNC_MAJOR_VERSION;
+               int xsync_minor = SYNC_MINOR_VERSION;
+
+               if (!XSyncQueryExtension(dpy, &xsync_event_base, &xsync_error_base) || !XSyncInitialize(dpy, &xsync_major, &xsync_minor))
+                       die("No XSync extension; exiting.\n");
+
+               int i;
+               XSyncSystemCounter *counters = XSyncListSystemCounters(dpy, &i);
+               while (i--)
+                       if (!strcmp(counters[i].name, "IDLETIME"))
+                               idle = counters[i].counter;
+               XSyncFreeSystemCounterList(counters);
+
+               if (idle == None)
+                       die("No IDLETIME counter! xorg-server 1.3 and higher should support it. Exiting.\n");
+
+               XSyncIntToValue(&idle_timeout, idle_time * 1000);
+               get_alarm(&idle_alarm, idle, XSyncPositiveComparison, idle_timeout);
+       }
+
+       XEvent ev;
+
+       while (!XNextEvent(dpy, &ev)) {
+               if (ev.type == xsync_event_base + XSyncAlarmNotify) {
+                       XSyncAlarmNotifyEvent *e = (XSyncAlarmNotifyEvent*)&ev;
+
+                       if (e->alarm == idle_alarm) {
+                               int overflow;
+                               XSyncValue reset_timeout;
+                               XSyncValue minus_one;
+
+                               XSyncIntToValue(&minus_one, -1);
+                               XSyncValueAdd(&reset_timeout, e->counter_value, minus_one, &overflow);
+                               get_alarm(&reset_alarm, idle, XSyncNegativeComparison, reset_timeout);
+
+                               return true;
+                       } else if (e->alarm == reset_alarm) {
+                               get_alarm(&idle_alarm, idle, XSyncPositiveComparison, idle_timeout);
+                       }
+               }
+       }
+
+       return false;
+}
+
+void reset_idle_time()
+{
+       if (!dpy) {
+               if (!(dpy = XOpenDisplay(NULL))) {
+                       fputs("Could not open X11 display.\n", stderr);
+                       return;
+               }
+       }
+
+       XScreenSaverSuspend(dpy, True);
+       XSync(dpy, False);
+       XScreenSaverSuspend(dpy, False);
+       XSync(dpy, False); 
+}
diff --git a/idle_x11.h b/idle_x11.h
new file mode 100644 (file)
index 0000000..9bc48f1
--- /dev/null
@@ -0,0 +1,3 @@
+
+bool wait_for_idle_time(int idle_time);
+void reset_idle_time();
index ab7d509341105b2a942a45dd1558d27c371ba232..0e24b9e05ff6462e3b8a095f8fc768afbcad9d83 100644 (file)
--- a/oble.cpp
+++ b/oble.cpp
 #include <iostream>
 #include <time.h>
 #include "oble.h"
+#include "idle_x11.h"
 
 using namespace std;
 
 // argument for cvFlip(src, dest, FLIP_TYPE)
 #define MIRROR 1
 
+#define DEBUG 0
+
 CvHaarClassifierCascade* load_object_detector(const char* cascade_path)
 {
        return (CvHaarClassifierCascade*)cvLoad(cascade_path);
@@ -59,6 +62,7 @@ void detect_and_draw_objects(IplImage* image,
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq* faces;
        int i, scale = 1;
+       static int saw_last_time = 0;
 
        /* if the flag is specified, down-scale the input image to get a
                 performance boost w/o loosing quality (perhaps) */
@@ -77,7 +81,25 @@ void detect_and_draw_objects(IplImage* image,
        if(0 < faces->total)
        {
                t_current = time(NULL);
-               //system("./gss-poke.py");
+               if(DEBUG)
+               {
+                       printf(":) face \n");
+               }
+               if(saw_last_time)
+               {
+                       if(DEBUG)printf("\t\tpoking\n");
+                       reset_idle_time();
+                       system("gnome-screensaver-command --poke");
+               }
+               saw_last_time = 1;
+       }
+       else
+       {
+               saw_last_time = 0;
+               if(DEBUG)
+               {
+                       printf(":( no face \n");
+               }
        }
 
        /* draw all the rectangles */
@@ -105,7 +127,10 @@ void screensave(time_t t_current)
        if(elapse > timeout && elapse != last_elapse)
        {
                last_elapse = elapse;
-               printf("elapse = %d\n", elapse);
+               if(DEBUG)
+               {
+                       printf("elapse = %d\n", elapse);
+               }
                if(!activated)
                {
                        printf("activated\n");
@@ -161,7 +186,7 @@ int main(int argc, char** argv)
                detect_and_draw_objects(mirrored, cascade, 1);
                cvShowImage("mywindow", mirrored);
                // Do not release the frame!
-               screensave(t_current);
+               //screensave(t_current);
 
                //If ESC key pressed, Key=0x10001B under OpenCV 0.9.7(linux version),
                //remove higher bits using AND operator