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(¶m)) 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(¶m)) 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(¶m); 981 } 982 983 float V4L2Device::GetFrameRate() { 984 v4l2_streamparm param; 985 if (!GetParam(¶m)) 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