00001 #ifndef FREENECT_DEVICE_T01IELX0
00002 #define FREENECT_DEVICE_T01IELX0
00003
00004 #include <boost/shared_ptr.hpp>
00005 #include <boost/noncopyable.hpp>
00006 #include <boost/thread/mutex.hpp>
00007 #include <stdexcept>
00008
00009 #include <libfreenect.h>
00010 #include <libfreenect-registration.h>
00011 #include <freenect_camera/image_buffer.hpp>
00012
00013 namespace freenect_camera {
00014
00015 static const std::string PRODUCT_NAME = "Xbox NUI Camera";
00016 static const unsigned PRODUCT_ID = 0x2ae;
00017 static const std::string VENDOR_NAME = "Microsoft";
00018 static const unsigned VENDOR_ID = 0x45e;
00019
00020 typedef freenect_resolution OutputMode;
00021
00022 bool isImageMode(const ImageBuffer& buffer) {
00023 return buffer.metadata.video_format == FREENECT_VIDEO_BAYER;
00024 }
00025
00026 class FreenectDriver;
00027
00028 class FreenectDevice : public boost::noncopyable {
00029
00030 public:
00031
00032 FreenectDevice(freenect_context* driver, std::string serial) {
00033 if (freenect_open_device_by_camera_serial(driver, &device_, serial.c_str()) < 0) {
00034 throw std::runtime_error("[ERROR] Unable to open specified kinect");
00035 }
00036 freenect_set_user(device_, this);
00037 freenect_set_depth_callback(device_, freenectDepthCallback);
00038 freenect_set_video_callback(device_, freenectVideoCallback);
00039 device_serial_ = serial;
00040 registration_ = freenect_copy_registration(device_);
00041
00042
00043 streaming_video_ = should_stream_video_ = false;
00044 new_video_resolution_ = getDefaultImageMode();
00045 new_video_format_ = FREENECT_VIDEO_BAYER;
00046 video_buffer_.metadata.resolution = FREENECT_RESOLUTION_DUMMY;
00047 video_buffer_.metadata.video_format = FREENECT_VIDEO_DUMMY;
00048
00049 streaming_depth_ = should_stream_depth_ = false;
00050 new_depth_resolution_ = getDefaultDepthMode();
00051 new_depth_format_ = FREENECT_DEPTH_MM;
00052 depth_buffer_.metadata.resolution = FREENECT_RESOLUTION_DUMMY;
00053 depth_buffer_.metadata.depth_format = FREENECT_DEPTH_DUMMY;
00054 }
00055
00056 ~FreenectDevice() {
00057 shutdown();
00058 }
00059
00060 void shutdown() {
00061 freenect_close_device(device_);
00062 freenect_destroy_registration(®istration_);
00063 }
00064
00065
00066
00068 unsigned getBus() const {
00069 return 0;
00070 }
00071
00073 unsigned getAddress() const {
00074 return 0;
00075 }
00076
00077 const char* getProductName() const {
00078 return PRODUCT_NAME.c_str();
00079 }
00080
00081 const char* getSerialNumber() const {
00082 return device_serial_.c_str();
00083 }
00084
00085 bool hasImageStream() const {
00086 return true;
00087 }
00088
00089 bool hasDepthStream() const {
00090 return true;
00091 }
00092
00093 bool hasIRStream() const {
00094 return true;
00095 }
00096
00097 bool isDepthRegistrationSupported() const {
00098 return true;
00099 }
00100
00101 bool isSynchronizationSupported() const {
00102 return false;
00103 }
00104
00105 bool isSynchronized() const {
00106 return false;
00107 }
00108
00109 bool setSynchronization(bool on_off) const {
00110 throw std::runtime_error("[ERROR] The kinect does not support hardware synchronization");
00111 }
00112
00116 float getBaseline() const {
00117 return 0.01 * registration_.zero_plane_info.dcmos_emitter_dist;
00118 }
00119
00120
00121
00122 template<typename T> void registerImageCallback (
00123 void (T::*callback)(const ImageBuffer& image, void* cookie),
00124 T& instance, void* cookie = NULL) {
00125 image_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
00126 }
00127
00128 template<typename T> void registerDepthCallback (
00129 void (T::*callback)(const ImageBuffer& depth_image, void* cookie),
00130 T& instance, void* cookie = NULL) {
00131 depth_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
00132 }
00133
00134 template<typename T> void registerIRCallback (
00135 void (T::*callback)(const ImageBuffer& ir_image, void* cookie),
00136 T& instance, void* cookie = NULL) {
00137 ir_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
00138 }
00139
00140
00141
00142 OutputMode getImageOutputMode() {
00143 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00144 return video_buffer_.metadata.resolution;
00145 }
00146
00147 void setImageOutputMode(OutputMode mode) {
00148 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00149 new_video_resolution_ = mode;
00150 }
00151
00152 OutputMode getDefaultImageMode() const {
00153 return FREENECT_RESOLUTION_MEDIUM;
00154 }
00155
00156 bool findCompatibleImageMode(const OutputMode& mode, OutputMode& compatible_mode) const {
00157 freenect_frame_mode new_mode =
00158 freenect_find_video_mode(mode, video_buffer_.metadata.video_format);
00159 if (!new_mode.is_valid) {
00160 compatible_mode = getDefaultImageMode();
00161 return false;
00162 }
00163 compatible_mode = mode;
00164 return true;
00165 }
00166
00167 void stopImageStream() {
00168 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00169 should_stream_video_ =
00170 (isImageStreamRunning()) ? false : streaming_video_;
00171 }
00172
00173 void startImageStream() {
00174 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00175 new_video_format_ = FREENECT_VIDEO_BAYER;
00176 should_stream_video_ = true;
00177 }
00178
00179 bool isImageStreamRunning() {
00180 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00181 return streaming_video_ && _isImageModeEnabled();
00182 }
00183
00184 void stopIRStream() {
00185 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00186 should_stream_video_ =
00187 (isIRStreamRunning()) ? false : streaming_video_;
00188 }
00189
00190 void startIRStream() {
00191 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00192 new_video_format_ = FREENECT_VIDEO_IR_10BIT;
00193 should_stream_video_ = true;
00194 }
00195
00196 bool isIRStreamRunning() {
00197 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00198 return streaming_video_ && !_isImageModeEnabled();
00199 }
00200
00201
00202
00203 OutputMode getDepthOutputMode() {
00204 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00205 return depth_buffer_.metadata.resolution;
00206 }
00207
00208 void setDepthOutputMode(OutputMode mode) {
00209 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00210 new_depth_resolution_ = mode;
00211 }
00212
00213 OutputMode getDefaultDepthMode() const {
00214 return FREENECT_RESOLUTION_MEDIUM;
00215 }
00216
00217 bool findCompatibleDepthMode(const OutputMode& mode, OutputMode& compatible_mode) const {
00218 freenect_frame_mode new_mode =
00219 freenect_find_depth_mode(mode, depth_buffer_.metadata.depth_format);
00220 if (!new_mode.is_valid) {
00221 compatible_mode = getDefaultDepthMode();
00222 return false;
00223 }
00224 compatible_mode = mode;
00225 return true;
00226 }
00227
00228 bool isDepthRegistered() {
00229 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00230 return depth_buffer_.metadata.depth_format == FREENECT_DEPTH_REGISTERED;
00231 }
00232
00233 void setDepthRegistration(bool enable) {
00234 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00235 new_depth_format_ =
00236 (enable) ? FREENECT_DEPTH_REGISTERED : FREENECT_DEPTH_MM;
00237 }
00238
00239 void stopDepthStream() {
00240 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00241 should_stream_depth_ = false;
00242 }
00243
00244 void startDepthStream() {
00245 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00246 should_stream_depth_ = true;
00247 }
00248
00249 bool isDepthStreamRunning() {
00250 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00251 return streaming_depth_;
00252 }
00253
00254
00255
00256 static void freenectDepthCallback(
00257 freenect_device *dev, void *depth, uint32_t timestamp) {
00258
00259 FreenectDevice* device =
00260 static_cast<FreenectDevice*>(freenect_get_user(dev));
00261 device->depthCallback(depth);
00262 }
00263
00264 static void freenectVideoCallback(
00265 freenect_device *dev, void *video, uint32_t timestamp) {
00266
00267 FreenectDevice* device =
00268 static_cast<FreenectDevice*>(freenect_get_user(dev));
00269 device->videoCallback(video);
00270 }
00271
00272 private:
00273
00274 friend class FreenectDriver;
00275
00276 freenect_device* device_;
00277 std::string device_serial_;
00278 freenect_registration registration_;
00279
00280 boost::function<void(const ImageBuffer&)> image_callback_;
00281 boost::function<void(const ImageBuffer&)> depth_callback_;
00282 boost::function<void(const ImageBuffer&)> ir_callback_;
00283
00284 ImageBuffer video_buffer_;
00285 bool streaming_video_;
00286 bool should_stream_video_;
00287 freenect_resolution new_video_resolution_;
00288 freenect_video_format new_video_format_;
00289
00290 ImageBuffer depth_buffer_;
00291 bool streaming_depth_;
00292 bool should_stream_depth_;
00293 freenect_resolution new_depth_resolution_;
00294 freenect_depth_format new_depth_format_;
00295
00296
00297
00298 boost::recursive_mutex m_settings_;
00299
00300 void executeChanges() {
00301 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00302
00303 bool change_video_settings =
00304 video_buffer_.metadata.video_format != new_video_format_ ||
00305 video_buffer_.metadata.resolution != new_video_resolution_ ||
00306 streaming_video_ != should_stream_video_;
00307
00308 if (change_video_settings) {
00309
00310 freenect_stop_video(device_);
00311 streaming_video_ = false;
00312
00313 if (video_buffer_.metadata.resolution != new_video_resolution_ ||
00314 video_buffer_.metadata.video_format != new_video_format_) {
00315 try {
00316 allocateBufferVideo(video_buffer_, new_video_format_,
00317 new_video_resolution_, registration_);
00318 } catch (std::runtime_error& e) {
00319 printf("[ERROR] Unsupported video format/resolution provided. %s\n",
00320 e.what());
00321 printf("[INFO] Setting default settings (RGB/VGA)\n");
00322 allocateBufferVideo(video_buffer_, FREENECT_VIDEO_BAYER,
00323 FREENECT_RESOLUTION_MEDIUM, registration_);
00324 }
00325 freenect_set_video_mode(device_, video_buffer_.metadata);
00326 freenect_set_video_buffer(device_, video_buffer_.image_buffer.get());
00327 new_video_resolution_ = video_buffer_.metadata.resolution;
00328 new_video_format_ = video_buffer_.metadata.video_format;
00329 }
00330
00331 if (should_stream_video_) {
00332 freenect_start_video(device_);
00333 streaming_video_ = true;
00334 }
00335 }
00336
00337 bool change_depth_settings =
00338 depth_buffer_.metadata.depth_format != new_depth_format_ ||
00339 depth_buffer_.metadata.resolution != new_depth_resolution_ ||
00340 streaming_depth_ != should_stream_depth_;
00341
00342 if (change_depth_settings) {
00343
00344 freenect_stop_depth(device_);
00345 streaming_depth_ = false;
00346
00347 if (depth_buffer_.metadata.resolution != new_depth_resolution_ ||
00348 depth_buffer_.metadata.depth_format != new_depth_format_) {
00349 try {
00350 allocateBufferDepth(depth_buffer_, new_depth_format_,
00351 new_depth_resolution_, registration_);
00352 } catch (std::runtime_error& e) {
00353 printf("[ERROR] Unsupported depth format/resolution provided. %s\n",
00354 e.what());
00355 printf("[INFO] Setting default settings (depth registered/VGA)\n");
00356 allocateBufferDepth(depth_buffer_, FREENECT_DEPTH_MM,
00357 FREENECT_RESOLUTION_MEDIUM, registration_);
00358 }
00359 freenect_set_depth_mode(device_, depth_buffer_.metadata);
00360 freenect_set_depth_buffer(device_, depth_buffer_.image_buffer.get());
00361 new_depth_resolution_ = depth_buffer_.metadata.resolution;
00362 new_depth_format_ = depth_buffer_.metadata.depth_format;
00363 }
00364
00365 if (should_stream_depth_) {
00366 freenect_start_depth(device_);
00367 streaming_depth_ = true;
00368 }
00369 }
00370 }
00371
00372 bool _isImageModeEnabled() {
00373 boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
00374 return isImageMode(video_buffer_);
00375 }
00376
00377 void depthCallback(void* depth) {
00378 boost::lock_guard<boost::mutex> buffer_lock(depth_buffer_.mutex);
00379 assert(depth == depth_buffer_.image_buffer.get());
00380 depth_callback_.operator()(depth_buffer_);
00381 }
00382
00383 void videoCallback(void* video) {
00384 boost::lock_guard<boost::mutex> buffer_lock(video_buffer_.mutex);
00385 assert(video == video_buffer_.image_buffer.get());
00386 if (isImageMode(video_buffer_)) {
00387 image_callback_.operator()(video_buffer_);
00388 } else {
00389 ir_callback_.operator()(video_buffer_);
00390 }
00391 }
00392
00393 };
00394 }
00395
00396 #endif