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> |
| 11 #else | 11 #else |
| 12 #include <linux/videodev2.h> | 12 #include <linux/videodev2.h> |
| 13 #endif | 13 #endif |
| 14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
| 15 #include <sys/mman.h> | 15 #include <sys/mman.h> |
| 16 | 16 |
| 17 #include <list> | 17 #include <list> |
| 18 #include <string> | 18 #include <string> |
| 19 | 19 |
| 20 #include "base/bind.h" | 20 #include "base/bind.h" |
| 21 #include "base/files/file_enumerator.h" | 21 #include "base/files/file_enumerator.h" |
| 22 #include "base/files/scoped_file.h" | 22 #include "base/files/scoped_file.h" |
| 23 #include "base/posix/eintr_wrapper.h" | 23 #include "base/posix/eintr_wrapper.h" |
| 24 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 25 #if defined(OS_CHROMEOS) | |
| 26 #include "media/video/capture/linux/video_capture_device_chromeos.h" | |
| 27 #endif | |
| 25 | 28 |
| 26 namespace media { | 29 namespace media { |
| 27 | 30 |
| 28 // Max number of video buffers VideoCaptureDeviceLinux can allocate. | 31 // Max number of video buffers VideoCaptureDeviceLinux can allocate. |
| 29 enum { kMaxVideoBuffers = 2 }; | 32 enum { kMaxVideoBuffers = 2 }; |
| 30 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. | 33 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. |
| 31 enum { kCaptureTimeoutUs = 200000 }; | 34 enum { kCaptureTimeoutUs = 200000 }; |
| 32 // The number of continuous timeouts tolerated before treated as error. | 35 // The number of continuous timeouts tolerated before treated as error. |
| 33 enum { kContinuousTimeoutLimit = 10 }; | 36 enum { kContinuousTimeoutLimit = 10 }; |
| 34 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask | 37 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 if (!ReadIdFile(vidPath, &usb_id)) | 245 if (!ReadIdFile(vidPath, &usb_id)) |
| 243 return ""; | 246 return ""; |
| 244 usb_id.append(":"); | 247 usb_id.append(":"); |
| 245 if (!ReadIdFile(pidPath, &usb_id)) | 248 if (!ReadIdFile(pidPath, &usb_id)) |
| 246 return ""; | 249 return ""; |
| 247 | 250 |
| 248 return usb_id; | 251 return usb_id; |
| 249 } | 252 } |
| 250 | 253 |
| 251 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { | 254 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
| 255 #if defined(OS_CHROMEOS) | |
| 256 VideoCaptureDeviceChromeOS* self = | |
| 257 new VideoCaptureDeviceChromeOS(device_name); | |
| 258 #else | |
| 252 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); | 259 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); |
| 260 #endif | |
| 253 if (!self) | 261 if (!self) |
|
tommi (sloooow) - chröme
2014/05/13 11:02:51
nit: we don't check the return value from new()
Zachary Kuznia
2014/05/13 13:54:29
Done.
| |
| 254 return NULL; | 262 return NULL; |
| 255 // Test opening the device driver. This is to make sure it is available. | 263 // Test opening the device driver. This is to make sure it is available. |
| 256 // We will reopen it again in our worker thread when someone | 264 // We will reopen it again in our worker thread when someone |
| 257 // allocates the camera. | 265 // allocates the camera. |
| 258 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); | 266 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); |
| 259 if (!fd.is_valid()) { | 267 if (!fd.is_valid()) { |
| 260 DVLOG(1) << "Cannot open device"; | 268 DVLOG(1) << "Cannot open device"; |
| 261 delete self; | 269 delete self; |
| 262 return NULL; | 270 return NULL; |
| 263 } | 271 } |
| 264 | 272 |
| 265 return self; | 273 return self; |
| 266 } | 274 } |
| 267 | 275 |
| 268 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) | 276 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) |
| 269 : state_(kIdle), | 277 : state_(kIdle), |
| 270 device_name_(device_name), | 278 device_name_(device_name), |
| 271 v4l2_thread_("V4L2Thread"), | 279 v4l2_thread_("V4L2Thread"), |
| 272 buffer_pool_(NULL), | 280 buffer_pool_(NULL), |
| 273 buffer_pool_size_(0), | 281 buffer_pool_size_(0), |
| 274 timeout_count_(0) {} | 282 timeout_count_(0), |
| 283 rotation_(0) { | |
| 284 } | |
| 275 | 285 |
| 276 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { | 286 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { |
| 277 state_ = kIdle; | 287 state_ = kIdle; |
| 278 // Check if the thread is running. | 288 // Check if the thread is running. |
| 279 // This means that the device have not been DeAllocated properly. | 289 // This means that the device have not been DeAllocated properly. |
| 280 DCHECK(!v4l2_thread_.IsRunning()); | 290 DCHECK(!v4l2_thread_.IsRunning()); |
| 281 v4l2_thread_.Stop(); | 291 v4l2_thread_.Stop(); |
| 282 } | 292 } |
| 283 | 293 |
| 284 void VideoCaptureDeviceLinux::AllocateAndStart( | 294 void VideoCaptureDeviceLinux::AllocateAndStart( |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 306 FROM_HERE, | 316 FROM_HERE, |
| 307 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, | 317 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, |
| 308 base::Unretained(this))); | 318 base::Unretained(this))); |
| 309 v4l2_thread_.Stop(); | 319 v4l2_thread_.Stop(); |
| 310 // Make sure no buffers are still allocated. | 320 // Make sure no buffers are still allocated. |
| 311 // This can happen (theoretically) if an error occurs when trying to stop | 321 // This can happen (theoretically) if an error occurs when trying to stop |
| 312 // the camera. | 322 // the camera. |
| 313 DeAllocateVideoBuffers(); | 323 DeAllocateVideoBuffers(); |
| 314 } | 324 } |
| 315 | 325 |
| 326 void VideoCaptureDeviceLinux::SetRotation(int rotation) { | |
| 327 if (v4l2_thread_.IsRunning()) { | |
| 328 v4l2_thread_.message_loop()->PostTask( | |
| 329 FROM_HERE, | |
| 330 base::Bind(&VideoCaptureDeviceLinux::SetRotationOnV4L2Thread, | |
| 331 base::Unretained(this), rotation)); | |
| 332 } else { | |
| 333 // If the |v4l2_thread_| is not running, there's no race condition and | |
| 334 // |rotation_| can be set directly. | |
| 335 rotation_ = rotation; | |
| 336 } | |
| 337 } | |
| 338 | |
| 339 void VideoCaptureDeviceLinux::SetRotationOnV4L2Thread(int rotation) { | |
| 340 DCHECK(v4l2_thread_.IsRunning() && | |
| 341 v4l2_thread_.message_loop() == base::MessageLoop::current()); | |
|
tommi (sloooow) - chröme
2014/05/13 11:02:51
BelongsToCurrentThread()?
Zachary Kuznia
2014/05/13 13:54:29
Done.
| |
| 342 rotation_ = rotation; | |
|
tommi (sloooow) - chröme
2014/05/13 11:02:51
DCHECK valid values of rotation?
Zachary Kuznia
2014/05/13 13:54:29
Done.
| |
| 343 } | |
| 344 | |
| 316 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, | 345 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, |
| 317 int height, | 346 int height, |
| 318 int frame_rate, | 347 int frame_rate, |
| 319 scoped_ptr<Client> client) { | 348 scoped_ptr<Client> client) { |
| 320 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 349 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 321 | 350 |
| 322 client_ = client.Pass(); | 351 client_ = client.Pass(); |
| 323 | 352 |
| 324 // Need to open camera with O_RDWR after Linux kernel 3.3. | 353 // Need to open camera with O_RDWR after Linux kernel 3.3. |
| 325 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); | 354 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 v4l2_buffer buffer; | 543 v4l2_buffer buffer; |
| 515 memset(&buffer, 0, sizeof(buffer)); | 544 memset(&buffer, 0, sizeof(buffer)); |
| 516 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 545 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 517 buffer.memory = V4L2_MEMORY_MMAP; | 546 buffer.memory = V4L2_MEMORY_MMAP; |
| 518 // Dequeue a buffer. | 547 // Dequeue a buffer. |
| 519 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { | 548 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { |
| 520 client_->OnIncomingCapturedData( | 549 client_->OnIncomingCapturedData( |
| 521 static_cast<uint8*>(buffer_pool_[buffer.index].start), | 550 static_cast<uint8*>(buffer_pool_[buffer.index].start), |
| 522 buffer.bytesused, | 551 buffer.bytesused, |
| 523 capture_format_, | 552 capture_format_, |
| 524 0, | 553 rotation_, |
| 525 base::TimeTicks::Now()); | 554 base::TimeTicks::Now()); |
| 526 | 555 |
| 527 // Enqueue the buffer again. | 556 // Enqueue the buffer again. |
| 528 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { | 557 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { |
| 529 SetErrorState(base::StringPrintf( | 558 SetErrorState(base::StringPrintf( |
| 530 "Failed to enqueue capture buffer errno %d", errno)); | 559 "Failed to enqueue capture buffer errno %d", errno)); |
| 531 } | 560 } |
| 532 } else { | 561 } else { |
| 533 SetErrorState(base::StringPrintf( | 562 SetErrorState(base::StringPrintf( |
| 534 "Failed to dequeue capture buffer errno %d", errno)); | 563 "Failed to dequeue capture buffer errno %d", errno)); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 | 643 |
| 615 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 644 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 616 DCHECK(!v4l2_thread_.IsRunning() || | 645 DCHECK(!v4l2_thread_.IsRunning() || |
| 617 v4l2_thread_.message_loop() == base::MessageLoop::current()); | 646 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
| 618 DVLOG(1) << reason; | 647 DVLOG(1) << reason; |
| 619 state_ = kError; | 648 state_ = kError; |
| 620 client_->OnError(reason); | 649 client_->OnError(reason); |
| 621 } | 650 } |
| 622 | 651 |
| 623 } // namespace media | 652 } // namespace media |
| OLD | NEW |