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 const std::string& device_name, |
| 257 VideoCaptureFormats* capture_formats) { |
| 258 |
| 259 int fd = open(device_name.c_str(), O_RDONLY); |
| 260 if (fd < 0) |
| 261 return; |
| 262 |
| 263 media::VideoCaptureCapability capture_format; |
| 264 |
| 265 v4l2_capability device; |
| 266 // Test if this is a V4L2 capture device. |
| 267 if ((ioctl(fd, VIDIOC_QUERYCAP, &device) == 0) && |
| 268 (device.capabilities & V4L2_CAP_VIDEO_CAPTURE) && |
| 269 !(device.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { |
| 270 // Retrieve the caps one by one, first get colorspace, then sizes, then |
| 271 // framerates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. |
| 272 v4l2_fmtdesc pixel_format = {}; |
| 273 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 274 while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) { |
| 275 capture_format.color = media::V4l2ColorToVideoCaptureColorFormat( |
| 276 static_cast<int32>(pixel_format.pixelformat)); |
| 277 |
| 278 v4l2_frmsizeenum frame_size = {}; |
| 279 frame_size.pixel_format = pixel_format.pixelformat; |
| 280 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) { |
| 281 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
| 282 capture_format.width = frame_size.discrete.width; |
| 283 capture_format.height = frame_size.discrete.height; |
| 284 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { |
| 285 // What to do here? We get a min-max pair for width and height, and a |
| 286 // step for each dimensions. Is not a crazy format, ViVi uses it. |
| 287 // TODO(mcasas) see crbug.com/249953 |
| 288 NOTIMPLEMENTED(); |
| 289 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
| 290 // Same here as the case before: TODO(mcasas) see crbug.com/249953 |
| 291 NOTIMPLEMENTED(); |
| 292 } |
| 293 v4l2_frmivalenum frame_interval = {}; |
| 294 frame_interval.pixel_format = pixel_format.pixelformat; |
| 295 frame_interval.width = frame_size.discrete.width; |
| 296 frame_interval.height = frame_size.discrete.height; |
| 297 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) { |
| 298 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
| 299 capture_format.frame_rate = |
| 300 (frame_interval.discrete.numerator != 0) |
| 301 ? (static_cast<float>(frame_interval.discrete.denominator) / |
| 302 static_cast<float>(frame_interval.discrete.numerator)) |
| 303 : 0; |
| 304 |
| 305 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { |
| 306 // Same here as the case above: TODO(mcasas) see crbug.com/249953 |
| 307 NOTIMPLEMENTED(); |
| 308 break; |
| 309 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
| 310 // Same here as the case before: TODO(mcasas) see crbug.com/249953 |
| 311 NOTIMPLEMENTED(); |
| 312 break; |
| 313 } |
| 314 capture_formats->insert(capture_formats->end(), capture_format); |
| 315 ++frame_interval.index; |
| 316 } |
| 317 ++frame_size.index; |
| 318 } |
| 319 ++pixel_format.index; |
| 320 } |
| 321 } else { |
| 322 // The selected device is not video capture as we like it. |
| 323 capture_formats->clear(); |
| 324 } |
| 325 close(fd); |
| 326 } |
| 327 |
255 void VideoCaptureDeviceLinux::OnAllocate(int width, | 328 void VideoCaptureDeviceLinux::OnAllocate(int width, |
256 int height, | 329 int height, |
257 int frame_rate, | 330 int frame_rate, |
258 EventHandler* observer) { | 331 EventHandler* observer) { |
259 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 332 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
260 | 333 |
261 observer_ = observer; | 334 observer_ = observer; |
262 | 335 |
263 // Need to open camera with O_RDWR after Linux kernel 3.3. | 336 // 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) { | 337 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { |
(...skipping 20 matching lines...) Expand all Loading... |
285 &v4l2_formats); | 358 &v4l2_formats); |
286 | 359 |
287 v4l2_fmtdesc fmtdesc; | 360 v4l2_fmtdesc fmtdesc; |
288 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | 361 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); |
289 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 362 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
290 | 363 |
291 // Enumerate image formats. | 364 // Enumerate image formats. |
292 std::list<int>::iterator best = v4l2_formats.end(); | 365 std::list<int>::iterator best = v4l2_formats.end(); |
293 while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { | 366 while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { |
294 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); | 367 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); |
295 fmtdesc.index++; | 368 ++fmtdesc.index; |
296 } | 369 } |
297 | 370 |
298 if (best == v4l2_formats.end()) { | 371 if (best == v4l2_formats.end()) { |
299 SetErrorState("Failed to find a supported camera format."); | 372 SetErrorState("Failed to find a supported camera format."); |
300 return; | 373 return; |
301 } | 374 } |
302 | 375 |
303 // Set format and frame size now. | 376 // Set format and frame size now. |
304 v4l2_format video_fmt; | 377 v4l2_format video_fmt; |
305 memset(&video_fmt, 0, sizeof(video_fmt)); | 378 memset(&video_fmt, 0, sizeof(video_fmt)); |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 } | 515 } |
443 v4l2_thread_.message_loop()->PostDelayedTask( | 516 v4l2_thread_.message_loop()->PostDelayedTask( |
444 FROM_HERE, | 517 FROM_HERE, |
445 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 518 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
446 base::Unretained(this)), | 519 base::Unretained(this)), |
447 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); | 520 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); |
448 } | 521 } |
449 | 522 |
450 // Check if select timeout. | 523 // Check if select timeout. |
451 if (result == 0) { | 524 if (result == 0) { |
452 timeout_count_++; | 525 ++timeout_count_; |
453 if (timeout_count_ >= kContinuousTimeoutLimit) { | 526 if (timeout_count_ >= kContinuousTimeoutLimit) { |
454 SetErrorState(base::StringPrintf( | 527 SetErrorState(base::StringPrintf( |
455 "Continuous timeout %d times", timeout_count_)); | 528 "Continuous timeout %d times", timeout_count_)); |
456 timeout_count_ = 0; | 529 timeout_count_ = 0; |
457 return; | 530 return; |
458 } | 531 } |
459 } else { | 532 } else { |
460 timeout_count_ = 0; | 533 timeout_count_ = 0; |
461 } | 534 } |
462 | 535 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 } | 576 } |
504 | 577 |
505 if (r_buffer.count > kMaxVideoBuffers) { | 578 if (r_buffer.count > kMaxVideoBuffers) { |
506 r_buffer.count = kMaxVideoBuffers; | 579 r_buffer.count = kMaxVideoBuffers; |
507 } | 580 } |
508 | 581 |
509 buffer_pool_size_ = r_buffer.count; | 582 buffer_pool_size_ = r_buffer.count; |
510 | 583 |
511 // Map the buffers. | 584 // Map the buffers. |
512 buffer_pool_ = new Buffer[r_buffer.count]; | 585 buffer_pool_ = new Buffer[r_buffer.count]; |
513 for (unsigned int i = 0; i < r_buffer.count; i++) { | 586 for (unsigned int i = 0; i < r_buffer.count; ++i) { |
514 v4l2_buffer buffer; | 587 v4l2_buffer buffer; |
515 memset(&buffer, 0, sizeof(buffer)); | 588 memset(&buffer, 0, sizeof(buffer)); |
516 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 589 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
517 buffer.memory = V4L2_MEMORY_MMAP; | 590 buffer.memory = V4L2_MEMORY_MMAP; |
518 buffer.index = i; | 591 buffer.index = i; |
519 | 592 |
520 if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) { | 593 if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) { |
521 return false; | 594 return false; |
522 } | 595 } |
523 | 596 |
(...skipping 11 matching lines...) Expand all Loading... |
535 } | 608 } |
536 } | 609 } |
537 return true; | 610 return true; |
538 } | 611 } |
539 | 612 |
540 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { | 613 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { |
541 if (!buffer_pool_) | 614 if (!buffer_pool_) |
542 return; | 615 return; |
543 | 616 |
544 // Unmaps buffers. | 617 // Unmaps buffers. |
545 for (int i = 0; i < buffer_pool_size_; i++) { | 618 for (int i = 0; i < buffer_pool_size_; ++i) { |
546 munmap(buffer_pool_[i].start, buffer_pool_[i].length); | 619 munmap(buffer_pool_[i].start, buffer_pool_[i].length); |
547 } | 620 } |
548 v4l2_requestbuffers r_buffer; | 621 v4l2_requestbuffers r_buffer; |
549 memset(&r_buffer, 0, sizeof(r_buffer)); | 622 memset(&r_buffer, 0, sizeof(r_buffer)); |
550 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 623 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
551 r_buffer.memory = V4L2_MEMORY_MMAP; | 624 r_buffer.memory = V4L2_MEMORY_MMAP; |
552 r_buffer.count = 0; | 625 r_buffer.count = 0; |
553 | 626 |
554 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { | 627 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { |
555 SetErrorState("Failed to reset buf."); | 628 SetErrorState("Failed to reset buf."); |
556 } | 629 } |
557 | 630 |
558 delete [] buffer_pool_; | 631 delete [] buffer_pool_; |
559 buffer_pool_ = NULL; | 632 buffer_pool_ = NULL; |
560 buffer_pool_size_ = 0; | 633 buffer_pool_size_ = 0; |
561 } | 634 } |
562 | 635 |
563 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 636 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
564 DVLOG(1) << reason; | 637 DVLOG(1) << reason; |
565 state_ = kError; | 638 state_ = kError; |
566 observer_->OnError(); | 639 observer_->OnError(); |
567 } | 640 } |
568 | 641 |
569 } // namespace media | 642 } // namespace media |
OLD | NEW |