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

Side by Side Diff: media/capture/video/linux/v4l2_capture_delegate.cc

Issue 2344123002: ImageCapture: Implement TakePhoto() for Linux/CrOs (Closed)
Patch Set: CaptureVideo TakePhoto() for Linux/CrOs: Removed logs and reorganized code slightly. Created 4 years, 3 months 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
OLDNEW
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/linux/video_capture_device_linux.h" 19 #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"
20 23
21 namespace media { 24 namespace media {
22 25
23 // Desired number of video buffers to allocate. The actual number of allocated 26 // Desired number of video buffers to allocate. The actual number of allocated
24 // buffers by v4l2 driver can be higher or lower than this number. 27 // buffers by v4l2 driver can be higher or lower than this number.
25 // kNumVideoBuffers should not be too small, or Chrome may not return enough 28 // kNumVideoBuffers should not be too small, or Chrome may not return enough
26 // buffers back to driver in time. 29 // buffers back to driver in time.
27 const uint32_t kNumVideoBuffers = 4; 30 const uint32_t kNumVideoBuffers = 4;
28 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. 31 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw.
29 // This value has been fine tuned. Before changing or modifying it see 32 // This value has been fine tuned. Before changing or modifying it see
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) 317 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
315 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0"); 318 SetErrorState(FROM_HERE, "Failed to VIDIOC_REQBUFS with count = 0");
316 319
317 // At this point we can close the device. 320 // At this point we can close the device.
318 // This is also needed for correctly changing settings later via VIDIOC_S_FMT. 321 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
319 device_fd_.reset(); 322 device_fd_.reset();
320 is_capturing_ = false; 323 is_capturing_ = false;
321 client_.reset(); 324 client_.reset();
322 } 325 }
323 326
327 void V4L2CaptureDelegate::TakePhoto(
328 VideoCaptureDevice::TakePhotoCallback callback) {
329 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
330 take_photo_callbacks_.push(std::move(callback));
331 }
332
324 void V4L2CaptureDelegate::SetRotation(int rotation) { 333 void V4L2CaptureDelegate::SetRotation(int rotation) {
325 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 334 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
326 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0); 335 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
327 rotation_ = rotation; 336 rotation_ = rotation;
328 } 337 }
329 338
330 V4L2CaptureDelegate::~V4L2CaptureDelegate() {} 339 V4L2CaptureDelegate::~V4L2CaptureDelegate() {}
331 340
332 bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) { 341 bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) {
333 v4l2_buffer buffer; 342 v4l2_buffer buffer;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 const scoped_refptr<BufferTracker>& buffer_tracker = 403 const scoped_refptr<BufferTracker>& buffer_tracker =
395 buffer_tracker_pool_[buffer.index]; 404 buffer_tracker_pool_[buffer.index];
396 405
397 base::TimeDelta timestamp = 406 base::TimeDelta timestamp =
398 base::TimeDelta::FromSeconds(buffer.timestamp.tv_sec) + 407 base::TimeDelta::FromSeconds(buffer.timestamp.tv_sec) +
399 base::TimeDelta::FromMicroseconds(buffer.timestamp.tv_usec); 408 base::TimeDelta::FromMicroseconds(buffer.timestamp.tv_usec);
400 client_->OnIncomingCapturedData( 409 client_->OnIncomingCapturedData(
401 buffer_tracker->start(), buffer_tracker->payload_size(), 410 buffer_tracker->start(), buffer_tracker->payload_size(),
402 capture_format_, rotation_, base::TimeTicks::Now(), timestamp); 411 capture_format_, rotation_, base::TimeTicks::Now(), timestamp);
403 412
413 while (!take_photo_callbacks_.empty()) {
414 VideoCaptureDevice::TakePhotoCallback cb =
415 std::move(take_photo_callbacks_.front());
416 take_photo_callbacks_.pop();
417
418 mojom::BlobPtr blob = GetPhotoBlob(buffer_tracker, buffer);
419 if (blob)
420 cb.Run(std::move(blob));
421 else
422 DLOG(ERROR) << "blob pointer is null.";
423 }
424
404 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { 425 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
405 SetErrorState(FROM_HERE, "Failed to enqueue capture buffer"); 426 SetErrorState(FROM_HERE, "Failed to enqueue capture buffer");
406 return; 427 return;
407 } 428 }
408 } 429 }
409 430
410 v4l2_task_runner_->PostTask( 431 v4l2_task_runner_->PostTask(
411 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); 432 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
412 } 433 }
413 434
435 mojom::BlobPtr V4L2CaptureDelegate::GetPhotoBlob(
436 const scoped_refptr<BufferTracker>& buffer_tracker,
437 const v4l2_buffer& buffer) {
438 uint32 src_format;
439 switch (capture_format_.pixel_format) {
440 case VideoPixelFormat::PIXEL_FORMAT_MJPEG: {
441 mojom::BlobPtr blob = mojom::Blob::New();
442 blob->data.resize(buffer.bytesused);
443 memcpy(blob->data.data(), buffer_tracker->start(), buffer.bytesused);
444 blob->mime_type = "image/jpeg";
445 return blob;
446 }
447 case VideoPixelFormat::PIXEL_FORMAT_UYVY:
448 src_format = libyuv::FOURCC_UYVY;
449 break;
450 case VideoPixelFormat::PIXEL_FORMAT_YUY2:
451 src_format = libyuv::FOURCC_YUY2;
452 break;
453 default:
mcasas 2016/09/16 18:59:15 I missed this one. It's a good practice to not use
454 DLOG(ERROR) << "FORMAT not supported."
455 << VideoPixelFormatToString(capture_format_.pixel_format);
456 return nullptr;
457 }
458
459 std::unique_ptr<uint8_t[]> dst_argb(new uint8_t[VideoFrame::AllocationSize(
460 PIXEL_FORMAT_ARGB, capture_format_.frame_size)]);
461 if (ConvertToARGB(buffer_tracker->start(), buffer.bytesused, dst_argb.get(),
462 capture_format_.frame_size.width() * 4, 0 /* crop_x_pos */,
463 0 /* crop_y_pos */, capture_format_.frame_size.width(),
464 capture_format_.frame_size.height(),
465 capture_format_.frame_size.width(),
466 capture_format_.frame_size.height(),
467 libyuv::RotationMode::kRotate0, src_format) != 0) {
468 return nullptr;
469 }
470
471 mojom::BlobPtr blob = mojom::Blob::New();
472 const gfx::PNGCodec::ColorFormat codec_color_format =
473 (kN32_SkColorType == kRGBA_8888_SkColorType) ? gfx::PNGCodec::FORMAT_RGBA
474 : gfx::PNGCodec::FORMAT_BGRA;
475 const bool result = gfx::PNGCodec::Encode(
476 dst_argb.get(), codec_color_format, capture_format_.frame_size,
477 capture_format_.frame_size.width() * 4, true /* discard_transparency */,
478 std::vector<gfx::PNGCodec::Comment>(), &blob->data);
479 DCHECK(result);
480
481 blob->mime_type = "image/png";
482 return blob;
483 }
484
414 void V4L2CaptureDelegate::SetErrorState( 485 void V4L2CaptureDelegate::SetErrorState(
415 const tracked_objects::Location& from_here, 486 const tracked_objects::Location& from_here,
416 const std::string& reason) { 487 const std::string& reason) {
417 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 488 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
418 is_capturing_ = false; 489 is_capturing_ = false;
419 client_->OnError(from_here, reason); 490 client_->OnError(from_here, reason);
420 } 491 }
421 492
422 V4L2CaptureDelegate::BufferTracker::BufferTracker() {} 493 V4L2CaptureDelegate::BufferTracker::BufferTracker() {}
423 494
(...skipping 14 matching lines...) Expand all
438 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; 509 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace";
439 return false; 510 return false;
440 } 511 }
441 start_ = static_cast<uint8_t*>(start); 512 start_ = static_cast<uint8_t*>(start);
442 length_ = buffer.length; 513 length_ = buffer.length;
443 payload_size_ = 0; 514 payload_size_ = 0;
444 return true; 515 return true;
445 } 516 }
446 517
447 } // namespace media 518 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/linux/v4l2_capture_delegate.h ('k') | media/capture/video/linux/video_capture_device_linux.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698