Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media_v4l2_device.h"
      6 
      7 #include <assert.h>
      8 #include <time.h>
      9 #include <sys/stat.h>
     10 
     11 #include <string>
     12 #include <utility>
     13 
     14 #define CHECK(a) assert(a)
     15 #define MAJOR(dev) (((uint32_t)(dev)) >> 8)
     16 #define MINOR(dev) (((uint32_t)(dev)) & 0xff)
     17 #define V4L2_VIDEO_CAPTURE_MAJOR      81
     18 #define V4L2_VIDEO_CAPTURE_MINOR_MIN  0
     19 #define V4L2_VIDEO_CAPTURE_MINOR_MAX  64
     20 
     21 V4L2Device::V4L2Device(const char* dev_name,
     22                        uint32_t buffers)
     23     : dev_name_(dev_name),
     24       io_(IO_METHOD_UNDEFINED),
     25       fd_(-1),
     26       v4l2_buffers_(NULL),
     27       num_buffers_(0),
     28       min_buffers_(buffers),
     29       stopped_(false),
     30       initialized_(false) {
     31 }
     32 
     33 V4L2Device::~V4L2Device() {
     34   if (initialized_)
     35     UninitDevice();
     36   CloseDevice();
     37 }
     38 
     39 bool V4L2Device::OpenDevice() {
     40   struct stat st;
     41   if (-1 == stat(dev_name_, &st)) {
     42     printf("<<< Error: could not find v4l2 device %s: (%d) %s.>>>\n",
     43            dev_name_, errno, strerror(errno));
     44     return false;
     45   }
     46 
     47   if (!S_ISCHR(st.st_mode)) {
     48     printf("<<< Error: specified v4l2 device %s is not char device.>>>\n",
     49            dev_name_);
     50     return false;
     51   }
     52 
     53   if (MAJOR(st.st_rdev) != V4L2_VIDEO_CAPTURE_MAJOR
     54       || MINOR(st.st_rdev) >= V4L2_VIDEO_CAPTURE_MINOR_MAX) {
     55     printf("<<< Error: specified v4l2 device %s is not v4l2 device.>>>\n",
     56            dev_name_);
     57     return false;
     58   }
     59 
     60   fd_ = open(dev_name_, O_RDWR | O_NONBLOCK, 0);
     61   if (-1 == fd_) {
     62     printf("<<< Error: specified v4l2 device %s could not be opened.>>>\n",
     63            dev_name_);
     64     return false;
     65   }
     66 
     67   v4l2_capability cap;
     68   if (!ProbeCaps(&cap))
     69     return false;
     70 
     71   if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
     72     printf("<<< Error: %s does not support video capture.>>>\n", dev_name_);
     73     return false;
     74   }
     75 
     76   return true;
     77 }
     78 
     79 void V4L2Device::CloseDevice() {
     80   if (fd_ != -1)
     81     close(fd_);
     82   fd_ = -1;
     83 }
     84 
     85 bool V4L2Device::InitDevice(IOMethod io,
     86                             uint32_t width,
     87                             uint32_t height,
     88                             uint32_t pixfmt,
     89                             float fps,
     90                             ConstantFramerate constant_framerate,
     91                             uint32_t num_skip_frames) {
     92   io_ = io;
     93   // Crop/Format setting could live across session.
     94   // We should always initialized them when supported.
     95   v4l2_cropcap cropcap;
     96   memset(&cropcap, 0, sizeof(cropcap));
     97   if (GetCropCap(&cropcap)) {
     98     v4l2_crop crop;
     99     memset(&crop, 0, sizeof(crop));
    100     // Use default capture rectangle.
    101     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    102     crop.c = cropcap.defrect;
    103     SetCrop(&crop);
    104   }
    105 
    106   v4l2_format fmt;
    107   if (!GetV4L2Format(&fmt))
    108     return false;
    109 
    110   fmt.fmt.pix.width = width;
    111   fmt.fmt.pix.height = height;
    112   fmt.fmt.pix.pixelformat = pixfmt;
    113   fmt.fmt.pix.field = V4L2_FIELD_NONE;
    114 
    115   if (-1 == DoIoctl(VIDIOC_S_FMT, &fmt)) {
    116     printf("<<< Error: VIDIOC_S_FMT on %s.>>>\n", dev_name_);
    117     return false;
    118   }
    119 
    120   v4l2_capability cap;
    121   if (!ProbeCaps(&cap))
    122     return false;
    123 
    124   switch (io_) {
    125     case IO_METHOD_MMAP:
    126     case IO_METHOD_USERPTR:
    127       if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
    128         printf("<<< Error: %s does not support streaming.>>>\n", dev_name_);
    129         return false;
    130       }
    131       break;
    132     default:
    133       printf("<<< Error: IO method should be defined.>>>\n");
    134       return false;
    135   }
    136 
    137   v4l2_streamparm param;
    138   if (!GetParam(&param))
    139     return false;
    140 
    141   if (param.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
    142     if (fps > 0) {
    143       SetFrameRate(fps);
    144     } else {
    145       printf("<<< Error: fps %f should be a positive number.>>>\n", fps);
    146       return false;
    147     }
    148   }
    149   float actual_fps = GetFrameRate();
    150 
    151   int32_t constant_framerate_setting;
    152   std::string constant_framerate_msg = "";
    153   switch (constant_framerate) {
    154     case DEFAULT_FRAMERATE_SETTING:
    155       constant_framerate_setting = 1;
    156       break;
    157     case ENABLE_CONSTANT_FRAMERATE:
    158       constant_framerate_setting = 0;
    159       constant_framerate_msg = " with constant framerate";
    160       break;
    161     case DISABLE_CONSTANT_FRAMERATE:
    162       constant_framerate_setting = 1;
    163       constant_framerate_msg = " without constant framerate";
    164       break;
    165     default:
    166       printf("<<< Error: Invalid constant framerate setting: %d. >>>\n",
    167           constant_framerate);
    168       return false;
    169   }
    170   SetControl(V4L2_CID_EXPOSURE_AUTO_PRIORITY, constant_framerate_setting);
    171 
    172   printf("actual format for capture %dx%d %c%c%c%c picture at %.2f fps%s\n",
    173          fmt.fmt.pix.width, fmt.fmt.pix.height,
    174          (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    175          (pixfmt >> 16) & 0xff, (pixfmt >> 24 ) & 0xff, actual_fps,
    176          constant_framerate_msg.c_str());
    177   frame_timestamps_.clear();
    178   num_skip_frames_ = num_skip_frames;
    179 
    180   bool ret = false;
    181   switch (io_) {
    182     case IO_METHOD_MMAP:
    183       ret = InitMmapIO();
    184       break;
    185     case IO_METHOD_USERPTR:
    186       ret = InitUserPtrIO(fmt.fmt.pix.sizeimage);
    187       break;
    188     default:
    189       printf("<<< Error: IO method should be defined.>>>\n");
    190       return false;
    191   }
    192   if (ret)
    193     initialized_ = true;
    194   return ret;
    195 }
    196 
    197 bool V4L2Device::UninitDevice() {
    198   v4l2_requestbuffers req;
    199   memset(&req, 0, sizeof(req));
    200   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    201   switch (io_) {
    202     case IO_METHOD_MMAP:
    203       for (uint32_t i = 0; i < num_buffers_; ++i)
    204         if (-1 == munmap(v4l2_buffers_[i].start, v4l2_buffers_[i].length)) {
    205           printf("<<< Error: munmap() on %s failed.>>>\n", dev_name_);
    206           return false;
    207         }
    208 
    209       req.memory = V4L2_MEMORY_MMAP;
    210       if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    211         printf("<<< Error: VIDIOC_REQBUFS for MMAP failed on %s: %s.>>>\n",
    212             dev_name_, strerror(errno));
    213         return false;
    214       }
    215       break;
    216     case IO_METHOD_USERPTR:
    217       req.memory = V4L2_MEMORY_USERPTR;
    218       if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    219         printf("<<< Error: VIDIOC_REQBUFS for USERPTR failed on %s.: %s>>>\n",
    220             dev_name_, strerror(errno));
    221         return false;
    222       }
    223 
    224       for (uint32_t i = 0; i < num_buffers_; ++i)
    225         free(v4l2_buffers_[i].start);
    226       break;
    227     default:
    228       printf("<<< Error: IO method should be defined.>>>\n");
    229       return false;
    230   }
    231   FreeBuffer();
    232   initialized_ = false;
    233   return true;
    234 }
    235 
    236 bool V4L2Device::StartCapture() {
    237   for (uint32_t i = 0; i < num_buffers_; ++i) {
    238     if (!EnqueueBuffer(i))
    239       return false;
    240   }
    241   v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    242   if (-1 == DoIoctl(VIDIOC_STREAMON, &type)) {
    243     printf("<<< Error: VIDIOC_STREAMON on %s.>>>\n", dev_name_);
    244     return false;
    245   }
    246 
    247   uint32_t buf_index, data_size;
    248   for (size_t i = 0; i < num_skip_frames_; i++) {
    249     if (!ReadOneFrame(&buf_index, &data_size))
    250       return false;
    251     if (!EnqueueBuffer(buf_index))
    252       return false;
    253   }
    254 
    255   return true;
    256 }
    257 
    258 bool V4L2Device::StopCapture() {
    259   v4l2_buf_type type;
    260   switch (io_) {
    261     case IO_METHOD_MMAP:
    262     case IO_METHOD_USERPTR:
    263       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    264       if (-1 == DoIoctl(VIDIOC_STREAMOFF, &type)) {
    265         printf("<<< Error: VIDIOC_STREAMOFF on %s.>>>\n", dev_name_);
    266         return false;
    267       }
    268       break;
    269     default:
    270       printf("<<< Error: IO method should be defined.>>>\n");
    271       return false;
    272   }
    273   return true;
    274 }
    275 
    276 void V4L2Device::ProcessImage(const void* p) {
    277   printf(".");
    278   fflush(stdout);
    279 }
    280 
    281 // Do capture for duration of |time_in_sec|.
    282 bool V4L2Device::Run(uint32_t time_in_sec) {
    283   stopped_ = false;
    284   if (!time_in_sec)
    285     return false;
    286 
    287   uint64_t start_in_nanosec = Now();
    288   uint32_t buffer_index, data_size;
    289   while (!stopped_) {
    290     int32_t r = ReadOneFrame(&buffer_index, &data_size);
    291     if (r < 0)
    292       return false;
    293     if (r) {
    294       ProcessImage(v4l2_buffers_[buffer_index].start);
    295       if (!EnqueueBuffer(buffer_index))
    296         return false;
    297     }
    298     uint64_t end_in_nanosec = Now();
    299     if ( end_in_nanosec - start_in_nanosec >= time_in_sec * 1000000000ULL)
    300       break;
    301   }
    302   // All resolutions should have at least 1 fps.
    303   float actual_fps = static_cast<float>(GetNumFrames()) / time_in_sec;
    304   printf("\n<<< Info: Actual fps is %f on %s.>>>\n", actual_fps, dev_name_);
    305   if (actual_fps < 1.0) {
    306     printf("<<< Error: The actual fps is too low on %s.>>>\n", dev_name_);
    307     return false;
    308   }
    309   return true;
    310 }
    311 
    312 bool V4L2Device::Stop() {
    313   stopped_ = true;
    314   return true;
    315 }
    316 
    317 int32_t V4L2Device::DoIoctl(int32_t request, void* arg) {
    318   int32_t r;
    319   do {
    320     r = ioctl(fd_, request, arg);
    321   } while (-1 == r && EINTR == errno);
    322   return r;
    323 }
    324 
    325 // return 1 : successful to retrieve a frame from device
    326 // return 0 : EAGAIN
    327 // negative : error
    328 int32_t V4L2Device::ReadOneFrame(uint32_t* buffer_index, uint32_t* data_size) {
    329   fd_set fds;
    330   FD_ZERO(&fds);
    331   FD_SET(fd_, &fds);
    332   timeval tv;
    333   tv.tv_sec = 2;  // Normal timeout will be 2 seconds.
    334   tv.tv_usec = 0;
    335   int32_t r = select(fd_ + 1, &fds, NULL, NULL, &tv);
    336   if (-1 == r) {
    337     if (EINTR == errno)  // If interrupted, try again.
    338       return 0;
    339     printf("<<< Error: select() failed on %s.>>>\n", dev_name_);
    340     return -1;
    341   }
    342   if (0 == r) {
    343     printf("<<< Error: select() timeout on %s.>>>\n", dev_name_);
    344     return -1;
    345   }
    346 
    347   v4l2_buffer buf;
    348   int64_t ts;
    349   memset(&buf, 0, sizeof(buf));
    350   switch (io_) {
    351     case IO_METHOD_MMAP:
    352       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    353       buf.memory = V4L2_MEMORY_MMAP;
    354       if (-1 == DoIoctl(VIDIOC_DQBUF, &buf)) {
    355         switch (errno) {
    356           case EAGAIN:
    357             return 0;
    358           case EIO:
    359             // Could ignore EIO, see spec.
    360             // Fall through.
    361           default:
    362             printf("<<< Error: VIDIOC_DQBUF failed on %s.>>>\n", dev_name_);
    363             return -2;
    364         }
    365       }
    366       // For checking constant frame rate, we have to use HW timestamp from
    367       // v4l2_buffer to get more stable timestamp.
    368       // Since kerenel after 3.18 have a fix to disable hardware timestamp
    369       // (https://patchwork.kernel.org/patch/6874491/), we have to manually
    370       // enable HW timestamp via /sys/module/uvcvideo/parameters/hwtimestamps.
    371       ts = buf.timestamp.tv_sec * 1000000000LL + buf.timestamp.tv_usec * 1000;
    372       frame_timestamps_.push_back(ts);
    373       CHECK(buf.index < num_buffers_);
    374       // TODO: uvcvideo driver ignores this field. This is negligible,
    375       // so disabling this for now until we get a fix into the upstream driver.
    376       // CHECK(buf.field == V4L2_FIELD_NONE);  // progressive only.
    377       break;
    378     case IO_METHOD_USERPTR:
    379       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    380       buf.memory = V4L2_MEMORY_USERPTR;
    381       if (-1 == DoIoctl(VIDIOC_DQBUF, &buf)) {
    382         switch (errno) {
    383           case EAGAIN:
    384             return 0;
    385           case EIO:
    386             // Could ignore EIO, see spec.
    387             // Fall through.
    388           default:
    389             printf("<<< Error: VIDIOC_DQBUF failed on %s.>>>\n", dev_name_);
    390             return -2;
    391         }
    392       }
    393       ts = buf.timestamp.tv_sec * 1000000000LL + buf.timestamp.tv_usec * 1000;
    394       frame_timestamps_.push_back(ts);
    395       CHECK(buf.index < num_buffers_);
    396       break;
    397     default:
    398       printf("<<< Error: IO method should be defined.>>>\n");
    399       return -1;
    400   }
    401   if (buffer_index)
    402     *buffer_index = buf.index;
    403   if (data_size)
    404     *data_size = buf.bytesused;
    405   return 1;
    406 }
    407 
    408 bool V4L2Device::EnqueueBuffer(uint32_t buffer_index) {
    409   v4l2_buffer buf;
    410   memset(&buf, 0, sizeof(buf));
    411   switch (io_) {
    412     case IO_METHOD_MMAP:
    413       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    414       buf.memory = V4L2_MEMORY_MMAP;
    415       buf.index = buffer_index;
    416       if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    417         printf("<<< Error: VIDIOC_QBUF failed on %s.>>>\n", dev_name_);
    418         return false;
    419       }
    420       break;
    421     case IO_METHOD_USERPTR:
    422       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    423       buf.memory = V4L2_MEMORY_USERPTR;
    424       buf.index = buffer_index;
    425       buf.m.userptr = (unsigned long) v4l2_buffers_[buffer_index].start;
    426       buf.length = v4l2_buffers_[buffer_index].length;
    427       if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    428         printf("<<< Error: VIDIOC_QBUF failed on %s.>>>\n", dev_name_);
    429         return false;
    430       }
    431       break;
    432     default:
    433       printf("<<< Error: IO method should be defined.>>>\n");
    434       return false;
    435   }
    436   return true;
    437 }
    438 
    439 bool V4L2Device::AllocateBuffer(uint32_t buffer_count) {
    440   v4l2_buffers_ = new Buffer[buffer_count];
    441   if (!v4l2_buffers_) {
    442     printf("<<< Error: Out of memory.>>>\n");
    443     return false;
    444   }
    445   return true;
    446 }
    447 
    448 bool V4L2Device::FreeBuffer() {
    449   free(v4l2_buffers_);
    450   v4l2_buffers_ = NULL;
    451   return true;
    452 }
    453 
    454 bool V4L2Device::InitMmapIO() {
    455   v4l2_requestbuffers req;
    456   memset(&req, 0, sizeof(req));
    457   req.count = min_buffers_;
    458   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    459   req.memory = V4L2_MEMORY_MMAP;
    460   if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    461     if (EINVAL == errno)
    462       printf("<<< Error: mmap() io is not supported on %s.>>>\n", dev_name_);
    463     else
    464       printf("<<< Error: VIDIOC_REQBUFS for MMAP(%d) failed on %s: %s.>>>\n",
    465           min_buffers_, dev_name_, strerror(errno));
    466     return false;
    467   }
    468 
    469   if (req.count < min_buffers_) {
    470     printf("<<< Error: Insufficient buffer memory on %s >>>\n",
    471             dev_name_);  // TODO(jiesun) :add flexibilities.
    472     return false;
    473   }
    474 
    475   if (!AllocateBuffer(req.count))
    476     return false;
    477 
    478   for (num_buffers_ = 0; num_buffers_ < req.count; ++num_buffers_) {
    479     v4l2_buffer buf;
    480     memset(&buf, 0, sizeof(buf));
    481     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    482     buf.memory = V4L2_MEMORY_MMAP;
    483     buf.index = num_buffers_;
    484     if (-1 == DoIoctl(VIDIOC_QUERYBUF, &buf)) {
    485       printf("<<< Error: VIDIOC_QUERYBUF failed on %s.>>>\n", dev_name_);
    486       return false;
    487     }
    488     v4l2_buffers_[num_buffers_].length = buf.length;
    489     v4l2_buffers_[num_buffers_].start =
    490         mmap(NULL,  // Start anywhere.
    491              buf.length,
    492              PROT_READ | PROT_WRITE,
    493              MAP_SHARED,
    494              fd_, buf.m.offset);
    495     if (MAP_FAILED == v4l2_buffers_[num_buffers_].start) {
    496       printf("<<< Error: mmap() failed on %s.>>>\n", dev_name_);
    497       return false;
    498     }
    499   }
    500   return true;
    501 }
    502 
    503 bool V4L2Device::InitUserPtrIO(uint32_t buffer_size) {
    504   v4l2_requestbuffers req;
    505   memset(&req, 0, sizeof(req));
    506   req.count = min_buffers_;
    507   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    508   req.memory = V4L2_MEMORY_USERPTR;
    509 
    510   // Align up buffer_size to page size boundary.
    511   uint32_t page_size = getpagesize();
    512   buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
    513   if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    514     if (EINVAL == errno)
    515       printf("<<< Error: user pointer is not supported on %s.>>>\n", dev_name_);
    516     else
    517       printf("<<< Error: VIDIOC_REQBUFS for USERPTR(%d) failed on %s: %s.>>>\n",
    518           min_buffers_, dev_name_, strerror(errno));
    519     return false;
    520   }
    521 
    522   if (!AllocateBuffer(4))
    523     return false;
    524 
    525   for (num_buffers_ = 0; num_buffers_ < min_buffers_; ++num_buffers_) {
    526     v4l2_buffers_[num_buffers_].length = buffer_size;
    527     v4l2_buffers_[num_buffers_].start = memalign(page_size, buffer_size);
    528     if (!v4l2_buffers_[num_buffers_].start) {
    529       printf("<<< Error: Out of memory.>>>\n");
    530       return false;
    531     }
    532   }
    533   return true;
    534 }
    535 
    536 bool V4L2Device::EnumInput() {
    537   v4l2_input input;
    538   int32_t index;
    539   if (-1 == DoIoctl(VIDIOC_G_INPUT, &index)) {
    540     printf("<<< Info: VIDIOC_G_INPUT not supported.>>>\n");
    541     return false;
    542   }
    543 
    544   for (int32_t i = 0 ; ; ++i) {
    545     memset(&input, 0, sizeof(input));
    546     input.index = i;
    547     if (-1 == DoIoctl(VIDIOC_ENUMINPUT, &input)) {
    548       if (i == 0) {
    549         printf("<<< Info: VIDIOC_ENUMINPUT not supported.>>>\n");
    550         return false;
    551       } else {
    552         break;
    553       }
    554     }
    555     printf("Current input: %s %s\n", input.name, i == index ? "*" : "");
    556   }
    557   return true;
    558 }
    559 
    560 bool V4L2Device::EnumStandard() {
    561   v4l2_input input;
    562   v4l2_standard standard;
    563   memset(&input, 0, sizeof(input));
    564   if (-1 == DoIoctl(VIDIOC_G_INPUT, &input.index)) {
    565     printf("<<< Info: VIDIOC_G_INPUT not supported.>>>\n");
    566     return false;
    567   }
    568 
    569   if (-1 == DoIoctl(VIDIOC_ENUMINPUT, &input)) {
    570     printf("<<< Info: VIDIOC_ENUMINPUT not supported.>>>\n");
    571     return false;
    572   }
    573 
    574   printf("Current input %s supports:\n", input.name);
    575   memset(&standard, 0, sizeof(standard));
    576   standard.index = 0;
    577   while (0 == DoIoctl(VIDIOC_ENUMSTD, &standard)) {
    578     if (standard.id & input.std)
    579       printf("%s\n", standard.name);
    580     standard.index++;
    581   }
    582   // EINVAL indicates the end of the enumeration, which cannot be
    583   // empty unless this device falls under the USB exception.
    584   if (errno != EINVAL || standard.index == 0) {
    585     printf("<<< Info: VIDIOC_ENUMSTD not supported.>>>\n");
    586     return false;
    587   }
    588   return true;
    589 }
    590 
    591 bool V4L2Device::EnumControl(bool show_menu) {
    592   v4l2_queryctrl query_ctrl;
    593   memset(&query_ctrl, 0, sizeof(query_ctrl));
    594   // Query V4L2_CID_CAMERA_CLASS_BASE is for V4L2_CID_EXPOSURE_AUTO_PRIORITY.
    595   std::vector<std::pair<uint32_t, uint32_t>> query_ctrl_sets;
    596   query_ctrl_sets.push_back(std::make_pair(V4L2_CID_BASE, V4L2_CID_LASTP1));
    597   query_ctrl_sets.push_back(std::make_pair(V4L2_CID_CAMERA_CLASS_BASE,
    598                                            V4L2_CID_TILT_SPEED));
    599 
    600   for (int i = 0; i < query_ctrl_sets.size(); i++) {
    601     for (query_ctrl.id = query_ctrl_sets[i].first;
    602          query_ctrl.id < query_ctrl_sets[i].second;
    603          ++query_ctrl.id) {
    604       if (0 == DoIoctl(VIDIOC_QUERYCTRL, &query_ctrl)) {
    605         if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    606             printf("Control %s is disabled\n", query_ctrl.name);
    607         } else {
    608             printf("Control %s is enabled(%d-%d:%d)\n",
    609                    query_ctrl.name, query_ctrl.minimum,
    610                    query_ctrl.maximum, query_ctrl.default_value);
    611         }
    612         if (query_ctrl.type == V4L2_CTRL_TYPE_MENU && show_menu)
    613           EnumControlMenu(query_ctrl);
    614       } else if (errno != EINVAL) {
    615         printf("<<< Info: VIDIOC_query_ctrl not supported.>>>\n");
    616         return false;
    617       }
    618     }
    619   }
    620 
    621   for (query_ctrl.id = V4L2_CID_PRIVATE_BASE;; query_ctrl.id++) {
    622     if (0 == DoIoctl(VIDIOC_QUERYCTRL, &query_ctrl)) {
    623       if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
    624         printf("Private Control %s is disabled\n", query_ctrl.name);
    625       else
    626         printf("Private Control %s is enabled\n", query_ctrl.name);
    627       if (query_ctrl.type == V4L2_CTRL_TYPE_MENU && show_menu)
    628         EnumControlMenu(query_ctrl);
    629     } else {
    630       // Assume private control ids are contiguous.
    631       if (errno == EINVAL)
    632         break;
    633       printf("<<< Info: VIDIOC_query_ctrl not supported.>>>\n");
    634       return false;
    635     }
    636   }
    637   return true;
    638 }
    639 
    640 bool V4L2Device::EnumControlMenu(const v4l2_queryctrl& query_ctrl) {
    641   v4l2_querymenu query_menu;
    642   memset(&query_menu, 0, sizeof(query_menu));
    643   printf("\t\tMenu items:\n");
    644   query_menu.id = query_ctrl.id;
    645   for (query_menu.index = query_ctrl.minimum;
    646        query_menu.index <= query_ctrl.maximum;
    647        ++query_menu.index) {
    648     if (0 == DoIoctl(VIDIOC_QUERYMENU, &query_menu)) {
    649       printf("\t\t\t%s\n", query_menu.name);
    650     } else {
    651       printf("<<< Info: VIDIOC_QUERYMENU not supported.>>>\n");
    652       return false;
    653     }
    654   }
    655   return true;
    656 }
    657 
    658 bool V4L2Device::EnumFormat(uint32_t* num_formats, bool show_fmt) {
    659   uint32_t i;
    660   for (i = 0; ; ++i) {
    661     v4l2_fmtdesc format_desc;
    662     memset(&format_desc, 0, sizeof(format_desc));
    663     format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    664     format_desc.index = i;
    665     if (-1 == DoIoctl(VIDIOC_ENUM_FMT, &format_desc)) {
    666       if (i == 0) {
    667           printf("<<< Info: VIDIOC_ENUM_FMT not supported.>>>\n");
    668           return false;
    669       } else {
    670           break;
    671       }
    672     }
    673     if (show_fmt)
    674       printf("<<< Info supported format #%d: %s (%c%c%c%c) >>>\n",
    675              i+1, format_desc.description,
    676              (format_desc.pixelformat >> 0) & 0xff,
    677              (format_desc.pixelformat >> 8) & 0xff,
    678              (format_desc.pixelformat >> 16) & 0xff,
    679              (format_desc.pixelformat >> 24) & 0xff);
    680   }
    681 
    682   if (num_formats)
    683     *num_formats = i;
    684   return true;
    685 }
    686 
    687 bool V4L2Device::GetPixelFormat(uint32_t index, uint32_t* pixfmt) {
    688   v4l2_fmtdesc format_desc;
    689   memset(&format_desc, 0, sizeof(format_desc));
    690   format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    691   format_desc.index = index;
    692   if (-1 == DoIoctl(VIDIOC_ENUM_FMT, &format_desc))
    693     return false;
    694   if (pixfmt)
    695     *pixfmt = format_desc.pixelformat;
    696   return true;
    697 }
    698 
    699 bool V4L2Device::EnumFrameSize(
    700     uint32_t pixfmt, uint32_t* num_sizes, bool show_frmsize) {
    701   uint32_t i;
    702   for (i = 0; ; ++i) {
    703     v4l2_frmsizeenum frmsize_desc;
    704     memset(&frmsize_desc, 0, sizeof(frmsize_desc));
    705     frmsize_desc.pixel_format = pixfmt;
    706     frmsize_desc.index = i;
    707     if (-1 == DoIoctl(VIDIOC_ENUM_FRAMESIZES, &frmsize_desc)) {
    708       if (i == 0) {
    709         printf("<<< Info: VIDIOC_ENUM_FRAMESIZES not supported.>>>\n");
    710         return false;
    711       } else {
    712         break;
    713       }
    714     }
    715     if (show_frmsize) {
    716       switch (frmsize_desc.type) {
    717         case V4L2_FRMSIZE_TYPE_DISCRETE:
    718           printf("<<< Info supported discrete frame size #%d:"
    719                  " for pixel format(%c%c%c%c): %dx%d >>>\n", i+1,
    720                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    721                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    722                  frmsize_desc.discrete.width,
    723                  frmsize_desc.discrete.height);
    724           break;
    725         case V4L2_FRMSIZE_TYPE_CONTINUOUS:
    726           printf("<<< Info supported discrete frame size #%d:"
    727                  " for pixel format(%c%c%c%c): "
    728                  " from %dx%d to %dx%d >>>\n", i+1,
    729                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    730                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    731                  frmsize_desc.stepwise.min_width,
    732                  frmsize_desc.stepwise.min_height,
    733                  frmsize_desc.stepwise.max_width,
    734                  frmsize_desc.stepwise.max_height);
    735           break;
    736         case V4L2_FRMSIZE_TYPE_STEPWISE:
    737           printf("<<< Info supported discrete frame size #%d:"
    738                  " for pixel format(%c%c%c%c): "
    739                  " from %dx%d to %dx%d step(%d,%d) >>>\n", i+1,
    740                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    741                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    742                  frmsize_desc.stepwise.min_width,
    743                  frmsize_desc.stepwise.min_height,
    744                  frmsize_desc.stepwise.max_width,
    745                  frmsize_desc.stepwise.max_height,
    746                  frmsize_desc.stepwise.step_width,
    747                  frmsize_desc.stepwise.step_height);
    748           break;
    749       }
    750     }
    751   }
    752   if (num_sizes)
    753     *num_sizes = i;
    754   return true;
    755 }
    756 
    757 bool V4L2Device::GetFrameSize(
    758     uint32_t index, uint32_t pixfmt, uint32_t *width, uint32_t *height) {
    759   v4l2_frmsizeenum frmsize_desc;
    760   memset(&frmsize_desc, 0, sizeof(frmsize_desc));
    761   frmsize_desc.pixel_format = pixfmt;
    762   frmsize_desc.index = index;
    763   if (-1 == DoIoctl(VIDIOC_ENUM_FRAMESIZES, &frmsize_desc)) {
    764     printf("<<< Error: VIDIOC_ENUM_FRAMESIZES not supported.>>>\n");
    765     return false;
    766   }
    767   if (frmsize_desc.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
    768     printf("<<< Error: frame size type %d not supported.>>>\n",
    769            frmsize_desc.type);
    770     return false;
    771   }
    772 
    773   if (width && height) {
    774     *width = frmsize_desc.discrete.width;
    775     *height = frmsize_desc.discrete.height;
    776   }
    777   return true;
    778 }
    779 
    780 bool V4L2Device::EnumFrameInterval(
    781     uint32_t pixfmt, uint32_t width, uint32_t height, uint32_t* num_intervals,
    782     bool show_intervals) {
    783   uint32_t i;
    784   for (i = 0; ; ++i) {
    785     v4l2_frmivalenum frm_interval;
    786     memset(&frm_interval, 0, sizeof(frm_interval));
    787     frm_interval.pixel_format = pixfmt;
    788     frm_interval.width = width;
    789     frm_interval.height = height;
    790     frm_interval.index = i;
    791     if (-1 == DoIoctl(VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval)) {
    792       if (i == 0) {
    793         printf("<<< Error: VIDIOC_ENUM_FRAMEINTERVALS not supported.>>>\n");
    794         return false;
    795       } else {
    796         break;
    797       }
    798     }
    799     if (show_intervals) {
    800       switch(frm_interval.type) {
    801         case V4L2_FRMIVAL_TYPE_DISCRETE:
    802           printf("<<< Info supported discrete frame interval #%d:"
    803                  " for pixel format(%c%c%c%c): %dx%d: %d/%d >>>\n", i+1,
    804                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    805                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    806                  width, height, frm_interval.discrete.numerator,
    807                  frm_interval.discrete.denominator);
    808           break;
    809         case V4L2_FRMIVAL_TYPE_CONTINUOUS:
    810           printf("<<< Info supported continuous frame interval #%d:"
    811                  " for pixel format(%c%c%c%c): %dx%d:"
    812                  " from %d/%d to %d/%d >>>\n", i+1,
    813                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    814                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    815                  width, height,
    816                  frm_interval.stepwise.min.numerator,
    817                  frm_interval.stepwise.min.denominator,
    818                  frm_interval.stepwise.max.numerator,
    819                  frm_interval.stepwise.max.denominator);
    820           break;
    821         case V4L2_FRMIVAL_TYPE_STEPWISE:
    822           printf("<<< Info supported stepwise frame interval #%d:"
    823                  " for pixel format(%c%c%c%c): %dx%d:"
    824                  " from %d/%d to %d/%d step(%d,%d) >>>\n", i+1,
    825                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    826                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    827                  width, height,
    828                  frm_interval.stepwise.min.numerator,
    829                  frm_interval.stepwise.min.denominator,
    830                  frm_interval.stepwise.max.numerator,
    831                  frm_interval.stepwise.max.denominator,
    832                  frm_interval.stepwise.step.numerator,
    833                  frm_interval.stepwise.step.denominator);
    834           break;
    835         default:
    836           printf("<<< Error: unsupported frame interval type %d: for index %d"
    837                  " pixel format(%c%c%c%c): %dx%d >>>\n", frm_interval.type,
    838                  i+1, (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    839                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff, width, height);
    840           return false;
    841       }
    842     }
    843   }
    844   if (num_intervals)
    845     *num_intervals = i;
    846   return true;
    847 }
    848 
    849 bool V4L2Device::GetFrameInterval(
    850     uint32_t index, uint32_t pixfmt, uint32_t width, uint32_t height,
    851     float* frame_rate) {
    852   v4l2_frmivalenum frm_interval;
    853   memset(&frm_interval, 0, sizeof(frm_interval));
    854   frm_interval.pixel_format = pixfmt;
    855   frm_interval.width = width;
    856   frm_interval.height = height;
    857   frm_interval.index = index;
    858   if (-1 == DoIoctl(VIDIOC_ENUM_FRAMEINTERVALS, &frm_interval)) {
    859     printf("<<< Error: VIDIOC_ENUM_FRAMEINTERVALS not supported.>>>\n");
    860     return false;
    861   }
    862   if (frm_interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
    863     printf("<<< Error: frame interval type %d not supported.>>>\n",
    864            frm_interval.type);
    865     return false;
    866   }
    867 
    868   if (frame_rate) {
    869     *frame_rate = static_cast<float>(frm_interval.discrete.denominator) /
    870         frm_interval.discrete.numerator;
    871   }
    872   return true;
    873 }
    874 
    875 bool V4L2Device::QueryControl(uint32_t id, v4l2_queryctrl* ctrl) {
    876   memset(ctrl, 0, sizeof(*ctrl));
    877   ctrl->id = id;
    878   if (-1 == DoIoctl(VIDIOC_QUERYCTRL, ctrl)) {
    879     if (errno != EINVAL) return false;
    880     printf("%d is not supported\n", id);
    881     return false;
    882   }
    883   if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
    884     printf("%d is not supported\n", id);
    885     return false;
    886   }
    887   return true;
    888 }
    889 
    890 bool V4L2Device::SetControl(uint32_t id, int32_t value) {
    891   v4l2_control control;
    892   control.id = id;
    893   control.value = value;
    894   if (-1 == DoIoctl(VIDIOC_S_CTRL, &control)) {
    895     printf("<<< Error: VIDIOC_S_CTRL failed. %d>>>\n", errno);
    896     return false;
    897   }
    898   return true;
    899 }
    900 
    901 bool V4L2Device::GetCropCap(v4l2_cropcap* cropcap) {
    902   if (-1 == DoIoctl(VIDIOC_CROPCAP, cropcap)) {
    903     printf("<<< Warning: VIDIOC_CROPCAP not supported.>>>\n");
    904     return false;
    905   }
    906   return true;
    907 }
    908 
    909 bool V4L2Device::GetCrop(v4l2_crop* crop) {
    910   if (-1 == DoIoctl(VIDIOC_G_CROP, crop)) {
    911     printf("<<< Warning: VIDIOC_G_CROP not supported.>>>\n");
    912     return false;
    913   }
    914   printf("crop: %d, %d, %d, %d\n",
    915          crop->c.left, crop->c.top,
    916          crop->c.width, crop->c.height);
    917   return true;
    918 }
    919 
    920 bool V4L2Device::SetCrop(v4l2_crop* crop) {
    921   if (-1 == DoIoctl(VIDIOC_S_CROP, crop)) {
    922     printf("<<< Warning: VIDIOC_S_CROP not supported.>>>\n");
    923     return false;
    924   }
    925   return true;
    926 }
    927 
    928 bool V4L2Device::ProbeCaps(v4l2_capability* cap, bool show_caps) {
    929   if (-1 == DoIoctl(VIDIOC_QUERYCAP, cap)) {
    930     printf("<<< Error: VIDIOC_QUERYCAP on %s.>>>\n", dev_name_);
    931     return false;
    932   }
    933 
    934   if (show_caps) {
    935     if (cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)
    936       printf("<<< Info: %s support video capture interface.>>>\n", dev_name_);
    937     if (cap->capabilities & V4L2_CAP_VIDEO_OUTPUT)
    938       printf("<<< Info: %s support video output interface.>>>\n", dev_name_);
    939     if (cap->capabilities & V4L2_CAP_VIDEO_OVERLAY)
    940       printf("<<< Info: %s support video overlay interface.>>>\n", dev_name_);
    941     if (cap->capabilities & V4L2_CAP_AUDIO)
    942       printf("<<< Info: %s support audio i/o interface.>>>\n", dev_name_);
    943 
    944     if (cap->capabilities & V4L2_CAP_STREAMING)
    945       printf("<<< Info: %s support streaming i/o interface.>>>\n", dev_name_);
    946   }
    947 
    948   return true;
    949 }
    950 
    951 uint32_t V4L2Device::MapFourCC(const char* fourcc) {
    952   return v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
    953 }
    954 
    955 bool V4L2Device::GetParam(v4l2_streamparm* param) {
    956   param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    957   if (-1 == DoIoctl(VIDIOC_G_PARM, param)) {
    958     printf("<<< Warning: VIDIOC_G_PARM not supported.>>>\n");
    959     return false;
    960   }
    961 
    962   return true;
    963 }
    964 
    965 bool V4L2Device::SetParam(v4l2_streamparm* param) {
    966   if (-1 == DoIoctl(VIDIOC_S_PARM, param)) {
    967     printf("<<< Warning: VIDIOC_S_PARM not supported.>>>\n");
    968     return false;
    969   }
    970   return true;
    971 }
    972 
    973 bool V4L2Device::SetFrameRate(float fps) {
    974   v4l2_streamparm param;
    975   if (!GetParam(&param))
    976     return false;
    977 
    978   const int kFrameRatePrecision = 10000;
    979   param.parm.capture.timeperframe.numerator = kFrameRatePrecision;
    980   param.parm.capture.timeperframe.denominator = fps * kFrameRatePrecision;
    981   return SetParam(&param);
    982 }
    983 
    984 float V4L2Device::GetFrameRate() {
    985   v4l2_streamparm param;
    986   if (!GetParam(&param))
    987     return -1;
    988   return static_cast<float>(param.parm.capture.timeperframe.denominator) /
    989       param.parm.capture.timeperframe.numerator;
    990 }
    991 
    992 bool V4L2Device::GetV4L2Format(v4l2_format* format) {
    993   memset(format, 0, sizeof(v4l2_format));
    994   format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    995 
    996   if (-1 == DoIoctl(VIDIOC_G_FMT, format)) {
    997     printf("<<< Error: VIDIOC_G_FMT on %s.>>>\n", dev_name_);
    998     return false;
    999   }
   1000   return true;
   1001 }
   1002 
   1003 uint64_t V4L2Device::Now() {
   1004   struct timespec ts;
   1005   int res = clock_gettime(CLOCK_MONOTONIC, &ts);
   1006   CHECK(res == 0);
   1007   return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
   1008 }
   1009