freenect_device.hpp
Go to the documentation of this file.
1 #ifndef FREENECT_DEVICE_T01IELX0
2 #define FREENECT_DEVICE_T01IELX0
3 
4 #include <boost/shared_ptr.hpp>
5 #include <boost/noncopyable.hpp>
6 #include <boost/thread/mutex.hpp>
7 #include <boost/date_time/posix_time/ptime.hpp>
8 #include <stdexcept>
9 
10 #include <libfreenect.h>
11 #include <libfreenect_registration.h>
13 
14 namespace freenect_camera {
15 
16  static const std::string PRODUCT_NAME = "Xbox NUI Camera";
17  static const unsigned PRODUCT_ID = 0x2ae;
18  static const std::string VENDOR_NAME = "Microsoft";
19  static const unsigned VENDOR_ID = 0x45e;
20 
21  typedef freenect_resolution OutputMode;
22 
23  bool isImageMode(const ImageBuffer& buffer) {
24  return buffer.metadata.video_format == FREENECT_VIDEO_BAYER;
25  }
26 
27  class FreenectDriver;
28 
29  class FreenectDevice : public boost::noncopyable {
30 
31  public:
32 
33  FreenectDevice(freenect_context* driver, std::string serial) {
34  openDevice(driver, serial);
36 
37  //Initialize default variables
40  new_video_format_ = FREENECT_VIDEO_BAYER;
41  video_buffer_.metadata.resolution = FREENECT_RESOLUTION_DUMMY;
42  video_buffer_.metadata.video_format = FREENECT_VIDEO_DUMMY;
43 
46  new_depth_format_ = FREENECT_DEPTH_MM;
47  depth_buffer_.metadata.resolution = FREENECT_RESOLUTION_DUMMY;
48  depth_buffer_.metadata.depth_format = FREENECT_DEPTH_DUMMY;
49 
50  publishers_ready_ = false;
51  }
52 
53 
55  shutdown();
56  }
57 
59  device_flush_start_time_ = boost::posix_time::microsec_clock::local_time();
60  device_flush_enabled_ = true;
61  ROS_INFO("Starting a 3s RGB and Depth stream flush.");
62  }
63 
64  void openDevice(freenect_context* driver, std::string serial) {
65  if (freenect_open_device_by_camera_serial(driver, &device_, serial.c_str()) < 0) {
66  throw std::runtime_error("[ERROR] Unable to open specified kinect");
67  }
68  freenect_set_user(device_, this);
69  freenect_set_depth_callback(device_, freenectDepthCallback);
70  freenect_set_video_callback(device_, freenectVideoCallback);
71  driver_ = driver;
72  device_serial_ = serial;
73  registration_ = freenect_copy_registration(device_);
74  }
75 
76  void shutdown() {
77  freenect_close_device(device_);
78  freenect_destroy_registration(&registration_);
79  }
80 
81  /* DEVICE SPECIFIC FUNCTIONS */
82 
84  unsigned getBus() const {
85  return 0;
86  }
87 
89  unsigned getAddress() const {
90  return 0;
91  }
92 
93  const char* getProductName() const {
94  return PRODUCT_NAME.c_str();
95  }
96 
97  const char* getSerialNumber() const {
98  return device_serial_.c_str();
99  }
100 
101  bool hasImageStream() const {
102  return true;
103  }
104 
105  bool hasDepthStream() const {
106  return true;
107  }
108 
109  bool hasIRStream() const {
110  return true;
111  }
112 
114  return true;
115  }
116 
118  return false;
119  }
120 
121  bool isSynchronized() const {
122  return false;
123  }
124 
125  bool setSynchronization(bool on_off) const {
126  throw std::runtime_error("[ERROR] The kinect does not support hardware synchronization");
127  }
128 
132  float getBaseline() const {
133  return 0.01 * registration_.zero_plane_info.dcmos_emitter_dist;
134  }
135 
136  /* CALLBACK ASSIGNMENT FUNCTIONS */
137 
138  template<typename T> void registerImageCallback (
139  void (T::*callback)(const ImageBuffer& image, void* cookie),
140  T& instance, void* cookie = NULL) {
141  image_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
142  }
143 
144  template<typename T> void registerDepthCallback (
145  void (T::*callback)(const ImageBuffer& depth_image, void* cookie),
146  T& instance, void* cookie = NULL) {
147  depth_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
148  }
149 
150  template<typename T> void registerIRCallback (
151  void (T::*callback)(const ImageBuffer& ir_image, void* cookie),
152  T& instance, void* cookie = NULL) {
153  ir_callback_ = boost::bind(callback, boost::ref(instance), _1, cookie);
154  }
155 
157  publishers_ready_ = true;
158  }
159 
160  /* IMAGE SETTINGS FUNCTIONS */
161 
162  OutputMode getImageOutputMode() {
163  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
164  return video_buffer_.metadata.resolution;
165  }
166 
167  void setImageOutputMode(OutputMode mode) {
168  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
169  new_video_resolution_ = mode;
170  }
171 
172  OutputMode getDefaultImageMode() const {
173  return FREENECT_RESOLUTION_MEDIUM;
174  }
175 
176  bool findCompatibleImageMode(const OutputMode& mode, OutputMode& compatible_mode) const {
177  freenect_frame_mode new_mode =
178  freenect_find_video_mode(mode, video_buffer_.metadata.video_format);
179  if (!new_mode.is_valid) {
180  compatible_mode = getDefaultImageMode();
181  return false;
182  }
183  compatible_mode = mode;
184  return true;
185  }
186 
188  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
189  //std::cout << "STOP IMAGE STREAM" << std::endl;
192  }
193 
195  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
196  //std::cout << "START IMAGE STREAM" << std::endl;
197  new_video_format_ = FREENECT_VIDEO_BAYER;
198  should_stream_video_ = true;
199  }
200 
202  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
204  }
205 
206  void stopIRStream() {
207  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
209  (isIRStreamRunning()) ? false : streaming_video_;
210  }
211 
212  void startIRStream() {
213  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
214  new_video_format_ = FREENECT_VIDEO_IR_10BIT;
215  should_stream_video_ = true;
216  }
217 
219  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
221  }
222 
223  /* DEPTH SETTINGS FUNCTIONS */
224 
225  OutputMode getDepthOutputMode() {
226  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
227  return depth_buffer_.metadata.resolution;
228  }
229 
230  void setDepthOutputMode(OutputMode mode) {
231  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
232  new_depth_resolution_ = mode;
233  }
234 
235  OutputMode getDefaultDepthMode() const {
236  return FREENECT_RESOLUTION_MEDIUM;
237  }
238 
239  bool findCompatibleDepthMode(const OutputMode& mode, OutputMode& compatible_mode) const {
240  freenect_frame_mode new_mode =
241  freenect_find_depth_mode(mode, depth_buffer_.metadata.depth_format);
242  if (!new_mode.is_valid) {
243  compatible_mode = getDefaultDepthMode();
244  return false;
245  }
246  compatible_mode = mode;
247  return true;
248  }
249 
251  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
252  return depth_buffer_.metadata.depth_format == FREENECT_DEPTH_REGISTERED;
253  }
254 
255  void setDepthRegistration(bool enable) {
256  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
258  (enable) ? FREENECT_DEPTH_REGISTERED : FREENECT_DEPTH_MM;
259  }
260 
262  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
263  should_stream_depth_ = false;
264  }
265 
267  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
268  should_stream_depth_ = true;
269  }
270 
272  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
274  }
275 
276  /* LIBFREENECT ASYNC CALLBACKS */
277 
279  freenect_device *dev, void *depth, uint32_t timestamp) {
280 
281  FreenectDevice* device =
282  static_cast<FreenectDevice*>(freenect_get_user(dev));
283  device->depthCallback(depth);
284  }
285 
287  freenect_device *dev, void *video, uint32_t timestamp) {
288 
289  FreenectDevice* device =
290  static_cast<FreenectDevice*>(freenect_get_user(dev));
291  device->videoCallback(video);
292  }
293 
294  private:
295 
296  friend class FreenectDriver;
297 
298  freenect_context* driver_;
299  freenect_device* device_;
300  std::string device_serial_;
301  freenect_registration registration_;
302 
303  boost::function<void(const ImageBuffer&)> image_callback_;
304  boost::function<void(const ImageBuffer&)> depth_callback_;
305  boost::function<void(const ImageBuffer&)> ir_callback_;
306 
310  freenect_resolution new_video_resolution_;
311  freenect_video_format new_video_format_;
312 
316  freenect_resolution new_depth_resolution_;
317  freenect_depth_format new_depth_format_;
318 
319  /* Prevents changing settings unless the freenect thread in the driver
320  * is ready */
321  boost::recursive_mutex m_settings_;
322 
323  boost::posix_time::ptime device_flush_start_time_;
326 
327  void executeChanges() {
328  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
329  //ROS_INFO_THROTTLE(1.0, "exec changes");
330 
331  bool stop_device_flush = false;
332 
333  if (device_flush_enabled_) {
334  boost::posix_time::ptime current_time =
335  boost::posix_time::microsec_clock::local_time();
336  if ((current_time - device_flush_start_time_).total_milliseconds() > 3000) {
337  device_flush_enabled_ = false;
338  stop_device_flush = true;
339  ROS_INFO("Stopping device RGB and Depth stream flush.");
340  }
341  }
342 
343  bool change_video_settings =
344  video_buffer_.metadata.video_format != new_video_format_ ||
345  video_buffer_.metadata.resolution != new_video_resolution_ ||
346  ((streaming_video_ != should_stream_video_) && !device_flush_enabled_) ||
347  device_flush_enabled_ && !streaming_video_ ||
348  stop_device_flush;
349 
350  if (change_video_settings) {
352  // Stop video stream
353  if (streaming_video_) {
354  //ROS_INFO(" stopping video images...");
355  freenect_stop_video(device_);
356  streaming_video_ = false;
357  return;
358  }
359  // Allocate buffer for video if settings have changed
360  if (video_buffer_.metadata.resolution != new_video_resolution_ ||
361  video_buffer_.metadata.video_format != new_video_format_) {
362  try {
363  allocateBufferVideo(video_buffer_, new_video_format_,
364  new_video_resolution_, registration_);
365  } catch (std::runtime_error& e) {
366  printf("[ERROR] Unsupported video format/resolution provided. %s\n",
367  e.what());
368  printf("[INFO] Setting default settings (RGB/VGA)\n");
369  allocateBufferVideo(video_buffer_, FREENECT_VIDEO_BAYER,
370  FREENECT_RESOLUTION_MEDIUM, registration_);
371  }
372  freenect_set_video_mode(device_, video_buffer_.metadata);
373  freenect_set_video_buffer(device_, video_buffer_.image_buffer.get());
374  new_video_resolution_ = video_buffer_.metadata.resolution;
375  new_video_format_ = video_buffer_.metadata.video_format;
376  }
377  // Restart stream if required
378  if (should_stream_video_ || device_flush_enabled_) {
379  int rgb_out = freenect_start_video(device_);
380  //ROS_INFO(" streaming rgb images... %i", rgb_out);
381  streaming_video_ = true;
382  }
383 
384  // Don't make more than 1 change at a time
385  return;
386  }
387 
388  bool change_depth_settings =
389  depth_buffer_.metadata.depth_format != new_depth_format_ ||
390  depth_buffer_.metadata.resolution != new_depth_resolution_ ||
391  ((streaming_depth_ != should_stream_depth_) && !device_flush_enabled_) ||
392  device_flush_enabled_ && !streaming_depth_ ||
393  stop_device_flush;
394 
395  if (change_depth_settings) {
396  //ROS_INFO("change depth called");
397  // Stop depth stream
398  if (streaming_depth_) {
399  //ROS_INFO(" stopping depth images...");
400  freenect_stop_depth(device_);
401  streaming_depth_ = false;
402  return;
403  }
404  // Allocate buffer for depth if settings have changed
405  if (depth_buffer_.metadata.resolution != new_depth_resolution_ ||
406  depth_buffer_.metadata.depth_format != new_depth_format_) {
407  try {
408  allocateBufferDepth(depth_buffer_, new_depth_format_,
409  new_depth_resolution_, registration_);
410  } catch (std::runtime_error& e) {
411  printf("[ERROR] Unsupported depth format/resolution provided. %s\n",
412  e.what());
413  printf("[INFO] Setting default settings (depth registered/VGA)\n");
414  allocateBufferDepth(depth_buffer_, FREENECT_DEPTH_MM,
415  FREENECT_RESOLUTION_MEDIUM, registration_);
416  }
417  freenect_set_depth_mode(device_, depth_buffer_.metadata);
418  freenect_set_depth_buffer(device_, depth_buffer_.image_buffer.get());
419  new_depth_resolution_ = depth_buffer_.metadata.resolution;
420  new_depth_format_ = depth_buffer_.metadata.depth_format;
421  }
422  // Restart stream if required
423  if (should_stream_depth_ || device_flush_enabled_) {
424  int depth_out = freenect_start_depth(device_);
425  //ROS_INFO(" streaming depth images... %i", depth_out);
426  streaming_depth_ = true;
427  return;
428  }
429  }
430  }
431 
433  boost::lock_guard<boost::recursive_mutex> lock(m_settings_);
434  return isImageMode(video_buffer_);
435  }
436 
437  void depthCallback(void* depth) {
438  boost::lock_guard<boost::mutex> buffer_lock(depth_buffer_.mutex);
439  assert(depth == depth_buffer_.image_buffer.get());
440  if (publishers_ready_) {
441  depth_callback_.operator()(depth_buffer_);
442  }
443  }
444 
445  void videoCallback(void* video) {
446  boost::lock_guard<boost::mutex> buffer_lock(video_buffer_.mutex);
447  assert(video == video_buffer_.image_buffer.get());
448  if (publishers_ready_) {
449  if (isImageMode(video_buffer_)) {
450  image_callback_.operator()(video_buffer_);
451  } else {
452  ir_callback_.operator()(video_buffer_);
453  }
454  }
455  }
456 
457  };
458 }
459 
460 #endif /* end of include guard: FREENECT_DEVICE_T01IELX0 */
bool setSynchronization(bool on_off) const
freenect_resolution new_depth_resolution_
static void freenectDepthCallback(freenect_device *dev, void *depth, uint32_t timestamp)
void registerIRCallback(void(T::*callback)(const ImageBuffer &ir_image, void *cookie), T &instance, void *cookie=NULL)
OutputMode getDefaultImageMode() const
freenect_resolution new_video_resolution_
void setImageOutputMode(OutputMode mode)
void openDevice(freenect_context *driver, std::string serial)
boost::posix_time::ptime device_flush_start_time_
static const std::string VENDOR_NAME
void allocateBufferDepth(ImageBuffer &buffer, const freenect_depth_format &format, const freenect_resolution &resolution, const freenect_registration &registration)
void registerImageCallback(void(T::*callback)(const ImageBuffer &image, void *cookie), T &instance, void *cookie=NULL)
boost::shared_array< unsigned char > image_buffer
freenect_resolution OutputMode
bool findCompatibleImageMode(const OutputMode &mode, OutputMode &compatible_mode) const
static const unsigned VENDOR_ID
static void freenectVideoCallback(freenect_device *dev, void *video, uint32_t timestamp)
boost::function< void(const ImageBuffer &)> depth_callback_
Holds an image buffer with all the metadata required to transmit the image over ROS channels...
bool isImageMode(const ImageBuffer &buffer)
#define ROS_INFO(...)
void registerDepthCallback(void(T::*callback)(const ImageBuffer &depth_image, void *cookie), T &instance, void *cookie=NULL)
FreenectDevice(freenect_context *driver, std::string serial)
freenect_video_format new_video_format_
bool findCompatibleDepthMode(const OutputMode &mode, OutputMode &compatible_mode) const
OutputMode getDefaultDepthMode() const
freenect_registration registration_
freenect_depth_format new_depth_format_
void setDepthOutputMode(OutputMode mode)
boost::function< void(const ImageBuffer &)> image_callback_
const char * getSerialNumber() const
void allocateBufferVideo(ImageBuffer &buffer, const freenect_video_format &format, const freenect_resolution &resolution, const freenect_registration &registration)
boost::function< void(const ImageBuffer &)> ir_callback_
static const std::string PRODUCT_NAME
freenect_frame_mode metadata
static const unsigned PRODUCT_ID
const char * getProductName() const
boost::recursive_mutex m_settings_


freenect_camera
Author(s): Patrick Mihelich, Suat Gedikli, Radu Bogdan Rusu (original openni_camera driver)., Piyush Khandelwal (libfreenect port).
autogenerated on Fri Mar 20 2020 03:22:26