Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: chrome/browser/chromeos/login/camera.cc

Issue 4228002: Moved ownership of camera thread to user image screen (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Compile fix Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/chromeos/login/camera.h" 5 #include "chrome/browser/chromeos/login/camera.h"
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 #include <fcntl.h> // low-level i/o 8 #include <fcntl.h> // low-level i/o
9 #include <unistd.h> 9 #include <unistd.h>
10 #include <errno.h> 10 #include <errno.h>
11 #include <sys/stat.h> 11 #include <sys/stat.h>
12 #include <sys/types.h> 12 #include <sys/types.h>
13 #include <sys/time.h> 13 #include <sys/time.h>
14 #include <sys/mman.h> 14 #include <sys/mman.h>
15 #include <sys/ioctl.h> 15 #include <sys/ioctl.h>
16 #include <asm/types.h> // for videodev2.h 16 #include <asm/types.h> // for videodev2.h
17 #include <linux/videodev2.h> 17 #include <linux/videodev2.h>
18 18
19 #include <algorithm> 19 #include <algorithm>
20 #include <vector> 20 #include <vector>
21 21
22 #include "base/logging.h" 22 #include "base/logging.h"
23 #include "base/string_util.h" 23 #include "base/string_util.h"
24 #include "base/stringprintf.h" 24 #include "base/stringprintf.h"
25 #include "base/thread.h"
25 #include "base/time.h" 26 #include "base/time.h"
26 #include "chrome/browser/browser_thread.h" 27 #include "chrome/browser/browser_thread.h"
27 #include "gfx/size.h" 28 #include "gfx/size.h"
28 #include "skia/ext/image_operations.h" 29 #include "skia/ext/image_operations.h"
29 #include "third_party/skia/include/core/SkBitmap.h" 30 #include "third_party/skia/include/core/SkBitmap.h"
30 #include "third_party/skia/include/core/SkColorPriv.h" 31 #include "third_party/skia/include/core/SkColorPriv.h"
31 32
32 namespace chromeos { 33 namespace chromeos {
33 34
34 namespace { 35 namespace {
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 if (sizes[i].GetArea() > max_area) { 107 if (sizes[i].GetArea() > max_area) {
107 max_size_index = i; 108 max_size_index = i;
108 max_area = sizes[i].GetArea(); 109 max_area = sizes[i].GetArea();
109 } 110 }
110 } 111 }
111 return sizes[max_size_index]; 112 return sizes[max_size_index];
112 } 113 }
113 114
114 // Default camera device name. 115 // Default camera device name.
115 const char kDeviceName[] = "/dev/video0"; 116 const char kDeviceName[] = "/dev/video0";
116 // Name for camera thread.
117 const char kCameraThreadName[] = "Chrome_CameraThread";
118 // Default width of each frame received from the camera. 117 // Default width of each frame received from the camera.
119 const int kFrameWidth = 640; 118 const int kFrameWidth = 640;
120 // Default height of each frame received from the camera. 119 // Default height of each frame received from the camera.
121 const int kFrameHeight = 480; 120 const int kFrameHeight = 480;
122 // Number of buffers to request from the device. 121 // Number of buffers to request from the device.
123 const int kRequestBuffersCount = 4; 122 const int kRequestBuffersCount = 4;
124 // Timeout for select() call in microseconds. 123 // Timeout for select() call in microseconds.
125 const long kSelectTimeout = 1 * base::Time::kMicrosecondsPerSecond; 124 const long kSelectTimeout = 1 * base::Time::kMicrosecondsPerSecond;
126 125
127 } // namespace 126 } // namespace
128 127
129 // static
130 Lock Camera::image_lock_;
131
132 // static
133 Lock Camera::thread_lock_;
134
135 /////////////////////////////////////////////////////////////////////////////// 128 ///////////////////////////////////////////////////////////////////////////////
136 // Camera, public members: 129 // Camera, public members:
137 130
138 Camera::Camera(Delegate* delegate, bool mirrored) 131 Camera::Camera(Delegate* delegate, base::Thread* thread, bool mirrored)
139 : delegate_(delegate), 132 : delegate_(delegate),
140 camera_thread_(kCameraThreadName), 133 thread_(thread),
141 device_name_(kDeviceName), 134 device_name_(kDeviceName),
142 device_descriptor_(-1), 135 device_descriptor_(-1),
143 is_capturing_(false), 136 is_capturing_(false),
144 desired_width_(kFrameWidth), 137 desired_width_(kFrameWidth),
145 desired_height_(kFrameHeight), 138 desired_height_(kFrameHeight),
146 frame_width_(kFrameWidth), 139 frame_width_(kFrameWidth),
147 frame_height_(kFrameHeight), 140 frame_height_(kFrameHeight),
148 mirrored_(mirrored) { 141 mirrored_(mirrored) {
149 } 142 }
150 143
151 Camera::~Camera() { 144 Camera::~Camera() {
152 DCHECK_EQ(-1, device_descriptor_) << "Don't forget to uninitialize camera."; 145 DCHECK_EQ(-1, device_descriptor_) << "Don't forget to uninitialize camera.";
153 } 146 }
154 147
155 // If this method is called there's no need to call PostCameraThreadAck().
156 void Camera::ReportFailure() { 148 void Camera::ReportFailure() {
157 DCHECK(IsOnCameraThread()); 149 DCHECK(IsOnCameraThread());
158 if (device_descriptor_ == -1) { 150 if (device_descriptor_ == -1) {
159 BrowserThread::PostTask( 151 BrowserThread::PostTask(
160 BrowserThread::UI, 152 BrowserThread::UI,
161 FROM_HERE, 153 FROM_HERE,
162 NewRunnableMethod(this, 154 NewRunnableMethod(this,
163 &Camera::OnInitializeFailure)); 155 &Camera::OnInitializeFailure));
164 } else if (!is_capturing_) { 156 } else if (!is_capturing_) {
165 BrowserThread::PostTask( 157 BrowserThread::PostTask(
166 BrowserThread::UI, 158 BrowserThread::UI,
167 FROM_HERE, 159 FROM_HERE,
168 NewRunnableMethod(this, 160 NewRunnableMethod(this,
169 &Camera::OnStartCapturingFailure)); 161 &Camera::OnStartCapturingFailure));
170 } else { 162 } else {
171 BrowserThread::PostTask( 163 BrowserThread::PostTask(
172 BrowserThread::UI, 164 BrowserThread::UI,
173 FROM_HERE, 165 FROM_HERE,
174 NewRunnableMethod(this, 166 NewRunnableMethod(this,
175 &Camera::OnCaptureFailure)); 167 &Camera::OnCaptureFailure));
176 } 168 }
177 } 169 }
178 170
179 void Camera::Initialize(int desired_width, int desired_height) { 171 void Camera::Initialize(int desired_width, int desired_height) {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181 PostCameraTask( 173 PostCameraTask(
174 FROM_HERE,
182 NewRunnableMethod(this, 175 NewRunnableMethod(this,
183 &Camera::DoInitialize, 176 &Camera::DoInitialize,
184 desired_width, 177 desired_width,
185 desired_height)); 178 desired_height));
186 } 179 }
187 180
188 void Camera::DoInitialize(int desired_width, int desired_height) { 181 void Camera::DoInitialize(int desired_width, int desired_height) {
189 DCHECK(IsOnCameraThread()); 182 DCHECK(IsOnCameraThread());
190 DCHECK(delegate_);
191 183
192 if (device_descriptor_ != -1) { 184 if (device_descriptor_ != -1) {
193 LOG(WARNING) << "Camera is initialized already."; 185 LOG(WARNING) << "Camera is initialized already.";
194 PostCameraThreadAck();
195 return; 186 return;
196 } 187 }
197 188
198 int fd = OpenDevice(device_name_.c_str()); 189 int fd = OpenDevice(device_name_.c_str());
199 if (fd == -1) { 190 if (fd == -1) {
200 ReportFailure(); 191 ReportFailure();
201 return; 192 return;
202 } 193 }
203 194
204 v4l2_capability cap; 195 v4l2_capability cap;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 if (!InitializeReadingMode(fd)) { 231 if (!InitializeReadingMode(fd)) {
241 ReportFailure(); 232 ReportFailure();
242 return; 233 return;
243 } 234 }
244 235
245 device_descriptor_ = fd; 236 device_descriptor_ = fd;
246 frame_width_ = frame_size.width(); 237 frame_width_ = frame_size.width();
247 frame_height_ = frame_size.height(); 238 frame_height_ = frame_size.height();
248 desired_width_ = desired_width; 239 desired_width_ = desired_width;
249 desired_height_ = desired_height; 240 desired_height_ = desired_height;
250 // No need to call PostCameraThreadAck() back as this method
251 // is being posted instead.
252 BrowserThread::PostTask( 241 BrowserThread::PostTask(
253 BrowserThread::UI, 242 BrowserThread::UI,
254 FROM_HERE, 243 FROM_HERE,
255 NewRunnableMethod(this, &Camera::OnInitializeSuccess)); 244 NewRunnableMethod(this, &Camera::OnInitializeSuccess));
256 } 245 }
257 246
258 void Camera::CameraThreadAck() {
259 }
260
261 void Camera::PostCameraThreadAck() {
262 BrowserThread::PostTask(
263 BrowserThread::UI,
264 FROM_HERE,
265 NewRunnableMethod(this, &Camera::CameraThreadAck));
266 }
267
268 void Camera::Uninitialize() { 247 void Camera::Uninitialize() {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270 PostCameraTask(NewRunnableMethod(this, &Camera::DoUninitialize)); 249 PostCameraTask(FROM_HERE, NewRunnableMethod(this, &Camera::DoUninitialize));
271 } 250 }
272 251
273 void Camera::DoUninitialize() { 252 void Camera::DoUninitialize() {
274 DCHECK(IsOnCameraThread()); 253 DCHECK(IsOnCameraThread());
275 if (device_descriptor_ == -1) { 254 if (device_descriptor_ == -1) {
276 LOG(WARNING) << "Calling uninitialize for uninitialized camera."; 255 LOG(WARNING) << "Calling uninitialize for uninitialized camera.";
277 PostCameraThreadAck();
278 return; 256 return;
279 } 257 }
280 DoStopCapturing(); 258 DoStopCapturing();
281 UnmapVideoBuffers(); 259 UnmapVideoBuffers();
282 if (close(device_descriptor_) == -1) 260 if (close(device_descriptor_) == -1)
283 log_errno("Closing the device failed."); 261 log_errno("Closing the device failed.");
284 device_descriptor_ = -1; 262 device_descriptor_ = -1;
285 // Maintain a reference so that camera object isn't deleted on wrong thread.
286 PostCameraThreadAck();
287 } 263 }
288 264
289 void Camera::StartCapturing() { 265 void Camera::StartCapturing() {
290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
291 PostCameraTask(NewRunnableMethod(this, &Camera::DoStartCapturing)); 267 PostCameraTask(FROM_HERE,
268 NewRunnableMethod(this, &Camera::DoStartCapturing));
292 } 269 }
293 270
294 void Camera::DoStartCapturing() { 271 void Camera::DoStartCapturing() {
295 DCHECK(IsOnCameraThread()); 272 DCHECK(IsOnCameraThread());
296 if (is_capturing_) { 273 if (is_capturing_) {
297 LOG(WARNING) << "Capturing is already started."; 274 LOG(WARNING) << "Capturing is already started.";
298 PostCameraThreadAck();
299 return; 275 return;
300 } 276 }
301 277
302 for (size_t i = 0; i < buffers_.size(); ++i) { 278 for (size_t i = 0; i < buffers_.size(); ++i) {
303 v4l2_buffer buffer = {}; 279 v4l2_buffer buffer = {};
304 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 280 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
305 buffer.memory = V4L2_MEMORY_MMAP; 281 buffer.memory = V4L2_MEMORY_MMAP;
306 buffer.index = i; 282 buffer.index = i;
307 if (xioctl(device_descriptor_, VIDIOC_QBUF, &buffer) == -1) { 283 if (xioctl(device_descriptor_, VIDIOC_QBUF, &buffer) == -1) {
308 log_errno("VIDIOC_QBUF failed."); 284 log_errno("VIDIOC_QBUF failed.");
309 ReportFailure(); 285 ReportFailure();
310 return; 286 return;
311 } 287 }
312 } 288 }
313 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 289 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
314 if (xioctl(device_descriptor_, VIDIOC_STREAMON, &type) == -1) { 290 if (xioctl(device_descriptor_, VIDIOC_STREAMON, &type) == -1) {
315 log_errno("VIDIOC_STREAMON failed."); 291 log_errno("VIDIOC_STREAMON failed.");
316 ReportFailure(); 292 ReportFailure();
317 return; 293 return;
318 } 294 }
319 // No need to post DidProcessCameraThreadMethod() as this method is 295 // No need to post DidProcessCameraThreadMethod() as this method is
320 // being posted instead. 296 // being posted instead.
321 BrowserThread::PostTask( 297 BrowserThread::PostTask(
322 BrowserThread::UI, 298 BrowserThread::UI,
323 FROM_HERE, 299 FROM_HERE,
324 NewRunnableMethod(this, 300 NewRunnableMethod(this,
325 &Camera::OnStartCapturingSuccess)); 301 &Camera::OnStartCapturingSuccess));
326 is_capturing_ = true; 302 is_capturing_ = true;
327 PostCameraTask(NewRunnableMethod(this, &Camera::OnCapture)); 303 PostCameraTask(FROM_HERE,
304 NewRunnableMethod(this, &Camera::OnCapture));
328 } 305 }
329 306
330 void Camera::StopCapturing() { 307 void Camera::StopCapturing() {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
332 PostCameraTask(NewRunnableMethod(this, &Camera::DoStopCapturing)); 309 PostCameraTask(FROM_HERE,
310 NewRunnableMethod(this, &Camera::DoStopCapturing));
333 } 311 }
334 312
335 void Camera::DoStopCapturing() { 313 void Camera::DoStopCapturing() {
336 DCHECK(IsOnCameraThread()); 314 DCHECK(IsOnCameraThread());
337 if (!is_capturing_) { 315 if (!is_capturing_) {
338 PostCameraThreadAck();
339 LOG(WARNING) << "Calling StopCapturing when capturing is not started."; 316 LOG(WARNING) << "Calling StopCapturing when capturing is not started.";
340 return; 317 return;
341 } 318 }
342 // OnCapture must exit if this flag is not set. 319 // OnCapture must exit if this flag is not set.
343 is_capturing_ = false; 320 is_capturing_ = false;
344 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 321 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
345 if (xioctl(device_descriptor_, VIDIOC_STREAMOFF, &type) == -1) 322 if (xioctl(device_descriptor_, VIDIOC_STREAMOFF, &type) == -1)
346 log_errno("VIDIOC_STREAMOFF failed."); 323 log_errno("VIDIOC_STREAMOFF failed.");
347 // Maintain a reference so that camera object isn't deleted on wrong thread.
348 PostCameraThreadAck();
349 } 324 }
350 325
351 void Camera::GetFrame(SkBitmap* frame) { 326 void Camera::GetFrame(SkBitmap* frame) {
352 AutoLock lock(image_lock_); 327 AutoLock lock(image_lock_);
353 frame->swap(frame_image_); 328 frame->swap(frame_image_);
354 } 329 }
355 330
356 /////////////////////////////////////////////////////////////////////////////// 331 ///////////////////////////////////////////////////////////////////////////////
357 // Camera, private members: 332 // Camera, private members:
358 333
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 void Camera::UnmapVideoBuffers() { 398 void Camera::UnmapVideoBuffers() {
424 DCHECK(IsOnCameraThread()); 399 DCHECK(IsOnCameraThread());
425 for (size_t i = 0; i < buffers_.size(); ++i) { 400 for (size_t i = 0; i < buffers_.size(); ++i) {
426 if (munmap(buffers_[i].start, buffers_[i].length) == -1) 401 if (munmap(buffers_[i].start, buffers_[i].length) == -1)
427 log_errno("munmap failed."); 402 log_errno("munmap failed.");
428 } 403 }
429 } 404 }
430 405
431 void Camera::OnCapture() { 406 void Camera::OnCapture() {
432 DCHECK(IsOnCameraThread()); 407 DCHECK(IsOnCameraThread());
433 if (!is_capturing_) { 408 if (!is_capturing_)
434 // Maintain a reference so that camera object isn't deleted on wrong thread.
435 PostCameraThreadAck();
436 return; 409 return;
437 }
438 410
439 do { 411 do {
440 fd_set fds; 412 fd_set fds;
441 FD_ZERO(&fds); 413 FD_ZERO(&fds);
442 FD_SET(device_descriptor_, &fds); 414 FD_SET(device_descriptor_, &fds);
443 415
444 timeval tv = {}; 416 timeval tv = {};
445 tv.tv_sec = kSelectTimeout / base::Time::kMicrosecondsPerSecond; 417 tv.tv_sec = kSelectTimeout / base::Time::kMicrosecondsPerSecond;
446 tv.tv_usec = kSelectTimeout % base::Time::kMicrosecondsPerSecond; 418 tv.tv_usec = kSelectTimeout % base::Time::kMicrosecondsPerSecond;
447 419
448 int result = select(device_descriptor_ + 1, &fds, NULL, NULL, &tv); 420 int result = select(device_descriptor_ + 1, &fds, NULL, NULL, &tv);
449 if (result == -1) { 421 if (result == -1) {
450 if (errno == EINTR) 422 if (errno == EINTR)
451 continue; 423 continue;
452 log_errno("select() failed."); 424 log_errno("select() failed.");
453 ReportFailure(); 425 ReportFailure();
454 break; 426 break;
455 } 427 }
456 if (result == 0) { 428 if (result == 0) {
457 LOG(ERROR) << "select() timeout."; 429 LOG(ERROR) << "select() timeout.";
458 ReportFailure(); 430 ReportFailure();
459 break; 431 break;
460 } 432 }
461 // EAGAIN - continue select loop. 433 // EAGAIN - continue select loop.
462 } while (!ReadFrame()); 434 } while (!ReadFrame());
463 435
464 PostCameraTask(NewRunnableMethod(this, &Camera::OnCapture)); 436 PostCameraTask(FROM_HERE,
437 NewRunnableMethod(this, &Camera::OnCapture));
465 } 438 }
466 439
467 bool Camera::ReadFrame() { 440 bool Camera::ReadFrame() {
468 DCHECK(IsOnCameraThread()); 441 DCHECK(IsOnCameraThread());
469 v4l2_buffer buffer = {}; 442 v4l2_buffer buffer = {};
470 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 443 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
471 buffer.memory = V4L2_MEMORY_MMAP; 444 buffer.memory = V4L2_MEMORY_MMAP;
472 if (xioctl(device_descriptor_, VIDIOC_DQBUF, &buffer) == -1) { 445 if (xioctl(device_descriptor_, VIDIOC_DQBUF, &buffer) == -1) {
473 // Return false only in this case to try again. 446 // Return false only in this case to try again.
474 if (errno == EAGAIN) 447 if (errno == EAGAIN)
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 } 567 }
595 568
596 void Camera::OnCaptureFailure() { 569 void Camera::OnCaptureFailure() {
597 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 570 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
598 if (delegate_) 571 if (delegate_)
599 delegate_->OnCaptureFailure(); 572 delegate_->OnCaptureFailure();
600 } 573 }
601 574
602 bool Camera::IsOnCameraThread() const { 575 bool Camera::IsOnCameraThread() const {
603 AutoLock lock(thread_lock_); 576 AutoLock lock(thread_lock_);
604 return MessageLoop::current() == camera_thread_.message_loop(); 577 return thread_ && MessageLoop::current() == thread_->message_loop();
605 } 578 }
606 579
607 void Camera::PostCameraTask(Task* task) { 580 void Camera::PostCameraTask(const tracked_objects::Location& from_here,
581 Task* task) {
608 AutoLock lock(thread_lock_); 582 AutoLock lock(thread_lock_);
609 if (!camera_thread_.IsRunning()) 583 if (!thread_)
610 camera_thread_.Start(); 584 return;
611 camera_thread_.message_loop()->PostTask(FROM_HERE, task); 585 DCHECK(thread_->IsRunning());
586 thread_->message_loop()->PostTask(from_here, task);
612 } 587 }
613 588
614 } // namespace chromeos 589 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/login/camera.h ('k') | chrome/browser/chromeos/login/user_image_screen.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698