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