diff --git a/configure.ac b/configure.ac index 45b9565..6c372a3 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,7 @@ AC_PREREQ([2.61]) AC_PROG_CC AC_PROG_LIBTOOL AC_C_INLINE +AM_PROG_CC_C_O # Library versioning lt_major="0" @@ -31,6 +32,38 @@ AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build], [build_examples='no']) AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"]) +# Examples build +AC_ARG_ENABLE([x11-examples-build], [AS_HELP_STRING([--enable-x11-examples-build], + [build X11 example applications (default n)])], + [build_x11_examples=$enableval], + [build_x11_examples='no']) +AM_CONDITIONAL([BUILD_X11_EXAMPLES], [test "x$build_x11_examples" != "xno"]) + + +if test "x$build_x11_examples" != "xno"; then + # check for Xv extensions + # imported from Coriander + AC_DEFUN([AC_CHECK_XV],[ + AC_SUBST(XV_CFLAGS) + AC_SUBST(XV_LIBS) + AC_MSG_CHECKING(for Xv extensions) + AC_TRY_COMPILE([ + #include + #include ],[ + int main(void) { (void) XvGetPortAttribute(0, 0, 0, 0); return 0; } + ],xv=yes,xv=no); + AC_MSG_RESULT($xv) + if test x$xv = xyes; then + XV_LIBS="-lXv -lXext" + XV_CFLAGS="" + AC_DEFINE(HAVE_XV,1,[defined if XV video overlay is available]) + else + AC_MSG_ERROR([XV is required for X11 examples]) + fi + ]) + AC_CHECK_XV +fi + # Message logging AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])], [log_enabled=$enableval], diff --git a/examples/Makefile.am b/examples/Makefile.am index d7d4706..eb6dedb 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -13,3 +13,11 @@ verify_LDADD = ../libfprint/libfprint.la -lfprint img_capture_SOURCES = img_capture.c img_capture_LDADD = ../libfprint/libfprint.la -lfprint +if BUILD_X11_EXAMPLES +noinst_PROGRAMS += img_capture_continuous + +img_capture_continuous_CFLAGS = $(X_CFLAGS) $(XV_CFLAGS) +img_capture_continuous_SOURCES = img_capture_continuous.c +img_capture_continuous_LDADD = ../libfprint/libfprint.la -lfprint $(X_LIBS) $(X_PRE_LIBS) $(XV_LIBS) -lX11 $(X_EXTRA_LIBS); +endif + diff --git a/examples/img_capture_continuous.c b/examples/img_capture_continuous.c new file mode 100644 index 0000000..ca67b33 --- /dev/null +++ b/examples/img_capture_continuous.c @@ -0,0 +1,257 @@ +/* + * Example libfprint continuous image capture program + * Copyright (C) 2007 Daniel Drake + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +#define FORMAT 0x32595559 + +static int adaptor = -1; +static unsigned char *framebuffer = NULL; + +static Display *display = NULL; +static Window window=(Window)NULL; +static XvImage *xv_image = NULL; +static XvAdaptorInfo *info; +static GC gc; +static int connection = -1; + +/* based on macro by Bart Nabbe */ +#define GREY2YUV(grey, y, u, v)\ + y = (9798*grey + 19235*grey + 3736*grey) / 32768;\ + u = (-4784*grey - 9437*grey + 14221*grey) / 32768 + 128;\ + v = (20218*grey - 16941*grey - 3277*grey) / 32768 + 128;\ + y = y < 0 ? 0 : y;\ + u = u < 0 ? 0 : u;\ + v = v < 0 ? 0 : v;\ + y = y > 255 ? 255 : y;\ + u = u > 255 ? 255 : u;\ + v = v > 255 ? 255 : v + +static void grey2yuy2 (unsigned char *grey, unsigned char *YUV, int num) { + int i, j; + int y0, y1, u0, u1, v0, v1; + int gval; + + for (i = 0, j = 0; i < num; i += 2, j += 4) + { + gval = grey[i]; + GREY2YUV (gval, y0, u0 , v0); + gval = grey[i + 1]; + GREY2YUV (gval, y1, u1 , v1); + YUV[j + 0] = y0; + YUV[j + 1] = (u0+u1)/2; + YUV[j + 2] = y1; + YUV[j + 3] = (v0+v1)/2; + } +} + +static void display_frame(struct fp_img *img) +{ + int width = fp_img_get_width(img); + int height = fp_img_get_height(img); + unsigned char *data = fp_img_get_data(img); + + if (adaptor < 0) + return; + + grey2yuy2(data, framebuffer, width * height); + xv_image = XvCreateImage(display, info[adaptor].base_id, FORMAT, + framebuffer, width, height); + XvPutImage(display, info[adaptor].base_id, window, gc, xv_image, + 0, 0, width, height, 0, 0, width, height); +} + +static void QueryXv() +{ + int num_adaptors; + int num_formats; + XvImageFormatValues *formats = NULL; + int i,j; + char xv_name[5]; + + XvQueryAdaptors(display, DefaultRootWindow(display), &num_adaptors, + &info); + + for(i = 0; i < num_adaptors; i++) { + formats = XvListImageFormats(display, info[i].base_id, + &num_formats); + for(j = 0; j < num_formats; j++) { + xv_name[4] = 0; + memcpy(xv_name, &formats[j].id, 4); + if(formats[j].id == FORMAT) { + printf("using Xv format 0x%x %s %s\n", + formats[j].id, xv_name, + (formats[j].format==XvPacked) + ? "packed" : "planar"); + if (adaptor < 0) + adaptor = i; + } + } + } + XFree(formats); + if (adaptor < 0) + printf("No suitable Xv adaptor found\n"); +} + +static struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs) +{ + struct fp_dscv_dev *ddev = NULL; + int i; + + for (i = 0; ddev = discovered_devs[i]; i++) { + struct fp_driver *drv = fp_dscv_dev_get_driver(ddev); + printf("Found device claimed by %s driver\n", + fp_driver_get_full_name(drv)); + return ddev; + } + + return ddev; +} + +int main(void) +{ + int r = 1; + XEvent xev; + XGCValues xgcv; + long background=0x010203; + struct fp_dscv_dev *ddev; + struct fp_dscv_dev **discovered_devs; + struct fp_dev *dev; + struct fp_img_dev *imgdev; + int img_width; + int img_height; + int standardize = 0; + + r = fp_init(); + if (r < 0) { + fprintf(stderr, "Failed to initialize libfprint\n"); + exit(1); + } + + discovered_devs = fp_discover_devs(); + if (!discovered_devs) { + fprintf(stderr, "Could not discover devices\n"); + exit(1); + } + + ddev = discover_device(discovered_devs); + if (!ddev) { + fprintf(stderr, "No devices detected.\n"); + exit(1); + } + + dev = fp_dev_open(ddev); + fp_dscv_devs_free(discovered_devs); + if (!dev) { + fprintf(stderr, "Could not open device.\n"); + exit(1); + } + + imgdev = fp_dev_to_img_dev(dev); + if (!imgdev) { + fprintf(stderr, "could not get image dev, is this an imaging " + "device?\n"); + goto out; + } + + img_width = fp_imgdev_get_img_width(imgdev); + img_height = fp_imgdev_get_img_height(imgdev); + framebuffer = malloc(img_width * img_height * 2); + if (!framebuffer) + goto out; + + /* make the window */ + display = XOpenDisplay(getenv("DISPLAY")); + if(display == NULL) { + fprintf(stderr,"Could not open display \"%s\"\n", + getenv("DISPLAY")); + goto out; + } + + QueryXv(); + + if (adaptor < 0) + goto out; + + window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, + img_width, img_height, 0, + WhitePixel(display, DefaultScreen(display)), background); + + XSelectInput(display, window, StructureNotifyMask | KeyPressMask); + XMapWindow(display, window); + connection = ConnectionNumber(display); + + gc = XCreateGC(display, window, 0, &xgcv); + + printf("Press S to toggle standardized mode, Q to quit\n"); + + while (1) { /* event loop */ + struct fp_img *img; + + r = fp_imgdev_capture(imgdev, 1, &img); + if (r) { + fprintf(stderr, "image capture failed, code %d\n", r); + goto out; + } + if (standardize) + fp_img_standardize(img); + + display_frame(img); + fp_img_free(img); + XFlush(display); + + while (XPending(display) > 0) { + XNextEvent(display, &xev); + if (xev.type != KeyPress) + continue; + + switch (XKeycodeToKeysym(display, xev.xkey.keycode, 0)) { + case XK_q: + case XK_Q: + r = 0; + goto out; + break; + case XK_s: + case XK_S: + standardize = !standardize; + break; + } + } /* XPending */ + } + + r = 0; +out: + if (framebuffer) + free(framebuffer); + fp_dev_close(dev); + if ((void *) window != NULL) + XUnmapWindow(display, window); + if (display != NULL) + XFlush(display); + return r; +} + +