00001 #ifdef __linux__
00002
00003 #include "CameraDriverV4L2.h"
00004 #include "Shared/debuget.h"
00005
00006 #include "Shared/MarkScope.h"
00007
00008 #include <fcntl.h>
00009 #include <sys/ioctl.h>
00010 #include <sys/mman.h>
00011 #include <sys/types.h>
00012 #include <sys/time.h>
00013 #include <unistd.h>
00014 #include <errno.h>
00015
00016 using namespace std;
00017
00018 const std::string CameraDriverV4L2::autoRegisterCameraDriverV4L2 = DeviceDriver::getRegistry().registerType<CameraDriverV4L2>("Camera");
00019
00020 bool CameraDriverV4L2::advance()
00021 {
00022
00023
00024 int ret;
00025
00026 if (camfd < 0)
00027 return false;
00028
00029
00030 MarkScope l(lock);
00031
00032
00033 if (!streaming) {
00034 if (video_enable()) {
00035 return false;
00036 }
00037 }
00038
00039
00040
00041 ret = dequeue_buffer();
00042 if (ret < 0 && errno!= EAGAIN) {
00043 return false;
00044 }
00045
00046 timestamp = get_time();
00047
00048
00049
00050 if (downsample)
00051 downsample_yuyv();
00052 else
00053 upsample_yuyv();
00054
00055
00056
00057 ++frameCount;
00058 return true;
00059 }
00060
00061 int CameraDriverV4L2::dequeue_buffer()
00062 {
00063 int ret;
00064
00065
00066 memset( &v_buf, 0, sizeof (struct v4l2_buffer) );
00067 v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00068 v_buf.memory = V4L2_MEMORY_MMAP;
00069 ret = ioctl( camfd, VIDIOC_DQBUF, &v_buf );
00070 if (ret) {
00071 perror("Unable to dequeue buffer");
00072 return ret;
00073 }
00074
00075
00076
00077
00078
00079
00080
00081 if (captureBuf.size() != v_buf.length)
00082 captureBuf.resize(v_buf.length);
00083
00084
00085 memcpy(&captureBuf[0], v_mem[v_buf.index].start, v_buf.bytesused);
00086
00087
00088 ret = ioctl( camfd, VIDIOC_QBUF, &v_buf);
00089 if (ret < 0) {
00090 perror("Unable to requeue buffer");
00091 return ret;
00092 }
00093
00094 return 0;
00095 }
00096
00097 void CameraDriverV4L2::registerSource() {
00098 open_cam();
00099 path.addPrimitiveListener(this);
00100 resolution.addPrimitiveListener(this);
00101 queryOptions.addPrimitiveListener(this);
00102 userOptions.addCollectionListener(this);
00103 for(plist::DictionaryOf< plist::Primitive<int> >::const_iterator it=userOptions.begin(); it!=userOptions.end(); ++it)
00104 it->second->addPrimitiveListener(this);
00105 }
00106
00107 void CameraDriverV4L2::deregisterSource() {
00108 userOptions.removeCollectionListener(this);
00109 for(plist::DictionaryOf< plist::Primitive<int> >::const_iterator it=userOptions.begin(); it!=userOptions.end(); ++it)
00110 it->second->removePrimitiveListener(this);
00111 queryOptions.removePrimitiveListener(this);
00112 resolution.removePrimitiveListener(this);
00113 path.removePrimitiveListener(this);
00114 close_cam();
00115 }
00116
00117 void CameraDriverV4L2::doUnfreeze() {
00118 thread.start();
00119 }
00120
00121 void CameraDriverV4L2::doFreeze() {
00122 if(thread.isStarted())
00123 thread.stop().join();
00124 }
00125
00126 void CameraDriverV4L2::threadrun() {
00127 while(advance())
00128 Thread::testCurrentCancel();
00129 }
00130
00131
00132 void CameraDriverV4L2::plistValueChanged(const plist::PrimitiveBase& pl)
00133 {
00134 if (&pl == &path || &pl == &resolution) {
00135 MarkScope l(lock);
00136 open_cam();
00137 }
00138 else if (&pl == &queryOptions && queryOptions == true) {
00139 MarkScope l(lock);
00140 query_options(true);
00141 queryOptions = false;
00142 }
00143 else {
00144
00145 std::string name;
00146 for(plist::DictionaryOf< plist::Primitive<int> >::const_iterator it=userOptions.begin(); it!=userOptions.end(); ++it) {
00147 if(&pl == it->second) {
00148 name = it->first;
00149 break;
00150 }
00151 }
00152 if(name.size()==0) {
00153 std::cerr << "Could not find name for modified value" << std::endl;
00154 return;
00155 }
00156
00157
00158
00159
00160 MarkScope l(lock);
00161 close_cam();
00162 open_cam();
00163 }
00164 }
00165
00166 void CameraDriverV4L2::plistCollectionEntryAdded(plist::Collection& , plist::ObjectBase& obj) {
00167 plist::PrimitiveBase& prim = dynamic_cast<plist::PrimitiveBase&>(obj);
00168 prim.addPrimitiveListener(this);
00169 plistValueChanged(prim);
00170 }
00171 void CameraDriverV4L2::plistCollectionEntryRemoved(plist::Collection& , plist::ObjectBase& obj) {
00172 plist::PrimitiveBase& prim = dynamic_cast<plist::PrimitiveBase&>(obj);
00173 prim.removePrimitiveListener(this);
00174 }
00175 void CameraDriverV4L2::plistCollectionEntriesChanged(plist::Collection& ) {
00176
00177 MarkScope l(lock);
00178 close_cam();
00179 open_cam();
00180 }
00181
00182
00183 void CameraDriverV4L2::close_cam()
00184 {
00185 if(camfd >= 0) {
00186 if (v_mem.size() > 0) {
00187
00188 for (unsigned int i = 0; i < v_mem.size(); i++) {
00189 munmap( v_mem[i].start, v_mem[i].length );
00190 }
00191 v_mem.resize(0);
00192 }
00193
00194 if (streaming)
00195 video_disable();
00196
00197 ::close(camfd);
00198 camfd = -1;
00199 }
00200 }
00201
00202 void CameraDriverV4L2::open_cam()
00203 {
00204 int ret;
00205
00206 close_cam();
00207 if (path.size() == 0)
00208 return;
00209
00210
00211 if ((camfd = ::open(path.c_str(), O_RDWR, 0)) == -1) {
00212 perror ("ERROR opening V4L interface \n");
00213 return;
00214 }
00215
00216
00217 memset( &v_cap, 0, sizeof (struct v4l2_capability) );
00218 ret = ioctl( camfd, VIDIOC_QUERYCAP, &v_cap);
00219 if (ret < 0) {
00220 perror("Unable to query capabilities");
00221 close_cam();
00222 return;
00223 }
00224
00225 if ((v_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
00226 cout << "Error opening device " << path << ": video capture not supported.\n";
00227 close_cam();
00228 return;
00229 }
00230
00231 if (!(v_cap.capabilities & V4L2_CAP_STREAMING)) {
00232 cout << path << " does not support streaming i/o\n";
00233 close_cam();
00234 return;
00235 }
00236
00237
00238 if (select_format()) {
00239 cout << "Format selection failed.\n";
00240 close_cam();
00241 return;
00242 }
00243
00244
00245 struct v4l2_requestbuffers v_rb;
00246 memset( &v_rb, 0, sizeof (struct v4l2_requestbuffers) );
00247 v_rb.count = NUM_BUFFERS;
00248 v_rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00249 v_rb.memory = V4L2_MEMORY_MMAP;
00250
00251 ret = ioctl( camfd, VIDIOC_REQBUFS, &v_rb );
00252 if (ret < 0) {
00253 perror("Unable to allocate buffers");
00254 close_cam();
00255 return;
00256 }
00257
00258
00259 if(v_rb.count!=NUM_BUFFERS)
00260 cout << "Allocated " << v_rb.count << " buffers for capturing.\n";
00261 if (v_rb.count < MIN_BUFFERS) {
00262 cout << "Not enough buffers allocated for capturing.\n";
00263 close_cam();
00264 return;
00265 }
00266
00267
00268 v_mem.resize( v_rb.count );
00269
00270 for (unsigned int i = 0; i < v_rb.count; i++) {
00271 memset( &v_buf, 0, sizeof (struct v4l2_buffer) );
00272 v_buf.index = i;
00273 v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00274 v_buf.memory = V4L2_MEMORY_MMAP;
00275 ret = ioctl( camfd, VIDIOC_QUERYBUF, &v_buf );
00276 if (ret < 0) {
00277 perror("Unable to query buffer");
00278 goto cleanup;
00279 }
00280 v_mem[i].length = v_buf.length;
00281 v_mem[i].start = mmap (NULL, v_buf.length,
00282 PROT_READ | PROT_WRITE, MAP_SHARED,
00283 camfd, v_buf.m.offset);
00284 if (v_mem[i].start == MAP_FAILED) {
00285 perror("Unable to map buffer");
00286 goto cleanup;
00287 }
00288
00289 continue;
00290
00291 cleanup:
00292
00293 for (unsigned int j = 0; j < i; j++) {
00294 munmap( v_mem[j].start, v_mem[j].length );
00295 }
00296 v_mem.resize(0);
00297
00298
00299 close_cam();
00300 return;
00301 }
00302
00303 for (int i = 0; i < NUM_BUFFERS; ++i) {
00304 memset (&v_buf, 0, sizeof (struct v4l2_buffer));
00305 v_buf.index = i;
00306 v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00307 v_buf.memory = V4L2_MEMORY_MMAP;
00308 ret = ioctl (camfd, VIDIOC_QBUF, &v_buf);
00309 if (ret < 0) {
00310 perror("Unable to queue buffer");
00311 close_cam();
00312 return;
00313 }
00314 }
00315
00316
00317 query_options(false);
00318
00319
00320 for(plist::DictionaryOf< plist::Primitive<int> >::const_iterator it=userOptions.begin(); it!=userOptions.end(); ++it) {
00321 setControl(it->first,*it->second,false);
00322 }
00323
00324 return;
00325 }
00326
00327 bool CameraDriverV4L2::setControl(const std::string& name, int value, bool verbose) {
00328 map<std::string, struct v4l2_queryctrl>::const_iterator opt = options.find(name);
00329 if(opt==options.end()) {
00330 cerr << instanceName << " does not recognize setting " << name << std::endl;
00331 return false;
00332 }
00333
00334 MarkScope l(lock);
00335
00336 if(verbose)
00337 cout << "Setting \"" << (const char *)(opt->second.name) << "\" to " << value << "." << endl;
00338
00339 struct v4l2_control control;
00340 control.id = opt->second.id;
00341 control.value = value;
00342 int error = ioctl(camfd, VIDIOC_S_CTRL, &control);
00343 if (error!=0)
00344 cerr << "Unable to set control \"" << (const char *)(opt->second.name) << "\"." << endl;
00345
00346 return (error==0);
00347 }
00348
00349 int CameraDriverV4L2::video_enable()
00350 {
00351 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00352 int ret;
00353
00354 ret = ioctl (camfd, VIDIOC_STREAMON, &type);
00355 if (ret < 0) {
00356 perror("Unable to %s capture: %d.");
00357 return ret;
00358 }
00359
00360 streaming = true;
00361
00362 return 0;
00363 }
00364
00365 int CameraDriverV4L2::video_disable()
00366 {
00367 int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00368 int ret;
00369
00370 ret = ioctl( camfd, VIDIOC_STREAMOFF, &type);
00371 if (ret < 0) {
00372 perror("Unable to stop capture:");
00373 return ret;
00374 }
00375
00376 streaming = false;
00377
00378 return 0;
00379 }
00380
00381 string CameraDriverV4L2::v4l2_fourcc_inv(__u32 f)
00382 {
00383 char tmp[5];
00384 tmp[4] = 0;
00385 *((int *)tmp) = f;
00386
00387 return string(tmp);
00388 }
00389
00390 int CameraDriverV4L2::add_control(struct v4l2_queryctrl & queryctrl, bool v)
00391 {
00392 struct v4l2_querymenu querymenu;
00393 struct v4l2_control control_s;
00394
00395 control_s.id=queryctrl.id;
00396 ioctl(camfd, VIDIOC_G_CTRL, &control_s);
00397
00398 stringstream ss;
00399 ss << "Type: " << queryctrl.type << ", values: [" << queryctrl.minimum << " - " << queryctrl.maximum << "], stepsize "
00400 << queryctrl.step << ", default " << queryctrl.default_value << ".";
00401
00402
00403
00404 options[(char*)queryctrl.name] = queryctrl;
00405
00406 if (v) {
00407 cout << " " << (char*)(queryctrl.name) << ": " << ss.str() << endl;
00408
00409 if (queryctrl.type == V4L2_CTRL_TYPE_MENU) {
00410 printf (" Menu items: ");
00411 memset (&querymenu, 0, sizeof (querymenu));
00412 querymenu.id = queryctrl.id;
00413 for (querymenu.index = queryctrl.minimum;
00414 (decltype(queryctrl.maximum))querymenu.index <= queryctrl.maximum;
00415 querymenu.index++) {
00416 if (0 == ioctl (camfd, VIDIOC_QUERYMENU, &querymenu)) {
00417 printf ("\n index:%d name:%s", querymenu.index, querymenu.name);
00418 } else {
00419 printf ("error getting control menu");
00420 break;
00421 }
00422 }
00423 printf("\n");
00424 }
00425 }
00426
00427 return 0;
00428 }
00429
00430 int CameraDriverV4L2::query_options(bool v)
00431 {
00432 if (v)
00433 cout << "CAMERA DRIVER: Querying Camera Options" << endl;
00434
00435 if (camfd < 0) {
00436 if (v)
00437 cout << "CAMERA DRIVER: No camera connected." << endl;
00438 return -1;
00439 }
00440
00441
00442 options.clear();
00443
00444 if (v)
00445 cout << endl << "CAMERA DRIVER: Available Frame Formats:" << endl;
00446
00447
00448 int ret;
00449 int f = 0;
00450 struct v4l2_fmtdesc v_fmtdesc;
00451 while (true) {
00452 memset( &v_fmtdesc, 0, sizeof(struct v4l2_fmtdesc) );
00453 v_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00454 v_fmtdesc.index = f;
00455
00456 ret = ioctl( camfd, VIDIOC_ENUM_FMT, &v_fmtdesc );
00457 if (ret)
00458 break;
00459
00460 if (v) {
00461 cout << " " << v_fmtdesc.description << ":" << endl;
00462 cout << " " << "Frame size enumeration disabled." << endl;
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 f++;
00485 }
00486
00487
00488 struct v4l2_queryctrl queryctrl;
00489 struct v4l2_input* getinput;
00490
00491
00492 getinput=(struct v4l2_input *) calloc(1, sizeof(struct v4l2_input));
00493 memset(getinput, 0, sizeof(struct v4l2_input));
00494 getinput->index=0;
00495 ioctl(camfd, VIDIOC_ENUMINPUT, getinput);
00496 if (v) {
00497 cout << endl << "CAMERA DRIVER: Available controls (Type 1=Integer 2=Boolean 3=Menu 4=Button):" << endl;
00498 }
00499
00500
00501
00502 queryctrl.id = 0 | V4L2_CTRL_FLAG_NEXT_CTRL;
00503 if (ioctl(camfd, VIDIOC_QUERYCTRL, &queryctrl) == 0) {
00504 if (v) {
00505 cout << "CAMERA DRIVER: Using advanced method of enumerating controls." << endl;
00506 }
00507
00508
00509
00510 int r;
00511 queryctrl.id = 0;
00512 int current_ctrl = queryctrl.id;
00513 queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
00514
00515 while ((r = ioctl(camfd, VIDIOC_QUERYCTRL, &queryctrl)), r ? errno != EINVAL : 1) {
00516
00517
00518 if(r && (int)queryctrl.id <= current_ctrl) {
00519
00520
00521
00522 current_ctrl++;
00523 goto next_control;
00524 }
00525 current_ctrl = queryctrl.id;
00526
00527
00528 if(r || queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
00529 goto next_control;
00530
00531 add_control(queryctrl, v);
00532
00533 next_control:
00534 queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
00535 }
00536 } else {
00537 if (v) {
00538 cout << "CAMERA DRIVER: Using non-advanced method of enumerating controls." << endl;
00539 }
00540
00541 memset (&queryctrl, 0, sizeof (queryctrl));
00542 for (int ctrl_id = V4L2_CID_BASE; ctrl_id < V4L2_CID_LASTP1; ctrl_id++) {
00543 queryctrl.id = ctrl_id;
00544 if (0 == ioctl (camfd, VIDIOC_QUERYCTRL, &queryctrl)) {
00545 if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
00546 continue;
00547
00548 add_control(queryctrl, v);
00549
00550 } else {
00551 if (errno == EINVAL)
00552 continue;
00553 perror ("error getting base controls");
00554 }
00555 }
00556
00557
00558 for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
00559 queryctrl.id++) {
00560 if (0 == ioctl (camfd, VIDIOC_QUERYCTRL, &queryctrl)) {
00561 if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
00562 continue;
00563
00564 add_control(queryctrl, v);
00565 } else {
00566 if (errno == EINVAL)
00567 break;
00568 perror ("error getting private base controls");
00569 }
00570 }
00571 }
00572
00573 return 0;
00574 }
00575
00576 int CameraDriverV4L2::select_format()
00577 {
00578 int ret;
00579
00580 memset(&v_fmt, 0, sizeof (struct v4l2_format));
00581 v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00582 v_fmt.fmt.pix.field = V4L2_FIELD_ANY;
00583
00584
00585 ret = ioctl(camfd, VIDIOC_G_FMT, &v_fmt);
00586 if (ret) {
00587 perror("Unable to get image format");
00588 return ret;
00589 }
00590
00591
00592 unsigned int w = 0, h = 0;
00593 char c;
00594 stringstream ss(resolution);
00595 ss >> w >> c >> h;
00596
00597 v_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00598 v_fmt.fmt.pix.width = w*2;
00599 v_fmt.fmt.pix.height = h*2;
00600
00601 cout << "Trying " << v_fmt.fmt.pix.width << "x" << v_fmt.fmt.pix.height << "\n";
00602
00603
00604 if (ioctl(camfd, VIDIOC_S_FMT, &v_fmt) ||
00605 (v_fmt.fmt.pix.width != w*2) ||
00606 (v_fmt.fmt.pix.height != h*2)) {
00607
00608 v_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00609 v_fmt.fmt.pix.width = w;
00610 v_fmt.fmt.pix.height = h;
00611
00612 cout << "Trying " << v_fmt.fmt.pix.width << "x" << v_fmt.fmt.pix.height << "\n";
00613
00614 ret = ioctl(camfd, VIDIOC_S_FMT, &v_fmt);
00615 if (ret < 0) {
00616 perror("Unable to set format.");
00617 return ret;
00618 }
00619
00620 if ((v_fmt.fmt.pix.width != w) ||
00621 (v_fmt.fmt.pix.height != h)) {
00622 cout << "Format asked unavailable.\n";
00623 }
00624
00625 downsample = false;
00626 cout << "Image will be upsampled to " << v_fmt.fmt.pix.width << "x"
00627 << v_fmt.fmt.pix.height << ".\n";
00628 }
00629 else {
00630 downsample = true;
00631 cout << "Image will be downsampled to " << v_fmt.fmt.pix.width/2 << "x"
00632 << v_fmt.fmt.pix.height/2 << ".\n";
00633 }
00634
00635 return 0;
00636 }
00637
00638 void CameraDriverV4L2::downsample_yuyv()
00639 {
00640 unsigned int layer = 0, components = 3;
00641 unsigned int width = v_fmt.fmt.pix.width / 2;
00642 unsigned int height = v_fmt.fmt.pix.height / 2;
00643
00644 ssize_t reqSize = sizeof(ImageHeader) + width * height * components;
00645 RCRegion* region = getUnusedRegion(reqSize,0);
00646 unsigned char * buf = reinterpret_cast<unsigned char*>(region->Base());
00647 new (buf) ImageHeader(0, layer, width, height, components, frameCount, timestamp, nextName());
00648
00649 unsigned char * src = &captureBuf[0];
00650 const unsigned int srcStride=v_fmt.fmt.pix.width * 2;
00651 unsigned char * dst = buf + sizeof(ImageHeader);
00652 unsigned char * const dstEnd = dst + width*height*components;
00653
00654
00655 while (dst != dstEnd) {
00656 unsigned char * const rowEnd = dst + width * components;
00657 while (dst != rowEnd) {
00658 int y;
00659 int u, v;
00660
00661 y=*src;
00662 y+=*(src+srcStride);
00663 ++src;
00664
00665 u=*src;
00666 u+=*(src+srcStride);
00667 ++src;
00668
00669 y+=*src;
00670 y+=*(src+srcStride);
00671 ++src;
00672
00673 v=*src;
00674 v+=*(src+srcStride);
00675 ++src;
00676
00677 *dst++ = y/4;
00678 *dst++ = u/2;
00679 *dst++ = v/2;
00680 }
00681 src+=srcStride;
00682 }
00683 ASSERTRET(dst-buf==reqSize,"CameraDriverV4L2 bad downsample_yuyv " << reqSize << " vs " << (dst-buf));
00684 setImage(region);
00685 }
00686
00687 void CameraDriverV4L2::upsample_yuyv()
00688 {
00689 unsigned int layer = 0, components = 3;
00690 unsigned int width = v_fmt.fmt.pix.width;
00691 unsigned int height = v_fmt.fmt.pix.height;
00692
00693 ssize_t reqSize = sizeof(ImageHeader) + width * height * components;
00694 RCRegion* region = getUnusedRegion(reqSize,0);
00695 unsigned char * buf = reinterpret_cast<unsigned char*>(region->Base());
00696 new (buf) ImageHeader(0, layer, width, height, components, frameCount, timestamp, nextName());
00697
00698
00699 unsigned char * src = &captureBuf[0];
00700 unsigned char * dst = buf + sizeof(ImageHeader);
00701 unsigned char * const dstEnd = dst + width*height*components;
00702
00703
00704 while (dst != dstEnd) {
00705 unsigned char * const rowEnd = dst + width * components;
00706 while (dst != rowEnd) {
00707 int y1, y2;
00708 int u, v;
00709
00710 y1=*src;
00711 ++src;
00712
00713 u=*src;
00714 ++src;
00715
00716 y2=*src;
00717 ++src;
00718
00719 v=*src;
00720 ++src;
00721
00722 *dst++ = y1;
00723 *dst++ = u;
00724 *dst++ = v;
00725 *dst++ = y2;
00726 *dst++ = u;
00727 *dst++ = v;
00728 }
00729 }
00730 ASSERTRET(dst-buf==reqSize,"CameraDriverV4L2 bad upsample_yuyv " << reqSize << " vs " << (dst-buf));
00731 setImage(region);
00732 }
00733
00734
00735
00736
00737
00738
00739
00740 #endif