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

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

Issue 1124723006: VideoCaptureDeviceLinux: Add support for SPLANE+DMABUF V4L2 type capture (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: posciak@ review and rebase (AsPlatformFile(), ...BufferPoolUtilization...)). Created 5 years, 6 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/video/capture/linux/v4l2_capture_delegate.h" 5 #include "media/video/capture/linux/v4l2_capture_delegate.h"
6 6
7 #include <linux/version.h>
7 #include <poll.h> 8 #include <poll.h>
8 #include <sys/fcntl.h> 9 #include <sys/fcntl.h>
9 #include <sys/ioctl.h> 10 #include <sys/ioctl.h>
10 #include <sys/mman.h> 11 #include <sys/mman.h>
11 12
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/files/file_enumerator.h" 14 #include "base/files/file_enumerator.h"
14 #include "base/posix/eintr_wrapper.h" 15 #include "base/posix/eintr_wrapper.h"
15 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
16 #include "media/base/bind_to_current_loop.h" 17 #include "media/base/bind_to_current_loop.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 // MJPEG is usually sitting fairly low since we don't want to have to decode. 54 // MJPEG is usually sitting fairly low since we don't want to have to decode.
54 // However, is needed for large resolutions due to USB bandwidth limitations, 55 // However, is needed for large resolutions due to USB bandwidth limitations,
55 // so GetListOfUsableFourCcs() can duplicate it on top, see that method. 56 // so GetListOfUsableFourCcs() can duplicate it on top, see that method.
56 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG, 1}, 57 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG, 1},
57 // JPEG works as MJPEG on some gspca webcams from field reports, see 58 // JPEG works as MJPEG on some gspca webcams from field reports, see
58 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the least 59 // https://code.google.com/p/webrtc/issues/detail?id=529, put it as the least
59 // preferred format. 60 // preferred format.
60 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG, 1}, 61 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG, 1},
61 }; 62 };
62 63
64 // This function investigates if the driver supports Dma-Buf. Such capacity is
65 // not present in non-Ozone platforms nor for certain kernel versions.
66 static bool IsDmaBufCaptureSupported(const std::string& device_name,
67 v4l2_buf_type buf_type) {
68 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) || !defined(USE_OZONE)
69 return false;
70 #else
71 const base::ScopedFD fd(HANDLE_EINTR(open(device_name.c_str(), O_RDONLY)));
72 if (!fd.is_valid()) {
73 return false;
74 }
75 // Check if the V4L2 device supports Dma Buf capture.
76 v4l2_requestbuffers r_buffer = {};
77 r_buffer.type = buf_type;
78 r_buffer.memory = V4L2_MEMORY_DMABUF;
79 r_buffer.count = 1u;
80 if (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
81 return false;
82 return true;
83 #endif
84 }
85
63 // static 86 // static
64 scoped_refptr<V4L2CaptureDelegate> 87 scoped_refptr<V4L2CaptureDelegate>
65 V4L2CaptureDelegate::CreateV4L2CaptureDelegate( 88 V4L2CaptureDelegate::CreateV4L2CaptureDelegate(
66 const VideoCaptureDevice::Name& device_name, 89 const VideoCaptureDevice::Name& device_name,
67 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, 90 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner,
91 VideoCaptureDevice::Client* client,
92 bool allow_using_dma_bufs,
68 int power_line_frequency) { 93 int power_line_frequency) {
69 switch (device_name.capture_api_type()) { 94 switch (device_name.capture_api_type()) {
70 case VideoCaptureDevice::Name::V4L2_SINGLE_PLANE: 95 case VideoCaptureDevice::Name::V4L2_SINGLE_PLANE:
71 return make_scoped_refptr(new V4L2CaptureDelegateSinglePlane( 96 return make_scoped_refptr(new V4L2CaptureDelegateSinglePlane(
72 device_name, v4l2_task_runner, power_line_frequency)); 97 device_name, v4l2_task_runner,
98 power_line_frequency,
99 allow_using_dma_bufs &&
100 IsDmaBufCaptureSupported(device_name.id(),
101 V4L2_BUF_TYPE_VIDEO_CAPTURE)));
73 case VideoCaptureDevice::Name::V4L2_MULTI_PLANE: 102 case VideoCaptureDevice::Name::V4L2_MULTI_PLANE:
74 #if !defined(OS_OPENBSD) 103 #if !defined(OS_OPENBSD)
75 return make_scoped_refptr(new V4L2CaptureDelegateMultiPlane( 104 return make_scoped_refptr(new V4L2CaptureDelegateMultiPlane(
76 device_name, v4l2_task_runner, power_line_frequency)); 105 device_name, v4l2_task_runner, power_line_frequency));
77 default: 106 default:
78 #endif 107 #endif
79 NOTIMPLEMENTED() << "Unknown V4L2 capture API type"; 108 NOTIMPLEMENTED() << "Unknown V4L2 capture API type";
80 return scoped_refptr<V4L2CaptureDelegate>(); 109 return scoped_refptr<V4L2CaptureDelegate>();
81 } 110 }
82 } 111 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 for (const auto& plane : planes_) { 160 for (const auto& plane : planes_) {
132 if (plane.start == nullptr) 161 if (plane.start == nullptr)
133 continue; 162 continue;
134 const int result = munmap(plane.start, plane.length); 163 const int result = munmap(plane.start, plane.length);
135 PLOG_IF(ERROR, result < 0) << "Error munmap()ing V4L2 buffer"; 164 PLOG_IF(ERROR, result < 0) << "Error munmap()ing V4L2 buffer";
136 } 165 }
137 } 166 }
138 167
139 void V4L2CaptureDelegate::BufferTracker::AddMmapedPlane(uint8_t* const start, 168 void V4L2CaptureDelegate::BufferTracker::AddMmapedPlane(uint8_t* const start,
140 size_t length) { 169 size_t length) {
141 Plane plane; 170 Plane plane = {};
142 plane.start = start; 171 plane.start = start;
143 plane.length = length; 172 plane.length = length;
144 plane.payload_size = 0; 173 plane.payload_size = 0;
174 plane.fd = -1;
175 planes_.push_back(plane);
176 }
177
178 void V4L2CaptureDelegate::BufferTracker::AddNonMmapedPlane(int fd) {
179 Plane plane = {};
180 plane.fd = fd;
145 planes_.push_back(plane); 181 planes_.push_back(plane);
146 } 182 }
147 183
148 V4L2CaptureDelegate::V4L2CaptureDelegate( 184 V4L2CaptureDelegate::V4L2CaptureDelegate(
149 const VideoCaptureDevice::Name& device_name, 185 const VideoCaptureDevice::Name& device_name,
150 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner, 186 const scoped_refptr<base::SingleThreadTaskRunner>& v4l2_task_runner,
187 v4l2_memory memory_type,
151 int power_line_frequency) 188 int power_line_frequency)
152 : capture_type_((device_name.capture_api_type() == 189 : capture_type_((device_name.capture_api_type() ==
153 VideoCaptureDevice::Name::V4L2_SINGLE_PLANE) 190 VideoCaptureDevice::Name::V4L2_SINGLE_PLANE)
154 ? V4L2_BUF_TYPE_VIDEO_CAPTURE 191 ? V4L2_BUF_TYPE_VIDEO_CAPTURE
155 : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE), 192 : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE),
156 v4l2_task_runner_(v4l2_task_runner), 193 v4l2_task_runner_(v4l2_task_runner),
157 device_name_(device_name), 194 device_name_(device_name),
158 power_line_frequency_(power_line_frequency), 195 power_line_frequency_(power_line_frequency),
196 memory_type_(memory_type),
159 is_capturing_(false), 197 is_capturing_(false),
160 timeout_count_(0), 198 timeout_count_(0),
161 rotation_(0) { 199 rotation_(0) {
162 } 200 }
163 201
164 V4L2CaptureDelegate::~V4L2CaptureDelegate() { 202 V4L2CaptureDelegate::~V4L2CaptureDelegate() {
165 } 203 }
166 204
167 void V4L2CaptureDelegate::AllocateAndStart( 205 void V4L2CaptureDelegate::AllocateAndStart(
168 int width, 206 int width,
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 DVLOG(1) << "Error setting power line frequency removal"; 306 DVLOG(1) << "Error setting power line frequency removal";
269 } 307 }
270 308
271 capture_format_.frame_size.SetSize(video_fmt_.fmt.pix.width, 309 capture_format_.frame_size.SetSize(video_fmt_.fmt.pix.width,
272 video_fmt_.fmt.pix.height); 310 video_fmt_.fmt.pix.height);
273 capture_format_.frame_rate = frame_rate; 311 capture_format_.frame_rate = frame_rate;
274 capture_format_.pixel_format = pixel_format; 312 capture_format_.pixel_format = pixel_format;
275 313
276 v4l2_requestbuffers r_buffer = {}; 314 v4l2_requestbuffers r_buffer = {};
277 r_buffer.type = capture_type_; 315 r_buffer.type = capture_type_;
278 r_buffer.memory = V4L2_MEMORY_MMAP;
279 r_buffer.count = kNumVideoBuffers; 316 r_buffer.count = kNumVideoBuffers;
317 r_buffer.memory = memory_type();
280 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) { 318 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
281 SetErrorState("Error requesting MMAP buffers from V4L2"); 319 SetErrorState("Error requesting buffers from V4L2");
282 return; 320 return;
283 } 321 }
284 for (unsigned int i = 0; i < r_buffer.count; ++i) { 322 for (unsigned int i = 0; i < r_buffer.count; ++i) {
285 if (!MapAndQueueBuffer(i)) { 323 if (!MapAndQueueBuffer(i)) {
286 SetErrorState("Allocate buffer failed"); 324 SetErrorState("Allocate buffer failed");
287 return; 325 return;
288 } 326 }
289 } 327 }
290 328
291 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type_)) 329 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &capture_type_))
(...skipping 15 matching lines...) Expand all
307 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &capture_type_)) 345 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &capture_type_))
308 < 0) { 346 < 0) {
309 SetErrorState("VIDIOC_STREAMOFF failed"); 347 SetErrorState("VIDIOC_STREAMOFF failed");
310 return; 348 return;
311 } 349 }
312 350
313 buffer_tracker_pool_.clear(); 351 buffer_tracker_pool_.clear();
314 352
315 v4l2_requestbuffers r_buffer = {}; 353 v4l2_requestbuffers r_buffer = {};
316 r_buffer.type = capture_type_; 354 r_buffer.type = capture_type_;
317 r_buffer.memory = V4L2_MEMORY_MMAP;
318 r_buffer.count = 0; 355 r_buffer.count = 0;
356 r_buffer.memory = memory_type();
319 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) 357 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
320 SetErrorState("Failed to VIDIOC_REQBUFS with count = 0"); 358 SetErrorState("Failed to VIDIOC_REQBUFS with count = 0");
321 359
322 // At this point we can close the device. 360 // At this point we can close the device.
323 // This is also needed for correctly changing settings later via VIDIOC_S_FMT. 361 // This is also needed for correctly changing settings later via VIDIOC_S_FMT.
324 device_fd_.reset(); 362 device_fd_.reset();
325 is_capturing_ = false; 363 is_capturing_ = false;
326 client_.reset(); 364 client_.reset();
327 } 365 }
328 366
329 void V4L2CaptureDelegate::SetRotation(int rotation) { 367 void V4L2CaptureDelegate::SetRotation(int rotation) {
330 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 368 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
331 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0); 369 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
332 rotation_ = rotation; 370 rotation_ = rotation;
333 } 371 }
334 372
335 bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) { 373 bool V4L2CaptureDelegate::MapAndQueueBuffer(int index) {
336 v4l2_buffer buffer; 374 v4l2_buffer buffer;
337 FillV4L2Buffer(&buffer, index); 375 FillV4L2Buffer(&buffer, index, true /* for_enqueue */);
338 376
339 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) { 377 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
340 DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer"; 378 DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer";
341 return false; 379 return false;
342 } 380 }
343 381
344 const scoped_refptr<BufferTracker>& buffer_tracker = CreateBufferTracker(); 382 const scoped_refptr<BufferTracker>& buffer_tracker = CreateBufferTracker();
345 if (!buffer_tracker->Init(device_fd_.get(), buffer)) { 383 if (!buffer_tracker->Init(device_fd_.get(), buffer)) {
346 DLOG(ERROR) << "Error creating BufferTracker"; 384 DLOG(ERROR) << "Error creating BufferTracker";
347 return false; 385 return false;
348 } 386 }
349 buffer_tracker_pool_.push_back(buffer_tracker); 387 buffer_tracker_pool_.push_back(buffer_tracker);
350 388
351 // Enqueue the buffer in the drivers incoming queue. 389 // Enqueue the buffer in the drivers incoming queue.
352 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { 390 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
353 DLOG(ERROR) << "Error enqueuing a V4L2 buffer back into the driver"; 391 DLOG(ERROR) << "Error enqueuing a V4L2 buffer back into the driver";
354 return false; 392 return false;
355 } 393 }
356 return true; 394 return true;
357 } 395 }
358 396
359 void V4L2CaptureDelegate::FillV4L2Buffer(v4l2_buffer* buffer, 397 void V4L2CaptureDelegate::FillV4L2Buffer(v4l2_buffer* buffer,
360 int i) const { 398 int i,
399 bool for_enqueue) const {
361 memset(buffer, 0, sizeof(*buffer)); 400 memset(buffer, 0, sizeof(*buffer));
362 buffer->memory = V4L2_MEMORY_MMAP;
363 buffer->index = i; 401 buffer->index = i;
364 FinishFillingV4L2Buffer(buffer); 402 buffer->memory = memory_type();
403 FinishFillingV4L2Buffer(buffer, for_enqueue);
365 } 404 }
366 405
367 void V4L2CaptureDelegate::DoCapture() { 406 void V4L2CaptureDelegate::DoCapture() {
368 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 407 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
369 if (!is_capturing_) 408 if (!is_capturing_)
370 return; 409 return;
371 410
372 pollfd device_pfd = {}; 411 pollfd device_pfd = {};
373 device_pfd.fd = device_fd_.get(); 412 device_pfd.fd = device_fd_.get();
374 device_pfd.events = POLLIN; 413 device_pfd.events = POLLIN;
(...skipping 11 matching lines...) Expand all
386 timeout_count_ = 0; 425 timeout_count_ = 0;
387 return; 426 return;
388 } 427 }
389 } else { 428 } else {
390 timeout_count_ = 0; 429 timeout_count_ = 0;
391 } 430 }
392 431
393 // Deenqueue, send and reenqueue a buffer if the driver has filled one in. 432 // Deenqueue, send and reenqueue a buffer if the driver has filled one in.
394 if (device_pfd.revents & POLLIN) { 433 if (device_pfd.revents & POLLIN) {
395 v4l2_buffer buffer; 434 v4l2_buffer buffer;
396 FillV4L2Buffer(&buffer, 0); 435 FillV4L2Buffer(&buffer, 0, false /* for_enqueue */);
397 436
398 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) { 437 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) {
399 SetErrorState("Failed to dequeue capture buffer"); 438 SetErrorState("Failed to dequeue capture buffer");
400 return; 439 return;
401 } 440 }
402 441
403 SetPayloadSize(buffer_tracker_pool_[buffer.index], buffer); 442 SetPayloadSize(buffer_tracker_pool_[buffer.index], buffer);
404 SendBuffer(buffer_tracker_pool_[buffer.index], video_fmt_); 443 SendBuffer(buffer_tracker_pool_[buffer.index], video_fmt_);
405 444
406 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { 445 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
407 SetErrorState("Failed to enqueue capture buffer"); 446 SetErrorState("Failed to enqueue capture buffer");
408 return; 447 return;
409 } 448 }
410 } 449 }
411 450
412 v4l2_task_runner_->PostTask( 451 v4l2_task_runner_->PostTask(
413 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this)); 452 FROM_HERE, base::Bind(&V4L2CaptureDelegate::DoCapture, this));
414 } 453 }
415 454
416 void V4L2CaptureDelegate::SetErrorState(const std::string& reason) { 455 void V4L2CaptureDelegate::SetErrorState(const std::string& reason) {
417 DCHECK(v4l2_task_runner_->BelongsToCurrentThread()); 456 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
418 is_capturing_ = false; 457 is_capturing_ = false;
419 client_->OnError(reason); 458 client_->OnError(reason);
420 } 459 }
421 460
422 } // namespace media 461 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/linux/v4l2_capture_delegate.h ('k') | media/video/capture/linux/v4l2_capture_delegate_multi_plane.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698