Chromium Code Reviews| Index: media/video/capture/linux/v4l2_capture_delegate_single_plane.cc |
| diff --git a/media/video/capture/linux/v4l2_capture_delegate_single_plane.cc b/media/video/capture/linux/v4l2_capture_delegate_single_plane.cc |
| index e2e7e5b0da16a9c4b934b83bdfa567a1f1ab39d6..b650ba34c8006578902486a82fc196f70a7c1eb3 100644 |
| --- a/media/video/capture/linux/v4l2_capture_delegate_single_plane.cc |
| +++ b/media/video/capture/linux/v4l2_capture_delegate_single_plane.cc |
| @@ -4,10 +4,27 @@ |
| #include "media/video/capture/linux/v4l2_capture_delegate_single_plane.h" |
| +#include <linux/version.h> |
| #include <sys/mman.h> |
| namespace media { |
| +V4L2CaptureDelegateSinglePlane::V4L2CaptureDelegateSinglePlane( |
| + const VideoCaptureDevice::Name& device_name, |
| + const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, |
| + int power_line_frequency, |
| + bool try_to_use_dma_buf) |
| + : V4L2CaptureDelegate(device_name, v4l2_task_runner, power_line_frequency) { |
| + memory_type_ = V4L2_MEMORY_MMAP; |
| +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| + if (try_to_use_dma_buf) |
| + memory_type_ = V4L2_MEMORY_DMABUF; |
| +#endif |
| +} |
| + |
| +V4L2CaptureDelegateSinglePlane::~V4L2CaptureDelegateSinglePlane() { |
| +} |
| + |
| scoped_refptr<V4L2CaptureDelegate::BufferTracker> |
| V4L2CaptureDelegateSinglePlane::CreateBufferTracker() const { |
| return make_scoped_refptr(new BufferTrackerSPlane()); |
| @@ -25,8 +42,34 @@ bool V4L2CaptureDelegateSinglePlane::FillV4L2Format( |
| } |
| void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2Buffer( |
| - v4l2_buffer* buffer) const { |
| + v4l2_buffer* buffer, |
| + bool for_enqueue) const { |
| + buffer->memory = memory_type_; |
| buffer->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| + |
| +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| + if (memory_type_ == V4L2_MEMORY_MMAP) |
| + return; |
| + |
| + if (!for_enqueue) { |
| + 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_
|
| + return; |
| + } |
| + // For enqueueing, need to reserve an output buffer, keep it locally and pass |
| + // its |fd| into the V4L2 API. |
| + 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
|
| + client()->ReserveOutputBuffer(media::PIXEL_FORMAT_GPUMEMORYBUFFER, |
| + capture_format().frame_size); |
| + if (capture_buffer && capture_buffer->GetType() == gfx::OZONE_NATIVE_BUFFER) { |
| + buffer->m.fd = capture_buffer->AsPlatformFile(); |
| + |
| + allocated_buffers_.push_back(capture_buffer.release()); |
| + DVLOG(1) << "Sizeof allocated_buffers_ " << allocated_buffers_.size(); |
| + } else { |
| + 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
|
| + << "or has run out of buffers :-?"; |
| + } |
| +#endif |
| } |
| void V4L2CaptureDelegateSinglePlane::SetPayloadSize( |
| @@ -35,20 +78,58 @@ void V4L2CaptureDelegateSinglePlane::SetPayloadSize( |
| buffer_tracker->SetPlanePayloadSize(0, buffer.bytesused); |
| } |
| +void V4L2CaptureDelegateSinglePlane::FinishFillingV4L2RequestBuffers( |
| + v4l2_requestbuffers* request) const { |
| + request->memory = memory_type_; |
| +} |
| + |
| void V4L2CaptureDelegateSinglePlane::SendBuffer( |
| const scoped_refptr<BufferTracker>& buffer_tracker, |
| const v4l2_format& format) const { |
| - client()->OnIncomingCapturedData( |
| - buffer_tracker->GetPlaneStart(0), |
| + DVLOG(1) << __FUNCTION__; |
| + |
| + if (memory_type_ == V4L2_MEMORY_MMAP) { |
| + const size_t data_length = format.fmt.pix.sizeimage; |
| + DCHECK_GE(data_length, capture_format().ImageAllocationSize()); |
| + client()->OnIncomingCapturedData( |
| + buffer_tracker->GetPlaneStart(0), |
| buffer_tracker->GetPlanePayloadSize(0), |
| - capture_format(), |
| - rotation(), |
| - base::TimeTicks::Now()); |
| + capture_format(), |
| + rotation(), |
| + base::TimeTicks::Now()); |
| + return; |
| + } |
| + |
| +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| + // Search for the |fd| used for capture in |allocated_buffers_| and send it |
| + // to client() if found. Otherwise is an error. |
| + const int incoming_fd = buffer_tracker->GetFd(0); |
| + ScopedVector<VideoCaptureDevice::Client::Buffer>::iterator used_buffer = |
| + std::find_if(allocated_buffers_.begin(), allocated_buffers_.end(), |
| + [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
|
| + return incoming_fd == b->AsPlatformFile(); |
| + }); |
| + if (used_buffer == allocated_buffers_.end()) { |
| + DLOG(ERROR) << "Uh oh, captured |fd| is not found in the list :?"; |
| + 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
|
| + } |
| + client()->OnIncomingCapturedBuffer(make_scoped_ptr(*used_buffer), |
| + capture_format(), base::TimeTicks::Now()); |
| + 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
|
| +#endif |
| } |
| bool V4L2CaptureDelegateSinglePlane::BufferTrackerSPlane::Init( |
| int fd, |
| const v4l2_buffer& buffer) { |
| + DVLOG(1) << __FUNCTION__; |
| +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| + if (buffer.memory == V4L2_MEMORY_DMABUF) { |
| + 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
|
| + return true; |
| + } |
| +#endif |
| + |
| // Some devices require mmap() to be called with both READ and WRITE. |
| // See http://crbug.com/178582. |
| void* const start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, |