freenect_device.hpp
Go to the documentation of this file.
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         //Initialize default variables
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(&registration_);
00063       }
00064 
00065       /* DEVICE SPECIFIC FUNCTIONS */
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       /* CALLBACK ASSIGNMENT FUNCTIONS */
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       /* IMAGE SETTINGS FUNCTIONS */
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       /* DEPTH SETTINGS FUNCTIONS */
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       /* LIBFREENECT ASYNC CALLBACKS */
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       /* Prevents changing settings unless the freenect thread in the driver
00297        * is ready */
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           // Stop video stream
00310           freenect_stop_video(device_);
00311           streaming_video_ = false;
00312           // Allocate buffer for video if settings have changed
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           // Restart stream if required
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           // Stop depth stream
00344           freenect_stop_depth(device_);
00345           streaming_depth_ = false;
00346           // Allocate buffer for depth if settings have changed
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           // Restart stream if required
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 /* end of include guard: FREENECT_DEVICE_T01IELX0 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


freenect_camera
Author(s): Patrick Mihelich, Suat Gedikli, Radu Bogdan Rusu (original openni_camera driver). Piyush Khandelwal (libfreenect port).
autogenerated on Wed May 1 2013 10:40:36