diff --git a/CMakeLists.txt b/CMakeLists.txt index 441e66fc..2e5f9248 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ set (PROJECT_APIVER OPTION(BUILD_AUDIO "Build audio support" OFF) OPTION(BUILD_REDIST_PACKAGE "Build libfreenect in a legally-redistributable manner (only affects audio)" OFF) OPTION(BUILD_EXAMPLES "Build example programs" ON) +OPTION(BUILD_PROXYNECT "Build proxynect persistent-connection library" ON) OPTION(BUILD_FAKENECT "Build fakenect mock library" ON) OPTION(BUILD_C_SYNC "Build c synchronous library" ON) OPTION(BUILD_CPP "Build C++ Library (currently header only)" ON) @@ -145,6 +146,10 @@ IF(BUILD_FAKENECT) add_subdirectory (fakenect) ENDIF() +IF(BUILD_PROXYNECT) + add_subdirectory (proxynect) +ENDIF() + IF(BUILD_C_SYNC) add_subdirectory (wrappers/c_sync) ENDIF() diff --git a/proxynect/CMakeLists.txt b/proxynect/CMakeLists.txt new file mode 100644 index 00000000..a7e1acc5 --- /dev/null +++ b/proxynect/CMakeLists.txt @@ -0,0 +1,25 @@ +###################################################################################### +# Proxynect Persistent Kinect Library +###################################################################################### +SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib/proxynect) +add_library (proxynect SHARED proxynect.c proxyutils.c) +set_target_properties (proxynect PROPERTIES + VERSION ${PROJECT_VER} + SOVERSION ${PROJECT_APIVER} + OUTPUT_NAME freenect) + +install (TARGETS proxynect + DESTINATION "${PROJECT_LIBRARY_INSTALL_DIR}/proxynect") + +add_executable(proxydaemon proxydaemon.c proxyutils.c) +target_link_libraries(proxydaemon freenect m) +install (TARGETS proxydaemon + DESTINATION bin) + +CONFIGURE_FILE("proxynect.sh.in" + "proxynect.sh" + IMMEDIATE @ONLY) +install (PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/proxynect.sh + DESTINATION bin + RENAME proxynect) diff --git a/proxynect/README b/proxynect/README new file mode 100644 index 00000000..df01cd12 --- /dev/null +++ b/proxynect/README @@ -0,0 +1,29 @@ +=Proxynect= +© 2012 Robert Xiao + +==Description== +Proxynect runs a persistent daemon which controls a single device. Multiple subscribers using the proxynect library can connect to and control the device. + +Proxynect allows multiple processes to use the same Kinect, and avoids certain issues related to repeated reinitialization of the Kinect. + +==Daemon== +Run the daemon with +./proxydaemon [deviceindex] +If deviceindex is not specified, 0 is assumed. Press Ctrl+C to quit. + +The proxydaemon tries to avoid running if another instance seems to be active. Add "--force" to the command-line if you want to override this (e.g. if the last instance did not shutdown properly). + +==Library== +Use the resulting proxynect .so dynamically instead of libfreenect. + +==Build== +This is built with the main cmake script. + +This gives you a build/lib/proxynect/libfreenect.so that you dynamically link in instead of libfreenect.so. + +You can call proxynect in front of your application to automatically force the proxynect library to be used, e.g. + +proxynect glview + +==Credits== +This library is based on the fakenect library by Brandyn White. diff --git a/proxynect/proxydaemon.c b/proxynect/proxydaemon.c new file mode 100644 index 00000000..f0c1b36a --- /dev/null +++ b/proxynect/proxydaemon.c @@ -0,0 +1,220 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2012 Robert Xiao + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#include "proxynect.h" +#include + +#include +#include +#include + +#define log(level, ...) do { if(device->loglevel >= FREENECT_LOG_##level) { fprintf(stderr, __VA_ARGS__); } } while(0) + +volatile sig_atomic_t running = 1; + +struct proxynect_device *device; + +void depth_cb(freenect_device *dev, void *depth, uint32_t timestamp) +{ + int bufsel = !device->depth.bufsel; + + device->depth.frame_mode[bufsel] = freenect_get_current_depth_mode(dev); + memcpy(device->depth.data[bufsel], depth, device->depth.frame_mode[bufsel].bytes); + device->depth.bufsel = bufsel; + + device->depth.timestamp = timestamp; +} + + +void video_cb(freenect_device *dev, void *video, uint32_t timestamp) +{ + int bufsel = !device->video.bufsel; + + device->video.frame_mode[bufsel] = freenect_get_current_video_mode(dev); + memcpy(device->video.data[bufsel], video, device->video.frame_mode[bufsel].bytes); + device->video.bufsel = bufsel; + + device->video.timestamp = timestamp; +} + +int run() +{ + freenect_context *ctx; + freenect_device *dev; + + if(freenect_init(&ctx, 0)) { + log(FATAL, "Error: Failed to get context\n"); + return 1; + } + + freenect_set_log_level(ctx, device->loglevel); + + /* TODO: audio */ + freenect_select_subdevices(ctx, (freenect_device_flags)(FREENECT_DEVICE_MOTOR | FREENECT_DEVICE_CAMERA)); + + device->timestamp = 0; + device->video.bufsel = 0; + device->video.timestamp = 0; + device->depth.bufsel = 0; + device->depth.timestamp = 0; + + if(freenect_open_device(ctx, &dev, device->index)) { + log(FATAL, "Error: Failed to open device %d\n", device->index); + return 2; + } + + freenect_set_depth_mode(dev, freenect_find_depth_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT)); + freenect_start_depth(dev); + freenect_set_video_mode(dev, freenect_find_video_mode(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB)); + freenect_start_video(dev); + + freenect_set_depth_callback(dev, depth_cb); + freenect_set_video_callback(dev, video_cb); + + while (running && freenect_process_events(ctx) >= 0) { + if(device->settings.tilt_degs_changed) { + log(INFO, "Updating tilt degrees to %.1f\n", device->settings.tilt_degs); + freenect_set_tilt_degs(dev, device->settings.tilt_degs); + device->settings.tilt_degs_changed = 0; + } + + if(device->settings.led_changed) { + log(INFO, "Updating LED to %d\n", device->settings.led); + freenect_set_led(dev, device->settings.led); + device->settings.led_changed = 0; + } + + if(device->settings.video_mode_changed) { + freenect_frame_mode curmode = freenect_get_current_video_mode(dev); + if(!memcmp(&device->settings.video_mode, &curmode, sizeof(freenect_frame_mode))) { + log(DEBUG, "Ignoring video format update request for %d\n", device->settings.video_mode.video_format); + } else { + log(INFO, "Updating video format to %d\n", device->settings.video_mode.video_format); + freenect_stop_video(dev); + freenect_set_video_mode(dev, device->settings.video_mode); + freenect_start_video(dev); + } + device->settings.video_mode_changed = 0; + } + + if(device->settings.depth_mode_changed) { + freenect_frame_mode curmode = freenect_get_current_depth_mode(dev); + if(!memcmp(&device->settings.depth_mode, &curmode, sizeof(freenect_frame_mode))) { + log(DEBUG, "Ignoring depth format update request for %d\n", device->settings.depth_mode.depth_format); + } else { + log(INFO, "Updating depth format to %d\n", device->settings.depth_mode.depth_format); + freenect_stop_depth(dev); + freenect_set_depth_mode(dev, device->settings.depth_mode); + freenect_start_depth(dev); + } + device->settings.depth_mode_changed = 0; + } + + if(device->settings.flags_changed) { + int i; + for(i=0; isettings.flags_changed & flag) { + device->settings.flags_changed &= ~flag; + freenect_set_flag(dev, flag, (device->settings.flags & flag) ? FREENECT_ON : FREENECT_OFF); + } + } + } + + freenect_update_tilt_state(dev); + device->raw_state = *freenect_get_tilt_state(dev); + device->timestamp++; + } + + freenect_stop_depth(dev); + freenect_stop_video(dev); + freenect_close_device(dev); + freenect_shutdown(ctx); + + return 0; +} + +void signal_cleanup(int num) +{ + running = 0; + log(NOTICE, "Caught signal, cleaning up\n"); + signal(SIGINT, signal_cleanup); +} + +void usage() +{ + fprintf(stderr, "Opens a device for proxynect usage.\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " proxynect [--help] [--force] [--loglevel n] [device-index]\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c = 1; + int force = 0; + int loglevel = 0; + int index = 0; + device = NULL; + + while(c < argc) { + if(!strcmp(argv[c], "--help")) { + usage(); + } else if(!strcmp(argv[c], "--force")) { + force = 1; + } else if(!strcmp(argv[c], "--loglevel")) { + loglevel = atoi(argv[c+1]); + c++; + } else if(argv[c][0] == '-') { + fprintf(stderr, "Unrecognized option %s; use --help for help.\n", argv[c]); + exit(1); + } else { + index = atoi(argv[c]); + } + c++; + } + + if(index < 0) { + fprintf(stderr, "Error: Invalid device index %d\n", index); + return 1; + } + + device = create_device(index, force); + if(device == NULL) { + perror("Failed to create shared device"); + return 1; + } + + device->index = index; + device->loglevel = loglevel; + + signal(SIGINT, signal_cleanup); + + int ret = run(); + + destroy_device(device); + + return ret; +} diff --git a/proxynect/proxynect.c b/proxynect/proxynect.c new file mode 100644 index 00000000..db1730f4 --- /dev/null +++ b/proxynect/proxynect.c @@ -0,0 +1,469 @@ +/* + * This file is part of the OpenKinect Project. http://www.openkinect.org + * + * Copyright (c) 2012 Robert Xiao + * + * This code is licensed to you under the terms of the Apache License, version + * 2.0, or, at your option, the terms of the GNU General Public License, + * version 2.0. See the APACHE20 and GPL2 files for the text of the licenses, + * or the following URLs: + * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.gnu.org/licenses/gpl-2.0.txt + * + * If you redistribute this file in source form, modified or unmodified, you + * may: + * 1) Leave this header intact and distribute it under the same terms, + * accompanying it with the APACHE20 and GPL20 files, or + * 2) Delete the Apache 2.0 clause and accompany it with the GPL2 file, or + * 3) Delete the GPL v2 clause and accompany it with the APACHE20 file + * In all cases you must keep the copyright notice intact and include a copy + * of the CONTRIB file. + * + * Binary distributions must follow the binary distribution requirements of + * either License. + */ + +#include "proxynect.h" +#include + +#include +#include +#include + +#include +#include +#include +#include + +#define GRAVITY 9.80665 + +#define MAX_DEVICES 100 + +/* copied from cameras.c */ +#define MAKE_RESERVED(res, fmt) (uint32_t)(((res & 0xff) << 8) | (((fmt & 0xff)))) +#define RESERVED_TO_RESOLUTION(reserved) (freenect_resolution)((reserved >> 8) & 0xff) +#define RESERVED_TO_FORMAT(reserved) ((reserved) & 0xff) + +#define video_mode_count 12 +static freenect_frame_mode supported_video_modes[video_mode_count] = { + // reserved, resolution, format, bytes, width, height, data_bits_per_pixel, padding_bits_per_pixel, framerate, is_valid + {MAKE_RESERVED(FREENECT_RESOLUTION_HIGH, FREENECT_VIDEO_RGB), FREENECT_RESOLUTION_HIGH, {FREENECT_VIDEO_RGB}, 1280*1024*3, 1280, 1024, 24, 0, 10, 1 }, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_RGB), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_RGB}, 640*480*3, 640, 480, 24, 0, 30, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_HIGH, FREENECT_VIDEO_BAYER), FREENECT_RESOLUTION_HIGH, {FREENECT_VIDEO_BAYER}, 1280*1024, 1280, 1024, 8, 0, 10, 1 }, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_BAYER), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_BAYER}, 640*480, 640, 480, 8, 0, 30, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_HIGH, FREENECT_VIDEO_IR_8BIT), FREENECT_RESOLUTION_HIGH, {FREENECT_VIDEO_IR_8BIT}, 1280*1024, 1280, 1024, 8, 0, 10, 1 }, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_8BIT), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_IR_8BIT}, 640*488, 640, 488, 8, 0, 30, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_HIGH, FREENECT_VIDEO_IR_10BIT), FREENECT_RESOLUTION_HIGH, {FREENECT_VIDEO_IR_10BIT}, 1280*1024*2, 1280, 1024, 10, 6, 10, 1 }, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_10BIT), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_IR_10BIT}, 640*488*2, 640, 488, 10, 6, 30, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_HIGH, FREENECT_VIDEO_IR_10BIT_PACKED), FREENECT_RESOLUTION_HIGH, {FREENECT_VIDEO_IR_10BIT_PACKED}, 1280*1024*10/8, 1280, 1024, 10, 0, 10, 1 }, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_IR_10BIT_PACKED), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_IR_10BIT_PACKED}, 640*488*10/8, 640, 488, 10, 0, 30, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_YUV_RGB), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_YUV_RGB}, 640*480*3, 640, 480, 24, 0, 15, 1 }, + + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_VIDEO_YUV_RAW), FREENECT_RESOLUTION_MEDIUM, {FREENECT_VIDEO_YUV_RAW}, 640*480*2, 640, 480, 16, 0, 15, 1 }, +}; + +#define depth_mode_count 6 +static freenect_frame_mode supported_depth_modes[depth_mode_count] = { + // reserved, resolution, format, bytes, width, height, data_bits_per_pixel, padding_bits_per_pixel, framerate, is_valid + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_11BIT}, 640*480*2, 640, 480, 11, 5, 30, 1}, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_10BIT), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_10BIT}, 640*480*2, 640, 480, 10, 6, 30, 1}, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_11BIT_PACKED), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_11BIT_PACKED}, 640*480*11/8, 640, 480, 11, 0, 30, 1}, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_10BIT_PACKED), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_10BIT_PACKED}, 640*480*10/8, 640, 480, 10, 0, 30, 1}, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_REGISTERED), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_REGISTERED}, 640*480*2, 640, 480, 16, 0, 30, 1}, + {MAKE_RESERVED(FREENECT_RESOLUTION_MEDIUM, FREENECT_DEPTH_MM), FREENECT_RESOLUTION_MEDIUM, {FREENECT_DEPTH_MM}, 640*480*2, 640, 480, 16, 0, 30, 1}, +}; + +struct _freenect_context { + int num_devices; + freenect_device *first; +}; + +struct _freenect_device { + freenect_context *parent; + freenect_device *prev; + freenect_device *next; + + struct proxynect_device *device; + + void *user_data; + + uint32_t last_timestamp; + + freenect_video_cb video_cb; + uint8_t *video_buf; + uint32_t last_video; + int video_running; + + freenect_depth_cb depth_cb; + uint8_t *depth_buf; + uint32_t last_depth; + int depth_running; +}; + + +int freenect_init(freenect_context **ctx, freenect_usb_context *usb_ctx) { + freenect_context *newctx = (freenect_context *)malloc(sizeof(freenect_context)); + if(newctx == NULL) + return -1; + + newctx->num_devices = 0; + newctx->first = NULL; + + *ctx = newctx; + + return 0; +} + +int freenect_shutdown(freenect_context *ctx) { + while(ctx->first != NULL) { + freenect_close_device(ctx->first); + } + + free(ctx); + return 0; +} + +/* Logging not supported here (daemon does all the logging) */ +void freenect_set_log_level(freenect_context *ctx, freenect_loglevel level) {} +void freenect_set_log_callback(freenect_context *ctx, freenect_log_cb cb) {} + +int freenect_process_events(freenect_context *ctx) { + struct timeval timeout; + timeout.tv_sec = 60; + timeout.tv_usec = 0; + + return freenect_process_events_timeout(ctx, &timeout); +} + +void timeval_add(struct timeval *t1, struct timeval *t2) { + /* Add t2 to t1 */ + t1->tv_usec += t2->tv_usec; + if(t1->tv_usec >= 1000000) { + t1->tv_usec -= 1000000; + t1->tv_sec += 1; + } + t1->tv_sec += t2->tv_sec; +} + +int timeval_cmp(struct timeval *t1, struct timeval *t2) { + if(t1->tv_sec > t2->tv_sec) + return 1; + else if(t1->tv_sec < t2->tv_sec) + return -1; + else + return t1->tv_usec - t2->tv_usec; +} + +static void update_device(freenect_device *dev) { + if(dev->last_video != dev->device->video.timestamp && dev->video_running) { + int bufsel = dev->device->video.bufsel; + uint8_t *video_buf = dev->device->video.data[bufsel]; + freenect_frame_mode *video_format = &dev->device->video.frame_mode[bufsel]; + + if(dev->video_buf != NULL) { + memcpy(dev->video_buf, video_buf, video_format->bytes); + video_buf = dev->video_buf; + } + + dev->last_video = dev->device->video.timestamp; + + if(dev->video_cb != NULL) { + dev->video_cb(dev, video_buf, dev->last_video); + } + } + + if(dev->last_depth != dev->device->depth.timestamp && dev->depth_running) { + int bufsel = dev->device->depth.bufsel; + uint8_t *depth_buf = dev->device->depth.data[bufsel]; + freenect_frame_mode *depth_format = &dev->device->depth.frame_mode[bufsel]; + + if(dev->depth_buf != NULL) { + memcpy(dev->depth_buf, depth_buf, depth_format->bytes); + depth_buf = dev->depth_buf; + } + + dev->last_depth = dev->device->depth.timestamp; + + if(dev->depth_cb != NULL) { + dev->depth_cb(dev, depth_buf, dev->last_depth); + } + } +} + +int freenect_process_events_timeout(freenect_context *ctx, struct timeval* timeout) { + struct timeval end, cur; + gettimeofday(&end, NULL); + timeval_add(&end, timeout); + + while(1) { + gettimeofday(&cur, NULL); + if(timeval_cmp(&cur, &end) >= 0) + break; + + freenect_device *dev; + int updated = 0; + for(dev = ctx->first; dev != NULL; dev = dev->next) { + if(dev->last_timestamp != dev->device->timestamp) { + updated = 1; + update_device(dev); + dev->last_timestamp = dev->device->timestamp; + } + } + if(updated) + return 0; + usleep(1000); + } + return 0; +} + +int freenect_num_devices(freenect_context *ctx) { + int i; + for(i=0; idevice->settings.flags = (dev->device->settings.flags & ~flag) + | ((value == FREENECT_ON) ? flag : 0); + dev->device->settings.flags_changed |= flag; + return 0; +} + +void freenect_select_subdevices(freenect_context *ctx, freenect_device_flags subdevs) { + /* Do nothing: the device has already been opened by the daemon anyway */ +} + +int freenect_open_device(freenect_context *ctx, freenect_device **dev, int index) { + freenect_device *newdev = (freenect_device *)malloc(sizeof(freenect_device)); + newdev->parent = ctx; + + newdev->device = open_device(index); + if(newdev->device == NULL) { + perror("opening device"); + free(newdev); + return -1; + } + + newdev->next = ctx->first; + newdev->prev = NULL; + if(ctx->first != NULL) { + ctx->first->prev = newdev; + } + ctx->first = newdev; + newdev->user_data = NULL; + + newdev->last_timestamp = 0; + + newdev->video_cb = NULL; + newdev->video_buf = NULL; + newdev->last_video = 0; + newdev->video_running = 0; + + newdev->depth_cb = NULL; + newdev->depth_buf = NULL; + newdev->last_depth = 0; + newdev->depth_running = 0; + + *dev = newdev; + return 0; +} + +int freenect_open_device_by_camera_serial(freenect_context *ctx, freenect_device **dev, const char* camera_serial) { + /* XXX unsupported */ + return -1; +} + +int freenect_close_device(freenect_device *dev) { + close_device(dev->device); + if(dev->next != NULL) { + dev->next->prev = dev->prev; + } + + if(dev->prev != NULL) { + dev->prev->next = dev->next; + } else { + dev->parent->first = dev->next; + } + + free(dev); + return 0; +} + +void freenect_set_user(freenect_device *dev, void *user) { + dev->user_data = user; +} + +void *freenect_get_user(freenect_device *dev) { + return dev->user_data; +} + +void freenect_set_depth_callback(freenect_device *dev, freenect_depth_cb cb) { + dev->depth_cb = cb; +} + +void freenect_set_video_callback(freenect_device *dev, freenect_video_cb cb) { + dev->video_cb = cb; +} + +int freenect_set_depth_buffer(freenect_device *dev, void *buf) { + dev->depth_buf = buf; + return 0; +} + +int freenect_set_video_buffer(freenect_device *dev, void *buf) { + dev->video_buf = buf; + return 0; +} + +int freenect_start_depth(freenect_device *dev) { + dev->depth_running = 1; + return 0; +} + +int freenect_start_video(freenect_device *dev) { + dev->video_running = 1; + return 0; +} + +int freenect_stop_depth(freenect_device *dev) { + dev->depth_running = 0; + return 0; +} + +int freenect_stop_video(freenect_device *dev) { + dev->video_running = 0; + return 0; +} + +int freenect_update_tilt_state(freenect_device *dev) { + /* Accelerometer data is always considered up-to-date */ + return 0; +} + +freenect_raw_tilt_state* freenect_get_tilt_state(freenect_device *dev) { + return &dev->device->raw_state; +} + +double freenect_get_tilt_degs(freenect_raw_tilt_state *state) { + return ((double)state->tilt_angle) / 2.0; +} + +int freenect_set_tilt_degs(freenect_device *dev, double angle) { + dev->device->settings.tilt_degs = angle; + dev->device->settings.tilt_degs_changed = 1; + return 0; +} + +freenect_tilt_status_code freenect_get_tilt_status(freenect_raw_tilt_state *state) { + return state->tilt_status; +} + +int freenect_set_led(freenect_device *dev, freenect_led_options option) { + dev->device->settings.led = option; + dev->device->settings.led_changed = 1; + return 0; +} + +void freenect_get_mks_accel(freenect_raw_tilt_state *state, double* x, double* y, double* z) { + *x = (double)state->accelerometer_x/FREENECT_COUNTS_PER_G*GRAVITY; + *y = (double)state->accelerometer_y/FREENECT_COUNTS_PER_G*GRAVITY; + *z = (double)state->accelerometer_z/FREENECT_COUNTS_PER_G*GRAVITY; +} + +int freenect_get_video_mode_count() { + return video_mode_count; +} + +freenect_frame_mode freenect_get_video_mode(int mode_num) { + if (mode_num >= 0 && mode_num < video_mode_count) + return supported_video_modes[mode_num]; + freenect_frame_mode retval; + retval.is_valid = 0; + return retval; +} + +freenect_frame_mode freenect_get_current_video_mode(freenect_device *dev) { + return dev->device->video.frame_mode[dev->device->video.bufsel]; +} + +freenect_frame_mode freenect_find_video_mode(freenect_resolution res, freenect_video_format fmt) { + uint32_t unique_id = MAKE_RESERVED(res, fmt); + int i; + for(i = 0 ; i < video_mode_count; i++) { + if (supported_video_modes[i].reserved == unique_id) + return supported_video_modes[i]; + } + freenect_frame_mode retval; + retval.is_valid = 0; + return retval; +} + +int freenect_set_video_mode(freenect_device* dev, freenect_frame_mode mode) { + dev->device->settings.video_mode = mode; + dev->device->settings.video_mode_changed = 1; + return 0; +} + +int freenect_get_depth_mode_count() { + return depth_mode_count; +} + +freenect_frame_mode freenect_get_depth_mode(int mode_num) { + if (mode_num >= 0 && mode_num < depth_mode_count) + return supported_depth_modes[mode_num]; + freenect_frame_mode retval; + retval.is_valid = 0; + return retval; +} + +freenect_frame_mode freenect_get_current_depth_mode(freenect_device *dev) { + return dev->device->depth.frame_mode[dev->device->depth.bufsel]; +} + +freenect_frame_mode freenect_find_depth_mode(freenect_resolution res, freenect_depth_format fmt) { + uint32_t unique_id = MAKE_RESERVED(res, fmt); + int i; + for(i = 0 ; i < depth_mode_count; i++) { + if (supported_depth_modes[i].reserved == unique_id) + return supported_depth_modes[i]; + } + freenect_frame_mode retval; + retval.is_valid = 0; + return retval; +} + +int freenect_set_depth_mode(freenect_device* dev, const freenect_frame_mode mode) { + dev->device->settings.depth_mode = mode; + dev->device->settings.depth_mode_changed = 1; + return 0; +} diff --git a/proxynect/proxynect.h b/proxynect/proxynect.h new file mode 100644 index 00000000..41d9ff1f --- /dev/null +++ b/proxynect/proxynect.h @@ -0,0 +1,47 @@ +#include +#include + +struct proxynect_device { + int index; + freenect_loglevel loglevel; + + uint32_t timestamp; + + struct { + int bufsel; + uint32_t timestamp; + freenect_frame_mode frame_mode[2]; + uint8_t data[2][1280*1024*3]; + } video; + + struct { + int bufsel; + uint32_t timestamp; + freenect_frame_mode frame_mode[2]; + uint8_t data[2][640*480*2]; + } depth; + + freenect_raw_tilt_state raw_state; + + struct { + double tilt_degs; + int tilt_degs_changed; + + freenect_led_options led; + int led_changed; + + freenect_frame_mode video_mode; + int video_mode_changed; + + freenect_frame_mode depth_mode; + int depth_mode_changed; + + freenect_flag flags; + freenect_flag flags_changed; // bitmask + } settings; +}; + +struct proxynect_device *create_device(int index, int force); +struct proxynect_device *open_device(int index); +void close_device(struct proxynect_device *device); +void destroy_device(struct proxynect_device *device); diff --git a/proxynect/proxynect.sh.in b/proxynect/proxynect.sh.in new file mode 100755 index 00000000..697c4401 --- /dev/null +++ b/proxynect/proxynect.sh.in @@ -0,0 +1,46 @@ +#!/bin/bash + +# This file is part of the OpenKinect Project. http://www.openkinect.org +# +# Copyright (c) 2012 individual OpenKinect contributors. See the CONTRIB file +# for details. +# +# This code is licensed to you under the terms of the Apache License, version +# 2.0, or, at your option, the terms of the GNU General Public License, +# version 2.0. See the APACHE20 and GPL20 files for the text of the licenses, +# or the following URLs: +# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.gnu.org/licenses/gpl-2.0.txt +# +# If you redistribute this file in source form, modified or unmodified, +# you may: +# 1) Leave this header intact and distribute it under the same terms, +# accompanying it with the APACHE20 and GPL20 files, or +# 2) Delete the Apache 2.0 clause and accompany it with the GPL20 file, or +# 3) Delete the GPL v2.0 clause and accompany it with the APACHE20 file +# In all cases you must keep the copyright notice intact and include a copy +# of the CONTRIB file. +# Binary distributions must follow the binary distribution requirements of +# either License. + +# proxynect wrapper script: +# simplifies calling libfreenect applications under proxynect +# usage: proxynect app --arg=value + +# catch bad args +if [ $# -lt 1 ] +then + echo "Usage: $0 [args...]" + exit -1 +fi + +# set link path (LD_LIBRARY_PATH for Linux, DYLIB_LIBRARY_PATH for OS X) +if [ `uname` == "Darwin" ]; +then + export DYLD_LIBRARY_PATH="@CMAKE_INSTALL_PREFIX@/@PROJECT_LIBRARY_INSTALL_DIR@/proxynect/:${LD_LIBRARY_PATH}" +else + export LD_LIBRARY_PATH="@CMAKE_INSTALL_PREFIX@/@PROJECT_LIBRARY_INSTALL_DIR@/proxynect/:${LD_LIBRARY_PATH}" +fi + +# run desired app w/ args, now that environment is configured +"${@:1}" diff --git a/proxynect/proxyutils.c b/proxynect/proxyutils.c new file mode 100644 index 00000000..70e9d5ab --- /dev/null +++ b/proxynect/proxyutils.c @@ -0,0 +1,69 @@ +#include "proxynect.h" + +#include + +#include +#include +#include +#include + +static struct proxynect_device *map_device(int index, int flags) { + char fn[80]; + sprintf(fn, "/proxynect_%d", index); + + int fd = shm_open(fn, flags, 0777); + + if(fd < 0) { + goto fail; + } + + if(flags & O_CREAT) { + if(ftruncate(fd, sizeof(struct proxynect_device)) < 0) { + goto fail; + } + } + + struct proxynect_device *device = (struct proxynect_device *)mmap( + NULL, sizeof(struct proxynect_device), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + + if(device == MAP_FAILED) { + goto fail; + } + + close(fd); + + return device; + +fail: + if(fd >= 0) { + close(fd); + if(flags & O_CREAT) + shm_unlink(fn); + } + return NULL; +} + +struct proxynect_device *create_device(int index, int force) { + if(force) { + return map_device(index, O_RDWR | O_CREAT); + } else { + return map_device(index, O_RDWR | O_CREAT | O_EXCL); + } +} + +struct proxynect_device *open_device(int index) { + return map_device(index, O_RDWR); +} + +void close_device(struct proxynect_device *device) { + munmap(device, sizeof(struct proxynect_device)); +} + +void destroy_device(struct proxynect_device *device) { + char fn[80]; + sprintf(fn, "/proxynect_%d", device->index); + shm_unlink(fn); + + munmap(device, sizeof(struct proxynect_device)); +}