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 |