Chromium Code Reviews| 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/video/capture/linux/v4l2_capture_delegate_single_plane.h" | 5 #include "media/video/capture/linux/v4l2_capture_delegate_single_plane.h" |
| 6 | 6 |
| 7 #include <linux/version.h> | |
| 7 #include <sys/mman.h> | 8 #include <sys/mman.h> |
| 8 | 9 |
| 9 namespace media { | 10 namespace media { |
| 10 | 11 |
| 12 V4L2CaptureDelegateSinglePlane::V4L2CaptureDelegateSinglePlane( | |
| 13 const VideoCaptureDevice::Name& device_name, | |
| 14 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, | |
| 15 int power_line_frequency, | |
| 16 bool try_to_use_dma_buf) | |
| 17 : V4L2CaptureDelegate(device_name, v4l2_task_runner, power_line_frequency) { | |
| 18 memory_type_ = V4L2_MEMORY_MMAP; | |
| 19 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) | |
| 20 if (try_to_use_dma_buf) | |
| 21 memory_type_ = V4L2_MEMORY_DMABUF; | |
| 22 #endif | |
| 23 } | |
| 24 | |
| 25 V4L2CaptureDelegateSinglePlane::~V4L2CaptureDelegateSinglePlane() { | |
| 26 } | |
| 27 | |
| 11 scoped_refptr<V4L2CaptureDelegate::BufferTracker> | 28 scoped_refptr<V4L2CaptureDelegate::BufferTracker> |
| 12 V4L2CaptureDelegateSinglePlane::CreateBufferTracker() const { | 29 V4L2CaptureDelegateSinglePlane::CreateBufferTracker() const { |
| 13 return make_scoped_refptr(new BufferTrackerSPlane()); | 30 return make_scoped_refptr(new BufferTrackerSPlane()); |
| 14 } | 31 } |
| 15 | 32 |
| 16 bool V4L2CaptureDelegateSinglePlane::FillV4L2Format( | 33 bool V4L2CaptureDelegateSinglePlane::FillV4L2Format( |
| 17 v4l2_format* format, | 34 v4l2_format* format, |
| 18 uint32_t width, | 35 uint32_t width, |
| 19 uint32_t height, | 36 uint32_t height, |
| 20 uint32_t pixelformat_fourcc) const { | 37 uint32_t pixelformat_fourcc) const { |
| 21 format->fmt.pix.width = width; | 38 format->fmt.pix.width = width; |
| 22 format->fmt.pix.height = height; | 39 format->fmt.pix.height = height; |
| 23 format->fmt.pix.pixelformat = pixelformat_fourcc; | 40 format->fmt.pix.pixelformat = pixelformat_fourcc; |
| 24 return true; | 41 return true; |
| 25 } | 42 } |
| 26 | 43 |
| 27 void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2Buffer( | 44 void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2Buffer( |
| 28 v4l2_buffer* buffer) const { | 45 v4l2_buffer* buffer, |
| 46 bool for_enqueue) const { | |
| 47 buffer->memory = memory_type_; | |
| 29 buffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 48 buffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 49 | |
| 50 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) | |
| 51 if (memory_type_ == V4L2_MEMORY_MMAP) | |
| 52 return; | |
| 53 | |
| 54 if (!for_enqueue) { | |
| 55 DCHECK(buffer->m.fd); // For Dequeue, API should have filled |fd| in. | |
|
Pawel Osciak
2015/06/15 10:34:55
We call this before calling DQBUF, so it couldn't
mcasas
2015/06/17 01:30:53
First time this method is called, it's with
|for_
| |
| 56 return; | |
| 57 } | |
| 58 // For enqueueing, need to reserve an output buffer, keep it locally and pass | |
| 59 // its |fd| into the V4L2 API. | |
| 60 scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer = | |
|
Pawel Osciak
2015/06/15 10:34:55
Do we need to allocate buffers on each QBUF? Could
mcasas
2015/06/17 01:30:53
We don't allocate a Buffers on each QBUF, we
Rese
| |
| 61 client()->ReserveOutputBuffer(media::PIXEL_FORMAT_GPUMEMORYBUFFER, | |
| 62 capture_format().frame_size); | |
| 63 if (capture_buffer && capture_buffer->GetType() == gfx::OZONE_NATIVE_BUFFER) { | |
| 64 buffer->m.fd = capture_buffer->AsPlatformFile(); | |
| 65 | |
| 66 allocated_buffers_.push_back(capture_buffer.release()); | |
| 67 DVLOG(1) << "Sizeof allocated_buffers_ " << allocated_buffers_.size(); | |
| 68 } else { | |
| 69 DLOG(WARNING) << "Uh oh, platform does not support Dma-Buf allocation, " | |
|
Pawel Osciak
2015/06/15 10:34:55
We should propagate errors and SetErrorState() in
mcasas
2015/06/17 01:30:53
This is a Warning, and it was meant to be to help
| |
| 70 << "or has run out of buffers :-?"; | |
| 71 } | |
| 72 #endif | |
| 30 } | 73 } |
| 31 | 74 |
| 32 void V4L2CaptureDelegateSinglePlane::SetPayloadSize( | 75 void V4L2CaptureDelegateSinglePlane::SetPayloadSize( |
| 33 const scoped_refptr<BufferTracker>& buffer_tracker, | 76 const scoped_refptr<BufferTracker>& buffer_tracker, |
| 34 const v4l2_buffer& buffer) const { | 77 const v4l2_buffer& buffer) const { |
| 35 buffer_tracker->SetPlanePayloadSize(0, buffer.bytesused); | 78 buffer_tracker->SetPlanePayloadSize(0, buffer.bytesused); |
| 36 } | 79 } |
| 37 | 80 |
| 81 void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2RequestBuffers( | |
| 82 v4l2_requestbuffers* request) const { | |
| 83 request->memory = memory_type_; | |
| 84 } | |
| 85 | |
| 38 void V4L2CaptureDelegateSinglePlane::SendBuffer( | 86 void V4L2CaptureDelegateSinglePlane::SendBuffer( |
| 39 const scoped_refptr<BufferTracker>& buffer_tracker, | 87 const scoped_refptr<BufferTracker>& buffer_tracker, |
| 40 const v4l2_format& format) const { | 88 const v4l2_format& format) const { |
| 41 client()->OnIncomingCapturedData( | 89 DVLOG(1) << __FUNCTION__; |
| 42 buffer_tracker->GetPlaneStart(0), | 90 |
| 91 if (memory_type_ == V4L2_MEMORY_MMAP) { | |
| 92 const size_t data_length = format.fmt.pix.sizeimage; | |
| 93 DCHECK_GE(data_length, capture_format().ImageAllocationSize()); | |
| 94 client()->OnIncomingCapturedData( | |
| 95 buffer_tracker->GetPlaneStart(0), | |
| 43 buffer_tracker->GetPlanePayloadSize(0), | 96 buffer_tracker->GetPlanePayloadSize(0), |
| 44 capture_format(), | 97 capture_format(), |
| 45 rotation(), | 98 rotation(), |
| 46 base::TimeTicks::Now()); | 99 base::TimeTicks::Now()); |
| 100 return; | |
| 101 } | |
| 102 | |
| 103 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) | |
| 104 // Search for the |fd| used for capture in |allocated_buffers_| and send it | |
| 105 // to client() if found. Otherwise is an error. | |
| 106 const int incoming_fd = buffer_tracker->GetFd(0); | |
| 107 ScopedVector<VideoCaptureDevice::Client::Buffer>::iterator used_buffer = | |
| 108 std::find_if(allocated_buffers_.begin(), allocated_buffers_.end(), | |
| 109 [incoming_fd](const VideoCaptureDevice::Client::Buffer* b) { | |
|
Pawel Osciak
2015/06/15 10:34:55
const Buffer& possible?
mcasas
2015/06/17 01:30:53
ScopedVector keeps pointers, from which you can
ma
| |
| 110 return incoming_fd == b->AsPlatformFile(); | |
| 111 }); | |
| 112 if (used_buffer == allocated_buffers_.end()) { | |
| 113 DLOG(ERROR) << "Uh oh, captured |fd| is not found in the list :?"; | |
| 114 return; | |
|
Pawel Osciak
2015/06/15 10:34:55
Need to propagate the error.
mcasas
2015/06/17 01:30:53
Same as before, this was meant to be for
helping
| |
| 115 } | |
| 116 client()->OnIncomingCapturedBuffer(make_scoped_ptr(*used_buffer), | |
| 117 capture_format(), base::TimeTicks::Now()); | |
| 118 allocated_buffers_.weak_erase(used_buffer); | |
|
Pawel Osciak
2015/06/15 10:34:55
Perhaps we could use std::vector<scoped_refptr<>>
mcasas
2015/06/17 01:30:53
I wish! ReserveOutputBuffer() returns a scoped_ptr
| |
| 119 #endif | |
| 47 } | 120 } |
| 48 | 121 |
| 49 bool V4L2CaptureDelegateSinglePlane::BufferTrackerSPlane::Init( | 122 bool V4L2CaptureDelegateSinglePlane::BufferTrackerSPlane::Init( |
| 50 int fd, | 123 int fd, |
| 51 const v4l2_buffer& buffer) { | 124 const v4l2_buffer& buffer) { |
| 125 DVLOG(1) << __FUNCTION__; | |
| 126 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) | |
| 127 if (buffer.memory == V4L2_MEMORY_DMABUF) { | |
| 128 AddNonMmapedPlane(buffer.m.fd); | |
|
Pawel Osciak
2015/06/15 10:34:55
Would it be possible to have one AddPlane() method
mcasas
2015/06/17 01:30:53
Wouldn't it move this ifdef somewhere else, and
fo
| |
| 129 return true; | |
| 130 } | |
| 131 #endif | |
| 132 | |
| 52 // Some devices require mmap() to be called with both READ and WRITE. | 133 // Some devices require mmap() to be called with both READ and WRITE. |
| 53 // See http://crbug.com/178582. | 134 // See http://crbug.com/178582. |
| 54 void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, | 135 void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, |
| 55 MAP_SHARED, fd, buffer.m.offset); | 136 MAP_SHARED, fd, buffer.m.offset); |
| 56 if (start == MAP_FAILED) { | 137 if (start == MAP_FAILED) { |
| 57 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; | 138 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; |
| 58 return false; | 139 return false; |
| 59 } | 140 } |
| 60 AddMmapedPlane(static_cast<uint8_t*>(start), buffer.length); | 141 AddMmapedPlane(static_cast<uint8_t*>(start), buffer.length); |
| 61 return true; | 142 return true; |
| 62 } | 143 } |
| 63 | 144 |
| 64 } // namespace media | 145 } // namespace media |
| OLD | NEW |