Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/video/capture/linux/video_capture_device_linux.h" | 5 #include "media/video/capture/linux/video_capture_device_linux.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #if defined(OS_OPENBSD) | 9 #if defined(OS_OPENBSD) |
| 10 #include <sys/videoio.h> | 10 #include <sys/videoio.h> |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 GetListOfUsableFourCCs(false, &usable_fourccs); | 89 GetListOfUsableFourCCs(false, &usable_fourccs); |
| 90 | 90 |
| 91 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | 91 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); |
| 92 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 92 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 93 | 93 |
| 94 while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { | 94 while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { |
| 95 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), | 95 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
| 96 fmtdesc.pixelformat) != usable_fourccs.end()) | 96 fmtdesc.pixelformat) != usable_fourccs.end()) |
| 97 return true; | 97 return true; |
| 98 | 98 |
| 99 fmtdesc.index++; | 99 ++fmtdesc.index; |
| 100 } | 100 } |
| 101 return false; | 101 return false; |
| 102 } | 102 } |
| 103 | 103 |
| 104 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { | 104 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
| 105 int fd = -1; | 105 int fd = -1; |
| 106 | 106 |
| 107 // Empty the name list. | 107 // Empty the name list. |
| 108 device_names->clear(); | 108 device_names->clear(); |
| 109 | 109 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 245 // Make sure no buffers are still allocated. | 245 // Make sure no buffers are still allocated. |
| 246 // This can happen (theoretically) if an error occurs when trying to stop | 246 // This can happen (theoretically) if an error occurs when trying to stop |
| 247 // the camera. | 247 // the camera. |
| 248 DeAllocateVideoBuffers(); | 248 DeAllocateVideoBuffers(); |
| 249 } | 249 } |
| 250 | 250 |
| 251 const VideoCaptureDevice::Name& VideoCaptureDeviceLinux::device_name() { | 251 const VideoCaptureDevice::Name& VideoCaptureDeviceLinux::device_name() { |
| 252 return device_name_; | 252 return device_name_; |
| 253 } | 253 } |
| 254 | 254 |
| 255 void VideoCaptureDeviceLinux::GetDeviceSupportedFormats( | |
| 256 VideoCaptureFormats* capture_formats) { | |
|
perkj_chrome
2013/09/13 10:33:05
To be threadsafe - all v4l2 calls in this file is
mcasas
2013/09/24 15:02:27
Done.
| |
| 257 | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
remove blank line
mcasas
2013/09/24 15:02:27
Done.
| |
| 258 if (device_name_.id().empty()) | |
| 259 return; | |
| 260 int fd = open(device_name_.id().c_str(), O_RDONLY); | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
use file_util::ScopedFD
scherkus (not reviewing)
2013/09/12 17:56:00
this should be wrapped with HANDLE_EINTR()
mcasas
2013/09/24 15:02:27
Done.
| |
| 261 if (fd < 0) | |
| 262 return; | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
DPLOG(ERROR) << "Couldn't open " << device_name_.i
mcasas
2013/09/24 15:02:27
Done.
| |
| 263 | |
| 264 media::VideoCaptureCapability capture_format; | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
remove media::
mcasas
2013/09/24 15:02:27
Done.
| |
| 265 | |
| 266 v4l2_capability device; | |
| 267 // Test if this is a V4L2 capture device. | |
| 268 if ((ioctl(fd, VIDIOC_QUERYCAP, &device) == 0) && | |
| 269 (device.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | |
| 270 !(device.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { | |
| 271 // Retrieve the caps one by one, first get colorspace, then sizes, then | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
instead of having this large block of code indente
mcasas
2013/09/24 15:02:27
Done.
| |
| 272 // framerates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. | |
| 273 v4l2_fmtdesc pixel_format = {}; | |
| 274 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
| 275 while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) { | |
| 276 capture_format.color = media::V4l2ColorToVideoCaptureColorFormat( | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
remove media::
scherkus (not reviewing)
2013/09/12 17:56:00
do we have to cast here?
it seems we don't have t
mcasas
2013/09/24 15:02:27
Done.
mcasas
2013/09/24 15:02:27
Done.
| |
| 277 static_cast<int32>(pixel_format.pixelformat)); | |
| 278 | |
| 279 v4l2_frmsizeenum frame_size = {}; | |
| 280 frame_size.pixel_format = pixel_format.pixelformat; | |
| 281 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) { | |
| 282 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | |
| 283 capture_format.width = frame_size.discrete.width; | |
| 284 capture_format.height = frame_size.discrete.height; | |
| 285 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | |
| 286 // What to do here? We get a min-max pair for width and height, and a | |
| 287 // step for each dimensions. Is not a crazy format, ViVi uses it. | |
| 288 // TODO(mcasas) see crbug.com/249953 | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
nit: we format TODOs with a : after the )
also ca
scherkus (not reviewing)
2013/09/12 17:56:00
nit: use http:// in front of crbug.com (many text
mcasas
2013/09/24 15:02:27
Done.
mcasas
2013/09/24 15:02:27
Is an easy elaborate: support these devices :)
| |
| 289 NOTIMPLEMENTED(); | |
| 290 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { | |
| 291 // Same here as the case before: TODO(mcasas) see crbug.com/249953 | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
ditto
mcasas
2013/09/24 15:02:27
Done.
| |
| 292 NOTIMPLEMENTED(); | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
if these are unimplemented, do you mean to continu
mcasas
2013/09/24 15:02:27
I don't know this particular case. The proposed us
| |
| 293 } | |
| 294 v4l2_frmivalenum frame_interval = {}; | |
| 295 frame_interval.pixel_format = pixel_format.pixelformat; | |
| 296 frame_interval.width = frame_size.discrete.width; | |
| 297 frame_interval.height = frame_size.discrete.height; | |
| 298 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) { | |
| 299 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { | |
| 300 capture_format.frame_rate = | |
| 301 (frame_interval.discrete.numerator != 0) | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
I'd just use an if () statement here -- the ?: ope
mcasas
2013/09/24 15:02:27
Done.
| |
| 302 ? (static_cast<float>(frame_interval.discrete.denominator) / | |
| 303 static_cast<float>(frame_interval.discrete.numerator)) | |
| 304 : 0; | |
| 305 | |
| 306 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { | |
| 307 // Same here as the case above: TODO(mcasas) see crbug.com/249953 | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
nit: try to start TODO comments at the beginning o
mcasas
2013/09/24 15:02:27
Done.
| |
| 308 NOTIMPLEMENTED(); | |
| 309 break; | |
| 310 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { | |
| 311 // Same here as the case before: TODO(mcasas) see crbug.com/249953 | |
| 312 NOTIMPLEMENTED(); | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
ditto... is there a use case for inserting VideoCa
mcasas
2013/09/24 15:02:27
This is an easier case: yes, some devices might no
| |
| 313 break; | |
| 314 } | |
| 315 capture_formats->insert(capture_formats->end(), capture_format); | |
|
scherkus (not reviewing)
2013/09/12 17:56:00
push_back() ?
mcasas
2013/09/24 15:02:27
Done.
| |
| 316 ++frame_interval.index; | |
| 317 } | |
| 318 ++frame_size.index; | |
| 319 } | |
| 320 ++pixel_format.index; | |
| 321 } | |
| 322 } else { | |
| 323 // The selected device is not video capture as we like it. | |
| 324 capture_formats->clear(); | |
| 325 } | |
| 326 close(fd); | |
| 327 } | |
| 328 | |
| 255 void VideoCaptureDeviceLinux::OnAllocate(int width, | 329 void VideoCaptureDeviceLinux::OnAllocate(int width, |
| 256 int height, | 330 int height, |
| 257 int frame_rate, | 331 int frame_rate, |
| 258 EventHandler* observer) { | 332 EventHandler* observer) { |
| 259 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 333 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 260 | 334 |
| 261 observer_ = observer; | 335 observer_ = observer; |
| 262 | 336 |
| 263 // Need to open camera with O_RDWR after Linux kernel 3.3. | 337 // Need to open camera with O_RDWR after Linux kernel 3.3. |
| 264 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { | 338 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 285 &v4l2_formats); | 359 &v4l2_formats); |
| 286 | 360 |
| 287 v4l2_fmtdesc fmtdesc; | 361 v4l2_fmtdesc fmtdesc; |
| 288 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | 362 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); |
| 289 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 363 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 290 | 364 |
| 291 // Enumerate image formats. | 365 // Enumerate image formats. |
| 292 std::list<int>::iterator best = v4l2_formats.end(); | 366 std::list<int>::iterator best = v4l2_formats.end(); |
| 293 while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { | 367 while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { |
| 294 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); | 368 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); |
| 295 fmtdesc.index++; | 369 ++fmtdesc.index; |
| 296 } | 370 } |
| 297 | 371 |
| 298 if (best == v4l2_formats.end()) { | 372 if (best == v4l2_formats.end()) { |
| 299 SetErrorState("Failed to find a supported camera format."); | 373 SetErrorState("Failed to find a supported camera format."); |
| 300 return; | 374 return; |
| 301 } | 375 } |
| 302 | 376 |
| 303 // Set format and frame size now. | 377 // Set format and frame size now. |
| 304 v4l2_format video_fmt; | 378 v4l2_format video_fmt; |
| 305 memset(&video_fmt, 0, sizeof(video_fmt)); | 379 memset(&video_fmt, 0, sizeof(video_fmt)); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 442 } | 516 } |
| 443 v4l2_thread_.message_loop()->PostDelayedTask( | 517 v4l2_thread_.message_loop()->PostDelayedTask( |
| 444 FROM_HERE, | 518 FROM_HERE, |
| 445 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 519 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
| 446 base::Unretained(this)), | 520 base::Unretained(this)), |
| 447 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); | 521 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); |
| 448 } | 522 } |
| 449 | 523 |
| 450 // Check if select timeout. | 524 // Check if select timeout. |
| 451 if (result == 0) { | 525 if (result == 0) { |
| 452 timeout_count_++; | 526 ++timeout_count_; |
| 453 if (timeout_count_ >= kContinuousTimeoutLimit) { | 527 if (timeout_count_ >= kContinuousTimeoutLimit) { |
| 454 SetErrorState(base::StringPrintf( | 528 SetErrorState(base::StringPrintf( |
| 455 "Continuous timeout %d times", timeout_count_)); | 529 "Continuous timeout %d times", timeout_count_)); |
| 456 timeout_count_ = 0; | 530 timeout_count_ = 0; |
| 457 return; | 531 return; |
| 458 } | 532 } |
| 459 } else { | 533 } else { |
| 460 timeout_count_ = 0; | 534 timeout_count_ = 0; |
| 461 } | 535 } |
| 462 | 536 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 } | 577 } |
| 504 | 578 |
| 505 if (r_buffer.count > kMaxVideoBuffers) { | 579 if (r_buffer.count > kMaxVideoBuffers) { |
| 506 r_buffer.count = kMaxVideoBuffers; | 580 r_buffer.count = kMaxVideoBuffers; |
| 507 } | 581 } |
| 508 | 582 |
| 509 buffer_pool_size_ = r_buffer.count; | 583 buffer_pool_size_ = r_buffer.count; |
| 510 | 584 |
| 511 // Map the buffers. | 585 // Map the buffers. |
| 512 buffer_pool_ = new Buffer[r_buffer.count]; | 586 buffer_pool_ = new Buffer[r_buffer.count]; |
| 513 for (unsigned int i = 0; i < r_buffer.count; i++) { | 587 for (unsigned int i = 0; i < r_buffer.count; ++i) { |
| 514 v4l2_buffer buffer; | 588 v4l2_buffer buffer; |
| 515 memset(&buffer, 0, sizeof(buffer)); | 589 memset(&buffer, 0, sizeof(buffer)); |
| 516 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 590 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 517 buffer.memory = V4L2_MEMORY_MMAP; | 591 buffer.memory = V4L2_MEMORY_MMAP; |
| 518 buffer.index = i; | 592 buffer.index = i; |
| 519 | 593 |
| 520 if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) { | 594 if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) { |
| 521 return false; | 595 return false; |
| 522 } | 596 } |
| 523 | 597 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 535 } | 609 } |
| 536 } | 610 } |
| 537 return true; | 611 return true; |
| 538 } | 612 } |
| 539 | 613 |
| 540 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { | 614 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { |
| 541 if (!buffer_pool_) | 615 if (!buffer_pool_) |
| 542 return; | 616 return; |
| 543 | 617 |
| 544 // Unmaps buffers. | 618 // Unmaps buffers. |
| 545 for (int i = 0; i < buffer_pool_size_; i++) { | 619 for (int i = 0; i < buffer_pool_size_; ++i) { |
| 546 munmap(buffer_pool_[i].start, buffer_pool_[i].length); | 620 munmap(buffer_pool_[i].start, buffer_pool_[i].length); |
| 547 } | 621 } |
| 548 v4l2_requestbuffers r_buffer; | 622 v4l2_requestbuffers r_buffer; |
| 549 memset(&r_buffer, 0, sizeof(r_buffer)); | 623 memset(&r_buffer, 0, sizeof(r_buffer)); |
| 550 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 624 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 551 r_buffer.memory = V4L2_MEMORY_MMAP; | 625 r_buffer.memory = V4L2_MEMORY_MMAP; |
| 552 r_buffer.count = 0; | 626 r_buffer.count = 0; |
| 553 | 627 |
| 554 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { | 628 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { |
| 555 SetErrorState("Failed to reset buf."); | 629 SetErrorState("Failed to reset buf."); |
| 556 } | 630 } |
| 557 | 631 |
| 558 delete [] buffer_pool_; | 632 delete [] buffer_pool_; |
| 559 buffer_pool_ = NULL; | 633 buffer_pool_ = NULL; |
| 560 buffer_pool_size_ = 0; | 634 buffer_pool_size_ = 0; |
| 561 } | 635 } |
| 562 | 636 |
| 563 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 637 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 564 DVLOG(1) << reason; | 638 DVLOG(1) << reason; |
| 565 state_ = kError; | 639 state_ = kError; |
| 566 observer_->OnError(); | 640 observer_->OnError(); |
| 567 } | 641 } |
| 568 | 642 |
| 569 } // namespace media | 643 } // namespace media |
| OLD | NEW |