summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 16:52:25 +0000
committerwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 16:52:25 +0000
commit25bd71ae5f7770990ac30c5ad5ca8745a952e1c0 (patch)
tree2be2fd9c29d958ea434ba28da9cd92484a44734c
parent03eb799a4dac9b1d11b776fca068585db29cb20e (diff)
downloadchromium_src-25bd71ae5f7770990ac30c5ad5ca8745a952e1c0.zip
chromium_src-25bd71ae5f7770990ac30c5ad5ca8745a952e1c0.tar.gz
chromium_src-25bd71ae5f7770990ac30c5ad5ca8745a952e1c0.tar.bz2
add workarounds for some popular webcam.
1. bring device back to normal from bad state by querying all controls. 2. call ioctl with VIDIOC_TRY_FMT twice. 3. incorporate change from http://codereview.chromium.org/7753002/. "Improve stability when using a Logitech 9000 camera on Linux. Changed so that the device driver is opened and closed on the same thread as all the v4l2 calls." BUG=94134 TEST= Review URL: http://codereview.chromium.org/7743002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100165 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--media/media.gyp6
-rw-r--r--media/video/capture/linux/video_capture_device_linux.cc85
-rw-r--r--media/video/capture/linux/video_capture_device_linux.h4
-rw-r--r--media/video/capture/video_capture_device_unittest.cc24
4 files changed, 68 insertions, 51 deletions
diff --git a/media/media.gyp b/media/media.gyp
index 24dcc58..fcc9b53 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -202,8 +202,11 @@
'video/capture/linux/video_capture_device_linux.h',
'video/capture/video_capture.h',
'video/capture/video_capture_device.h',
+ 'video/capture/video_capture_device_dummy.cc',
+ 'video/capture/video_capture_device_dummy.h',
'video/capture/video_capture_proxy.cc',
'video/capture/video_capture_proxy.h',
+ 'video/capture/video_capture_types.h',
'video/capture/win/filter_base_win.cc',
'video/capture/win/filter_base_win.h',
'video/capture/win/pin_base_win.cc',
@@ -215,9 +218,6 @@
'video/capture/win/sink_input_pin_win.h',
'video/capture/win/video_capture_device_win.cc',
'video/capture/win/video_capture_device_win.h',
- 'video/capture/video_capture_device_dummy.cc',
- 'video/capture/video_capture_device_dummy.h',
- 'video/capture/video_capture_types.h',
'video/ffmpeg_video_decode_engine.cc',
'video/ffmpeg_video_decode_engine.h',
'video/picture.cc',
diff --git a/media/video/capture/linux/video_capture_device_linux.cc b/media/video/capture/linux/video_capture_device_linux.cc
index 8585a26..3062e6e 100644
--- a/media/video/capture/linux/video_capture_device_linux.cc
+++ b/media/video/capture/linux/video_capture_device_linux.cc
@@ -15,10 +15,22 @@
#include "base/file_util.h"
#include "base/stringprintf.h"
+// Workaround for some device. This query of all controls magically brings
+// device back to normal from bad state.
+// See http://crbug.com/94134.
+static void ResetCameraByEnumeratingIoctlsHACK(int fd) {
+ struct v4l2_queryctrl query_ctrl;
+ memset(&query_ctrl, 0, sizeof(query_ctrl));
+
+ for (query_ctrl.id = V4L2_CID_BASE;
+ query_ctrl.id < V4L2_CID_LASTP1;
+ query_ctrl.id++) {
+ ioctl(fd, VIDIOC_QUERYCTRL, &query_ctrl);
+ }
+}
+
namespace media {
-// Number of supported v4l2 color formats.
-enum { kColorFormats = 2 };
// Max number of video buffers VideoCaptureDeviceLinux can allocate.
enum { kMaxVideoBuffers = 2 };
// Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw.
@@ -28,7 +40,7 @@ enum { kCaptureTimeoutUs = 200000 };
enum { kCaptureSelectWaitMs = 10 };
// V4L2 color formats VideoCaptureDeviceLinux support.
-static const int32 kV4l2Fmts[kColorFormats] = {
+static const int32 kV4l2Fmts[] = {
V4L2_PIX_FMT_YUV420,
V4L2_PIX_FMT_YUYV
};
@@ -84,10 +96,17 @@ VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name);
if (!self)
return NULL;
- if (self->Init() != true) {
+ // Test opening the device driver. This is to make sure it is available.
+ // We will reopen it again in our worker thread when someone
+ // allocates the camera.
+ int fd = open(device_name.unique_id.c_str(), O_RDONLY);
+ if (fd < 0) {
+ DPLOG(ERROR) << "Cannot open device";
delete self;
return NULL;
}
+ close(fd);
+
return self;
}
@@ -113,13 +132,6 @@ VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() {
}
}
-bool VideoCaptureDeviceLinux::Init() {
- if ((device_fd_ = open(device_name_.unique_id.c_str(), O_RDONLY)) < 0) {
- return false;
- }
- return true;
-}
-
void VideoCaptureDeviceLinux::Allocate(int width,
int height,
int frame_rate,
@@ -161,21 +173,10 @@ void VideoCaptureDeviceLinux::DeAllocate() {
NewRunnableMethod(this, &VideoCaptureDeviceLinux::OnDeAllocate));
v4l2_thread_.Stop();
- // We need to close and open the device if we want to change the settings
- // Otherwise VIDIOC_S_FMT will return error
- // Sad but true. We still open the device in the Init function.
- close(device_fd_);
- device_fd_ = -1;
-
// Make sure no buffers are still allocated.
// This can happen (theoretically) if an error occurs when trying to stop
// the camera.
DeAllocateVideoBuffers();
-
- if (!Init() && state_ != kError) {
- SetErrorState("Failed to reinitialize camera");
- return;
- }
}
const VideoCaptureDevice::Name& VideoCaptureDeviceLinux::device_name() {
@@ -190,6 +191,11 @@ void VideoCaptureDeviceLinux::OnAllocate(int width,
observer_ = observer;
+ if ((device_fd_ = open(device_name_.unique_id.c_str(), O_RDONLY)) < 0) {
+ SetErrorState("Failed to open V4L2 device driver.");
+ return;
+ }
+
// Test if this is a V4L2 device.
v4l2_capability cap;
if (!((ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) &&
@@ -208,13 +214,21 @@ void VideoCaptureDeviceLinux::OnAllocate(int width,
video_fmt.fmt.pix.width = width;
video_fmt.fmt.pix.height = height;
+ // Some device failed in first VIDIOC_TRY_FMT with EBUSY or EIO.
+ // But second VIDIOC_TRY_FMT succeeds.
+ // See http://crbug.com/94134.
bool format_match = false;
- for (int i = 0; i < kColorFormats; i++) {
+ for (unsigned int i = 0; i < arraysize(kV4l2Fmts) && !format_match; i++) {
video_fmt.fmt.pix.pixelformat = kV4l2Fmts[i];
- if (ioctl(device_fd_, VIDIOC_TRY_FMT, &video_fmt) < 0) {
- continue;
+ for (int attempt = 0; attempt < 2 && !format_match; attempt++) {
+ ResetCameraByEnumeratingIoctlsHACK(device_fd_);
+ if (ioctl(device_fd_, VIDIOC_TRY_FMT, &video_fmt) < 0) {
+ if (errno != EIO)
+ break;
+ } else {
+ format_match = true;
+ }
}
- format_match = true;
}
if (!format_match) {
@@ -251,6 +265,12 @@ void VideoCaptureDeviceLinux::OnDeAllocate() {
if (state_ == kAllocated) {
state_ = kIdle;
}
+
+ // We need to close and open the device if we want to change the settings
+ // Otherwise VIDIOC_S_FMT will return error
+ // Sad but true.
+ close(device_fd_);
+ device_fd_ = -1;
}
void VideoCaptureDeviceLinux::OnStart() {
@@ -397,10 +417,23 @@ bool VideoCaptureDeviceLinux::AllocateVideoBuffers() {
}
void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() {
+ if (!buffer_pool_)
+ return;
+
// Unmaps buffers.
for (int i = 0; i < buffer_pool_size_; i++) {
munmap(buffer_pool_[i].start, buffer_pool_[i].length);
}
+ v4l2_requestbuffers r_buffer;
+ memset(&r_buffer, 0, sizeof(r_buffer));
+ r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ r_buffer.memory = V4L2_MEMORY_MMAP;
+ r_buffer.count = 0;
+
+ if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) {
+ SetErrorState("Failed to reset buf.");
+ }
+
delete [] buffer_pool_;
buffer_pool_ = NULL;
buffer_pool_size_ = 0;
diff --git a/media/video/capture/linux/video_capture_device_linux.h b/media/video/capture/linux/video_capture_device_linux.h
index adcb592..24caf17 100644
--- a/media/video/capture/linux/video_capture_device_linux.h
+++ b/media/video/capture/linux/video_capture_device_linux.h
@@ -22,10 +22,6 @@ class VideoCaptureDeviceLinux : public VideoCaptureDevice {
explicit VideoCaptureDeviceLinux(const Name& device_name);
virtual ~VideoCaptureDeviceLinux();
- // Opens the device driver for this device.
- // This function is used by the static VideoCaptureDevice::Create function.
- bool Init();
-
// VideoCaptureDevice implementation.
virtual void Allocate(int width,
int height,
diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc
index 8ba7a40..7cb40bc 100644
--- a/media/video/capture/video_capture_device_unittest.cc
+++ b/media/video/capture/video_capture_device_unittest.cc
@@ -69,9 +69,7 @@ TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) {
EXPECT_TRUE(device == NULL);
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_CaptureVGA) {
+TEST_F(VideoCaptureDeviceTest, CaptureVGA) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";
@@ -98,9 +96,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_CaptureVGA) {
device->DeAllocate();
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_Capture720p) {
+TEST_F(VideoCaptureDeviceTest, Capture720p) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";
@@ -129,9 +125,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_Capture720p) {
device->DeAllocate();
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_AllocateSameCameraTwice) {
+TEST_F(VideoCaptureDeviceTest, AllocateSameCameraTwice) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";
@@ -158,9 +152,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_AllocateSameCameraTwice) {
device2->DeAllocate();
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_AllocateBadSize) {
+TEST_F(VideoCaptureDeviceTest, AllocateBadSize) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";
@@ -181,9 +173,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_AllocateBadSize) {
device->DeAllocate();
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_ReAllocateCamera) {
+TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";
@@ -215,9 +205,7 @@ TEST_F(VideoCaptureDeviceTest, DISABLED_ReAllocateCamera) {
device->DeAllocate();
}
-// TODO(perkj): This test is disabled due to stability problem with certain
-// cameras. http://www.crbug.com/94134
-TEST_F(VideoCaptureDeviceTest, DISABLED_DeAllocateCameraWhileRunning) {
+TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) {
VideoCaptureDevice::GetDeviceNames(&names_);
if (!names_.size()) {
LOG(WARNING) << "No camera available. Exiting test.";