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 #include "ui/gfx/screen.h" | |
| 25 | 26 |
| 26 namespace media { | 27 namespace media { |
| 27 | 28 |
| 28 // Max number of video buffers VideoCaptureDeviceLinux can allocate. | 29 // Max number of video buffers VideoCaptureDeviceLinux can allocate. |
| 29 enum { kMaxVideoBuffers = 2 }; | 30 enum { kMaxVideoBuffers = 2 }; |
| 30 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. | 31 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. |
| 31 enum { kCaptureTimeoutUs = 200000 }; | 32 enum { kCaptureTimeoutUs = 200000 }; |
| 32 // The number of continuous timeouts tolerated before treated as error. | 33 // The number of continuous timeouts tolerated before treated as error. |
| 33 enum { kContinuousTimeoutLimit = 10 }; | 34 enum { kContinuousTimeoutLimit = 10 }; |
| 34 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask | 35 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 | 265 |
| 265 return self; | 266 return self; |
| 266 } | 267 } |
| 267 | 268 |
| 268 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) | 269 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) |
| 269 : state_(kIdle), | 270 : state_(kIdle), |
| 270 device_name_(device_name), | 271 device_name_(device_name), |
| 271 v4l2_thread_("V4L2Thread"), | 272 v4l2_thread_("V4L2Thread"), |
| 272 buffer_pool_(NULL), | 273 buffer_pool_(NULL), |
| 273 buffer_pool_size_(0), | 274 buffer_pool_size_(0), |
| 274 timeout_count_(0) {} | 275 timeout_count_(0), |
| 276 display_rotation_(gfx::Display::ROTATE_0) { | |
| 277 gfx::Screen* screen = | |
|
perkj_chrome
2014/05/09 10:11:28
This will be called on a special thread used only
| |
| 278 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE); | |
| 279 if (screen) { | |
| 280 SetDisplayRotation(screen->GetPrimaryDisplay()); | |
| 281 screen->AddObserver(this); | |
| 282 } | |
| 283 } | |
| 275 | 284 |
| 276 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { | 285 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { |
| 286 gfx::Screen* screen = | |
| 287 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE); | |
|
perkj_chrome
2014/05/09 10:11:28
Can there be a race here? ie, is it ok to not call
| |
| 288 if (screen) | |
| 289 screen->RemoveObserver(this); | |
| 290 | |
| 277 state_ = kIdle; | 291 state_ = kIdle; |
| 278 // Check if the thread is running. | 292 // Check if the thread is running. |
| 279 // This means that the device have not been DeAllocated properly. | 293 // This means that the device have not been DeAllocated properly. |
| 280 DCHECK(!v4l2_thread_.IsRunning()); | 294 DCHECK(!v4l2_thread_.IsRunning()); |
| 281 v4l2_thread_.Stop(); | 295 v4l2_thread_.Stop(); |
| 282 } | 296 } |
| 283 | 297 |
| 284 void VideoCaptureDeviceLinux::AllocateAndStart( | 298 void VideoCaptureDeviceLinux::AllocateAndStart( |
| 285 const VideoCaptureParams& params, | 299 const VideoCaptureParams& params, |
| 286 scoped_ptr<VideoCaptureDevice::Client> client) { | 300 scoped_ptr<VideoCaptureDevice::Client> client) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 306 FROM_HERE, | 320 FROM_HERE, |
| 307 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, | 321 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, |
| 308 base::Unretained(this))); | 322 base::Unretained(this))); |
| 309 v4l2_thread_.Stop(); | 323 v4l2_thread_.Stop(); |
| 310 // Make sure no buffers are still allocated. | 324 // Make sure no buffers are still allocated. |
| 311 // This can happen (theoretically) if an error occurs when trying to stop | 325 // This can happen (theoretically) if an error occurs when trying to stop |
| 312 // the camera. | 326 // the camera. |
| 313 DeAllocateVideoBuffers(); | 327 DeAllocateVideoBuffers(); |
| 314 } | 328 } |
| 315 | 329 |
| 330 void VideoCaptureDeviceLinux::OnDisplayBoundsChanged( | |
| 331 const gfx::Display& display) { | |
| 332 v4l2_thread_.message_loop()->PostTask( | |
|
perkj_chrome
2014/05/09 10:11:28
This thread is started in AllocateAndStart. So you
perkj_chrome
2014/05/09 10:28:44
oh- btw - this need a thread check to make sure it
| |
| 333 FROM_HERE, | |
| 334 base::Bind(&VideoCaptureDeviceLinux::SetDisplayRotation, | |
| 335 base::Unretained(this), display)); | |
| 336 } | |
| 337 | |
| 338 void VideoCaptureDeviceLinux::OnDisplayAdded( | |
| 339 const gfx::Display& /*new_display*/) {} | |
| 340 | |
| 341 void VideoCaptureDeviceLinux::OnDisplayRemoved( | |
| 342 const gfx::Display& /*old_display*/) {} | |
| 343 | |
| 344 void VideoCaptureDeviceLinux::SetDisplayRotation(const gfx::Display& display) { | |
| 345 DCHECK(!v4l2_thread_.IsRunning() || | |
| 346 v4l2_thread_.message_loop() == base::MessageLoop::current()); | |
| 347 if (display.IsInternal()) | |
| 348 display_rotation_ = display.rotation(); | |
|
perkj_chrome
2014/05/09 10:18:52
Add a todo and a comment that this will in fact ro
| |
| 349 } | |
| 350 | |
| 316 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, | 351 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, |
| 317 int height, | 352 int height, |
| 318 int frame_rate, | 353 int frame_rate, |
| 319 scoped_ptr<Client> client) { | 354 scoped_ptr<Client> client) { |
| 320 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 355 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 321 | 356 |
| 322 client_ = client.Pass(); | 357 client_ = client.Pass(); |
| 323 | 358 |
| 324 // Need to open camera with O_RDWR after Linux kernel 3.3. | 359 // 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))); | 360 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; | 549 v4l2_buffer buffer; |
| 515 memset(&buffer, 0, sizeof(buffer)); | 550 memset(&buffer, 0, sizeof(buffer)); |
| 516 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 551 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 517 buffer.memory = V4L2_MEMORY_MMAP; | 552 buffer.memory = V4L2_MEMORY_MMAP; |
| 518 // Dequeue a buffer. | 553 // Dequeue a buffer. |
| 519 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { | 554 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { |
| 520 client_->OnIncomingCapturedData( | 555 client_->OnIncomingCapturedData( |
| 521 static_cast<uint8*>(buffer_pool_[buffer.index].start), | 556 static_cast<uint8*>(buffer_pool_[buffer.index].start), |
| 522 buffer.bytesused, | 557 buffer.bytesused, |
| 523 capture_format_, | 558 capture_format_, |
| 524 0, | 559 display_rotation_ * 90, |
| 525 base::TimeTicks::Now()); | 560 base::TimeTicks::Now()); |
| 526 | 561 |
| 527 // Enqueue the buffer again. | 562 // Enqueue the buffer again. |
| 528 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { | 563 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { |
| 529 SetErrorState(base::StringPrintf( | 564 SetErrorState(base::StringPrintf( |
| 530 "Failed to enqueue capture buffer errno %d", errno)); | 565 "Failed to enqueue capture buffer errno %d", errno)); |
| 531 } | 566 } |
| 532 } else { | 567 } else { |
| 533 SetErrorState(base::StringPrintf( | 568 SetErrorState(base::StringPrintf( |
| 534 "Failed to dequeue capture buffer errno %d", errno)); | 569 "Failed to dequeue capture buffer errno %d", errno)); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 | 649 |
| 615 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 650 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 616 DCHECK(!v4l2_thread_.IsRunning() || | 651 DCHECK(!v4l2_thread_.IsRunning() || |
| 617 v4l2_thread_.message_loop() == base::MessageLoop::current()); | 652 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
| 618 DVLOG(1) << reason; | 653 DVLOG(1) << reason; |
| 619 state_ = kError; | 654 state_ = kError; |
| 620 client_->OnError(reason); | 655 client_->OnError(reason); |
| 621 } | 656 } |
| 622 | 657 |
| 623 } // namespace media | 658 } // namespace media |
| OLD | NEW |