| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |