| 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 allow_using_dma_bufs) |
| 17 : V4L2CaptureDelegate( |
| 18 device_name, |
| 19 v4l2_task_runner, |
| 20 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| 21 allow_using_dma_bufs ? V4L2_MEMORY_DMABUF : V4L2_MEMORY_MMAP, |
| 22 #else |
| 23 V4L2_MEMORY_MMAP, |
| 24 #endif |
| 25 power_line_frequency) { |
| 26 } |
| 27 |
| 28 V4L2CaptureDelegateSinglePlane::~V4L2CaptureDelegateSinglePlane() { |
| 29 } |
| 30 |
| 11 scoped_refptr<V4L2CaptureDelegate::BufferTracker> | 31 scoped_refptr<V4L2CaptureDelegate::BufferTracker> |
| 12 V4L2CaptureDelegateSinglePlane::CreateBufferTracker() const { | 32 V4L2CaptureDelegateSinglePlane::CreateBufferTracker() const { |
| 13 return make_scoped_refptr(new BufferTrackerSPlane()); | 33 return make_scoped_refptr(new BufferTrackerSPlane()); |
| 14 } | 34 } |
| 15 | 35 |
| 16 bool V4L2CaptureDelegateSinglePlane::FillV4L2Format( | 36 bool V4L2CaptureDelegateSinglePlane::FillV4L2Format( |
| 17 v4l2_format* format, | 37 v4l2_format* format, |
| 18 uint32_t width, | 38 uint32_t width, |
| 19 uint32_t height, | 39 uint32_t height, |
| 20 uint32_t pixelformat_fourcc) const { | 40 uint32_t pixelformat_fourcc) const { |
| 21 format->fmt.pix.width = width; | 41 format->fmt.pix.width = width; |
| 22 format->fmt.pix.height = height; | 42 format->fmt.pix.height = height; |
| 23 format->fmt.pix.pixelformat = pixelformat_fourcc; | 43 format->fmt.pix.pixelformat = pixelformat_fourcc; |
| 24 return true; | 44 return true; |
| 25 } | 45 } |
| 26 | 46 |
| 27 void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2Buffer( | 47 void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2Buffer( |
| 28 v4l2_buffer* buffer) const { | 48 v4l2_buffer* buffer, |
| 49 bool for_enqueue) const { |
| 29 buffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 50 buffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 51 |
| 52 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| 53 if (memory_type() == V4L2_MEMORY_MMAP) |
| 54 return; |
| 55 |
| 56 if (!for_enqueue) { |
| 57 DCHECK_NE(buffer->m.fd, -1); // API should have filled |fd| in for dequeue. |
| 58 return; |
| 59 } |
| 60 // For enqueueing, need to reserve an output buffer, keep it locally and pass |
| 61 // its |fd| into the V4L2 API. |
| 62 scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer = |
| 63 client()->ReserveOutputBuffer(media::PIXEL_FORMAT_GPUMEMORYBUFFER, |
| 64 capture_format().frame_size); |
| 65 if (!capture_buffer) |
| 66 return; |
| 67 |
| 68 DCHECK_EQ(capture_buffer->GetType(), gfx::OZONE_NATIVE_BUFFER); |
| 69 buffer->m.fd = capture_buffer->AsPlatformFile(); |
| 70 |
| 71 allocated_buffers_.push_back(capture_buffer.release()); |
| 72 DVLOG(1) << "Sizeof allocated_buffers_ " << allocated_buffers_.size(); |
| 73 #endif |
| 30 } | 74 } |
| 31 | 75 |
| 32 void V4L2CaptureDelegateSinglePlane::SetPayloadSize( | 76 void V4L2CaptureDelegateSinglePlane::SetPayloadSize( |
| 33 const scoped_refptr<BufferTracker>& buffer_tracker, | 77 const scoped_refptr<BufferTracker>& buffer_tracker, |
| 34 const v4l2_buffer& buffer) const { | 78 const v4l2_buffer& buffer) const { |
| 35 buffer_tracker->SetPlanePayloadSize(0, buffer.bytesused); | 79 buffer_tracker->SetPlanePayloadSize(0, buffer.bytesused); |
| 36 } | 80 } |
| 37 | 81 |
| 38 void V4L2CaptureDelegateSinglePlane::SendBuffer( | 82 void V4L2CaptureDelegateSinglePlane::SendBuffer( |
| 39 const scoped_refptr<BufferTracker>& buffer_tracker, | 83 const scoped_refptr<BufferTracker>& buffer_tracker, |
| 40 const v4l2_format& format) const { | 84 const v4l2_format& format) const { |
| 41 client()->OnIncomingCapturedData( | 85 DVLOG(1) << __FUNCTION__; |
| 42 buffer_tracker->GetPlaneStart(0), | 86 |
| 43 buffer_tracker->GetPlanePayloadSize(0), | 87 if (memory_type() == V4L2_MEMORY_MMAP) { |
| 44 capture_format(), | 88 const size_t data_length = format.fmt.pix.sizeimage; |
| 45 rotation(), | 89 DCHECK_GE(data_length, capture_format().ImageAllocationSize()); |
| 46 base::TimeTicks::Now()); | 90 client()->OnIncomingCapturedData( |
| 91 buffer_tracker->GetPlaneStart(0), |
| 92 buffer_tracker->GetPlanePayloadSize(0), |
| 93 capture_format(), |
| 94 rotation(), |
| 95 base::TimeTicks::Now()); |
| 96 return; |
| 97 } |
| 98 |
| 99 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| 100 // Search for the |fd| used for capture in |allocated_buffers_| and send it |
| 101 // to client(). |
| 102 const int incoming_fd = buffer_tracker->GetPlaneFd(0); |
| 103 ScopedVector<VideoCaptureDevice::Client::Buffer>::iterator used_buffer = |
| 104 std::find_if(allocated_buffers_.begin(), allocated_buffers_.end(), |
| 105 [incoming_fd](VideoCaptureDevice::Client::Buffer* b) { |
| 106 return incoming_fd == b->AsPlatformFile(); |
| 107 }); |
| 108 CHECK(used_buffer != allocated_buffers_.end()) |
| 109 << "Uh oh, captured |fd| is not found in the list :?"; |
| 110 client()->OnIncomingCapturedBuffer(make_scoped_ptr(*used_buffer), |
| 111 capture_format(), base::TimeTicks::Now()); |
| 112 allocated_buffers_.weak_erase(used_buffer); |
| 113 #endif |
| 47 } | 114 } |
| 48 | 115 |
| 49 bool V4L2CaptureDelegateSinglePlane::BufferTrackerSPlane::Init( | 116 bool V4L2CaptureDelegateSinglePlane::BufferTrackerSPlane::Init( |
| 50 int fd, | 117 int fd, |
| 51 const v4l2_buffer& buffer) { | 118 const v4l2_buffer& buffer) { |
| 119 DVLOG(1) << __FUNCTION__; |
| 120 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| 121 if (buffer.memory == V4L2_MEMORY_DMABUF) { |
| 122 AddNonMmapedPlane(buffer.m.fd); |
| 123 return true; |
| 124 } |
| 125 #endif |
| 126 |
| 52 // Some devices require mmap() to be called with both READ and WRITE. | 127 // Some devices require mmap() to be called with both READ and WRITE. |
| 53 // See http://crbug.com/178582. | 128 // See http://crbug.com/178582. |
| 54 void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, | 129 void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, |
| 55 MAP_SHARED, fd, buffer.m.offset); | 130 MAP_SHARED, fd, buffer.m.offset); |
| 56 if (start == MAP_FAILED) { | 131 if (start == MAP_FAILED) { |
| 57 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; | 132 DLOG(ERROR) << "Error mmap()ing a V4L2 buffer into userspace"; |
| 58 return false; | 133 return false; |
| 59 } | 134 } |
| 60 AddMmapedPlane(static_cast<uint8_t*>(start), buffer.length); | 135 AddMmapedPlane(static_cast<uint8_t*>(start), buffer.length); |
| 61 return true; | 136 return true; |
| 62 } | 137 } |
| 63 | 138 |
| 64 } // namespace media | 139 } // namespace media |
| OLD | NEW |