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 |