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