v4l2.cpp

00001
00002 /***************************************************************************
00003  *  v4l2.cpp - Video4Linux 2 camera access
00004  *
00005  *  Created: Sat Jul  5 20:40:20 2008
00006  *  Copyright  2008  Tobias Kellner
00007  *
00008  ****************************************************************************/
00009
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023
00024 #include <cams/v4l2.h>
00025
00026 #include <core/exception.h>
00027 #include <core/exceptions/software.h>
00028 #include <utils/logging/liblogger.h>
00029 #include <fvutils/system/camargp.h>
00030
00031 #include <fcntl.h>
00032 #include <sys/ioctl.h>
00033 #include <sys/mman.h>
00034 #include <iostream>
00035 #include <cstring>
00036 #include <cerrno>
00037 #include <cstdlib>
00038 #include <linux/version.h>
00039
00040 using std::cout;
00041 using std::endl;
00042 using std::string;
00043 using fawkes::Exception;
00044 using fawkes::MissingParameterException;
00045 using fawkes::NotImplementedException;
00046 using fawkes::LibLogger;
00047 
00048 /// @cond INTERNALS
00049 class V4L2CameraData
00050 {
00051  public:
00052   v4l2_capability caps;        //< Device capabilites
00053 };
00054 
00055 /// @endcond
00056 
00057 
00058 /** @class V4L2Camera <cams/v4l2.h>
00059  * Video4Linux 2 camera access implementation.
00060  *
00061  * @todo UPTR method
00062  * @todo Standards queries (VIDIOC_ENUMSTD)
00063  * @todo v4l2_pix_format.field
00064  * @author Tobias Kellner
00065  */
00066
00067 
00068 /** Constructor.
00069  * @param device_name device file name (e.g. /dev/video0)
00070  */
00071 V4L2Camera::V4L2Camera(const char *device_name)
00072 {
00073   _opened = _started = false;
00074   _nao_hacks = _switch_u_v = false;
00075   _width = _height = _bytes_per_line = _fps = _buffers_length = 0;
00076   _current_buffer = -1;
00077   _brightness.set = _contrast.set = _saturation.set = _hue.set =
00078     _red_balance.set = _blue_balance.set = _exposure.set = _gain.set =
00079     _lens_x.set = _lens_y.set = false;
00080   _aec = _awb = _agc = _h_flip = _v_flip = NOT_SET;
00081   _read_method = MMAP;
00082   memset(_format, 0, 5);
00083   _frame_buffers = NULL;
00084   _capture_time = NULL;
00085   _device_name = strdup(device_name);
00086   _data = new V4L2CameraData();
00087 }
00088
00089 
00090 /** Constructor.
00091  * Initialize camera with parameters from camera argument parser.
00092  * Supported arguments:
00093  * *Required:
00094  * - device=DEV, device file, for example /dev/video0 (required)
00095  * *Optional:
00096  * - read_method=METHOD, preferred read method
00097  *    READ: read()
00098  *    MMAP: memory mapping
00099  *    UPTR: user pointer
00100  * - format=FOURCC, preferred format
00101  * - size=WIDTHxHEIGHT, preferred image size
00102  * - switch_u_v=true/false, switch U and V channels
00103  * - fps=FPS, frames per second
00104  * - aec=true/false, Auto Exposition enabled [warning: only valid on nao]
00105  * - awb=true/false, Auto White Balance enabled
00106  * - agc=true/false, Auto Gain enabled
00107  * - h_flip=true/false, Horizontal mirror
00108  * - v_flip=true/false, Vertical mirror
00109  * - brightness=BRIGHT, Brightness [0-255] (def. 128)
00110  * - contrast=CONTR, Contrast [0-127] (def. 64)
00111  * - saturation=SAT, Saturation [0-256] (def. 128)
00112  * - hue=HUE, Hue [-180-180] (def. 0)
00113  * - red_balance=RB, Red Balance [0-255] (def. 128)
00114  * - blue_balance=BB, Blue Balance [0-255] (def. 128)
00115  * - exposure=EXP, Exposure [0-65535] (def. 60)
00116  * - gain=GAIN, Gain [0-255] (def. 0)
00117  * - lens_x=CORR, Lens Correction X [0-255] (def. 0)
00118  * - lens_y=CORR, Lens Correction Y [0-255] (def. 0)
00119  * @param cap camera argument parser
00120  */
00121 V4L2Camera::V4L2Camera(const CameraArgumentParser *cap)
00122 {
00123   _opened = _started = false;
00124   _nao_hacks = false;
00125   _width = _height = _bytes_per_line = _buffers_length = 0;
00126   _current_buffer = -1;
00127   _frame_buffers = NULL;
00128   _capture_time = NULL;
00129   _data = new V4L2CameraData();
00130
00131   if (cap->has("device")) _device_name = strdup(cap->get("device").c_str());
00132   else throw MissingParameterException("V4L2Cam: Missing device");
00133
00134
00135   if (cap->has("read_method"))
00136   {
00137     string rm = cap->get("read_method");
00138     if (rm.compare("READ") == 0) _read_method = READ;
00139     else if (rm.compare("MMAP") == 0) _read_method = MMAP;
00140     else if (rm.compare("UPTR") == 0) _read_method = UPTR;
00141     else throw Exception("V4L2Cam: Invalid read method");
00142   }
00143   else
00144   {
00145     _read_method = UPTR;
00146   }
00147
00148
00149   if (cap->has("format"))
00150   {
00151     string fmt = cap->get("format");
00152     if (fmt.length() != 4) throw Exception("V4L2Cam: Invalid format fourcc");
00153     strncpy(_format, fmt.c_str(), 4);
00154     _format[4] = '\0';
00155   }
00156   else
00157   {
00158     memset(_format, 0, 5);
00159   }
00160
00161
00162   if (cap->has("size"))
00163   {
00164     string size = cap->get("size");
00165     string::size_type pos;
00166     if ((pos = size.find('x')) == string::npos) throw Exception("V4L2Cam: invalid image size string");
00167     if ((pos == (size.length() - 1))) throw Exception("V4L2Cam: invalid image size string");
00168
00169     unsigned int mult = 1;
00170     for (string::size_type i = pos - 1; i != string::npos; --i)
00171     {
00172       _width += (size.at(i) - '0') * mult;
00173       mult *= 10;
00174     }
00175
00176     mult = 1;
00177     for (string::size_type i = size.length() - 1; i > pos; --i)
00178     {
00179       _height += (size.at(i) - '0') * mult;
00180       mult *= 10;
00181     }
00182   }
00183
00184
00185   if (cap->has("switch_u_v"))
00186   {
00187     _switch_u_v = (cap->get("switch_u_v").compare("true") == 0);
00188   }
00189   else
00190   {
00191     _switch_u_v = false;
00192   }
00193
00194
00195   if (cap->has("fps"))
00196   {
00197     if ((_fps = atoi(cap->get("fps").c_str())) == 0) throw Exception("V4L2Cam: invalid fps string");
00198   }
00199   else
00200   {
00201     _fps = 0;
00202   }
00203
00204
00205   if (cap->has("aec"))
00206   {
00207     _aec = (cap->get("aec").compare("true") == 0 ? TRUE : FALSE);
00208   }
00209   else
00210   {
00211     _aec = NOT_SET;
00212   }
00213
00214
00215   if (cap->has("awb"))
00216   {
00217     _awb = (cap->get("awb").compare("true") == 0 ? TRUE : FALSE);
00218   }
00219   else
00220   {
00221     _awb = NOT_SET;
00222   }
00223
00224
00225   if (cap->has("agc"))
00226   {
00227     _agc = (cap->get("agc").compare("true") == 0 ? TRUE : FALSE);
00228   }
00229   else
00230   {
00231     _agc = NOT_SET;
00232   }
00233
00234
00235   if (cap->has("h_flip"))
00236   {
00237     _h_flip = (cap->get("h_flip").compare("true") == 0 ? TRUE : FALSE);
00238   }
00239   else
00240   {
00241     _h_flip = NOT_SET;
00242   }
00243
00244
00245   if (cap->has("v_flip"))
00246   {
00247     _v_flip = (cap->get("v_flip").compare("true") == 0 ? TRUE : FALSE);
00248   }
00249   else
00250   {
00251     _v_flip = NOT_SET;
00252   }
00253
00254
00255   if (cap->has("brightness"))
00256   {
00257     _brightness.set = true;
00258     _brightness.value = atoi(cap->get("brightness").c_str());
00259   }
00260   else
00261   {
00262     _brightness.set = false;
00263   }
00264
00265
00266   if (cap->has("contrast"))
00267   {
00268     _contrast.set = true;
00269     _contrast.value = atoi(cap->get("contrast").c_str());
00270   }
00271   else
00272   {
00273     _contrast.set = false;
00274   }
00275
00276
00277   if (cap->has("saturation"))
00278   {
00279     _saturation.set = true;
00280     _saturation.value = atoi(cap->get("saturation").c_str());
00281   }
00282   else
00283   {
00284     _saturation.set = false;
00285   }
00286
00287
00288   if (cap->has("hue"))
00289   {
00290     _hue.set = true;
00291     _hue.value = atoi(cap->get("hue").c_str());
00292   }
00293   else
00294   {
00295     _hue.set = false;
00296   }
00297
00298
00299   if (cap->has("red_balance"))
00300   {
00301     _red_balance.set = true;
00302     _red_balance.value = atoi(cap->get("red_balance").c_str());
00303   }
00304   else
00305   {
00306     _red_balance.set = false;
00307   }
00308
00309
00310   if (cap->has("blue_balance"))
00311   {
00312     _blue_balance.set = true;
00313     _blue_balance.value = atoi(cap->get("blue_balance").c_str());
00314   }
00315   else
00316   {
00317     _blue_balance.set = false;
00318   }
00319
00320
00321   if (cap->has("exposure"))
00322   {
00323     _exposure.set = true;
00324     _exposure.value = atoi(cap->get("exposure").c_str());
00325   }
00326   else
00327   {
00328     _exposure.set = false;
00329   }
00330
00331
00332   if (cap->has("gain"))
00333   {
00334     _gain.set = true;
00335     _gain.value = atoi(cap->get("gain").c_str());
00336   }
00337   else
00338   {
00339     _gain.set = false;
00340   }
00341
00342
00343   if (cap->has("lens_x"))
00344   {
00345     _lens_x.set = true;
00346     _lens_x.value = atoi(cap->get("lens_x").c_str());
00347   }
00348   else
00349   {
00350     _lens_x.set = false;
00351   }
00352
00353
00354   if (cap->has("lens_y"))
00355   {
00356     _lens_y.set = true;
00357     _lens_y.value = atoi(cap->get("lens_y").c_str());
00358   }
00359   else
00360   {
00361     _lens_y.set = false;
00362   }
00363 }
00364
00365 
00366 /** Protected Constructor.
00367  * Gets called from V4LCamera, when the device has already been opened
00368  * and determined to be a V4L2 device.
00369  * @param device_name device file name (e.g. /dev/video0)
00370  * @param dev file descriptor of the opened device
00371  */
00372 V4L2Camera::V4L2Camera(const char *device_name, int dev)
00373 {
00374   _opened = true;
00375   _started = false;
00376   _nao_hacks = _switch_u_v = false;
00377   _width = _height = _bytes_per_line = _buffers_length = _fps = 0;
00378   _current_buffer = -1;
00379   _brightness.set = _contrast.set = _saturation.set = _hue.set =
00380     _red_balance.set = _blue_balance.set = _exposure.set = _gain.set =
00381     _lens_x.set = _lens_y.set = false;
00382   _aec = _awb = _agc = _h_flip = _v_flip = NOT_SET;
00383   _read_method = UPTR;
00384   memset(_format, 0, 5);
00385   _frame_buffers = NULL;
00386   _capture_time = NULL;
00387   _device_name = strdup(device_name);
00388   _data = new V4L2CameraData();
00389
00390   _dev = dev;
00391
00392   // getting capabilities
00393   if (ioctl(_dev, VIDIOC_QUERYCAP, &_data->caps))
00394   {
00395     close();
00396     throw Exception("V4L2Cam: Could not get capabilities - probably not a v4l2 device");
00397   }
00398
00399   post_open();
00400 }
00401 
00402 /** Destructor. */
00403 V4L2Camera::~V4L2Camera()
00404 {
00405   if (_started) stop();
00406   if (_opened) close();
00407
00408   free(_device_name);
00409   delete _data;
00410 }
00411
00412 void
00413 V4L2Camera::open()
00414 {
00415   if (_started) stop();
00416   if(_opened) close();
00417
00418   _dev = ::open(_device_name, O_RDWR);
00419   if (_dev < 0) throw Exception("V4L2Cam: Could not open device");
00420
00421   _opened = true;
00422
00423   // getting capabilities
00424   if (ioctl(_dev, VIDIOC_QUERYCAP, &_data->caps))
00425   {
00426     close();
00427     throw Exception("V4L2Cam: Could not get capabilities - probably not a v4l2 device");
00428   }
00429
00430   post_open();
00431 }
00432 
00433 /**
00434  * Post-open() operations.
00435  * Precondition: _dev (file desc) and _data->caps (capabilities) are set.
00436  * @param dev file descriptor of the opened device
00437  */
00438 void
00439 V4L2Camera::post_open()
00440 {
00441   //LibLogger::log_debug("V4L2Cam", "select_read_method()");
00442   select_read_method();
00443
00444   //LibLogger::log_debug("V4L2Cam", "select_format()");
00445   select_format();
00446
00447   if (_fps)
00448   {
00449     //LibLogger::log_debug("V4L2Cam", "set_fps()");
00450     set_fps();
00451   }
00452
00453   //LibLogger::log_debug("V4L2Cam", "set_controls()");
00454   set_controls();
00455
00456   //LibLogger::log_debug("V4L2Cam", "create_buffer()");
00457   create_buffer();
00458
00459   //LibLogger::log_debug("V4L2Cam", "reset_cropping()");
00460   reset_cropping();
00461
00462 }
00463 
00464 /**
00465  * Find suitable reading method.
00466  * The one set in _read_method is preferred.
00467  * Postconditions:
00468  *  - _read_method and _buffers_length are set
00469  */
00470 void
00471 V4L2Camera::select_read_method()
00472 {
00473   /* try preferred method */
00474   if (!(_data->caps.capabilities &
00475         (_read_method == READ ? V4L2_CAP_READWRITE : V4L2_CAP_STREAMING)))
00476   {
00477     /* preferred read method not supported - try next */
00478     _read_method = (_read_method == READ ? MMAP : READ);
00479     if (!(_data->caps.capabilities &
00480           (_read_method == READ ? V4L2_CAP_READWRITE : V4L2_CAP_STREAMING)))
00481     {
00482       close();
00483       throw Exception("V4L2Cam: Neither read() nor streaming IO supported");
00484     }
00485   }
00486
00487   if (_read_method != READ)
00488   {
00489     v4l2_requestbuffers buf;
00490
00491     /* Streaming IO - Try 1st method, and if that fails 2nd */
00492     for (int i = 0; i < 2; ++i)
00493     {
00494       if (_read_method == MMAP)
00495       {
00496         _buffers_length = MMAP_NUM_BUFFERS;
00497         buf.count = _buffers_length;
00498         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00499         buf.memory = V4L2_MEMORY_MMAP;
00500       }
00501       else /* UPTR */
00502       {
00503         _buffers_length = 0;
00504         buf.count = 0;
00505         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00506         buf.memory = V4L2_MEMORY_USERPTR;
00507       }
00508
00509       if (ioctl(_dev, VIDIOC_REQBUFS, &buf))
00510       {
00511         if (errno != EINVAL)
00512         {
00513           close();
00514           throw Exception("V4L2Cam: REQBUFS query failed");
00515         }
00516
00517         /* Not supported */
00518         if (i == 1)
00519         {
00520           close();
00521           throw Exception("V4L2Cam: Neither memory mapped nor user pointer IO supported");
00522         }
00523
00524         /* try other method */
00525         _read_method = (_read_method == MMAP ? UPTR : MMAP);
00526         continue;
00527       }
00528
00529       /* Method supported */
00530       if ((_read_method == MMAP) && (buf.count < _buffers_length))
00531       {
00532         close();
00533         throw Exception("V4L2Cam: Not enough memory for the buffers");
00534       }
00535
00536       break;
00537     }
00538   }
00539   else /* Read IO */
00540   {
00541     _buffers_length = 1;
00542   }
00543
00544   switch (_read_method)
00545   {
00546     case READ:
00547       LibLogger::log_debug("V4L2Cam", "Using read() method");
00548       break;
00549
00550     case MMAP:
00551       LibLogger::log_debug("V4L2Cam", "Using memory mapping method");
00552       break;
00553
00554     case UPTR:
00555       LibLogger::log_debug("V4L2Cam", "Using user pointer method");
00556       //TODO
00557       throw Exception("V4L2Cam: user pointer method not supported yet");
00558       break;
00559   }
00560 }
00561 
00562 /**
00563  * Find suitable image format.
00564  * The one set in _format (if any) is preferred.
00565  * Postconditions:
00566  *  - _format is set (and selected)
00567  *  - _colorspace is set accordingly
00568  *  - _width, _height, and _bytes_per_line are set
00569  */
00570 void
00571 V4L2Camera::select_format()
00572 {
00573   bool preferred_found = false;
00574   v4l2_fmtdesc format_desc;
00575
00576   char fourcc[5] = "    ";
00577
00578   if (strcmp(_format, ""))
00579   {
00580     /* Try to select preferred format */
00581     memset(&format_desc, 0, sizeof(format_desc));
00582     format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00583     for (format_desc.index = 0; ioctl(_dev, VIDIOC_ENUM_FMT, &format_desc) == 0; format_desc.index++)
00584     {
00585       fourcc[0] = static_cast<char>(format_desc.pixelformat & 0xFF);
00586       fourcc[1] = static_cast<char>((format_desc.pixelformat >> 8) & 0xFF);
00587       fourcc[2] = static_cast<char>((format_desc.pixelformat >> 16) & 0xFF);
00588       fourcc[3] = static_cast<char>((format_desc.pixelformat >> 24) & 0xFF);
00589
00590       if (strcmp(_format, fourcc) == 0)
00591       {
00592         preferred_found = true;
00593         break;
00594       }
00595     }
00596   }
00597
00598   if (!preferred_found)
00599   {
00600     /* Preferred format not found (or none selected)
00601        -> just take first available format */
00602     memset(&format_desc, 0, sizeof(format_desc));
00603     format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00604     format_desc.index = 0;
00605     if (ioctl(_dev, VIDIOC_ENUM_FMT, &format_desc))
00606     {
00607       close();
00608       throw Exception("V4L2Cam: No image format found");
00609     }
00610
00611     fourcc[0] = static_cast<char>(format_desc.pixelformat & 0xFF);
00612     fourcc[1] = static_cast<char>((format_desc.pixelformat >> 8) & 0xFF);
00613     fourcc[2] = static_cast<char>((format_desc.pixelformat >> 16) & 0xFF);
00614     fourcc[3] = static_cast<char>((format_desc.pixelformat >> 24) & 0xFF);
00615   }
00616
00617   /* Now set this format */
00618   v4l2_format format;
00619   memset(&format, 0, sizeof(format));
00620   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00621   if (ioctl(_dev, VIDIOC_G_FMT, &format))
00622   {
00623     close();
00624     throw Exception("V4L2Cam: Format query failed");
00625   }
00626
00627   //LibLogger::log_debug("V4L2Cam", "setting %dx%d (%s) - type %d", _width, _height, fourcc, format.type);
00628
00629   format.fmt.pix.pixelformat = v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
00630   format.fmt.pix.field       = V4L2_FIELD_ANY;
00631   if (_width)
00632     format.fmt.pix.width = _width;
00633   if (_height)
00634     format.fmt.pix.height = _height;
00635
00636   if (ioctl(_dev, VIDIOC_S_FMT, &format))
00637   {
00638     //throw Exception(errno, "Failed to set video format");
00639     //}
00640
00641     /* According to nao cam driver source code, G/S_STD isn't supported */
00642     // Nao workaround (Hack alert)
00643     LibLogger::log_warn("V4L2Cam", "Format setting failed (driver sucks) - %d: %s", errno, strerror(errno));
00644     LibLogger::log_info("V4L2Cam", "Trying workaround");
00645     _nao_hacks = true;
00646
00647     v4l2_std_id std;
00648     if (ioctl(_dev, VIDIOC_G_STD, &std))
00649     {
00650       close();
00651       throw Exception("V4L2Cam: Standard query (workaround) failed");
00652     }
00653
00654     if ((_width == 320) && (_height == 240))
00655     {
00656       std = 0x04000000UL; // QVGA
00657     }
00658     else
00659     {
00660       std = 0x08000000UL; // VGA
00661       _width = 640;
00662       _height = 480;
00663     }
00664     if (ioctl(_dev, VIDIOC_S_STD, &std))
00665     {
00666       close();
00667       throw Exception("V4L2Cam: Standard setting (workaround) failed");
00668     }
00669
00670     format.fmt.pix.width       = _width;
00671     format.fmt.pix.height      = _height;
00672     format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
00673     format.fmt.pix.field       = V4L2_FIELD_ANY;
00674
00675     if (ioctl(_dev, VIDIOC_S_FMT, &format))
00676     {
00677       close();
00678       throw Exception("V4L2Cam: Format setting (workaround) failed");
00679     }
00680
00681     if (_switch_u_v) _colorspace = YVY2;
00682   }
00683
00684   /* ...and store final values */
00685   _format[0] = static_cast<char>(format.fmt.pix.pixelformat & 0xFF);
00686   _format[1] = static_cast<char>((format.fmt.pix.pixelformat >> 8) & 0xFF);
00687   _format[2] = static_cast<char>((format.fmt.pix.pixelformat >> 16) & 0xFF);
00688   _format[3] = static_cast<char>((format.fmt.pix.pixelformat >> 24) & 0xFF);
00689
00690   if (!_nao_hacks || !_switch_u_v)
00691   {
00692     if (strcmp(_format, "RGB3") == 0) _colorspace = RGB;
00693     else if (strcmp(_format, "Y41P") == 0) _colorspace = YUV411_PACKED; //different byte ordering
00694     else if (strcmp(_format, "411P") == 0) _colorspace = YUV411_PLANAR;
00695     else if (strcmp(_format, "YUYV") == 0) _colorspace = YUY2;
00696     else if (strcmp(_format, "BGR3") == 0) _colorspace = BGR;
00697     else if (strcmp(_format, "UYVY") == 0) _colorspace = YUV422_PACKED;
00698     else if (strcmp(_format, "422P") == 0) _colorspace = YUV422_PLANAR;
00699     else if (strcmp(_format, "GREY") == 0) _colorspace = GRAY8;
00700     else if (strcmp(_format, "RGB4") == 0) _colorspace = RGB_WITH_ALPHA;
00701     else if (strcmp(_format, "BGR4") == 0) _colorspace = BGR_WITH_ALPHA;
00702     else if (strcmp(_format, "BA81") == 0) _colorspace = BAYER_MOSAIC_BGGR;
00703     else if (strcmp(_format, "Y16 ") == 0) _colorspace = MONO16;
00704     else _colorspace = CS_UNKNOWN;
00705   }
00706
00707   if (!_nao_hacks)
00708   {
00709     _width = format.fmt.pix.width;
00710     _height = format.fmt.pix.height;
00711   }
00712
00713   _bytes_per_line = format.fmt.pix.bytesperline;
00714
00715   /* Hack for bad drivers */
00716   if (_bytes_per_line == 0)
00717   {
00718     LibLogger::log_warn("V4L2Cam", "bytesperline is 0 (driver sucks)");
00719     _bytes_per_line = colorspace_buffer_size(_colorspace, _width, _height) / _height;
00720   }
00721
00722   LibLogger::log_debug("V4L2Cam", "w%d h%d bpl%d cs%d fmt%s", _width, _height, _bytes_per_line, _colorspace, _format);
00723 }
00724 
00725 /**
00726  * Set desired FPS count.
00727  */
00728 void
00729 V4L2Camera::set_fps()
00730 {
00731   if (!(_data->caps.capabilities & V4L2_CAP_TIMEPERFRAME) && !_nao_hacks)
00732   {
00733     LibLogger::log_warn("V4L2Cam", "FPS change not supported");
00734     return;
00735   }
00736
00737   v4l2_streamparm param;
00738   param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00739   if (ioctl(_dev, VIDIOC_G_PARM, &param))
00740   {
00741     close();
00742     throw Exception("V4L2Cam: Streaming parameter query failed");
00743   }
00744
00745   param.parm.capture.timeperframe.numerator = 1;
00746   param.parm.capture.timeperframe.denominator = _fps;
00747   param.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
00748   if (ioctl(_dev, VIDIOC_S_PARM, &param))
00749   {
00750     //close();
00751     //throw Exception("V4L2Cam: Streaming parameter setting failed");
00752     LibLogger::log_warn("V4L2Cam", "Streaming parameter setting failed - %d: %2", errno, strerror(errno));
00753   }
00754   else
00755   {
00756     LibLogger::log_debug("V4L2Cam", "FPS set - %d/%d",
00757                          param.parm.capture.timeperframe.numerator,
00758                          param.parm.capture.timeperframe.denominator);
00759   }
00760 }
00761 
00762 /**
00763  * Set Camera controls.
00764  */
00765 void
00766 V4L2Camera::set_controls()
00767 {
00768   if (_aec != NOT_SET)
00769   {
00770     LibLogger::log_debug("V4L2Cam", (_aec == TRUE ? "enabling AEC" : "disabling AEC"));
00771     if (!_nao_hacks) LibLogger::log_warn("V4L2Cam", "AEC toggling will only work on Nao");
00772
00773     set_one_control("AEC", V4L2_CID_AUDIO_MUTE, //<- this is why it will only work on Naos ;)
00774                     (_aec == TRUE ? 1 : 0));
00775   }
00776
00777   if (_awb != NOT_SET)
00778   {
00779     LibLogger::log_debug("V4L2Cam", (_awb == TRUE ? "enabling AWB" : "disabling AWB"));
00780     set_one_control("AWB", V4L2_CID_AUTO_WHITE_BALANCE, (_awb == TRUE ? 1 : 0));
00781   }
00782
00783   if (_agc != NOT_SET)
00784   {
00785     LibLogger::log_debug("V4L2Cam", (_agc == TRUE ? "enabling AGC" : "disabling AGC"));
00786     set_one_control("AGC", V4L2_CID_AUTOGAIN, (_agc == TRUE ? 1 : 0));
00787   }
00788
00789   if (_h_flip != NOT_SET)
00790   {
00791     LibLogger::log_debug("V4L2Cam", (_h_flip == TRUE ? "enabling horizontal flip" : "disabling horizontal flip"));
00792     set_one_control("hflip", V4L2_CID_HFLIP, (_h_flip == TRUE ? 1 : 0));
00793   }
00794
00795   if (_v_flip != NOT_SET)
00796   {
00797     LibLogger::log_debug("V4L2Cam", (_v_flip == TRUE ? "enabling vertical flip" : "disabling vertical flip"));
00798     set_one_control("vhflip", V4L2_CID_VFLIP, (_v_flip == TRUE ? 1 : 0));
00799   }
00800
00801   if (_brightness.set)
00802   {
00803     LibLogger::log_debug("V4L2Cam", "Setting brighness to %d", _brightness.value);
00804     set_one_control("brightness", V4L2_CID_BRIGHTNESS, _brightness.value);
00805   }
00806
00807   if (_contrast.set)
00808   {
00809     LibLogger::log_debug("V4L2Cam", "Setting contrast to %d", _contrast.value);
00810     set_one_control("contrast", V4L2_CID_CONTRAST, _contrast.value);
00811   }
00812
00813   if (_saturation.set)
00814   {
00815     LibLogger::log_debug("V4L2Cam", "Setting saturation to %d", _saturation.value);
00816     set_one_control("saturation", V4L2_CID_SATURATION, _saturation.value);
00817   }
00818
00819   if (_hue.set)
00820   {
00821     LibLogger::log_debug("V4L2Cam", "Setting hue to %d", _hue.value);
00822     set_one_control("hue", V4L2_CID_HUE, _hue.value);
00823   }
00824
00825   if (_red_balance.set)
00826   {
00827     LibLogger::log_debug("V4L2Cam", "Setting red balance to %d", _red_balance.value);
00828     set_one_control("red balance", V4L2_CID_RED_BALANCE, _red_balance.value);
00829   }
00830
00831   if (_blue_balance.set)
00832   {
00833     LibLogger::log_debug("V4L2Cam", "Setting blue balance to %d", _blue_balance.value);
00834     set_one_control("blue balance", V4L2_CID_BLUE_BALANCE, _blue_balance.value);
00835   }
00836
00837   if (_exposure.set)
00838   {
00839     LibLogger::log_debug("V4L2Cam", "Setting exposure to %d", _exposure.value);
00840     set_one_control("exposure", V4L2_CID_EXPOSURE, _exposure.value);
00841   }
00842
00843   if (_gain.set)
00844   {
00845     LibLogger::log_debug("V4L2Cam", "Setting gain to %d", _gain.value);
00846     set_one_control("gain", V4L2_CID_GAIN, _gain.value);
00847   }
00848
00849   if (_lens_x.set)
00850   {
00851     LibLogger::log_debug("V4L2Cam", "Setting horizontal lens correction to %d", _lens_x.value);
00852     set_one_control("lens x", V4L2_CID_HCENTER/*_DEPRECATED*/, _lens_x.value);
00853   }
00854
00855   if (_lens_y.set)
00856   {
00857     LibLogger::log_debug("V4L2Cam", "Setting vertical lens correction to %d", _lens_y.value);
00858     set_one_control("lens y", V4L2_CID_VCENTER/*_DEPRECATED*/, _lens_y.value);
00859   }
00860 }
00861 
00862 /**
00863  * Set one Camera control value.
00864  * @param ctrl name of the value
00865  * @param id ID of the value
00866  * @param value value to set
00867  */
00868 void
00869 V4L2Camera::set_one_control(const char *ctrl, unsigned int id, int value)
00870 {
00871   v4l2_queryctrl queryctrl;
00872   v4l2_control control;
00873
00874   memset(&queryctrl, 0, sizeof(queryctrl));
00875   queryctrl.id = id;
00876
00877   if (ioctl(_dev, VIDIOC_QUERYCTRL, &queryctrl))
00878   {
00879     if (errno == EINVAL)
00880     {
00881       LibLogger::log_error("V4L2Cam", "Control %s not supported", ctrl);
00882       return;
00883     }
00884
00885     close();
00886     throw Exception("V4L2Cam: %s Control query failed", ctrl);
00887   }
00888   if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
00889   {
00890     LibLogger::log_error("V4L2Cam", "Control %s disabled", ctrl);
00891     return;
00892   }
00893
00894   memset(&control, 0, sizeof(control));
00895   control.id = id;
00896   control.value = value;
00897
00898   if (ioctl(_dev, VIDIOC_S_CTRL, &control))
00899   {
00900     close();
00901     throw Exception("V4L2Cam: %s Control setting failed", ctrl);
00902   }
00903 }
00904 
00905 /**
00906  * Get one Camera control value.
00907  * @param ctrl name of the value
00908  * @param id ID of the value
00909  * @return current value
00910  */
00911 int
00912 V4L2Camera::get_one_control(const char *ctrl, unsigned int id)
00913 {
00914   v4l2_queryctrl queryctrl;
00915   v4l2_control control;
00916
00917   memset(&queryctrl, 0, sizeof(queryctrl));
00918   queryctrl.id = id;
00919
00920   if (ioctl(_dev, VIDIOC_QUERYCTRL, &queryctrl))
00921   {
00922     if (errno == EINVAL)
00923     {
00924       LibLogger::log_error("V4L2Cam", "Control %s not supported", ctrl);
00925       return 0;
00926     }
00927
00928     close();
00929     throw Exception("V4L2Cam: %s Control query failed", ctrl);
00930   }
00931   if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
00932   {
00933     LibLogger::log_error("V4L2Cam", "Control %s disabled", ctrl);
00934     return 0;
00935   }
00936
00937   memset(&control, 0, sizeof(control));
00938   control.id = id;
00939
00940   if (ioctl(_dev, VIDIOC_G_CTRL, &control))
00941   {
00942     close();
00943     throw Exception("V4L2Cam: %s Control value reading failed", ctrl);
00944   }
00945
00946   return control.value;
00947 }
00948 
00949 /**
00950  * Create a buffer for image transfer.
00951  * Preconditions:
00952  *  - _read_method is set
00953  *  - _height and _bytes_per_line are set
00954  *  - _buffers_length is set
00955  * Postconditions:
00956  *  - _frame_buffers is set up
00957  */
00958 void
00959 V4L2Camera::create_buffer()
00960 {
00961   _frame_buffers = new FrameBuffer[_buffers_length];
00962
00963   switch (_read_method)
00964   {
00965     case READ:
00966     {
00967       _frame_buffers[0].size = _bytes_per_line * _height;
00968       _frame_buffers[0].buffer = static_cast<unsigned char *>(malloc(_frame_buffers[0].size));
00969       if (_frame_buffers[0].buffer == NULL)
00970       {
00971         close();
00972         throw Exception("V4L2Cam: Out of memory");
00973       }
00974       break;
00975     }
00976
00977     case MMAP:
00978     {
00979       for (unsigned int i = 0; i < _buffers_length; ++i)
00980       {
00981         /* Query status of buffer */
00982         v4l2_buffer buffer;
00983
00984         memset(&buffer, 0, sizeof (buffer));
00985         buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00986         buffer.memory = V4L2_MEMORY_MMAP;
00987         buffer.index = i;
00988
00989         if (ioctl(_dev, VIDIOC_QUERYBUF, &buffer))
00990         {
00991           close();
00992           throw Exception("V4L2Cam: Buffer query failed");
00993         }
00994
00995         _frame_buffers[i].size = buffer.length;
00996         _frame_buffers[i].buffer = static_cast<unsigned char *>(
00997           mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, _dev, buffer.m.offset)
00998         );
00999         if (_frame_buffers[i].buffer == MAP_FAILED)
01000         {
01001           close();
01002           throw Exception("V4L2Cam: Memory mapping failed");
01003         }
01004       }
01005
01006       break;
01007     }
01008
01009     case UPTR:
01010       /* not supported yet */
01011       break;
01012   }
01013 }
01014 
01015 /**
01016  * Reset cropping parameters.
01017  */
01018 void
01019 V4L2Camera::reset_cropping()
01020 {
01021   v4l2_cropcap cropcap;
01022   v4l2_crop crop;
01023
01024   memset(&cropcap, 0, sizeof(cropcap));
01025   cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01026
01027   if (ioctl(_dev, VIDIOC_CROPCAP, &cropcap))
01028   {
01029     LibLogger::log_warn("V4L2Cam", "cropcap query failed (driver sucks) - %d: %s", errno, strerror(errno));
01030   }
01031
01032   memset(&crop, 0, sizeof(crop));
01033   crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01034   crop.c = cropcap.defrect;
01035
01036   /* Ignore if cropping is not supported (EINVAL). */
01037   if (ioctl(_dev, VIDIOC_S_CROP, &crop) && errno != EINVAL)
01038   {
01039     LibLogger::log_warn("V4L2Cam", "cropping query failed (driver sucks) - %d: %s", errno, strerror(errno));
01040   }
01041 }
01042
01043 void
01044 V4L2Camera::close()
01045 {
01046   //LibLogger::log_debug("V4L2Cam", "close()");
01047
01048   if (_started) stop();
01049
01050   if (_opened)
01051   {
01052     ::close(_dev);
01053     _opened = false;
01054     _dev = 0;
01055   }
01056
01057   if (_frame_buffers)
01058   {
01059     switch (_read_method)
01060     {
01061       case READ:
01062       {
01063         free(_frame_buffers[0].buffer);
01064         break;
01065       }
01066
01067       case MMAP:
01068       {
01069         for (unsigned int i = 0; i < _buffers_length; ++i)
01070         {
01071           munmap(_frame_buffers[i].buffer, _frame_buffers[i].size);
01072         }
01073         break;
01074       }
01075
01076       case UPTR:
01077         /* not supported yet */
01078         break;
01079     }
01080     delete[] _frame_buffers;
01081     _frame_buffers = NULL;
01082     _current_buffer = -1;
01083   }
01084
01085   if (_capture_time)
01086   {
01087     delete _capture_time;
01088     _capture_time = 0;
01089   }
01090 }
01091
01092 void
01093 V4L2Camera::start()
01094 {
01095   //LibLogger::log_info("V4L2Cam", "start()");
01096
01097   if (!_opened) throw Exception("VL42Cam: Camera not opened");
01098
01099   if (_started) stop();
01100
01101   switch (_read_method)
01102   {
01103     case READ:
01104       /* nothing to do here */
01105       break;
01106
01107     case MMAP:
01108     {
01109       /* enqueue buffers */
01110       for (unsigned int i = 0; i < _buffers_length; ++i)
01111       {
01112         v4l2_buffer buffer;
01113         memset(&buffer, 0, sizeof(buffer));
01114         buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01115         buffer.memory = V4L2_MEMORY_MMAP;
01116         buffer.index = i;
01117
01118         if (ioctl(_dev, VIDIOC_QBUF, &buffer))
01119         {
01120           close();
01121           throw Exception("V4L2Cam: Enqueuing buffer failed");
01122         }
01123       }
01124
01125       /* start streaming */
01126       int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01127       if (ioctl(_dev, VIDIOC_STREAMON, &type))
01128       {
01129         close();
01130         throw Exception("V4L2Cam: Starting stream failed");
01131       }
01132       break;
01133     }
01134
01135     case UPTR:
01136       /* not supported yet */
01137       break;
01138   }
01139
01140   //LibLogger::log_debug("V4L2Cam", "start() complete");
01141   _started = true;
01142 }
01143
01144 void
01145 V4L2Camera::stop()
01146 {
01147   //LibLogger::log_debug("V4L2Cam", "stop()");
01148
01149   if (!_started) return;
01150
01151   switch(_read_method)
01152   {
01153     case READ:
01154       /* nothing to do here */
01155       break;
01156
01157     case MMAP: /* fall through */
01158     case UPTR:
01159     {
01160       /* stop streaming */
01161       int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01162       if (ioctl(_dev, VIDIOC_STREAMOFF, &type))
01163       {
01164         close();
01165         throw Exception("V4L2Cam: Stopping stream failed");
01166       }
01167       break;
01168     }
01169   }
01170
01171   _current_buffer = -1;
01172   _started = false;
01173 }
01174
01175 bool
01176 V4L2Camera::ready()
01177 {
01178   //LibLogger::log_debug("V4L2Cam", "ready()");
01179
01180   return _started;
01181 }
01182
01183 void
01184 V4L2Camera::flush()
01185 {
01186   //LibLogger::log_debug("V4L2Cam", "flush()");
01187   /* not needed */
01188 }
01189
01190 void
01191 V4L2Camera::capture()
01192 {
01193   //LibLogger::log_debug("V4L2Cam", "capture()");
01194
01195   if (!_started) return;
01196
01197   switch (_read_method)
01198   {
01199     case READ:
01200     {
01201       _current_buffer = 0;
01202       //LibLogger::log_debug("V4L2Cam", "calling read()");
01203       if (read(_dev, _frame_buffers[_current_buffer].buffer, _frame_buffers[_current_buffer].size) == -1)
01204       {
01205         //TODO: errno handling
01206         LibLogger::log_warn("V4L2Cam", "read() failed with code %d: %s", errno, strerror(errno));
01207       }
01208       //LibLogger::log_debug("V4L2Cam", "returned from read()");
01209
01210       //No timestamping support here - just take current system time
01211       if (_capture_time)
01212       {
01213         _capture_time->stamp();
01214       }
01215       else
01216       {
01217         _capture_time = new fawkes::Time();
01218       }
01219
01220       break;
01221     }
01222
01223     case MMAP:
01224     {
01225       /* dequeue buffer */
01226       v4l2_buffer buffer;
01227       memset(&buffer, 0, sizeof(buffer));
01228       buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01229       buffer.memory = V4L2_MEMORY_MMAP;
01230
01231       if (ioctl(_dev, VIDIOC_DQBUF, &buffer))
01232       {
01233         //TODO: errno handling -> EAGAIN, ...?
01234         close();
01235         throw Exception("V4L2Cam: Dequeuing buffer failed");
01236       }
01237
01238       _current_buffer = buffer.index;
01239
01240       if (_capture_time)
01241       {
01242         _capture_time->set_time(&buffer.timestamp);
01243       }
01244       else
01245       {
01246         _capture_time = new fawkes::Time(&buffer.timestamp);
01247       }
01248       break;
01249     }
01250
01251     case UPTR:
01252       /* not supported yet */
01253       break;
01254   }
01255 }
01256
01257 unsigned char *
01258 V4L2Camera::buffer()
01259 {
01260   //LibLogger::log_debug("V4L2Cam", "buffer()");
01261
01262   return (_current_buffer == -1 ? NULL : _frame_buffers[_current_buffer].buffer);
01263 }
01264
01265 unsigned int
01266 V4L2Camera::buffer_size()
01267 {
01268   //LibLogger::log_debug("V4L2Cam", "buffer_size()");
01269
01270   return (_opened && (_current_buffer != -1) ? _frame_buffers[_current_buffer].size : 0);
01271 }
01272
01273 void
01274 V4L2Camera::dispose_buffer()
01275 {
01276   //LibLogger::log_debug("V4L2Cam", "dispose_buffer()");
01277
01278   if (!_opened) return;
01279
01280   switch(_read_method)
01281   {
01282     case READ:
01283       /* nothing to do here */
01284       break;
01285
01286     case MMAP:
01287     {
01288       /* enqueue next buffer */
01289       v4l2_buffer buffer;
01290       memset(&buffer, 0, sizeof(buffer));
01291       buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01292       buffer.memory = V4L2_MEMORY_MMAP;
01293       buffer.index = _current_buffer;
01294       if (ioctl(_dev, VIDIOC_QBUF, &buffer))
01295       {
01296         close();
01297         throw Exception("V4L2Cam: Enqueuing buffer failed");
01298       }
01299       break;
01300     }
01301
01302     case UPTR:
01303       /* not supported yet */
01304       break;
01305   }
01306
01307   _current_buffer = -1;
01308 }
01309
01310 unsigned int
01311 V4L2Camera::pixel_width()
01312 {
01313   //LibLogger::log_debug("V4L2Cam", "pixel_width()");
01314
01315   return _width;
01316 }
01317
01318 unsigned int
01319 V4L2Camera::pixel_height()
01320 {
01321   //LibLogger::log_debug("V4L2Cam", "pixel_height()");
01322
01323   return _height;
01324 }
01325
01326 colorspace_t
01327 V4L2Camera::colorspace()
01328 {
01329   //LibLogger::log_debug("V4L2Cam", "colorspace()");
01330
01331   if (!_opened)
01332     return CS_UNKNOWN;
01333   else
01334     return _colorspace;
01335 }
01336
01337 fawkes::Time *
01338 V4L2Camera::capture_time()
01339 {
01340   return _capture_time;
01341 }
01342
01343 void
01344 V4L2Camera::set_image_number(unsigned int n)
01345 {
01346   //LibLogger::log_debug("V4L2Cam", "set_image_number(%d)", n);
01347
01348   /* not needed */
01349 }
01350
01351
01352 /* --- CameraControls --- */
01353
01354 bool
01355 V4L2Camera::auto_gain()
01356 {
01357   return get_one_control("AGC", V4L2_CID_AUTOGAIN);
01358 }
01359
01360 void
01361 V4L2Camera::set_auto_gain(bool enabled)
01362 {
01363   LibLogger::log_debug("V4L2Cam", (enabled ? "enabling AGC" : "disabling AGC"));
01364   set_one_control("AGC", V4L2_CID_AUTOGAIN, (enabled ? 1 : 0));
01365 }
01366
01367 bool
01368 V4L2Camera::auto_white_balance()
01369 {
01370   return get_one_control("AWB", V4L2_CID_AUTO_WHITE_BALANCE);
01371 }
01372
01373 void
01374 V4L2Camera::set_auto_white_balance(bool enabled)
01375 {
01376   LibLogger::log_debug("V4L2Cam", (enabled ? "enabling AWB" : "disabling AWB"));
01377   set_one_control("AWB", V4L2_CID_AUTO_WHITE_BALANCE, (enabled ? 1 : 0));
01378 }
01379
01380 bool
01381 V4L2Camera::auto_exposure()
01382 {
01383   if (!_nao_hacks) LibLogger::log_warn("V4L2Cam", "AEC will only work on Nao");
01384   return get_one_control("AEC", V4L2_CID_AUDIO_MUTE);
01385 }
01386
01387 void
01388 V4L2Camera::set_auto_exposure(bool enabled)
01389 {
01390   LibLogger::log_debug("V4L2Cam", (enabled ? "enabling AEC" : "disabling AEC"));
01391   if (!_nao_hacks) LibLogger::log_warn("V4L2Cam", "AEC toggling will only work on Nao");
01392
01393   set_one_control("AEC", V4L2_CID_AUDIO_MUTE, //<- this is why it will only work on Naos ;)
01394                   (enabled ? 1 : 0));
01395 }
01396
01397 int
01398 V4L2Camera::red_balance()
01399 {
01400   return get_one_control("red balance", V4L2_CID_RED_BALANCE);
01401 }
01402
01403 void
01404 V4L2Camera::set_red_balance(int red_balance)
01405 {
01406   LibLogger::log_debug("V4L2Cam", "Setting red balance to %d", red_balance);
01407   set_one_control("red balance", V4L2_CID_RED_BALANCE, red_balance);
01408 }
01409
01410 int
01411 V4L2Camera::blue_balance()
01412 {
01413   return get_one_control("blue balance", V4L2_CID_BLUE_BALANCE);
01414 }
01415
01416 void
01417 V4L2Camera::set_blue_balance(int blue_balance)
01418 {
01419   LibLogger::log_debug("V4L2Cam", "Setting blue balance to %d", blue_balance);
01420   set_one_control("blue balance", V4L2_CID_BLUE_BALANCE, blue_balance);
01421 }
01422
01423 int
01424 V4L2Camera::u_balance()
01425 {
01426   throw NotImplementedException("No such method in the V4L2 standard");
01427 }
01428
01429 void
01430 V4L2Camera::set_u_balance(int u_balance)
01431 {
01432   throw NotImplementedException("No such method in the V4L2 standard");
01433 }
01434
01435 int
01436 V4L2Camera::v_balance()
01437 {
01438   throw NotImplementedException("No such method in the V4L2 standard");
01439 }
01440
01441 void
01442 V4L2Camera::set_v_balance(int v_balance)
01443 {
01444   throw NotImplementedException("No such method in the V4L2 standard");
01445 }
01446
01447 unsigned int
01448 V4L2Camera::brightness()
01449 {
01450   return get_one_control("brightness", V4L2_CID_BRIGHTNESS);
01451 }
01452
01453 void
01454 V4L2Camera::set_brightness(unsigned int brightness)
01455 {
01456   LibLogger::log_debug("V4L2Cam", "Setting brighness to %d", brightness);
01457   set_one_control("brightness", V4L2_CID_BRIGHTNESS, brightness);
01458 }
01459
01460 unsigned int
01461 V4L2Camera::contrast()
01462 {
01463   return get_one_control("contrast", V4L2_CID_CONTRAST);
01464 }
01465
01466 void
01467 V4L2Camera::set_contrast(unsigned int contrast)
01468 {
01469   LibLogger::log_debug("V4L2Cam", "Setting contrast to %d", contrast);
01470   set_one_control("contrast", V4L2_CID_CONTRAST, contrast);
01471 }
01472
01473 unsigned int
01474 V4L2Camera::saturation()
01475 {
01476   return get_one_control("saturation", V4L2_CID_SATURATION);
01477 }
01478
01479 void
01480 V4L2Camera::set_saturation(unsigned int saturation)
01481 {
01482   LibLogger::log_debug("V4L2Cam", "Setting saturation to %d", saturation);
01483   set_one_control("saturation", V4L2_CID_SATURATION, saturation);
01484 }
01485
01486 int
01487 V4L2Camera::hue()
01488 {
01489   return get_one_control("hue", V4L2_CID_HUE);
01490 }
01491
01492 void
01493 V4L2Camera::set_hue(int hue)
01494 {
01495   LibLogger::log_debug("V4L2Cam", "Setting hue to %d", hue);
01496   set_one_control("hue", V4L2_CID_HUE, hue);
01497 }
01498
01499 unsigned int
01500 V4L2Camera::exposure()
01501 {
01502   return get_one_control("exposure", V4L2_CID_EXPOSURE);
01503 }
01504
01505 void
01506 V4L2Camera::set_exposure(unsigned int exposure)
01507 {
01508   LibLogger::log_debug("V4L2Cam", "Setting exposure to %d", exposure);
01509   set_one_control("exposure", V4L2_CID_EXPOSURE, exposure);
01510 }
01511
01512 unsigned int
01513 V4L2Camera::gain()
01514 {
01515   return get_one_control("gain", V4L2_CID_GAIN);
01516 }
01517
01518 void
01519 V4L2Camera::set_gain(unsigned int gain)
01520 {
01521   LibLogger::log_debug("V4L2Cam", "Setting gain to %u", gain);
01522   set_one_control("gain", V4L2_CID_GAIN, gain);
01523 }
01524
01525
01526 const char *
01527 V4L2Camera::format()
01528 {
01529   return _format;
01530 }
01531
01532 void
01533 V4L2Camera::set_format(const char *format)
01534 {
01535   strncpy(_format, format, 4);
01536   _format[4] = '\0';
01537   select_format();
01538 }
01539
01540 unsigned int
01541 V4L2Camera::width()
01542 {
01543   return pixel_width();
01544 }
01545
01546 unsigned int
01547 V4L2Camera::height()
01548 {
01549   return pixel_height();
01550 }
01551
01552 void
01553 V4L2Camera::set_size(unsigned int width,
01554                      unsigned int height)
01555 {
01556   _width = width;
01557   _height = height;
01558   select_format();
01559 }
01560
01561 bool
01562 V4L2Camera::horiz_mirror()
01563 {
01564   return (get_one_control("hflip", V4L2_CID_HFLIP) != 0);
01565 }
01566
01567 bool
01568 V4L2Camera::vert_mirror()
01569 {
01570   return (get_one_control("vflip", V4L2_CID_VFLIP) != 0);
01571 }
01572
01573 void
01574 V4L2Camera::set_horiz_mirror(bool enabled)
01575 {
01576   LibLogger::log_debug("V4L2Cam", (enabled ? "enabling horizontal flip" : "disabling horizontal flip"));
01577   set_one_control("hflip", V4L2_CID_HFLIP, (enabled ? 1 : 0));
01578 }
01579
01580 void
01581 V4L2Camera::set_vert_mirror(bool enabled)
01582 {
01583   LibLogger::log_debug("V4L2Cam", (enabled ? "enabling vertical flip" : "disabling vertical flip"));
01584   set_one_control("vflip", V4L2_CID_VFLIP, (enabled ? 1 : 0));
01585 }
01586 
01587 /** Get the number of frames per second that have been requested from the camera.
01588  * A return value of 0 means that fps haven't been set yet through the camera.
01589  * @return the currently requested fps or 0 if not set yet
01590  */
01591 unsigned int
01592 V4L2Camera::fps()
01593 {
01594   return _fps;
01595 }
01596
01597 void
01598 V4L2Camera::set_fps(unsigned int fps)
01599 {
01600   _fps = fps;
01601   set_fps();
01602 }
01603
01604 unsigned int
01605 V4L2Camera::lens_x_corr()
01606 {
01607   return get_one_control("lens x", V4L2_CID_HCENTER/*_DEPRECATED*/);
01608 }
01609
01610 unsigned int
01611 V4L2Camera::lens_y_corr()
01612 {
01613   return get_one_control("lens y", V4L2_CID_VCENTER/*_DEPRECATED*/);
01614 }
01615
01616 void
01617 V4L2Camera::set_lens_x_corr(unsigned int x_corr)
01618 {
01619   LibLogger::log_debug("V4L2Cam", "Setting horizontal lens correction to %d", x_corr);
01620   set_one_control("lens x", V4L2_CID_HCENTER/*_DEPRECATED*/, x_corr);
01621 }
01622
01623 void
01624 V4L2Camera::set_lens_y_corr(unsigned int y_corr)
01625 {
01626   LibLogger::log_debug("V4L2Cam", "Setting vertical lens correction to %d", y_corr);
01627   set_one_control("lens x", V4L2_CID_VCENTER/*_DEPRECATED*/, y_corr);
01628 }
01629
01630
01631 void
01632 V4L2Camera::print_info()
01633 {
01634  /* General capabilities */
01635   cout <<
01636     "=========================================================================="
01637     << endl << _device_name << " (" << _data->caps.card << ") - " << _data->caps.bus_info
01638     << endl << "Driver: " << _data->caps.driver << " (ver " <<
01639     ((_data->caps.version >> 16) & 0xFF) << "." <<
01640     ((_data->caps.version >> 8) & 0xFF) << "." <<
01641     (_data->caps.version & 0xFF) << ")" << endl <<
01642     "--------------------------------------------------------------------------"
01643     << endl;
01644
01645   /* General capabilities */
01646   cout << "Capabilities:" << endl;
01647   if (_data->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)
01648     cout << " + Video capture interface supported" << endl;
01649   if (_data->caps.capabilities & V4L2_CAP_VIDEO_OUTPUT)
01650     cout << " + Video output interface supported" << endl;
01651   if (_data->caps.capabilities & V4L2_CAP_VIDEO_OVERLAY)
01652     cout << " + Video overlay interface supported" << endl;
01653   if (_data->caps.capabilities & V4L2_CAP_VBI_CAPTURE)
01654     cout << " + Raw VBI capture interface supported" << endl;
01655   if (_data->caps.capabilities & V4L2_CAP_VBI_OUTPUT)
01656     cout << " + Raw VBI output interface supported" << endl;
01657   if (_data->caps.capabilities & V4L2_CAP_SLICED_VBI_CAPTURE)
01658     cout << " + Sliced VBI capture interface supported" << endl;
01659   if (_data->caps.capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
01660     cout << " + Sliced VBI output interface supported" << endl;
01661   if (_data->caps.capabilities & V4L2_CAP_RDS_CAPTURE)
01662     cout << " + RDS_CAPTURE set" << endl;
01663   /* Not included in Nao's version
01664   if (caps.capabilities & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
01665     cout << " + Video output overlay interface supported" << endl; */
01666   if (_data->caps.capabilities & V4L2_CAP_TUNER)
01667     cout << " + Has some sort of tuner" << endl;
01668   if (_data->caps.capabilities & V4L2_CAP_AUDIO)
01669     cout << " + Has audio inputs or outputs" << endl;
01670   if (_data->caps.capabilities & V4L2_CAP_RADIO)
01671     cout << " + Has a radio receiver" << endl;
01672   if (_data->caps.capabilities & V4L2_CAP_READWRITE)
01673     cout << " + read() and write() IO supported" << endl;
01674   if (_data->caps.capabilities & V4L2_CAP_ASYNCIO)
01675     cout << " + asynchronous IO supported" << endl;
01676   if (_data->caps.capabilities & V4L2_CAP_STREAMING)
01677     cout << " + streaming IO supported" << endl;
01678   if (_data->caps.capabilities & V4L2_CAP_TIMEPERFRAME)
01679     cout << " + timeperframe field is supported" << endl;
01680   cout << endl;
01681
01682   /* Inputs */
01683   cout << "Inputs:" << endl;
01684   v4l2_input input;
01685   memset(&input, 0, sizeof(input));
01686
01687   for (input.index = 0; ioctl(_dev, VIDIOC_ENUMINPUT, &input) == 0; input.index++)
01688   {
01689     cout << "Input " << input.index << ": " << input.name << endl;
01690
01691     cout << " |- Type: ";
01692     switch (input.type)
01693     {
01694       case V4L2_INPUT_TYPE_TUNER:
01695         cout << "Tuner";
01696         break;
01697
01698       case V4L2_INPUT_TYPE_CAMERA:
01699         cout << "Camera";
01700         break;
01701
01702       default:
01703         cout << "Unknown";
01704     }
01705     cout << endl;
01706
01707     cout << " |- Supported standards:";
01708     if (input.std == 0)
01709     {
01710       cout << " Unknown" << endl;
01711     }
01712     else
01713     {
01714       cout << endl;
01715
01716       v4l2_standard standard;
01717       memset (&standard, 0, sizeof(standard));
01718       standard.index = 0;
01719
01720       for (standard.index = 0; ioctl(_dev, VIDIOC_ENUMSTD, &standard) == 0; standard.index++)
01721       {
01722         if (standard.id & input.std) cout << "  + " << standard.name << endl;
01723       }
01724     }
01725   }
01726   if (input.index == 0) cout << "None" << endl;
01727   cout << endl;
01728
01729   /* Outputs */
01730   cout << "Outputs:" << endl;
01731   v4l2_output output;
01732   memset (&output, 0, sizeof(output));
01733
01734   for (output.index = 0; ioctl(_dev, VIDIOC_ENUMOUTPUT, &output) == 0; output.index++)
01735   {
01736     cout << " + Output " << output.index << ": " << output.name << endl;
01737
01738     cout << " |- Type: ";
01739     switch (output.type)
01740     {
01741       case V4L2_OUTPUT_TYPE_MODULATOR:
01742         cout << "TV Modulator";
01743         break;
01744
01745       case V4L2_OUTPUT_TYPE_ANALOG:
01746         cout << "Analog output";
01747         break;
01748
01749       default:
01750         cout << "Unknown";
01751     }
01752     cout << endl;
01753
01754     cout << " |- Supported standards:";
01755     if (output.std == 0)
01756     {
01757       cout << " Unknown" << endl;
01758     }
01759     else
01760     {
01761       cout << endl;
01762
01763       v4l2_standard standard;
01764       memset (&standard, 0, sizeof (standard));
01765       standard.index = 0;
01766
01767       for (standard.index = 0; ioctl(_dev, VIDIOC_ENUMSTD, &standard) == 0; standard.index++)
01768       {
01769         if (standard.id & output.std) cout << "  + " << standard.name << endl;
01770       }
01771     }
01772   }
01773   if (output.index == 0) cout << "None" << endl;
01774   cout << endl;
01775
01776   /* Supported formats */
01777   cout << "Formats:" << endl;
01778   v4l2_fmtdesc format_desc;
01779   memset(&format_desc, 0, sizeof(format_desc));
01780   format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01781
01782   char fourcc[5] = "    ";
01783   for (format_desc.index = 0; ioctl(_dev, VIDIOC_ENUM_FMT, &format_desc) == 0; format_desc.index++)
01784   {
01785     fourcc[0] = static_cast<char>(format_desc.pixelformat & 0xFF);
01786     fourcc[1] = static_cast<char>((format_desc.pixelformat >> 8) & 0xFF);
01787     fourcc[2] = static_cast<char>((format_desc.pixelformat >> 16) & 0xFF);
01788     fourcc[3] = static_cast<char>((format_desc.pixelformat >> 24) & 0xFF);
01789
01790     colorspace_t cs = CS_UNKNOWN;
01791     if (strcmp(fourcc, "RGB3") == 0) cs = RGB;
01792     else if (strcmp(fourcc, "Y41P") == 0) cs = YUV411_PACKED; //different byte ordering
01793     else if (strcmp(fourcc, "411P") == 0) cs = YUV411_PLANAR;
01794     else if (strcmp(fourcc, "YUYV") == 0) cs = YUY2;
01795     else if (strcmp(fourcc, "BGR3") == 0) cs = BGR;
01796     else if (strcmp(fourcc, "UYVY") == 0) cs = YUV422_PACKED;
01797     else if (strcmp(fourcc, "422P") == 0) cs = YUV422_PLANAR;
01798     else if (strcmp(fourcc, "GREY") == 0) cs = GRAY8;
01799     else if (strcmp(fourcc, "RGB4") == 0) cs = RGB_WITH_ALPHA;
01800     else if (strcmp(fourcc, "BGR4") == 0) cs = BGR_WITH_ALPHA;
01801     else if (strcmp(fourcc, "BA81") == 0) cs = BAYER_MOSAIC_BGGR;
01802     else if (strcmp(fourcc, "Y16 ") == 0) cs = MONO16;
01803
01804     cout << " + Format " << format_desc.index << ": " << fourcc <<
01805       " (" << format_desc.description << ")";
01806     if (format_desc.flags & V4L2_FMT_FLAG_COMPRESSED) cout << " [Compressed]";
01807     cout << endl << " |- Colorspace: " << colorspace_to_string(cs) << endl;
01808   }
01809   cout << endl;
01810
01811   /* Current Format */
01812   v4l2_format format;
01813   memset(&format, 0, sizeof(format));
01814   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
01815   if (ioctl(_dev, VIDIOC_G_FMT, &format)) throw Exception("V4L2Cam: Format query failed");
01816   fourcc[0] = static_cast<char>(format.fmt.pix.pixelformat & 0xFF);
01817   fourcc[1] = static_cast<char>((format.fmt.pix.pixelformat >> 8) & 0xFF);
01818   fourcc[2] = static_cast<char>((format.fmt.pix.pixelformat >> 16) & 0xFF);
01819   fourcc[3] = static_cast<char>((format.fmt.pix.pixelformat >> 24) & 0xFF);
01820
01821   cout << " Current Format:" << endl <<
01822     " " << format.fmt.pix.width << "x" << format.fmt.pix.height <<
01823     " (" << fourcc << ")" << endl <<
01824     " " << format.fmt.pix.bytesperline << " bytes per line" << endl <<
01825     " Total size: " << format.fmt.pix.sizeimage << endl;
01826
01827   /* Supported Controls */
01828   cout << "Controls:" << endl;
01829   v4l2_queryctrl queryctrl;
01830   v4l2_querymenu querymenu;
01831
01832   memset(&queryctrl, 0, sizeof(queryctrl));
01833
01834   for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1;
01835        queryctrl.id++)
01836   {
01837     if (ioctl(_dev, VIDIOC_QUERYCTRL, &queryctrl))
01838     {
01839       if (errno == EINVAL) continue;
01840
01841       cout << "Control query failed" << endl;
01842       return;
01843     }
01844     if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue;
01845
01846     cout << " + " <<  queryctrl.name << " [" <<
01847       (queryctrl.id - V4L2_CID_BASE) << "] (";
01848     switch (queryctrl.type)
01849     {
01850       case V4L2_CTRL_TYPE_INTEGER:
01851         cout << "int [" << queryctrl.minimum << "-" << queryctrl.maximum <<
01852           " /" << queryctrl.step << " def " << queryctrl.default_value <<
01853           "]";
01854         break;
01855
01856       case V4L2_CTRL_TYPE_MENU:
01857         cout << "menu [def " << queryctrl.default_value << "]";
01858         break;
01859
01860       case V4L2_CTRL_TYPE_BOOLEAN:
01861         cout << "bool [def " << queryctrl.default_value << "]";
01862         break;
01863
01864       case V4L2_CTRL_TYPE_BUTTON:
01865         cout << "button";
01866         break;
01867
01868 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
01869       case V4L2_CTRL_TYPE_INTEGER64:
01870         cout << "int64";
01871         break;
01872
01873       case V4L2_CTRL_TYPE_CTRL_CLASS:
01874         cout << "ctrl_class";
01875         break;
01876 #endif
01877     }
01878     cout << ")" << endl;
01879
01880     if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
01881     {
01882       cout << " |- Menu items:" << endl;
01883
01884       memset(&querymenu, 0, sizeof(querymenu));
01885       querymenu.id = queryctrl.id;
01886
01887       for (querymenu.index = queryctrl.minimum;
01888            querymenu.index <= static_cast<unsigned long int>(queryctrl.maximum);
01889            querymenu.index++)
01890       {
01891         if (ioctl(_dev, VIDIOC_QUERYMENU, &querymenu))
01892         {
01893           cout << "Getting menu items failed" << endl;
01894           return;
01895         }
01896         cout << " |   + " << querymenu.name << endl;
01897       }
01898     }
01899   }
01900   if (queryctrl.id == V4L2_CID_BASE) cout << "None" << endl;
01901   cout << endl;
01902
01903   /* Supported Private Controls */
01904   cout << "Private Controls:" << endl;
01905   for (queryctrl.id = V4L2_CID_PRIVATE_BASE; ; queryctrl.id++)
01906   {
01907     if (ioctl(_dev, VIDIOC_QUERYCTRL, &queryctrl))
01908     {
01909       if (errno == EINVAL) break;
01910
01911       cout << "Private Control query failed" << endl;
01912       return;
01913     }
01914
01915     if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue;
01916
01917     cout << " + " <<  queryctrl.name << " [" <<
01918       (queryctrl.id - V4L2_CID_PRIVATE_BASE) << "] (";
01919     switch (queryctrl.type)
01920     {
01921       case V4L2_CTRL_TYPE_INTEGER:
01922         cout << "int [" << queryctrl.minimum << "-" << queryctrl.maximum <<
01923           " /" << queryctrl.step << " def " << queryctrl.default_value <<
01924           "]";
01925         break;
01926
01927       case V4L2_CTRL_TYPE_MENU:
01928         cout << "menu [def " << queryctrl.default_value << "]";
01929         break;
01930
01931       case V4L2_CTRL_TYPE_BOOLEAN:
01932         cout << "bool [def " << queryctrl.default_value << "]";
01933         break;
01934
01935       case V4L2_CTRL_TYPE_BUTTON:
01936         cout << "button";
01937         break;
01938
01939 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
01940       case V4L2_CTRL_TYPE_INTEGER64:
01941         cout << "int64";
01942         break;
01943
01944       case V4L2_CTRL_TYPE_CTRL_CLASS:
01945         cout << "ctrl_class";
01946         break;
01947 #endif
01948     }
01949     cout << ")" << endl;
01950
01951     if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
01952     {
01953       cout << " |- Menu items:" << endl;
01954
01955       memset(&querymenu, 0, sizeof(querymenu));
01956       querymenu.id = queryctrl.id;
01957
01958       for (querymenu.index = queryctrl.minimum;
01959            querymenu.index <= static_cast<unsigned long int>(queryctrl.maximum);
01960            querymenu.index++)
01961       {
01962         if (ioctl(_dev, VIDIOC_QUERYMENU, &querymenu))
01963         {
01964           cout << "Getting menu items failed" << endl;
01965           return;
01966         }
01967         cout << " |   + " << querymenu.name << endl;
01968       }
01969     }
01970   }
01971   if (queryctrl.id == V4L2_CID_PRIVATE_BASE) cout << "None" << endl;
01972
01973   cout <<
01974     "=========================================================================="
01975     << endl;
01976 }