| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/capture/video/linux/v4l2_capture_delegate.h" | 5 #include "media/capture/video/linux/v4l2_capture_delegate.h" |
| 6 | 6 |
| 7 #include <poll.h> | 7 #include <poll.h> |
| 8 #include <sys/fcntl.h> | 8 #include <sys/fcntl.h> |
| 9 #include <sys/ioctl.h> | 9 #include <sys/ioctl.h> |
| 10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
| 15 #include "base/posix/eintr_wrapper.h" | 15 #include "base/posix/eintr_wrapper.h" |
| 16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 18 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
| 19 #include "media/capture/video/blob_utils.h" |
| 19 #include "media/capture/video/linux/video_capture_device_linux.h" | 20 #include "media/capture/video/linux/video_capture_device_linux.h" |
| 20 #include "third_party/libyuv/include/libyuv.h" | |
| 21 #include "third_party/skia/include/core/SkImage.h" | |
| 22 #include "ui/gfx/codec/png_codec.h" | |
| 23 | 21 |
| 24 namespace media { | 22 namespace media { |
| 25 | 23 |
| 26 // Desired number of video buffers to allocate. The actual number of allocated | 24 // Desired number of video buffers to allocate. The actual number of allocated |
| 27 // buffers by v4l2 driver can be higher or lower than this number. | 25 // buffers by v4l2 driver can be higher or lower than this number. |
| 28 // kNumVideoBuffers should not be too small, or Chrome may not return enough | 26 // kNumVideoBuffers should not be too small, or Chrome may not return enough |
| 29 // buffers back to driver in time. | 27 // buffers back to driver in time. |
| 30 const uint32_t kNumVideoBuffers = 4; | 28 const uint32_t kNumVideoBuffers = 4; |
| 31 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. | 29 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. |
| 32 // This value has been fine tuned. Before changing or modifying it see | 30 // This value has been fine tuned. Before changing or modifying it see |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 base::TimeDelta::FromMicroseconds(buffer.timestamp.tv_usec); | 406 base::TimeDelta::FromMicroseconds(buffer.timestamp.tv_usec); |
| 409 client_->OnIncomingCapturedData( | 407 client_->OnIncomingCapturedData( |
| 410 buffer_tracker->start(), buffer_tracker->payload_size(), | 408 buffer_tracker->start(), buffer_tracker->payload_size(), |
| 411 capture_format_, rotation_, base::TimeTicks::Now(), timestamp); | 409 capture_format_, rotation_, base::TimeTicks::Now(), timestamp); |
| 412 | 410 |
| 413 while (!take_photo_callbacks_.empty()) { | 411 while (!take_photo_callbacks_.empty()) { |
| 414 VideoCaptureDevice::TakePhotoCallback cb = | 412 VideoCaptureDevice::TakePhotoCallback cb = |
| 415 std::move(take_photo_callbacks_.front()); | 413 std::move(take_photo_callbacks_.front()); |
| 416 take_photo_callbacks_.pop(); | 414 take_photo_callbacks_.pop(); |
| 417 | 415 |
| 418 mojom::BlobPtr blob = GetPhotoBlob(buffer_tracker, buffer.bytesused); | 416 mojom::BlobPtr blob = |
| 417 Blobify(buffer_tracker->start(), buffer.bytesused, capture_format_); |
| 419 if (blob) | 418 if (blob) |
| 420 cb.Run(std::move(blob)); | 419 cb.Run(std::move(blob)); |
| 421 } | 420 } |
| 422 | 421 |
| 423 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { | 422 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { |
| 424 SetErrorState(FROM_HERE, "Failed to enqueue capture buffer"); | 423 SetErrorState(FROM_HERE, "Failed to enqueue capture buffer"); |
| 425 return; | 424 return; |
| 426 } | 425 } |
| 427 } | 426 } |
| 428 | 427 |
| 429 v4l2_task_runner_->PostTask( | 428 v4l2_task_runner_->PostTask( |
| 430 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); | 429 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); |
| 431 } | 430 } |
| 432 | 431 |
| 433 mojom::BlobPtr V4L2CaptureDelegate::GetPhotoBlob( | |
| 434 const scoped_refptr<BufferTracker>& buffer_tracker, | |
| 435 const uint32_t bytesused) { | |
| 436 uint32 src_format; | |
| 437 | |
| 438 if (capture_format_.pixel_format == VideoPixelFormat::PIXEL_FORMAT_MJPEG) { | |
| 439 mojom::BlobPtr blob = mojom::Blob::New(); | |
| 440 blob->data.resize(bytesused); | |
| 441 memcpy(blob->data.data(), buffer_tracker->start(), bytesused); | |
| 442 blob->mime_type = "image/jpeg"; | |
| 443 return blob; | |
| 444 } else if (capture_format_.pixel_format == | |
| 445 VideoPixelFormat::PIXEL_FORMAT_UYVY) { | |
| 446 src_format = libyuv::FOURCC_UYVY; | |
| 447 } else if (capture_format_.pixel_format == | |
| 448 VideoPixelFormat::PIXEL_FORMAT_YUY2) { | |
| 449 src_format = libyuv::FOURCC_YUY2; | |
| 450 } else if (capture_format_.pixel_format == | |
| 451 VideoPixelFormat::PIXEL_FORMAT_I420) { | |
| 452 src_format = libyuv::FOURCC_I420; | |
| 453 } else if (capture_format_.pixel_format == | |
| 454 VideoPixelFormat::PIXEL_FORMAT_RGB24) { | |
| 455 src_format = libyuv::FOURCC_24BG; | |
| 456 } else { | |
| 457 return nullptr; | |
| 458 } | |
| 459 | |
| 460 std::unique_ptr<uint8_t[]> dst_argb(new uint8_t[VideoFrame::AllocationSize( | |
| 461 PIXEL_FORMAT_ARGB, capture_format_.frame_size)]); | |
| 462 if (ConvertToARGB(buffer_tracker->start(), bytesused, dst_argb.get(), | |
| 463 capture_format_.frame_size.width() * 4, 0 /* crop_x_pos */, | |
| 464 0 /* crop_y_pos */, capture_format_.frame_size.width(), | |
| 465 capture_format_.frame_size.height(), | |
| 466 capture_format_.frame_size.width(), | |
| 467 capture_format_.frame_size.height(), | |
| 468 libyuv::RotationMode::kRotate0, src_format) != 0) { | |
| 469 return nullptr; | |
| 470 } | |
| 471 | |
| 472 mojom::BlobPtr blob = mojom::Blob::New(); | |
| 473 const gfx::PNGCodec::ColorFormat codec_color_format = | |
| 474 (kN32_SkColorType == kRGBA_8888_SkColorType) ? gfx::PNGCodec::FORMAT_RGBA | |
| 475 : gfx::PNGCodec::FORMAT_BGRA; | |
| 476 const bool result = gfx::PNGCodec::Encode( | |
| 477 dst_argb.get(), codec_color_format, capture_format_.frame_size, | |
| 478 capture_format_.frame_size.width() * 4, true /* discard_transparency */, | |
| 479 std::vector<gfx::PNGCodec::Comment>(), &blob->data); | |
| 480 DCHECK(result); | |
| 481 | |
| 482 blob->mime_type = "image/png"; | |
| 483 return blob; | |
| 484 } | |
| 485 | |
| 486 void V4L2CaptureDelegate::SetErrorState( | 432 void V4L2CaptureDelegate::SetErrorState( |
| 487 const tracked_objects::Location& from_here, | 433 const tracked_objects::Location& from_here, |
| 488 const std::string& reason) { | 434 const std::string& reason) { |
| 489 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); | 435 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); |
| 490 is_capturing_ = false; | 436 is_capturing_ = false; |
| 491 client_->OnError(from_here, reason); | 437 client_->OnError(from_here, reason); |
| 492 } | 438 } |
| 493 | 439 |
| 494 V4L2CaptureDelegate::BufferTracker::BufferTracker() {} | 440 V4L2CaptureDelegate::BufferTracker::BufferTracker() {} |
| 495 | 441 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 510 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; | 456 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; |
| 511 return false; | 457 return false; |
| 512 } | 458 } |
| 513 start_ = static_cast<uint8_t*>(start); | 459 start_ = static_cast<uint8_t*>(start); |
| 514 length_ = buffer.length; | 460 length_ = buffer.length; |
| 515 payload_size_ = 0; | 461 payload_size_ = 0; |
| 516 return true; | 462 return true; |
| 517 } | 463 } |
| 518 | 464 |
| 519 } // namespace media | 465 } // namespace media |
| OLD | NEW |