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 #define CHECK(a) assert(a)
     12 #define MAJOR(dev) (((uint32_t)(dev)) >> 8)
     13 #define MINOR(dev) (((uint32_t)(dev)) & 0xff)
     14 #define V4L2_VIDEO_CAPTURE_MAJOR      81
     15 #define V4L2_VIDEO_CAPTURE_MINOR_MIN  0
     16 #define V4L2_VIDEO_CAPTURE_MINOR_MAX  64
     17 
     18 V4L2Device::V4L2Device(const char* dev_name,
     19                        IOMethod io,
     20                        uint32_t buffers)
     21     : dev_name_(dev_name),
     22       io_(io),
     23       fd_(-1),
     24       v4l2_buffers_(NULL),
     25       num_buffers_(0),
     26       min_buffers_(buffers),
     27       stopped_(false) {
     28 }
     29 
     30 bool V4L2Device::OpenDevice() {
     31   struct stat st;
     32   if (-1 == stat(dev_name_, &st)) {
     33     printf("<<< Error: could not find v4l2 device %s: (%d) %s.>>>\n",
     34            dev_name_, errno, strerror(errno));
     35     return false;
     36   }
     37 
     38   if (!S_ISCHR(st.st_mode)) {
     39     printf("<<< Error: specified v4l2 device %s is not char device.>>>\n",
     40            dev_name_);
     41     return false;
     42   }
     43 
     44   if (MAJOR(st.st_rdev) != V4L2_VIDEO_CAPTURE_MAJOR
     45       || MINOR(st.st_rdev) >= V4L2_VIDEO_CAPTURE_MINOR_MAX) {
     46     printf("<<< Error: specified v4l2 device %s is not v4l2 device.>>>\n",
     47            dev_name_);
     48     return false;
     49   }
     50 
     51   fd_ = open(dev_name_, O_RDWR | O_NONBLOCK, 0);
     52   if (-1 == fd_) {
     53     printf("<<< Error: specified v4l2 device %s could not be opened.>>>\n",
     54            dev_name_);
     55     return false;
     56   }
     57 
     58   v4l2_capability cap;
     59   if (!ProbeCaps(&cap))
     60     return false;
     61 
     62   if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
     63     printf("<<< Error: %s does not support video capture.>>>\n", dev_name_);
     64     return false;
     65   }
     66 
     67   switch (io_) {
     68     case IO_METHOD_READ:
     69       if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
     70         printf("<<< Error: %s does not support read i/o.>>>\n", dev_name_);
     71         return false;
     72       }
     73       break;
     74     case IO_METHOD_MMAP:
     75     case IO_METHOD_USERPTR:
     76       if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
     77         printf("<<< Error: %s does not support streaming.>>>\n", dev_name_);
     78         return false;
     79       }
     80       break;
     81   }
     82 
     83   return true;
     84 }
     85 
     86 void V4L2Device::CloseDevice() {
     87   if (fd_ != -1)
     88     close(fd_);
     89   fd_ = -1;
     90 }
     91 
     92 bool V4L2Device::InitDevice(uint32_t width,
     93                             uint32_t height,
     94                             uint32_t pixfmt,
     95                             uint32_t fps) {
     96   // Crop/Format setting could live across session.
     97   // We should always initialized them when supported.
     98   v4l2_cropcap cropcap;
     99   memset(&cropcap, 0, sizeof(cropcap));
    100   if (GetCropCap(&cropcap)) {
    101     v4l2_crop crop;
    102     memset(&crop, 0, sizeof(crop));
    103     // Use default capture rectangle.
    104     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    105     crop.c = cropcap.defrect;
    106     SetCrop(&crop);
    107   }
    108 
    109   v4l2_format fmt;
    110   memset(&fmt, 0, sizeof(fmt));
    111   fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    112 
    113   if (-1 == DoIoctl(VIDIOC_G_FMT, &fmt)) {
    114     printf("<<< Error: VIDIOC_G_FMT on %s.>>>\n", dev_name_);
    115     return false;
    116   }
    117 
    118   fmt.fmt.pix.width = width;
    119   fmt.fmt.pix.height = height;
    120   fmt.fmt.pix.pixelformat = pixfmt;
    121   fmt.fmt.pix.field = V4L2_FIELD_NONE;
    122 
    123   if (-1 == DoIoctl(VIDIOC_S_FMT, &fmt)) {
    124     printf("<<< Error: VIDIOC_S_FMT on %s.>>>\n", dev_name_);
    125     return false;
    126   }
    127 
    128   v4l2_capability cap;
    129   if (!ProbeCaps(&cap))
    130     return false;
    131 
    132   if (cap.capabilities & V4L2_CAP_TIMEPERFRAME) {
    133     if (fps > 0)
    134       SetFrameRate(fps);
    135     fps = GetFrameRate();
    136   } else {
    137     // TODO(jiesun): probably we should derive this from VIDIOC_G_STD
    138     fps = 30;
    139   }
    140 
    141   printf("actual format for capture %dx%d %c%c%c%c picture at %d fps\n",
    142          fmt.fmt.pix.width, fmt.fmt.pix.height,
    143          (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    144          (pixfmt >> 16) & 0xff, (pixfmt >> 24 ) & 0xff, fps);
    145   width_ = fmt.fmt.pix.width;
    146   height_ = fmt.fmt.pix.height;
    147   pixfmt_ = fmt;
    148 
    149   switch (io_) {
    150     case IO_METHOD_READ:
    151       return InitReadIO(fmt.fmt.pix.sizeimage);
    152     case IO_METHOD_MMAP:
    153       return InitMmapIO();
    154     case IO_METHOD_USERPTR:
    155       return InitUserPtrIO(fmt.fmt.pix.sizeimage);
    156   }
    157   return false;
    158 }
    159 
    160 bool V4L2Device::UninitDevice() {
    161   switch (io_) {
    162     case IO_METHOD_READ:
    163       // Only one buffer for read() i/o.
    164       free(v4l2_buffers_[0].start);
    165       break;
    166     case IO_METHOD_MMAP:
    167       for (uint32_t i = 0; i < num_buffers_; ++i)
    168         if (-1 == munmap(v4l2_buffers_[i].start, v4l2_buffers_[i].length)) {
    169           printf("<<< Error: munmap() on %s failed.>>>\n", dev_name_);
    170           return false;
    171         }
    172       break;
    173     case IO_METHOD_USERPTR:
    174       for (uint32_t i = 0; i < num_buffers_; ++i)
    175         free(v4l2_buffers_[i].start);
    176       break;
    177   }
    178   FreeBuffer();
    179   return true;
    180 }
    181 
    182 bool V4L2Device::StartCapture() {
    183   v4l2_buffer buf;
    184   uint32_t i;
    185   v4l2_buf_type type;
    186   switch (io_) {
    187     case IO_METHOD_READ:
    188       // Nothing to do.
    189       break;
    190     case IO_METHOD_MMAP:
    191       for (i = 0; i < num_buffers_; ++i) {
    192         memset(&buf, 0, sizeof(buf));
    193         buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    194         buf.memory = V4L2_MEMORY_MMAP;
    195         buf.index  = i;
    196         if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    197           printf("<<< Error: VIDIOC_QBUF on %s.>>>\n", dev_name_);
    198           return false;
    199         }
    200       }
    201       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    202       if (-1 == DoIoctl(VIDIOC_STREAMON, &type)) {
    203         printf("<<< Error: VIDIOC_STREAMON on %s.>>>\n", dev_name_);
    204         return false;
    205       }
    206       break;
    207     case IO_METHOD_USERPTR:
    208       for (i = 0; i < num_buffers_; ++i) {
    209         memset(&buf, 0, sizeof(buf));
    210         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    211         buf.memory = V4L2_MEMORY_USERPTR;
    212         buf.index = i;
    213         buf.m.userptr = (unsigned long) v4l2_buffers_[i].start;
    214         buf.length = v4l2_buffers_[i].length;
    215         if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    216           printf("<<< Error: VIDIOC_QBUF on %s.>>>\n", dev_name_);
    217           return false;
    218         }
    219       }
    220       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    221       if (-1 == DoIoctl(VIDIOC_STREAMON, &type)) {
    222         printf("<<< Error: VIDIOC_STREAMON on %s.>>>\n", dev_name_);
    223         return false;
    224       }
    225       break;
    226   }
    227   return true;
    228 }
    229 
    230 bool V4L2Device::StopCapture() {
    231   v4l2_buf_type type;
    232   switch (io_) {
    233     case IO_METHOD_READ:
    234       // Nothing to do.
    235       break;
    236     case IO_METHOD_MMAP:
    237     case IO_METHOD_USERPTR:
    238       type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    239       if (-1 == DoIoctl(VIDIOC_STREAMOFF, &type)) {
    240         printf("<<< Error: VIDIOC_STREAMOFF on %s.>>>\n", dev_name_);
    241         return false;
    242       }
    243       break;
    244   }
    245   return true;
    246 }
    247 
    248 void V4L2Device::ProcessImage(const void* p) {
    249   printf(".");
    250   fflush(stdout);
    251 }
    252 
    253 // Do capture for number of |frames| ( when time_in_sec == 0 )
    254 // or for duration of |time_in_sec|  ( when time_in_sec > 0 ).
    255 bool V4L2Device::Run(uint32_t frames, uint32_t time_in_sec) {
    256   stopped_ = false;
    257   if (time_in_sec) // duration setting override the frames setting.
    258     frames = 30 * time_in_sec; // Assume maximum fps is 30.
    259 
    260   uint64_t start_in_sec = Now();
    261   int32_t timeout = 5;  // Used 5 seconds for initial delay.
    262   while (!stopped_ && frames > 0) {
    263     fd_set fds;
    264     FD_ZERO(&fds);
    265     FD_SET(fd_, &fds);
    266     timeval tv;
    267     tv.tv_sec = timeout;
    268     tv.tv_usec = 0;
    269     timeout = 2;  // Normal timeout will be 2 seconds.
    270     int32_t r = select(fd_ + 1, &fds, NULL, NULL, &tv);
    271     if (-1 == r) {
    272       if (EINTR == errno)  // If interrupted, continue.
    273         continue;
    274       printf("<<< Error: select() failed on %s.>>>\n", dev_name_);
    275       return false;
    276     }
    277     if (0 == r) {
    278       printf("<<< Error: select() timeout on %s.>>>\n", dev_name_);
    279       return false;
    280     }
    281     r = ReadOneFrame();
    282     if (r < 0)
    283       return false;
    284     if (r)
    285       frames--;
    286     if (time_in_sec) {
    287       uint64_t end_in_sec = Now();
    288       if ( end_in_sec - start_in_sec >= time_in_sec )
    289         return true;
    290     }
    291   }
    292   return true;
    293 }
    294 
    295 bool V4L2Device::Stop() {
    296   stopped_ = true;
    297 }
    298 
    299 int32_t V4L2Device::DoIoctl(int32_t request, void* arg) {
    300   int32_t r;
    301   do {
    302     r = ioctl(fd_, request, arg);
    303   } while (-1 == r && EINTR == errno);
    304   return r;
    305 }
    306 
    307 // return 1 : successful to retrieve a frame from device
    308 // return 0 : EAGAIN
    309 // negative : error
    310 int32_t V4L2Device::ReadOneFrame() {
    311   v4l2_buffer buf;
    312   memset(&buf, 0, sizeof(buf));
    313   uint32_t i;
    314   switch (io_) {
    315     case IO_METHOD_READ:
    316       if (-1 == read(fd_, v4l2_buffers_[0].start, v4l2_buffers_[0].length)) {
    317         switch (errno) {
    318           case EAGAIN:
    319             return 0;
    320           case EIO:
    321             // Could ignore EIO, see spec.
    322             // Fall through.
    323           default:
    324             printf("<<< Error: read() failed on %s.>>>\n", dev_name_);
    325             return -1;
    326         }
    327       }
    328       ProcessImage(v4l2_buffers_[0].start);
    329       break;
    330     case IO_METHOD_MMAP:
    331       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    332       buf.memory = V4L2_MEMORY_MMAP;
    333       if (-1 == DoIoctl(VIDIOC_DQBUF, &buf)) {
    334         switch (errno) {
    335           case EAGAIN:
    336             return 0;
    337           case EIO:
    338             // Could ignore EIO, see spec.
    339             // Fall through.
    340           default:
    341             printf("<<< Error: VIDIOC_DQBUF failed on %s.>>>\n", dev_name_);
    342             return -2;
    343         }
    344       }
    345       CHECK(buf.index < num_buffers_);
    346       // TODO: uvcvideo driver ignores this field. This is negligible,
    347       // so disabling this for now until we get a fix into the upstream driver.
    348       // CHECK(buf.field == V4L2_FIELD_NONE);  // progressive only.
    349       ProcessImage(v4l2_buffers_[buf.index].start);
    350       if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    351         printf("<<< Error: VIDIOC_QBUF failed on %s.>>>\n", dev_name_);
    352         return -3;
    353       }
    354       break;
    355     case IO_METHOD_USERPTR:
    356       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    357       buf.memory = V4L2_MEMORY_USERPTR;
    358       if (-1 == DoIoctl(VIDIOC_DQBUF, &buf)) {
    359         switch (errno) {
    360           case EAGAIN:
    361             return 0;
    362           case EIO:
    363             // Could ignore EIO, see spec.
    364             // Fall through.
    365           default:
    366             printf("<<< Error: VIDIOC_DQBUF failed on %s.>>>\n", dev_name_);
    367             return -2;
    368         }
    369       }
    370       for (i = 0; i < num_buffers_; ++i) {
    371         if (buf.m.userptr == (unsigned long) v4l2_buffers_[i].start
    372             && buf.length == v4l2_buffers_[i].length)
    373           break;
    374       }
    375       CHECK(i < num_buffers_);
    376       ProcessImage(reinterpret_cast<void*>(buf.m.userptr));
    377       if (-1 == DoIoctl(VIDIOC_QBUF, &buf)) {
    378         printf("<<< Error: VIDIOC_QBUF failed on %s.>>>\n", dev_name_);
    379         return -3;
    380       }
    381       break;
    382   }
    383   return 1;
    384 }
    385 
    386 bool V4L2Device::AllocateBuffer(uint32_t buffer_count) {
    387   v4l2_buffers_ = new Buffer[buffer_count];
    388   if (!v4l2_buffers_) {
    389     printf("<<< Error: Out of memory.>>>\n");
    390     return false;
    391   }
    392   return true;
    393 }
    394 
    395 bool V4L2Device::FreeBuffer() {
    396   free(v4l2_buffers_);
    397   v4l2_buffers_ = NULL;
    398   return true;
    399 }
    400 
    401 bool V4L2Device::InitReadIO(uint32_t buffer_size) {
    402   if (!AllocateBuffer(1))
    403     return false;
    404   v4l2_buffers_[0].length = buffer_size;
    405   v4l2_buffers_[0].start = new uint8_t[buffer_size];
    406   if (!v4l2_buffers_[0].start) {
    407     printf("<<< Error: Out of memory.>>>\n");
    408     return false;
    409   }
    410   return true;
    411 }
    412 
    413 bool V4L2Device::InitMmapIO() {
    414   v4l2_requestbuffers req;
    415   memset(&req, 0, sizeof(req));
    416   req.count = min_buffers_;
    417   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    418   req.memory = V4L2_MEMORY_MMAP;
    419   if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    420     if (EINVAL == errno)
    421       printf("<<< Error: mmap() io is not supported on %s.>>>\n", dev_name_);
    422     else
    423       printf("<<< Error: VIDIOC_REQBUFS failed on %s.>>>\n", dev_name_);
    424     return false;
    425   }
    426 
    427   if (req.count < min_buffers_) {
    428     printf("<<< Error: Insufficient buffer memory on %s >>>\n",
    429             dev_name_);  // TODO(jiesun) :add flexibilities.
    430     return false;
    431   }
    432 
    433   if (!AllocateBuffer(req.count))
    434     return false;
    435 
    436   for (num_buffers_ = 0; num_buffers_ < req.count; ++num_buffers_) {
    437     v4l2_buffer buf;
    438     memset(&buf, 0, sizeof(buf));
    439     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    440     buf.memory = V4L2_MEMORY_MMAP;
    441     buf.index = num_buffers_;
    442     if (-1 == DoIoctl(VIDIOC_QUERYBUF, &buf)) {
    443       printf("<<< Error: VIDIOC_QUERYBUF failed on %s.>>>\n", dev_name_);
    444       return false;
    445     }
    446     v4l2_buffers_[num_buffers_].length = buf.length;
    447     v4l2_buffers_[num_buffers_].start =
    448         mmap(NULL,  // Start anywhere.
    449              buf.length,
    450              PROT_READ | PROT_WRITE,
    451              MAP_SHARED,
    452              fd_, buf.m.offset);
    453     if (MAP_FAILED == v4l2_buffers_[num_buffers_].start) {
    454       printf("<<< Error: mmap() failed on %s.>>>\n", dev_name_);
    455       return false;
    456     }
    457   }
    458   return true;
    459 }
    460 
    461 bool V4L2Device::InitUserPtrIO(uint32_t buffer_size) {
    462   v4l2_requestbuffers req;
    463   memset(&req, 0, sizeof(req));
    464   req.count = min_buffers_;
    465   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    466   req.memory = V4L2_MEMORY_USERPTR;
    467 
    468   // Align up buffer_size to page size boundary.
    469   uint32_t page_size = getpagesize();
    470   buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
    471   if (-1 == DoIoctl(VIDIOC_REQBUFS, &req)) {
    472     if (EINVAL == errno)
    473       printf("<<< Error: user pointer is not supported on %s.>>>\n", dev_name_);
    474     else
    475       printf("<<< Error: VIDIOC_REQBUFS failed on %s.>>>\n", dev_name_);
    476     return false;
    477   }
    478 
    479   if (!AllocateBuffer(4))
    480     return false;
    481 
    482   for (num_buffers_ = 0; num_buffers_ < min_buffers_; ++num_buffers_) {
    483     v4l2_buffers_[num_buffers_].length = buffer_size;
    484     v4l2_buffers_[num_buffers_].start = memalign(page_size, buffer_size);
    485     if (!v4l2_buffers_[num_buffers_].start) {
    486       printf("<<< Error: Out of memory.>>>\n");
    487       return false;
    488     }
    489   }
    490   return true;
    491 }
    492 
    493 bool V4L2Device::EnumInput() {
    494   v4l2_input input;
    495   int32_t index;
    496   if (-1 == DoIoctl(VIDIOC_G_INPUT, &index)) {
    497     printf("<<< Info: VIDIOC_G_INPUT not supported.>>>\n");
    498     return false;
    499   }
    500 
    501   for (int32_t i = 0 ; ; ++i) {
    502     memset(&input, 0, sizeof(input));
    503     input.index = i;
    504     if (-1 == DoIoctl(VIDIOC_ENUMINPUT, &input)) {
    505       if (i == 0) {
    506         printf("<<< Info: VIDIOC_ENUMINPUT not supported.>>>\n");
    507         return false;
    508       } else {
    509         break;
    510       }
    511     }
    512     printf("Current input: %s %s\n", input.name, i == index ? "*" : "");
    513   }
    514   return true;
    515 }
    516 
    517 bool V4L2Device::EnumStandard() {
    518   v4l2_input input;
    519   v4l2_standard standard;
    520   memset(&input, 0, sizeof(input));
    521   if (-1 == DoIoctl(VIDIOC_G_INPUT, &input.index)) {
    522     printf("<<< Info: VIDIOC_G_INPUT not supported.>>>\n");
    523     return false;
    524   }
    525 
    526   if (-1 == DoIoctl(VIDIOC_ENUMINPUT, &input)) {
    527     printf("<<< Info: VIDIOC_ENUMINPUT not supported.>>>\n");
    528     return false;
    529   }
    530 
    531   printf("Current input %s supports:\n", input.name);
    532   memset(&standard, 0, sizeof(standard));
    533   standard.index = 0;
    534   while (0 == DoIoctl(VIDIOC_ENUMSTD, &standard)) {
    535     if (standard.id & input.std)
    536       printf("%s\n", standard.name);
    537     standard.index++;
    538   }
    539   // EINVAL indicates the end of the enumeration, which cannot be
    540   // empty unless this device falls under the USB exception.
    541   if (errno != EINVAL || standard.index == 0) {
    542     printf("<<< Info: VIDIOC_ENUMSTD not supported.>>>\n");
    543     return false;
    544   }
    545   return true;
    546 }
    547 
    548 bool V4L2Device::EnumControl(bool show_menu) {
    549   v4l2_queryctrl query_ctrl;
    550   memset(&query_ctrl, 0, sizeof(query_ctrl));
    551   for (query_ctrl.id = V4L2_CID_BASE;
    552        query_ctrl.id < V4L2_CID_LASTP1;
    553        ++query_ctrl.id) {
    554     if (0 == DoIoctl(VIDIOC_QUERYCTRL, &query_ctrl)) {
    555       if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
    556           printf("Control %s is disabled\n", query_ctrl.name);
    557       } else {
    558           printf("Control %s is enabled(%d-%d:%d)\n",
    559                  query_ctrl.name, query_ctrl.minimum,
    560                  query_ctrl.maximum, query_ctrl.default_value);
    561       }
    562       if (query_ctrl.type == V4L2_CTRL_TYPE_MENU && show_menu)
    563         EnumControlMenu(query_ctrl);
    564     } else if (errno != EINVAL) {
    565       printf("<<< Info: VIDIOC_query_ctrl not supported.>>>\n");
    566       return false;
    567     }
    568   }
    569 
    570   for (query_ctrl.id = V4L2_CID_PRIVATE_BASE;; query_ctrl.id++) {
    571     if (0 == DoIoctl(VIDIOC_QUERYCTRL, &query_ctrl)) {
    572       if (query_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)
    573         printf("Private Control %s is disabled\n", query_ctrl.name);
    574       else
    575         printf("Private Control %s is enabled\n", query_ctrl.name);
    576       if (query_ctrl.type == V4L2_CTRL_TYPE_MENU && show_menu)
    577         EnumControlMenu(query_ctrl);
    578     } else {
    579       // Assume private control ids are contiguous.
    580       if (errno == EINVAL)
    581         break;
    582       printf("<<< Info: VIDIOC_query_ctrl not supported.>>>\n");
    583       return false;
    584     }
    585   }
    586   return true;
    587 }
    588 
    589 bool V4L2Device::EnumControlMenu(const v4l2_queryctrl& query_ctrl) {
    590   v4l2_querymenu query_menu;
    591   memset(&query_menu, 0, sizeof(query_menu));
    592   printf("\t\tMenu items:\n");
    593   query_menu.id = query_ctrl.id;
    594   for (query_menu.index = query_ctrl.minimum;
    595        query_menu.index <= query_ctrl.maximum;
    596        ++query_menu.index) {
    597     if (0 == DoIoctl(VIDIOC_QUERYMENU, &query_menu)) {
    598       printf("\t\t\t%s\n", query_menu.name);
    599     } else {
    600       printf("<<< Info: VIDIOC_QUERYMENU not supported.>>>\n");
    601       return false;
    602     }
    603   }
    604   return true;
    605 }
    606 
    607 bool V4L2Device::EnumFormat(uint32_t* num_formats, bool show_fmt) {
    608   uint32_t i;
    609   for (i = 0; ; ++i) {
    610     v4l2_fmtdesc format_desc;
    611     memset(&format_desc, 0, sizeof(format_desc));
    612     format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    613     format_desc.index = i;
    614     if (-1 == DoIoctl(VIDIOC_ENUM_FMT, &format_desc)) {
    615       if (i == 0) {
    616           printf("<<< Info: VIDIOC_ENUM_FMT not supported.>>>\n");
    617           return false;
    618       } else {
    619           break;
    620       }
    621     }
    622     if (show_fmt)
    623       printf("<<< Info supported format #%d: %s (%c%c%c%c) >>>\n",
    624              i+1, format_desc.description,
    625              (format_desc.pixelformat >> 0) & 0xff,
    626              (format_desc.pixelformat >> 8) & 0xff,
    627              (format_desc.pixelformat >> 16) & 0xff,
    628              (format_desc.pixelformat >> 24) & 0xff);
    629   }
    630 
    631   if (num_formats)
    632     *num_formats = i;
    633   return true;
    634 }
    635 
    636 uint32_t V4L2Device::GetPixelFormat(uint32_t index) {
    637   v4l2_fmtdesc format_desc;
    638   memset(&format_desc, 0, sizeof(format_desc));
    639   format_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    640   format_desc.index = index;
    641   if (-1 == DoIoctl(VIDIOC_ENUM_FMT, &format_desc))
    642     return 0xFFFFFFFF;
    643   return format_desc.pixelformat;
    644 }
    645 
    646 bool V4L2Device::EnumFrameSize(uint32_t pixfmt, bool show_frmsize) {
    647   for (uint32_t i = 0; ; ++i) {
    648     v4l2_frmsizeenum frmsize_desc;
    649     memset(&frmsize_desc, 0, sizeof(frmsize_desc));
    650     frmsize_desc.pixel_format = pixfmt;
    651     frmsize_desc.index = i;
    652     if (-1 == DoIoctl(VIDIOC_ENUM_FRAMESIZES, &frmsize_desc)) {
    653       if (i == 0) {
    654         printf("<<< Info: VIDIOC_ENUM_FRAMESIZES not supported.>>>\n");
    655         return false;
    656       } else {
    657         break;
    658       }
    659     }
    660     if (show_frmsize) {
    661       switch (frmsize_desc.type) {
    662         case V4L2_FRMSIZE_TYPE_DISCRETE:
    663           printf("<<< Info supported discrete frame size #%d:"
    664                  " for pixel foramt(%c%c%c%c): %dx%d >>>\n", i+1,
    665                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    666                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    667                  frmsize_desc.discrete.width,
    668                  frmsize_desc.discrete.height);
    669           break;
    670         case V4L2_FRMSIZE_TYPE_CONTINUOUS:
    671           printf("<<< Info supported discrete frame size #%d:"
    672                  " for pixel foramt(%c%c%c%c): "
    673                  " from %dx%d to %dx%d >>>\n", i+1,
    674                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    675                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    676                  frmsize_desc.stepwise.min_width,
    677                  frmsize_desc.stepwise.min_height,
    678                  frmsize_desc.stepwise.max_width,
    679                  frmsize_desc.stepwise.max_height);
    680           break;
    681         case V4L2_FRMSIZE_TYPE_STEPWISE:
    682           printf("<<< Info supported discrete frame size #%d:"
    683                  " for pixel foramt(%c%c%c%c): "
    684                  " from %dx%d to %dx%d step(%d,%d) >>>\n", i+1,
    685                  (pixfmt >> 0) & 0xff, (pixfmt >> 8) & 0xff,
    686                  (pixfmt >> 16) & 0xff, (pixfmt >> 24) & 0xff,
    687                  frmsize_desc.stepwise.min_width,
    688                  frmsize_desc.stepwise.min_height,
    689                  frmsize_desc.stepwise.max_width,
    690                  frmsize_desc.stepwise.max_height,
    691                  frmsize_desc.stepwise.step_width,
    692                  frmsize_desc.stepwise.step_height);
    693           break;
    694       }
    695     }
    696   }
    697   return true;
    698 }
    699 
    700 bool V4L2Device::QueryControl(uint32_t id, v4l2_queryctrl* ctrl) {
    701   memset(ctrl, 0, sizeof(*ctrl));
    702   ctrl->id = id;
    703   if (-1 == DoIoctl(VIDIOC_QUERYCTRL, ctrl)) {
    704     if (errno != EINVAL) return false;
    705     printf("%d is not supported\n", id);
    706     return false;
    707   }
    708   if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
    709     printf("%d is not supported\n", id);
    710     return false;
    711   }
    712   return true;
    713 }
    714 
    715 bool V4L2Device::SetControl(uint32_t id, int32_t value) {
    716   v4l2_control control;
    717   control.id = id;
    718   control.value = value;
    719   if (-1 == DoIoctl(VIDIOC_S_CTRL, &control)) {
    720     printf("<<< Info: VIDIOC_S_CTRL failed. %d>>>\n", errno);
    721     return false;
    722   }
    723   return true;
    724 }
    725 
    726 bool V4L2Device::GetCropCap(v4l2_cropcap* cropcap) {
    727   if (-1 == DoIoctl(VIDIOC_CROPCAP, cropcap)) {
    728     printf("<<< Warning: VIDIOC_CROPCAP not supported.>>>\n");
    729     return false;
    730   }
    731   return true;
    732 }
    733 
    734 bool V4L2Device::GetCrop(v4l2_crop* crop) {
    735   if (-1 == DoIoctl(VIDIOC_G_CROP, crop)) {
    736     printf("<<< Warning: VIDIOC_G_CROP not supported.>>>\n");
    737     return false;
    738   }
    739   printf("crop: %d, %d, %d, %d\n",
    740          crop->c.left, crop->c.top,
    741          crop->c.width, crop->c.height);
    742   return true;
    743 }
    744 
    745 bool V4L2Device::SetCrop(v4l2_crop* crop) {
    746   if (-1 == DoIoctl(VIDIOC_S_CROP, crop)) {
    747     printf("<<< Warning: VIDIOC_S_CROP not supported.>>>\n");
    748     return false;
    749   }
    750   return true;
    751 }
    752 
    753 bool V4L2Device::ProbeCaps(v4l2_capability* cap, bool show_caps) {
    754   if (-1 == DoIoctl(VIDIOC_QUERYCAP, cap)) {
    755     printf("<<< Error: VIDIOC_QUERYCAP on %s.>>>\n", dev_name_);
    756     return false;
    757   }
    758 
    759   if (show_caps) {
    760     if (cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)
    761       printf("<<< Info: %s support video capture interface.>>>\n", dev_name_);
    762     if (cap->capabilities & V4L2_CAP_VIDEO_OUTPUT)
    763       printf("<<< Info: %s support video output interface.>>>\n", dev_name_);
    764     if (cap->capabilities & V4L2_CAP_VIDEO_OVERLAY)
    765       printf("<<< Info: %s support video overlay interface.>>>\n", dev_name_);
    766     if (cap->capabilities & V4L2_CAP_AUDIO)
    767       printf("<<< Info: %s support audio i/o interface.>>>\n", dev_name_);
    768 
    769     if (cap->capabilities & V4L2_CAP_READWRITE)
    770       printf("<<< Info: %s support read/write interface.>>>\n", dev_name_);
    771     if (cap->capabilities & V4L2_CAP_STREAMING)
    772       printf("<<< Info: %s support streaming i/o interface.>>>\n", dev_name_);
    773     if (cap->capabilities & V4L2_CAP_TIMEPERFRAME)
    774       printf("<<< Info: %s support flexible frame period.>>>\n", dev_name_);
    775   }
    776 
    777   return true;
    778 }
    779 
    780 uint32_t V4L2Device::MapFourCC(const char* fourcc) {
    781   return v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
    782 }
    783 
    784 bool V4L2Device::GetParam(v4l2_streamparm* param) {
    785   param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    786   if (-1 == DoIoctl(VIDIOC_G_PARM, param)) {
    787     printf("<<< Warning: VIDIOC_G_PARM not supported.>>>\n");
    788     return false;
    789   }
    790 
    791   return true;
    792 }
    793 
    794 bool V4L2Device::SetParam(v4l2_streamparm* param) {
    795   if (-1 == DoIoctl(VIDIOC_S_PARM, param)) {
    796     printf("<<< Warning: VIDIOC_S_PARM not supported.>>>\n");
    797     return false;
    798   }
    799   return true;
    800 }
    801 
    802 bool V4L2Device::SetFrameRate(uint32_t fps) {
    803   v4l2_streamparm param;
    804   if (!GetParam(&param))
    805     return false;
    806   param.parm.capture.timeperframe.numerator = 1;
    807   param.parm.capture.timeperframe.denominator = fps;
    808   return SetParam(&param);
    809 }
    810 
    811 uint32_t V4L2Device::GetFrameRate() {
    812   v4l2_streamparm param;
    813   if (!GetParam(&param))
    814     return -1;
    815   return (param.parm.capture.timeperframe.denominator /
    816           param.parm.capture.timeperframe.numerator);
    817 }
    818 
    819 uint64_t V4L2Device::Now() {
    820   struct timespec ts;
    821   int res = clock_gettime(CLOCK_MONOTONIC, &ts);
    822   CHECK(res == 0);
    823   return static_cast<uint64_t>(ts.tv_sec);
    824 }
    825