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