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 |