| 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> |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 delete self; | 189 delete self; |
| 190 return NULL; | 190 return NULL; |
| 191 } | 191 } |
| 192 close(fd); | 192 close(fd); |
| 193 | 193 |
| 194 return self; | 194 return self; |
| 195 } | 195 } |
| 196 | 196 |
| 197 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) | 197 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) |
| 198 : state_(kIdle), | 198 : state_(kIdle), |
| 199 client_(NULL), | |
| 200 device_name_(device_name), | 199 device_name_(device_name), |
| 201 device_fd_(-1), | 200 device_fd_(-1), |
| 202 v4l2_thread_("V4L2Thread"), | 201 v4l2_thread_("V4L2Thread"), |
| 203 buffer_pool_(NULL), | 202 buffer_pool_(NULL), |
| 204 buffer_pool_size_(0), | 203 buffer_pool_size_(0), |
| 205 timeout_count_(0) { | 204 timeout_count_(0) {} |
| 206 } | |
| 207 | 205 |
| 208 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { | 206 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { |
| 209 state_ = kIdle; | 207 state_ = kIdle; |
| 210 // Check if the thread is running. | 208 // Check if the thread is running. |
| 211 // This means that the device have not been DeAllocated properly. | 209 // This means that the device have not been DeAllocated properly. |
| 212 DCHECK(!v4l2_thread_.IsRunning()); | 210 DCHECK(!v4l2_thread_.IsRunning()); |
| 213 | 211 |
| 214 v4l2_thread_.Stop(); | 212 v4l2_thread_.Stop(); |
| 215 if (device_fd_ >= 0) { | 213 if (device_fd_ >= 0) { |
| 216 close(device_fd_); | 214 close(device_fd_); |
| 217 } | 215 } |
| 218 } | 216 } |
| 219 | 217 |
| 220 void VideoCaptureDeviceLinux::Allocate( | 218 void VideoCaptureDeviceLinux::AllocateAndStart( |
| 221 const VideoCaptureCapability& capture_format, | 219 const VideoCaptureCapability& capture_format, |
| 222 VideoCaptureDevice::Client* client) { | 220 scoped_ptr<VideoCaptureDevice::Client> client) { |
| 223 if (v4l2_thread_.IsRunning()) { | 221 if (v4l2_thread_.IsRunning()) { |
| 224 return; // Wrong state. | 222 return; // Wrong state. |
| 225 } | 223 } |
| 226 v4l2_thread_.Start(); | 224 v4l2_thread_.Start(); |
| 227 v4l2_thread_.message_loop() | 225 v4l2_thread_.message_loop()->PostTask( |
| 228 ->PostTask(FROM_HERE, | 226 FROM_HERE, |
| 229 base::Bind(&VideoCaptureDeviceLinux::OnAllocate, | 227 base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart, |
| 230 base::Unretained(this), | 228 base::Unretained(this), |
| 231 capture_format.width, | 229 capture_format.width, |
| 232 capture_format.height, | 230 capture_format.height, |
| 233 capture_format.frame_rate, | 231 capture_format.frame_rate, |
| 234 client)); | 232 base::Passed(&client))); |
| 235 } | 233 } |
| 236 | 234 |
| 237 void VideoCaptureDeviceLinux::Start() { | 235 void VideoCaptureDeviceLinux::StopAndDeAllocate() { |
| 238 if (!v4l2_thread_.IsRunning()) { | 236 if (!v4l2_thread_.IsRunning()) { |
| 239 return; // Wrong state. | 237 return; // Wrong state. |
| 240 } | 238 } |
| 241 v4l2_thread_.message_loop()->PostTask( | 239 v4l2_thread_.message_loop()->PostTask( |
| 242 FROM_HERE, | 240 FROM_HERE, |
| 243 base::Bind(&VideoCaptureDeviceLinux::OnStart, base::Unretained(this))); | 241 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, |
| 244 } | |
| 245 | |
| 246 void VideoCaptureDeviceLinux::Stop() { | |
| 247 if (!v4l2_thread_.IsRunning()) { | |
| 248 return; // Wrong state. | |
| 249 } | |
| 250 v4l2_thread_.message_loop()->PostTask( | |
| 251 FROM_HERE, | |
| 252 base::Bind(&VideoCaptureDeviceLinux::OnStop, base::Unretained(this))); | |
| 253 } | |
| 254 | |
| 255 void VideoCaptureDeviceLinux::DeAllocate() { | |
| 256 if (!v4l2_thread_.IsRunning()) { | |
| 257 return; // Wrong state. | |
| 258 } | |
| 259 v4l2_thread_.message_loop()->PostTask( | |
| 260 FROM_HERE, | |
| 261 base::Bind(&VideoCaptureDeviceLinux::OnDeAllocate, | |
| 262 base::Unretained(this))); | 242 base::Unretained(this))); |
| 263 v4l2_thread_.Stop(); | 243 v4l2_thread_.Stop(); |
| 264 | |
| 265 // Make sure no buffers are still allocated. | 244 // Make sure no buffers are still allocated. |
| 266 // This can happen (theoretically) if an error occurs when trying to stop | 245 // This can happen (theoretically) if an error occurs when trying to stop |
| 267 // the camera. | 246 // the camera. |
| 268 DeAllocateVideoBuffers(); | 247 DeAllocateVideoBuffers(); |
| 269 } | 248 } |
| 270 | 249 |
| 271 const VideoCaptureDevice::Name& VideoCaptureDeviceLinux::device_name() { | 250 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, |
| 272 return device_name_; | 251 int height, |
| 273 } | 252 int frame_rate, |
| 274 | 253 scoped_ptr<Client> client) { |
| 275 void VideoCaptureDeviceLinux::OnAllocate(int width, | |
| 276 int height, | |
| 277 int frame_rate, | |
| 278 Client* client) { | |
| 279 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 254 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 280 | 255 |
| 281 client_ = client; | 256 client_ = client.Pass(); |
| 282 | 257 |
| 283 // Need to open camera with O_RDWR after Linux kernel 3.3. | 258 // Need to open camera with O_RDWR after Linux kernel 3.3. |
| 284 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { | 259 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { |
| 285 SetErrorState("Failed to open V4L2 device driver."); | 260 SetErrorState("Failed to open V4L2 device driver."); |
| 286 return; | 261 return; |
| 287 } | 262 } |
| 288 | 263 |
| 289 // Test if this is a V4L2 capture device. | 264 // Test if this is a V4L2 capture device. |
| 290 v4l2_capability cap; | 265 v4l2_capability cap; |
| 291 if (!((ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) && | 266 if (!((ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) && |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 // Store our current width and height. | 336 // Store our current width and height. |
| 362 VideoCaptureCapability current_settings; | 337 VideoCaptureCapability current_settings; |
| 363 current_settings.color = V4l2ColorToVideoCaptureColorFormat( | 338 current_settings.color = V4l2ColorToVideoCaptureColorFormat( |
| 364 video_fmt.fmt.pix.pixelformat); | 339 video_fmt.fmt.pix.pixelformat); |
| 365 current_settings.width = video_fmt.fmt.pix.width; | 340 current_settings.width = video_fmt.fmt.pix.width; |
| 366 current_settings.height = video_fmt.fmt.pix.height; | 341 current_settings.height = video_fmt.fmt.pix.height; |
| 367 current_settings.frame_rate = frame_rate; | 342 current_settings.frame_rate = frame_rate; |
| 368 current_settings.expected_capture_delay = 0; | 343 current_settings.expected_capture_delay = 0; |
| 369 current_settings.interlaced = false; | 344 current_settings.interlaced = false; |
| 370 | 345 |
| 371 state_ = kAllocated; | |
| 372 // Report the resulting frame size to the client. | 346 // Report the resulting frame size to the client. |
| 373 client_->OnFrameInfo(current_settings); | 347 client_->OnFrameInfo(current_settings); |
| 374 } | |
| 375 | 348 |
| 376 void VideoCaptureDeviceLinux::OnDeAllocate() { | 349 // Start capturing. |
| 377 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | |
| 378 | |
| 379 // If we are in error state or capturing | |
| 380 // try to stop the camera. | |
| 381 if (state_ == kCapturing) { | |
| 382 OnStop(); | |
| 383 } | |
| 384 if (state_ == kAllocated) { | |
| 385 state_ = kIdle; | |
| 386 } | |
| 387 | |
| 388 // We need to close and open the device if we want to change the settings | |
| 389 // Otherwise VIDIOC_S_FMT will return error | |
| 390 // Sad but true. | |
| 391 close(device_fd_); | |
| 392 device_fd_ = -1; | |
| 393 } | |
| 394 | |
| 395 void VideoCaptureDeviceLinux::OnStart() { | |
| 396 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | |
| 397 | |
| 398 if (state_ != kAllocated) { | |
| 399 return; | |
| 400 } | |
| 401 | |
| 402 if (!AllocateVideoBuffers()) { | 350 if (!AllocateVideoBuffers()) { |
| 403 // Error, We can not recover. | 351 // Error, We can not recover. |
| 404 SetErrorState("Allocate buffer failed"); | 352 SetErrorState("Allocate buffer failed"); |
| 405 return; | 353 return; |
| 406 } | 354 } |
| 407 | 355 |
| 408 // Start UVC camera. | 356 // Start UVC camera. |
| 409 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 357 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 410 if (ioctl(device_fd_, VIDIOC_STREAMON, &type) == -1) { | 358 if (ioctl(device_fd_, VIDIOC_STREAMON, &type) == -1) { |
| 411 SetErrorState("VIDIOC_STREAMON failed"); | 359 SetErrorState("VIDIOC_STREAMON failed"); |
| 412 return; | 360 return; |
| 413 } | 361 } |
| 414 | 362 |
| 415 state_ = kCapturing; | 363 state_ = kCapturing; |
| 416 // Post task to start fetching frames from v4l2. | 364 // Post task to start fetching frames from v4l2. |
| 417 v4l2_thread_.message_loop()->PostTask( | 365 v4l2_thread_.message_loop()->PostTask( |
| 418 FROM_HERE, | 366 FROM_HERE, |
| 419 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 367 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
| 420 base::Unretained(this))); | 368 base::Unretained(this))); |
| 421 } | 369 } |
| 422 | 370 |
| 423 void VideoCaptureDeviceLinux::OnStop() { | 371 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { |
| 424 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 372 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 425 | 373 |
| 426 state_ = kAllocated; | |
| 427 | |
| 428 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 374 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 429 if (ioctl(device_fd_, VIDIOC_STREAMOFF, &type) < 0) { | 375 if (ioctl(device_fd_, VIDIOC_STREAMOFF, &type) < 0) { |
| 430 SetErrorState("VIDIOC_STREAMOFF failed"); | 376 SetErrorState("VIDIOC_STREAMOFF failed"); |
| 431 return; | 377 return; |
| 432 } | 378 } |
| 433 // We don't dare to deallocate the buffers if we can't stop | 379 // We don't dare to deallocate the buffers if we can't stop |
| 434 // the capture device. | 380 // the capture device. |
| 435 DeAllocateVideoBuffers(); | 381 DeAllocateVideoBuffers(); |
| 382 |
| 383 // We need to close and open the device if we want to change the settings |
| 384 // Otherwise VIDIOC_S_FMT will return error |
| 385 // Sad but true. |
| 386 close(device_fd_); |
| 387 device_fd_ = -1; |
| 388 state_ = kIdle; |
| 389 client_.reset(); |
| 436 } | 390 } |
| 437 | 391 |
| 438 void VideoCaptureDeviceLinux::OnCaptureTask() { | 392 void VideoCaptureDeviceLinux::OnCaptureTask() { |
| 439 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 393 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 440 | 394 |
| 441 if (state_ != kCapturing) { | 395 if (state_ != kCapturing) { |
| 442 return; | 396 return; |
| 443 } | 397 } |
| 444 | 398 |
| 445 fd_set r_set; | 399 fd_set r_set; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { | 528 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { |
| 575 SetErrorState("Failed to reset buf."); | 529 SetErrorState("Failed to reset buf."); |
| 576 } | 530 } |
| 577 | 531 |
| 578 delete [] buffer_pool_; | 532 delete [] buffer_pool_; |
| 579 buffer_pool_ = NULL; | 533 buffer_pool_ = NULL; |
| 580 buffer_pool_size_ = 0; | 534 buffer_pool_size_ = 0; |
| 581 } | 535 } |
| 582 | 536 |
| 583 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 537 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 538 DCHECK(!v4l2_thread_.IsRunning() || |
| 539 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
| 584 DVLOG(1) << reason; | 540 DVLOG(1) << reason; |
| 585 state_ = kError; | 541 state_ = kError; |
| 586 client_->OnError(); | 542 client_->OnError(); |
| 587 } | 543 } |
| 588 | 544 |
| 589 } // namespace media | 545 } // namespace media |
| OLD | NEW |