uvc.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2012 by Markus Bader *
3  * markus.bader@tuwien.ac.at *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
21 
22 #include <iomanip>
23 #include <tuw_uvc/uvc_defaults.h>
24 #include <tuw_uvc/uvc.h>
25 #include <boost/algorithm/string.hpp>
26 
27 extern "C" {
28 #include <libv4l2.h>
29 #include "luvcview/v4l2uvc.h"
30 #include "luvcview/color.h"
31 #include <linux/videodev2.h>
32 }
33 
34 /* Fixed point arithmetic */
35 #define FIXED Sint32
36 #define FIXED_BITS 16
37 #define TO_FIXED(X) (((Sint32)(X))<<(FIXED_BITS))
38 #define FROM_FIXED(X) (((Sint32)(X))>>(FIXED_BITS))
39 
40 
41 #define INCPANTILT 64 // 1°
42 
43 
44 #include <boost/interprocess/sync/scoped_lock.hpp>
45 typedef boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> Lock;
46 
47 //static const char version[] = VERSION;
48 
49 
50 
52 {
53  if(in == ' ') return '_';
54  if(!isalnum(in)) return '_';
55  return in;
56 }
57 
59 {
60  if(pVideoIn_) {
62  free(pVideoIn_);
63  }
64  freeLut();
65 }
66 
68  : pVideoIn_(NULL)
75  , fps_(DEFAULT_FPS)
76 {
77  mutexImage_.unlock();
78 }
79 
80 V4RCam::FD V4RCam::initCamera(const std::string &videoDevice)
81 {
82  if(!videoDevice.empty()) {
83  videoDevice_ = videoDevice;
84  }
85  pVideoIn_ = (struct vdIn *) calloc(1, sizeof(struct vdIn));
86  if(init_videoIn(pVideoIn_, (char *) videoDevice_.c_str(), width_, height_, fps_, format_, grabmethod_, (char *) aviFilename_.c_str()) < 0)
87  exit(1);
88  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
89  if(uvcGrab(pVideoIn_) < 0) {
90  printf("Error grabbing first image\n");
91  return 0;
92  }
93  if((width_ != pVideoIn_->width) || (height_ != pVideoIn_->height) || (fps_ != pVideoIn_->fps)){
95  height_ = pVideoIn_->height;
96  fps_ = pVideoIn_->fps;
97  printf("Error: image format not supported changed to: %ipix x %ipix @ %3.1fHz\n", width_, height_, fps_);
98  }
99  initLut();
100  gettimeofday(&timeLastFrame_, NULL);
101  return pVideoIn_->fd;
102 }
103 
104 
106 {
107 
108  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
109  Lock myLock(mutexImage_);
110  if(uvcGrab(pVideoIn_) < 0) {
111  printf("Error grabbing\n");
112  return false;
113  }
114  if(pVideoIn_->signalquit != 1) {
115  printf("videoIn->signalquit\n");
116  return false;
117  }
118  timeval now;
119  gettimeofday(&now, NULL);
120  durationLastFrame_ = (now.tv_sec - timeLastFrame_.tv_sec) * 1000.0; // sec to ms
121  durationLastFrame_ += (now.tv_usec - timeLastFrame_.tv_usec) / 1000.0; // us to ms
122  timeLastFrame_ = now;
123 
124  return true;
125 }
126 
127 
129 {
130  Lock myLock(mutexImage_);
131  if(entry->valid == false) {
132  entry->error_msg << "v4lgetInfo not valid\n";
133  return ERROR;
134  }
135  if((v4l2_ioctl(pVideoIn_->fd, VIDIOC_QUERYCTRL, entry->queryctrl)) < 0) {
136  entry->valid = false;
137  entry->error_msg << "v4l2_ioctl querycontrol error\n";
138  return ERROR;
139  } else if(entry->queryctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
140  entry->valid = false;
141  entry->error_msg << "control disabled\n";
142  return ERROR;
143  } else if(entry->hasValidType() == false) {
144  entry->valid = false;
145  entry->error_msg << "unsupported type\n";
146  return ERROR;
147  }
148  entry->varName = std::string((const char *) entry->queryctrl->name);
149  boost::algorithm::to_lower(entry->varName);
150 
151  std::transform(entry->varName.begin(), entry->varName.end(), entry->varName.begin(), V4RCam::removeNonAlNum);
152  boost::algorithm::trim_left_if(entry->varName, boost::algorithm::is_any_of("_"));
153  boost::algorithm::trim_right_if(entry->varName, boost::algorithm::is_any_of("_"));
154  boost::algorithm::replace_all(entry->varName, "___", "_");
155  boost::algorithm::replace_all(entry->varName, "__", "_");
156 
157  return OK;
158 }
159 
160 
162 {
163  Lock myLock(mutexImage_);
164  if(entry->valid == false) {
165  entry->error_msg << "v4lget not valid\n";
166  return ERROR;
167  }
168  struct v4l2_control control;
169  control.id = entry->queryctrl->id;
170 
171  if(v4l2_ioctl(pVideoIn_->fd, VIDIOC_G_CTRL, &control) < 0) {
172  entry->error_msg << "v4l2_ioctl get control error\n";
173  return ERROR;
174  }
175  entry->currentValue = control.value;
176  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
177  entry->info_msg << "current = " << entry->currentValue << "\n";
178  return OK;
179 }
180 
182 {
183  Lock myLock(mutexImage_);
184  if(entry->valid == false) {
185  entry->error_msg << "v4lset not valid\n";
186  return ERROR;
187  }
188  struct v4l2_control control;
189  control.id = entry->queryctrl->id;
190  control.value = entry->targetValue;
191  if(v4l2_ioctl(pVideoIn_->fd, VIDIOC_S_CTRL, &control) < 0) {
192  entry->error_msg << "v4l2_ioctl set( " << control.value << ") control error\n";
193  return ERROR;
194  }
195  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
196  entry->currentValue = entry->targetValue;
197  entry->info_msg << "current = " << entry->currentValue << "\n";
198  return OK;
199 }
201 {
202  Lock myLock(mutexImage_);
203  if(entry->currentValue == entry->targetValue) {
204  return OK;
205  }
206  if(entry->valid == false) {
207  entry->currentValue = entry->targetValue;
208  entry->error_msg << "v4lupdate not valid\n";
209  return ERROR;
210  }
211 
212  if(entry->targetValue % entry->queryctrl->step) {
213  entry->info_msg << "target value " << entry->targetValue << "between steps " << entry->queryctrl->step;
214  entry->targetValue = (entry->targetValue / entry->queryctrl->step) * entry->queryctrl->step;
215  entry->info_msg << "new target value = " << entry->targetValue << std::endl;
216  }
217  if(entry->targetValue > entry->queryctrl->maximum) {
218  entry->info_msg << "clipping taget value = " << entry->targetValue << " to maximum = " << entry->queryctrl->maximum << "\n";
219  entry->targetValue = entry->queryctrl->maximum;
220  }
221  if(entry->targetValue < entry->queryctrl->minimum) {
222  entry->info_msg << "clipping taget value = " << entry->targetValue << " to minimum = " << entry->queryctrl->minimum << "\n";
223  entry->targetValue = entry->queryctrl->minimum;
224  }
225 
226  struct v4l2_control control;
227  control.id = entry->queryctrl->id;
228  control.value = entry->targetValue;
229  if(v4l2_ioctl(pVideoIn_->fd, VIDIOC_S_CTRL, &control) < 0) {
230  entry->error_msg << "v4l2_ioctl set( " << control.value << ") control error\n";
231  return ERROR;
232  }
233  if(entry->queryctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) {
234  entry->info_msg << "entry is write only\n";
235  entry->currentValue = entry->targetValue;
236  } else {
237  if(v4l2_ioctl(pVideoIn_->fd, VIDIOC_G_CTRL, &control) < 0) {
238  entry->error_msg << "v4l2_ioctl get control error, to verify\n";
239  return ERROR;
240  }
241  entry->currentValue = control.value;
242  if(control.value != entry->targetValue) {
243  entry->error_msg << "v4l2_ioctl set and get are different. -> ";
244  entry->error_msg << entry->targetValue << " != " << control.value << std::endl;
245  return ERROR;
246  }
247  }
248  entry->info_msg << "current = " << entry->currentValue << "\n";
249  return OK;
250 }
251 
253  : valid(true)
254  , varName("NA")
255  , queryctrl(new v4l2_queryctrl)
256  , currentValue(-1)
257  , targetValue(-1)
258 {
259  queryctrl->id = id;
260 }
262 {
263  delete queryctrl;
264 }
266 {
267  if(queryctrl->type == V4L2_CTRL_TYPE_INTEGER) return true;
268  if(queryctrl->type == V4L2_CTRL_TYPE_BOOLEAN) return true;
269  if(queryctrl->type == V4L2_CTRL_TYPE_MENU) return true;
270  if(queryctrl->type == V4L2_CTRL_TYPE_BUTTON) return true;
271  if(queryctrl->type == V4L2_CTRL_TYPE_INTEGER64) return true;
272  if(queryctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) return true;
273  if(queryctrl->type == V4L2_CTRL_TYPE_STRING) return true;
274  if(queryctrl->type == V4L2_CTRL_TYPE_BITMASK) return true;
275  if(queryctrl->type == V4L2_CTRL_TYPE_BITMASK) return true;
276  return false;
277 }
279 {
280  std::stringstream ss;
281 
282  ss << std::setw(9) << std::hex << std::showbase << queryctrl->id << " = " << varName;
283  if(valid == false) return ss.str();
284  ss << " >> " << queryctrl->name << std::endl;
285  ss << std::dec << "current = " << currentValue << ", target = " << targetValue;
286  ss << ", min = " << queryctrl->minimum << ", max = " << queryctrl->maximum;
287  ss << ", default = " << queryctrl->default_value << ", step = " << queryctrl->step << std::endl;
288  ss << "flags =";
289  if(queryctrl->flags & V4L2_CTRL_FLAG_DISABLED) ss << " disabled";
290  if(queryctrl->flags & V4L2_CTRL_FLAG_GRABBED) ss << " grabbed";
291  if(queryctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) ss << " read only";
292  if(queryctrl->flags & V4L2_CTRL_FLAG_UPDATE) ss << " update";
293  if(queryctrl->flags & V4L2_CTRL_FLAG_INACTIVE) ss << " inactive";
294  if(queryctrl->flags & V4L2_CTRL_FLAG_SLIDER) ss << " slider";
295  if(queryctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY) ss << " write only";
296  if(queryctrl->flags & V4L2_CTRL_FLAG_VOLATILE) ss << " volatile";
297  if(queryctrl->flags == 0) ss << " empty";
298  ss << "; type =";
299  if(queryctrl->type == V4L2_CTRL_TYPE_INTEGER) ss << " integer";
300  else if(queryctrl->type == V4L2_CTRL_TYPE_BOOLEAN) ss << "boolean";
301  else if(queryctrl->type == V4L2_CTRL_TYPE_MENU) ss << "menu";
302  else if(queryctrl->type == V4L2_CTRL_TYPE_BUTTON) ss << "button";
303  else if(queryctrl->type == V4L2_CTRL_TYPE_INTEGER64) ss << "integer64";
304  else if(queryctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS) ss << "ctrl_class";
305  else if(queryctrl->type == V4L2_CTRL_TYPE_STRING) ss << "string";
306  else if(queryctrl->type == V4L2_CTRL_TYPE_BITMASK) ss << "bitmask";
307  else ss << "unsupported";
308  return ss.str();
309 }
310 
312 {
313  std::string str = error_msg.str();
314  error_msg.str(std::string());
315  return str;
316 }
318 {
319  std::string str = info_msg.str();
320  info_msg.str(std::string());
321  return str;
322 }
324 {
325  return !error_msg.str().empty();
326 };
328 {
329  return !info_msg.str().empty();
330 };
331 
332 std::string V4RCam::pullErrorMsg()
333 {
334  std::string str = error_msg_.str();
335  error_msg_.str(std::string());
336  return str;
337 }
338 std::string V4RCam::pullInfoMsg()
339 {
340  std::string str = info_msg_.str();
341  info_msg_.str(std::string());
342  return str;
343 }
345 {
346  return !error_msg_.str().empty();
347 };
348 bool V4RCam::hasInfoMsg() const
349 {
350  return !info_msg_.str().empty();
351 };
352 const std::vector<V4RCam::ControlEntryPtr > &V4RCam::detectControlEnties()
353 {
354  v4l2_queryctrl queryctrl;
355 
356  controlEntries_.clear();
357 
358  /* Try the extended control API first */
359 #ifdef V4L2_CTRL_FLAG_NEXT_CTRL // ref --> v4l3upc
360  queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
361  if(0 == v4l2_ioctl(pVideoIn_->fd, VIDIOC_QUERYCTRL, &queryctrl)) {
362  do {
363  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
364  controlEntries_.push_back(ControlEntryPtr(new ControlEntry(queryctrl.id)));
365  queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
366  } while(0 == v4l2_ioctl(pVideoIn_->fd, VIDIOC_QUERYCTRL, &queryctrl));
367  } else
368 #endif
369  {
370  /* Fall back on the standard API */
371  /* Check all the standard controls */
372  for(int i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++) {
373  controlEntries_.push_back(ControlEntryPtr(new ControlEntry(i)));
374  }
375  /* Check any custom controls */
376  for(queryctrl.id = V4L2_CID_PRIVATE_BASE; (v4l2_ioctl(pVideoIn_->fd, VIDIOC_QUERYCTRL, &queryctrl) == 0) ; queryctrl.id++) {
377  controlEntries_.push_back(ControlEntryPtr(new ControlEntry(queryctrl.id)));
378  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
379  }
380  }
381  for(unsigned int i = 0; i < controlEntries_.size(); i++) {
383  }
384  return controlEntries_;
385 }
386 
387 
388 int V4RCam::save_controls(const std::string &filename)
389 {
390  struct v4l2_queryctrl queryctrl;
391  struct v4l2_control control_s;
392  FILE *configfile;
393  memset(&queryctrl, 0, sizeof(queryctrl));
394  memset(&control_s, 0, sizeof(control_s));
395  configfile = fopen(filename.c_str(), "w");
396  if(configfile == NULL) {
397  error_msg_ << "saving configfile: " << filename << " failed" << std::endl;
398  } else {
399  fprintf(configfile, "id value # luvcview control settings configuration file\n");
400  for(std::vector<V4RCam::ControlEntryPtr>::const_iterator it = controlEntries_.begin(); it != controlEntries_.end(); it++) {
401  queryctrl.id = (*it)->queryctrl->id;
402  if(0 == ioctl(pVideoIn_->fd, VIDIOC_QUERYCTRL, &queryctrl)) {
403  if(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
404  continue;
405  control_s.id = queryctrl.id;
406  v4l2_ioctl(pVideoIn_->fd, VIDIOC_G_CTRL, &control_s);
407  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
408  fprintf(configfile, "%-10d %-10d # name:%-32s type:%d min:%-5d max:%-5d step:%-5d def:%d\n",
409  queryctrl.id, control_s.value, queryctrl.name, queryctrl.type, queryctrl.minimum,
410  queryctrl.maximum, queryctrl.step, queryctrl.default_value);
411  printf("%-10d %-10d # name:%-32s type:%d min:%-5d max:%-5d step:%-5d def:%d\n",
412  queryctrl.id, control_s.value, queryctrl.name, queryctrl.type, queryctrl.minimum,
413  queryctrl.maximum, queryctrl.step, queryctrl.default_value);
414  boost::this_thread::sleep(boost::posix_time::milliseconds(10));
415  }
416  }
417  fflush(configfile);
418  fclose(configfile);
419  boost::this_thread::sleep(boost::posix_time::milliseconds(100));
420  info_msg_ << "saved configfile: " << filename << std::endl;
421  }
422  return OK;
423 }
424 
425 int V4RCam::load_controls(const std::string &filename)//struct vdIn *vd)
426 {
427  struct v4l2_control control;
428  FILE *configfile;
429  memset(&control, 0, sizeof(control));
430  configfile = fopen(filename.c_str(), "r");
431  if(configfile == NULL) {
432  error_msg_ << "configfile: " << filename << " open failed" << std::endl;
433  } else {
434  info_msg_ << "loading controls from luvcview.cfg\n";
435  char buffer[0xFFF];
436  while(NULL != fgets(buffer, sizeof(buffer), configfile)) {
437  sscanf(buffer, "%i%i", &control.id, &control.value);
438  if(v4l2_ioctl(pVideoIn_->fd, VIDIOC_S_CTRL, &control))
439  info_msg_ << "ERROR id: " << control.id << " val: " << control.value << std::endl;
440  else
441  info_msg_ << "OK id: " << control.id << " val: " << control.value << std::endl;
442  boost::this_thread::sleep(boost::posix_time::milliseconds(20));
443  }
444  fclose(configfile);
445  info_msg_ << "loaded configfile: " << filename << std::endl;
446  }
447 }
448 
450  for(unsigned int i = 0; i < controlEntries_.size(); i++){
451  if(controlEntries_[i]->varName.compare(varName) == 0){
452  return controlEntries_[i];
453  }
454  }
455  return V4RCam::ControlEntryPtr();
456 }
static const int ERROR
Definition: uvc.h:44
#define DEFAULT_AVIFILENAME
Definition: uvc_defaults.h:31
std::string pullInfoMsg()
Definition: uvc.cpp:338
int fd
Definition: v4l2uvc.h:44
#define DEFAULT_HEIGHT
Definition: uvc_defaults.h:35
int v4lset(ControlEntryPtr entry)
Definition: uvc.cpp:181
int FD
Definition: uvc.h:48
ControlEntry(int id)
Definition: uvc.cpp:252
boost::interprocess::scoped_lock< boost::interprocess::interprocess_mutex > Lock
Definition: uvc.cpp:45
bool hasInfoMsg() const
returns false if therer are any error msgs waiting for pull
Definition: uvc.cpp:327
#define DEFAULT_FPS
Definition: uvc_defaults.h:36
#define DEFAULT_VIDEODEVICE
Definition: uvc_defaults.h:30
const std::vector< ControlEntryPtr > & detectControlEnties()
Definition: uvc.cpp:352
v4l2_queryctrl * queryctrl
name of the v4l2 control
Definition: uvc.h:59
int format_
not supported yet
Definition: uvc.h:83
int signalquit
Definition: v4l2uvc.h:63
bool hasValidType() const
creates an info string related to the v4l2 control
Definition: uvc.cpp:265
std::stringstream error_msg
info msgs stream
Definition: uvc.h:63
float fps
Definition: v4l2uvc.h:59
int height_
image width
Definition: uvc.h:86
std::string videoDevice_
pointer to the v4l2 device
Definition: uvc.h:81
void freeLut(void)
Definition: color.c:120
std::string aviFilename_
device name /dev/videoX
Definition: uvc.h:82
std::string varName
Definition: uvc.h:58
bool hasErrorMsg() const
Definition: uvc.cpp:344
int close_v4l2(struct vdIn *vd)
Definition: v4l2uvc.c:677
std::string pullErrorMsg()
return true if the value type is supported
Definition: uvc.cpp:311
int grabmethod_
image formate
Definition: uvc.h:84
bool grab()
destructor
Definition: uvc.cpp:105
int save_controls(const std::string &filename)
Definition: uvc.cpp:388
#define DEFAULT_WIDTH
Definition: uvc_defaults.h:34
std::stringstream error_msg_
Definition: uvc.h:179
int v4lupdate(ControlEntryPtr entry)
Definition: uvc.cpp:200
std::stringstream info_msg
target value to set after a write
Definition: uvc.h:62
timeval timeLastFrame_
frames per second
Definition: uvc.h:88
#define DEFAULT_FORMAT
Definition: uvc_defaults.h:32
int uvcGrab(struct vdIn *vd)
Definition: v4l2uvc.c:562
Definition: utils.c:55
int height
Definition: v4l2uvc.h:58
void initLut(void)
Definition: color.c:78
static char removeNonAlNum(char in)
Definition: uvc.cpp:51
int width
Definition: v4l2uvc.h:57
bool valid
destructor
Definition: uvc.h:57
int width_
Definition: uvc.h:85
ControlEntryPtr getControlEntry(std::string varName)
Definition: uvc.cpp:449
Definition: v4l2uvc.h:43
std::string getQueryCtrlInfo() const
error msgs in the case something happend
Definition: uvc.cpp:278
static struct in in
Definition: utils.c:176
boost::interprocess::interprocess_mutex mutexImage_
duration between last and the frame before the last one
Definition: uvc.h:90
int targetValue
current value of the control after read or set
Definition: uvc.h:61
int v4lgetInfo(ControlEntryPtr entry)
v4lcontrols
Definition: uvc.cpp:128
vdIn * pVideoIn_
Definition: uvc.h:80
std::vector< ControlEntryPtr > controlEntries_
mutex to secure critical sections
Definition: uvc.h:91
int load_controls(const std::string &filename)
Definition: uvc.cpp:425
double durationLastFrame_
time stamp of the last frame
Definition: uvc.h:89
boost::shared_ptr< ControlEntry > ControlEntryPtr
Definition: uvc.h:71
int v4lget(ControlEntryPtr entry)
Definition: uvc.cpp:161
int init_videoIn(struct vdIn *vd, char *device, int width, int height, float fps, int format, int grabmethod, char *avifilename)
Definition: v4l2uvc.c:105
static const int OK
Definition: uvc.h:43
V4RCam()
shared pointer for ControlEntry
Definition: uvc.cpp:67
bool hasErrorMsg() const
clears the info_msgs stringstream and crates a info string
Definition: uvc.cpp:323
std::stringstream info_msg_
Definition: uvc.h:178
FD initCamera(const std::string &videoDevice="")
vector of the current supported control entries
Definition: uvc.cpp:80
bool hasInfoMsg() const
Definition: uvc.cpp:348
~V4RCam()
construtor
Definition: uvc.cpp:58
int currentValue
pointer to the original related control
Definition: uvc.h:60
std::string pullErrorMsg()
Definition: uvc.cpp:332
float fps_
image height
Definition: uvc.h:87
std::string pullInfoMsg()
clears the error_msgs stringstream and crates a info string
Definition: uvc.cpp:317
#define DEFAULT_GRABMETHODE
Definition: uvc_defaults.h:33
~ControlEntry()
construtor
Definition: uvc.cpp:261


tuw_uvc
Author(s): Markus Bader
autogenerated on Mon Jun 10 2019 15:39:24