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 |