21 Cam::Cam(
const char *_device,
mode_t _mode,
int _width,
int _height,
int _fps)
22 : mode(_mode), device(_device),
23 motion_threshold_luminance(100), motion_threshold_count(-1),
24 width(_width), height(_height), fps(_fps), rgb_frame(NULL)
26 printf(
"opening %s\n", _device);
27 if ((
fd = open(_device, O_RDWR)) == -1)
28 throw std::runtime_error(
"couldn't open " +
device);
29 memset(&
fmt, 0,
sizeof(v4l2_format));
30 memset(&
cap, 0,
sizeof(v4l2_capability));
31 if (ioctl(
fd, VIDIOC_QUERYCAP, &
cap) < 0)
32 throw std::runtime_error(
"couldn't query " +
device);
33 if (!(
cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
34 throw std::runtime_error(
device +
" does not support capture");
35 if (!(
cap.capabilities & V4L2_CAP_STREAMING))
36 throw std::runtime_error(
device +
" does not support streaming");
39 memset(&f, 0,
sizeof(f));
41 f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
43 while ((ret = ioctl(
fd, VIDIOC_ENUM_FMT, &f)) == 0)
45 printf(
"pixfmt %d = '%4s' desc = '%s'\n",
46 f.index++, (
char *)&f.pixelformat, f.description);
48 v4l2_frmsizeenum fsize;
50 fsize.pixel_format = f.pixelformat;
51 while ((ret = ioctl(
fd, VIDIOC_ENUM_FRAMESIZES, &fsize)) == 0)
54 if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE)
56 printf(
" discrete: %ux%u: ",
57 fsize.discrete.width, fsize.discrete.height);
59 v4l2_frmivalenum fival;
61 fival.pixel_format = f.pixelformat;
62 fival.width = fsize.discrete.width;
63 fival.height = fsize.discrete.height;
64 while ((ret = ioctl(
fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival)) == 0)
67 if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
70 fival.discrete.numerator, fival.discrete.denominator);
73 printf(
"I only handle discrete frame intervals...\n");
77 else if (fsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS)
79 printf(
" continuous: %ux%u to %ux%u\n",
80 fsize.stepwise.min_width, fsize.stepwise.min_height,
81 fsize.stepwise.max_width, fsize.stepwise.max_height);
83 else if (fsize.type == V4L2_FRMSIZE_TYPE_STEPWISE)
85 printf(
" stepwise: %ux%u to %ux%u step %ux%u\n",
86 fsize.stepwise.min_width, fsize.stepwise.min_height,
87 fsize.stepwise.max_width, fsize.stepwise.max_height,
88 fsize.stepwise.step_width, fsize.stepwise.step_height);
92 printf(
" fsize.type not supported: %d\n", fsize.type);
97 throw std::runtime_error(
"error enumerating frame formats");
98 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
102 fmt.fmt.pix.pixelformat =
'Y' | (
'U' << 8) | (
'Y' << 16) | (
'V' << 24);
104 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
105 fmt.fmt.pix.field = V4L2_FIELD_ANY;
106 if ((ret = ioctl(
fd, VIDIOC_S_FMT, &
fmt)) < 0)
107 throw std::runtime_error(
"couldn't set format");
109 throw std::runtime_error(
"pixel format unavailable");
110 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
111 streamparm.parm.capture.timeperframe.numerator = 1;
115 if (errno == ENOTTY) {
116 ROS_WARN(
"VIDIOC_S_PARM not spported on this v4l2 device, framerate not set");
118 throw std::runtime_error(
"unable to set framerate");
120 v4l2_queryctrl queryctrl;
121 memset(&queryctrl, 0,
sizeof(queryctrl));
122 uint32_t i = V4L2_CID_BASE;
126 if ((ret = ioctl(
fd, VIDIOC_QUERYCTRL, &queryctrl)) == 0 &&
127 !(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED))
129 const char *ctrl_type = NULL;
130 if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER)
132 else if (queryctrl.type == V4L2_CTRL_TYPE_BOOLEAN)
134 else if (queryctrl.type == V4L2_CTRL_TYPE_BUTTON)
135 ctrl_type =
"button";
136 else if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
138 printf(
" %s (%s, %d, id = %x): %d to %d (%d)\n",
140 queryctrl.name, queryctrl.flags, queryctrl.id,
141 queryctrl.minimum, queryctrl.maximum, queryctrl.step);
142 if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
144 v4l2_querymenu querymenu;
145 memset(&querymenu, 0,
sizeof(querymenu));
146 querymenu.id = queryctrl.id;
148 while (ioctl(
fd, VIDIOC_QUERYMENU, &querymenu) == 0)
150 printf(
" %d: %s\n", querymenu.index, querymenu.name);
174 memset(&
rb, 0,
sizeof(
rb));
176 rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
177 rb.memory = V4L2_MEMORY_MMAP;
178 if (ioctl(
fd, VIDIOC_REQBUFS, &
rb) < 0)
179 throw std::runtime_error(
"unable to allocate buffers");
184 memset(&
buf, 0,
sizeof(
buf));
186 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
187 buf.flags = V4L2_BUF_FLAG_TIMECODE;
189 buf.timestamp.tv_sec = 0;
190 buf.timestamp.tv_usec = 0;
191 buf.memory = V4L2_MEMORY_MMAP;
192 if (ioctl(
fd, VIDIOC_QUERYBUF, &
buf) < 0)
193 throw std::runtime_error(
"unable to query buffer");
195 throw std::runtime_error(
"buffer length is bogus");
196 mem[i] = mmap(0,
buf.length, PROT_READ|PROT_WRITE, MAP_SHARED,
fd,
buf.m.offset);
198 if (
mem[i] == MAP_FAILED)
199 throw std::runtime_error(
"couldn't map buffer");
204 memset(&
buf, 0,
sizeof(
buf));
206 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
207 buf.flags = V4L2_BUF_FLAG_TIMECODE;
209 buf.timestamp.tv_sec = 0;
210 buf.timestamp.tv_usec = 0;
211 buf.memory = V4L2_MEMORY_MMAP;
212 if (ioctl(
fd, VIDIOC_QBUF, &
buf) < 0)
213 throw std::runtime_error(
"unable to queue buffer");
215 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
216 if (ioctl(
fd, VIDIOC_STREAMON, &type) < 0)
217 throw std::runtime_error(
"unable to start capture");
225 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE, ret;
226 if ((ret = ioctl(
fd, VIDIOC_STREAMOFF, &type)) < 0)
227 perror(
"VIDIOC_STREAMOFF");
230 perror(
"failed to unmap buffer");
242 string v4l_path =
"/sys/class/video4linux";
243 DIR *d = opendir(v4l_path.c_str());
245 throw std::runtime_error(
"couldn't open " + v4l_path);
246 struct dirent *ent, *ent2, *ent3;
248 struct v4l2_capability v4l2_cap;
249 while ((ent = readdir(d)) != NULL)
251 if (strncmp(ent->d_name,
"video", 5))
253 string dev_name = string(
"/dev/") + string(ent->d_name);
254 printf(
"enumerating %s ...\n", dev_name.c_str());
255 if ((fd = open(dev_name.c_str(), O_RDWR)) == -1)
256 throw std::runtime_error(
"couldn't open " + dev_name +
" perhaps the " +
257 "permissions are not set correctly?");
258 if ((ret = ioctl(fd, VIDIOC_QUERYCAP, &v4l2_cap)) < 0)
259 throw std::runtime_error(
"couldn't query " + dev_name);
260 printf(
"name = [%s]\n", v4l2_cap.card);
261 printf(
"driver = [%s]\n", v4l2_cap.driver);
262 printf(
"location = [%s]\n", v4l2_cap.bus_info);
264 string v4l_dev_path = v4l_path + string(
"/") + string(ent->d_name) +
267 DIR *d2 = opendir(v4l_dev_path.c_str());
269 throw std::runtime_error(
"couldn't open " + v4l_dev_path);
271 while ((ent2 = readdir(d2)) != NULL)
273 if (strncmp(ent2->d_name,
"input", 5))
276 DIR *input = opendir((v4l_dev_path +
string(
"/") +
string(ent2->d_name)).c_str());
277 bool output_set =
false;
278 while ((ent3 = readdir(input)) != NULL)
280 if (!strncmp(ent3->d_name,
"input", 5))
282 input_dir = (string(
"input/") + string(ent3->d_name )).c_str();
288 input_dir = ent2->d_name;
292 if (!input_dir.length())
293 throw std::runtime_error(
"couldn't find input dir in " + v4l_dev_path);
294 string vid_fname = v4l_dev_path + string(
"/") + input_dir +
295 string(
"/id/vendor");
296 string pid_fname = v4l_dev_path + string(
"/") + input_dir +
297 string(
"/id/product");
298 string ver_fname = v4l_dev_path + string(
"/") + input_dir +
299 string(
"/id/version");
300 char vid[5], pid[5], ver[5];
301 FILE *vid_fp = fopen(vid_fname.c_str(),
"r");
303 throw std::runtime_error(
"couldn't open " + vid_fname);
304 if (!fgets(vid,
sizeof(vid), vid_fp))
305 throw std::runtime_error(
"couldn't read VID from " + vid_fname);
308 printf(
"vid = [%s]\n", vid);
309 FILE *pid_fp = fopen(pid_fname.c_str(),
"r");
311 throw std::runtime_error(
"couldn't open " + pid_fname);
312 if (!fgets(pid,
sizeof(pid), pid_fp))
313 throw std::runtime_error(
"couldn't read PID from " + pid_fname);
315 printf(
"pid = [%s]\n", pid);
316 FILE *ver_fp = fopen(ver_fname.c_str(),
"r");
318 throw std::runtime_error(
"couldn't open " + ver_fname);
319 if (!fgets(ver,
sizeof(ver), ver_fp))
320 throw std::runtime_error(
"couldn't read version from " + ver_fname);
322 printf(
"ver = [%s]\n", ver);
328 inline unsigned char sat(
float f)
330 return (
unsigned char)( f >= 255 ? 255 : (f < 0 ? 0 : f));
333 int Cam::grab(
unsigned char **frame, uint32_t &bytes_used)
344 ret = select(
fd + 1, &rdset, NULL, NULL, &timeout);
347 printf(
"select timeout in grab\n");
352 perror(
"couldn't grab image");
355 if (!FD_ISSET(
fd, &rdset))
357 memset(&
buf, 0,
sizeof(
buf));
358 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
359 buf.memory = V4L2_MEMORY_MMAP;
360 if (ioctl(
fd, VIDIOC_DQBUF, &
buf) < 0)
361 throw std::runtime_error(
"couldn't dequeue buffer");
362 bytes_used =
buf.bytesused;
365 int num_pixels_different = 0;
366 unsigned char *pyuv = (
unsigned char *)
mem[
buf.index];
370 for (
unsigned i = 0; i <
width *
height * 2; i += 4)
372 *prgb++ =
sat(pyuv[i]+1.402
f *(pyuv[i+3]-128));
373 *prgb++ =
sat(pyuv[i]-0.34414
f*(pyuv[i+1]-128)-0.71414
f*(pyuv[i+3]-128));
374 *prgb++ =
sat(pyuv[i]+1.772
f *(pyuv[i+1]-128));
375 *prgb++ =
sat(pyuv[i+2]+1.402
f*(pyuv[i+3]-128));
376 *prgb++ =
sat(pyuv[i+2]-0.34414
f*(pyuv[i+1]-128)-0.71414
f*(pyuv[i+3]-128));
377 *prgb++ =
sat(pyuv[i+2]+1.772
f*(pyuv[i+1]-128));
380 num_pixels_different++;
383 num_pixels_different++;
406 *frame = (uint8_t *)
mem[
buf.index];
411 *frame = (
unsigned char *)
mem[
buf.index];
419 if (ioctl(
fd, VIDIOC_QBUF, &
buf) < 0)
420 throw std::runtime_error(
"couldn't requeue buffer");
427 printf(
"Capture file not open: Can't %s\n", name.c_str());
431 struct v4l2_queryctrl queryctrl;
432 memset(&queryctrl, 0,
sizeof(queryctrl));
434 if (v4l2_ioctl(
fd, VIDIOC_QUERYCTRL, &queryctrl) < 0) {
435 if (errno == EINVAL) {
438 ROS_WARN(
"Failed query %s", name.c_str());
450 printf(
"Capture file not open: Can't %s\n", name.c_str());
455 printf(
"Setting %s is not supported\n", name.c_str());
459 struct v4l2_control control;
460 memset(&control, 0,
sizeof(control));
462 control.value = value;
463 if (v4l2_ioctl(
fd, VIDIOC_S_CTRL, &control) < 0) {
464 ROS_WARN(
"Failed to change %s to %d", name.c_str(), control.value);
476 if (ioctl(
fd, VIDIOC_G_CTRL, &c) == 0)
478 printf(
"current value of %d is %d\n",
id, c.value);
485 if (ioctl(
fd, VIDIOC_S_CTRL, &c) < 0)
487 perror(
"unable to set control");
488 throw std::runtime_error(
"unable to set control");
unsigned char * rgb_frame
unsigned char sat(float f)
CSU32 V4L2_CID_LAST_EXTCTR
void release(unsigned buf_idx)
CSU32 V4L2_CID_PRIVATE_LAST
bool set_v4l2_control(int id, int value, const std::string &name)
int motion_threshold_count
void set_control(uint32_t id, int val)
CSU32 V4L2_CID_CAMERA_CLASS_BASE_NEW
CSU32 V4L2_CID_CAMERA_CLASS_LAST
enum uvc_cam::Cam::mode_t mode
void set_motion_thresholds(int lum, int count)
Cam(const char *device, mode_t _mode=MODE_RGB, int _width=640, int _height=480, int _fps=30)
unsigned char * last_yuv_frame
int motion_threshold_luminance
CSU32 V4L2_CID_PRIVATE_BASE_OLD
bool v4l2_query(int id, const std::string &name)
v4l2_streamparm streamparm
CSU32 V4L2_CID_BASE_EXTCTR
static const unsigned NUM_BUFFER
int grab(unsigned char **frame, uint32_t &bytes_used)