1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/gpu/v4l2/v4l2_device.h"
6
7 #include <fcntl.h>
8 #include <poll.h>
9 #include <linux/media.h>
10 #include <sys/ioctl.h>
11
12 #include <algorithm>
13 #include <set>
14
15 #include <libdrm/drm_fourcc.h>
16 #include <linux/videodev2.h>
17 #include <string.h>
18 #include <sys/mman.h>
19 #include <sstream>
20
21 #include "base/bind.h"
22 #include "base/logging.h"
23 #include "base/numerics/safe_conversions.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "build/build_config.h"
26 #include "media/base/bind_to_current_loop.h"
27 #include "media/base/color_plane_layout.h"
28 #include "media/base/video_types.h"
29 #include "media/gpu/chromeos/fourcc.h"
30 #include "media/gpu/macros.h"
31 #include "media/gpu/v4l2/generic_v4l2_device.h"
32 #include "ui/gfx/native_pixmap_handle.h"
33
34 #if defined(ARCH_CPU_ARMEL)
35 #include "media/gpu/v4l2/tegra_v4l2_device.h"
36 #endif
37 #if defined(AML_V4L2)
38 #include "media/gpu/v4l2/aml_v4l2_device.h"
39 #endif
40
41 #define REQUEST_DEVICE "/dev/media-dec0"
42
43 namespace media {
44
45 namespace {
46
47 // Maximum number of requests that can be created.
48 constexpr size_t kMaxNumRequests = 32;
49
50 } // namespace
51
V4L2ExtCtrl(uint32_t id)52 V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id) {
53 memset(&ctrl, 0, sizeof(ctrl));
54 ctrl.id = id;
55 }
56
V4L2ExtCtrl(uint32_t id,int32_t val)57 V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id, int32_t val) : V4L2ExtCtrl(id) {
58 ctrl.value = val;
59 }
60
61 // Class used to store the state of a buffer that should persist between
62 // reference creations. This includes:
63 // * Result of initial VIDIOC_QUERYBUF ioctl,
64 // * Plane mappings.
65 //
66 // Also provides helper functions.
67 class V4L2Buffer {
68 public:
69 static std::unique_ptr<V4L2Buffer> Create(scoped_refptr<V4L2Device> device,
70 enum v4l2_buf_type type,
71 enum v4l2_memory memory,
72 const struct v4l2_format& format,
73 size_t buffer_id);
74 ~V4L2Buffer();
75
76 void* GetPlaneMapping(const size_t plane);
77 size_t GetMemoryUsage() const;
v4l2_buffer() const78 const struct v4l2_buffer& v4l2_buffer() const { return v4l2_buffer_; }
79 scoped_refptr<VideoFrame> GetVideoFrame();
80
81 private:
82 V4L2Buffer(scoped_refptr<V4L2Device> device,
83 enum v4l2_buf_type type,
84 enum v4l2_memory memory,
85 const struct v4l2_format& format,
86 size_t buffer_id);
87 bool Query();
88 scoped_refptr<VideoFrame> CreateVideoFrame();
89
90 scoped_refptr<V4L2Device> device_;
91 std::vector<void*> plane_mappings_;
92
93 // V4L2 data as queried by QUERYBUF.
94 struct v4l2_buffer v4l2_buffer_ = {};
95 // WARNING: do not change this to a vector or something smaller than
96 // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
97 // the number of allocated planes, resulting in memory corruption.
98 struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES] = {{}};
99
100 struct v4l2_format format_;
101 scoped_refptr<VideoFrame> video_frame_;
102
103 DISALLOW_COPY_AND_ASSIGN(V4L2Buffer);
104 };
105
Create(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t buffer_id)106 std::unique_ptr<V4L2Buffer> V4L2Buffer::Create(scoped_refptr<V4L2Device> device,
107 enum v4l2_buf_type type,
108 enum v4l2_memory memory,
109 const struct v4l2_format& format,
110 size_t buffer_id) {
111 // Not using std::make_unique because constructor is private.
112 std::unique_ptr<V4L2Buffer> buffer(
113 new V4L2Buffer(device, type, memory, format, buffer_id));
114
115 if (!buffer->Query())
116 return nullptr;
117
118 return buffer;
119 }
120
V4L2Buffer(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t buffer_id)121 V4L2Buffer::V4L2Buffer(scoped_refptr<V4L2Device> device,
122 enum v4l2_buf_type type,
123 enum v4l2_memory memory,
124 const struct v4l2_format& format,
125 size_t buffer_id)
126 : device_(device), format_(format) {
127 DCHECK(V4L2_TYPE_IS_MULTIPLANAR(type));
128 DCHECK_LE(format.fmt.pix_mp.num_planes, base::size(v4l2_planes_));
129 v4l2_buffer_.m.planes = v4l2_planes_;
130 // Just in case we got more planes than we want.
131 v4l2_buffer_.length =
132 std::min(static_cast<size_t>(format.fmt.pix_mp.num_planes),
133 base::size(v4l2_planes_));
134 v4l2_buffer_.index = buffer_id;
135 v4l2_buffer_.type = type;
136 v4l2_buffer_.memory = memory;
137 plane_mappings_.resize(v4l2_buffer_.length);
138 }
139
~V4L2Buffer()140 V4L2Buffer::~V4L2Buffer() {
141 if (v4l2_buffer_.memory == V4L2_MEMORY_MMAP) {
142 for (size_t i = 0; i < plane_mappings_.size(); i++)
143 if (plane_mappings_[i] != nullptr)
144 device_->Munmap(plane_mappings_[i], v4l2_buffer_.m.planes[i].length);
145 }
146 }
147
Query()148 bool V4L2Buffer::Query() {
149 int ret = device_->Ioctl(VIDIOC_QUERYBUF, &v4l2_buffer_);
150 if (ret) {
151 VPLOGF(1) << "VIDIOC_QUERYBUF failed: ";
152 return false;
153 }
154
155 DCHECK(plane_mappings_.size() == v4l2_buffer_.length);
156
157 return true;
158 }
159
GetPlaneMapping(const size_t plane)160 void* V4L2Buffer::GetPlaneMapping(const size_t plane) {
161 if (plane >= plane_mappings_.size()) {
162 VLOGF(1) << "Invalid plane " << plane << " requested.";
163 return nullptr;
164 }
165
166 void* p = plane_mappings_[plane];
167 if (p)
168 return p;
169
170 // Do this check here to avoid repeating it after a buffer has been
171 // successfully mapped (we know we are of MMAP type by then).
172 if (v4l2_buffer_.memory != V4L2_MEMORY_MMAP) {
173 VLOGF(1) << "Cannot create mapping on non-MMAP buffer";
174 return nullptr;
175 }
176
177 p = device_->Mmap(NULL, v4l2_buffer_.m.planes[plane].length,
178 PROT_READ | PROT_WRITE, MAP_SHARED,
179 v4l2_buffer_.m.planes[plane].m.mem_offset);
180 if (p == MAP_FAILED) {
181 VPLOGF(1) << "mmap() failed: ";
182 return nullptr;
183 }
184
185 plane_mappings_[plane] = p;
186 return p;
187 }
188
GetMemoryUsage() const189 size_t V4L2Buffer::GetMemoryUsage() const {
190 size_t usage = 0;
191 for (size_t i = 0; i < v4l2_buffer_.length; i++) {
192 usage += v4l2_buffer_.m.planes[i].length;
193 }
194 return usage;
195 }
196
CreateVideoFrame()197 scoped_refptr<VideoFrame> V4L2Buffer::CreateVideoFrame() {
198 auto layout = V4L2Device::V4L2FormatToVideoFrameLayout(format_);
199 if (!layout) {
200 VLOGF(1) << "Cannot create frame layout for V4L2 buffers";
201 return nullptr;
202 }
203
204 std::vector<base::ScopedFD> dmabuf_fds = device_->GetDmabufsForV4L2Buffer(
205 v4l2_buffer_.index, v4l2_buffer_.length,
206 static_cast<enum v4l2_buf_type>(v4l2_buffer_.type));
207 if (dmabuf_fds.empty()) {
208 VLOGF(1) << "Failed to get DMABUFs of V4L2 buffer";
209 return nullptr;
210 }
211
212 // Duplicate the fd of the last v4l2 plane until the number of fds are the
213 // same as the number of color planes.
214 while (dmabuf_fds.size() != layout->planes().size()) {
215 int duped_fd = -1;
216 // Fd in dmabuf_fds is invalid with TegraV4L2Device. An invalid fd is added
217 // in the case.
218 if (dmabuf_fds.back().is_valid()) {
219 duped_fd = HANDLE_EINTR(dup(dmabuf_fds.back().get()));
220 if (duped_fd == -1) {
221 DLOG(ERROR) << "Failed duplicating dmabuf fd";
222 return nullptr;
223 }
224 }
225
226 dmabuf_fds.emplace_back(duped_fd);
227 }
228
229 gfx::Size size(format_.fmt.pix_mp.width, format_.fmt.pix_mp.height);
230
231 return VideoFrame::WrapExternalDmabufs(
232 *layout, gfx::Rect(size), size, std::move(dmabuf_fds), base::TimeDelta());
233 }
234
GetVideoFrame()235 scoped_refptr<VideoFrame> V4L2Buffer::GetVideoFrame() {
236 // We can create the VideoFrame only when using MMAP buffers.
237 if (v4l2_buffer_.memory != V4L2_MEMORY_MMAP) {
238 VLOGF(1) << "Cannot create video frame from non-MMAP buffer";
239 // video_frame_ should be null since that's its default value.
240 DCHECK_EQ(video_frame_, nullptr);
241 return video_frame_;
242 }
243
244 // Create the video frame instance if requiring it for the first time.
245 if (!video_frame_)
246 video_frame_ = CreateVideoFrame();
247
248 return video_frame_;
249 }
250
251 // A thread-safe pool of buffer indexes, allowing buffers to be obtained and
252 // returned from different threads. All the methods of this class are
253 // thread-safe. Users should keep a scoped_refptr to instances of this class
254 // in order to ensure the list remains alive as long as they need it.
255 class V4L2BuffersList : public base::RefCountedThreadSafe<V4L2BuffersList> {
256 public:
257 V4L2BuffersList() = default;
258 // Return a buffer to this list. Also can be called to set the initial pool
259 // of buffers.
260 // Note that it is illegal to return the same buffer twice.
261 void ReturnBuffer(size_t buffer_id);
262 // Get any of the buffers in the list. There is no order guarantee whatsoever.
263 base::Optional<size_t> GetFreeBuffer();
264 // Number of buffers currently in this list.
265 size_t size() const;
266
267 private:
268 friend class base::RefCountedThreadSafe<V4L2BuffersList>;
269 ~V4L2BuffersList() = default;
270
271 mutable base::Lock lock_;
272 std::set<size_t> free_buffers_ GUARDED_BY(lock_);
273 DISALLOW_COPY_AND_ASSIGN(V4L2BuffersList);
274 };
275
ReturnBuffer(size_t buffer_id)276 void V4L2BuffersList::ReturnBuffer(size_t buffer_id) {
277 base::AutoLock auto_lock(lock_);
278
279 auto inserted = free_buffers_.emplace(buffer_id);
280 DCHECK(inserted.second);
281 }
282
GetFreeBuffer()283 base::Optional<size_t> V4L2BuffersList::GetFreeBuffer() {
284 base::AutoLock auto_lock(lock_);
285
286 auto iter = free_buffers_.begin();
287 if (iter == free_buffers_.end()) {
288 DVLOGF(4) << "No free buffer available!";
289 return base::nullopt;
290 }
291
292 size_t buffer_id = *iter;
293 free_buffers_.erase(iter);
294
295 return buffer_id;
296 }
297
size() const298 size_t V4L2BuffersList::size() const {
299 base::AutoLock auto_lock(lock_);
300
301 return free_buffers_.size();
302 }
303
304 // Module-private class that let users query/write V4L2 buffer information.
305 // It also makes some private V4L2Queue methods available to this module only.
306 class V4L2BufferRefBase {
307 public:
308 V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
309 base::WeakPtr<V4L2Queue> queue);
310 ~V4L2BufferRefBase();
311
312 bool QueueBuffer();
313 void* GetPlaneMapping(const size_t plane);
314
315 scoped_refptr<VideoFrame> GetVideoFrame();
316 // Checks that the number of passed FDs is adequate for the current format
317 // and buffer configuration. Only useful for DMABUF buffers.
318 bool CheckNumFDsForFormat(const size_t num_fds) const;
319
320 // Data from the buffer, that users can query and/or write.
321 struct v4l2_buffer v4l2_buffer_;
322 // WARNING: do not change this to a vector or something smaller than
323 // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
324 // the number of allocated planes, resulting in memory corruption.
325 struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
326
327 private:
BufferId() const328 size_t BufferId() const { return v4l2_buffer_.index; }
329
330 friend class V4L2WritableBufferRef;
331 // A weak pointer to the queue this buffer belongs to. Will remain valid as
332 // long as the underlying V4L2 buffer is valid too.
333 // This can only be accessed from the sequence protected by sequence_checker_.
334 // Thread-safe methods (like ~V4L2BufferRefBase) must *never* access this.
335 base::WeakPtr<V4L2Queue> queue_;
336 // Where to return this buffer if it goes out of scope without being queued.
337 scoped_refptr<V4L2BuffersList> return_to_;
338 bool queued = false;
339
340 SEQUENCE_CHECKER(sequence_checker_);
341 DISALLOW_COPY_AND_ASSIGN(V4L2BufferRefBase);
342 };
343
V4L2BufferRefBase(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)344 V4L2BufferRefBase::V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
345 base::WeakPtr<V4L2Queue> queue)
346 : queue_(std::move(queue)), return_to_(queue_->free_buffers_) {
347 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
348 DCHECK(V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer.type));
349 DCHECK_LE(v4l2_buffer.length, base::size(v4l2_planes_));
350 DCHECK(return_to_);
351
352 memcpy(&v4l2_buffer_, &v4l2_buffer, sizeof(v4l2_buffer_));
353 memcpy(v4l2_planes_, v4l2_buffer.m.planes,
354 sizeof(struct v4l2_plane) * v4l2_buffer.length);
355 v4l2_buffer_.m.planes = v4l2_planes_;
356 }
357
~V4L2BufferRefBase()358 V4L2BufferRefBase::~V4L2BufferRefBase() {
359 // We are the last reference and are only accessing the thread-safe
360 // return_to_, so we are safe to call from any sequence.
361 // If we have been queued, then the queue is our owner so we don't need to
362 // return to the free buffers list.
363 if (!queued)
364 return_to_->ReturnBuffer(BufferId());
365 }
366
QueueBuffer()367 bool V4L2BufferRefBase::QueueBuffer() {
368 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
369
370 if (!queue_)
371 return false;
372
373 queued = queue_->QueueBuffer(&v4l2_buffer_);
374
375 return queued;
376 }
377
GetPlaneMapping(const size_t plane)378 void* V4L2BufferRefBase::GetPlaneMapping(const size_t plane) {
379 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
380
381 if (!queue_)
382 return nullptr;
383
384 return queue_->buffers_[BufferId()]->GetPlaneMapping(plane);
385 }
386
GetVideoFrame()387 scoped_refptr<VideoFrame> V4L2BufferRefBase::GetVideoFrame() {
388 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
389
390 // Used so we can return a const scoped_refptr& in all cases.
391 static const scoped_refptr<VideoFrame> null_videoframe;
392
393 if (!queue_)
394 return null_videoframe;
395
396 DCHECK_LE(BufferId(), queue_->buffers_.size());
397
398 return queue_->buffers_[BufferId()]->GetVideoFrame();
399 }
400
CheckNumFDsForFormat(const size_t num_fds) const401 bool V4L2BufferRefBase::CheckNumFDsForFormat(const size_t num_fds) const {
402 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
403
404 if (!queue_)
405 return false;
406
407 // We have not used SetFormat(), assume this is ok.
408 // Hopefully we standardize SetFormat() in the future.
409 if (!queue_->current_format_)
410 return true;
411
412 const size_t required_fds = queue_->current_format_->fmt.pix_mp.num_planes;
413 // Sanity check.
414 DCHECK_EQ(v4l2_buffer_.length, required_fds);
415 if (num_fds < required_fds) {
416 VLOGF(1) << "Insufficient number of FDs given for the current format. "
417 << num_fds << " provided, " << required_fds << " required.";
418 return false;
419 }
420
421 const auto* planes = v4l2_buffer_.m.planes;
422 for (size_t i = v4l2_buffer_.length - 1; i >= num_fds; --i) {
423 // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
424 // Otherwise, if offset == 0, return error as it is likely pointing to
425 // a new plane.
426 if (planes[i].data_offset == 0) {
427 VLOGF(1) << "Additional dmabuf fds point to a new buffer.";
428 return false;
429 }
430 }
431
432 return true;
433 }
434
V4L2WritableBufferRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)435 V4L2WritableBufferRef::V4L2WritableBufferRef(
436 const struct v4l2_buffer& v4l2_buffer,
437 base::WeakPtr<V4L2Queue> queue)
438 : buffer_data_(
439 std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
440 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
441 }
442
V4L2WritableBufferRef(V4L2WritableBufferRef && other)443 V4L2WritableBufferRef::V4L2WritableBufferRef(V4L2WritableBufferRef&& other)
444 : buffer_data_(std::move(other.buffer_data_)) {
445 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
446 DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
447 }
448
~V4L2WritableBufferRef()449 V4L2WritableBufferRef::~V4L2WritableBufferRef() {
450 // Only valid references should be sequence-checked
451 if (buffer_data_) {
452 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
453 }
454 }
455
operator =(V4L2WritableBufferRef && other)456 V4L2WritableBufferRef& V4L2WritableBufferRef::operator=(
457 V4L2WritableBufferRef&& other) {
458 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
459 DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
460
461 if (this == &other)
462 return *this;
463
464 buffer_data_ = std::move(other.buffer_data_);
465
466 return *this;
467 }
468
GetVideoFrame()469 scoped_refptr<VideoFrame> V4L2WritableBufferRef::GetVideoFrame() {
470 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
471 DCHECK(buffer_data_);
472
473 return buffer_data_->GetVideoFrame();
474 }
475
Memory() const476 enum v4l2_memory V4L2WritableBufferRef::Memory() const {
477 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
478 DCHECK(buffer_data_);
479
480 return static_cast<enum v4l2_memory>(buffer_data_->v4l2_buffer_.memory);
481 }
482
DoQueue(V4L2RequestRef * request_ref)483 bool V4L2WritableBufferRef::DoQueue(V4L2RequestRef* request_ref) && {
484 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
485 DCHECK(buffer_data_);
486
487 if (request_ref && buffer_data_->queue_->SupportsRequests())
488 request_ref->ApplyQueueBuffer(&(buffer_data_->v4l2_buffer_));
489
490 bool queued = buffer_data_->QueueBuffer();
491
492 // Clear our own reference.
493 buffer_data_.reset();
494
495 return queued;
496 }
497
QueueMMap(V4L2RequestRef * request_ref)498 bool V4L2WritableBufferRef::QueueMMap(
499 V4L2RequestRef* request_ref) && {
500 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
501 DCHECK(buffer_data_);
502
503 // Move ourselves so our data gets freed no matter when we return
504 V4L2WritableBufferRef self(std::move(*this));
505
506 if (self.Memory() != V4L2_MEMORY_MMAP) {
507 VLOGF(1) << "Called on invalid buffer type!";
508 return false;
509 }
510
511 return std::move(self).DoQueue(request_ref);
512 }
513
QueueUserPtr(const std::vector<void * > & ptrs,V4L2RequestRef * request_ref)514 bool V4L2WritableBufferRef::QueueUserPtr(
515 const std::vector<void*>& ptrs,
516 V4L2RequestRef* request_ref) && {
517 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
518 DCHECK(buffer_data_);
519
520 // Move ourselves so our data gets freed no matter when we return
521 V4L2WritableBufferRef self(std::move(*this));
522
523 if (self.Memory() != V4L2_MEMORY_USERPTR) {
524 VLOGF(1) << "Called on invalid buffer type!";
525 return false;
526 }
527
528 if (ptrs.size() != self.PlanesCount()) {
529 VLOGF(1) << "Provided " << ptrs.size() << " pointers while we require "
530 << self.buffer_data_->v4l2_buffer_.length << ".";
531 return false;
532 }
533
534 for (size_t i = 0; i < ptrs.size(); i++)
535 self.buffer_data_->v4l2_buffer_.m.planes[i].m.userptr =
536 reinterpret_cast<unsigned long>(ptrs[i]);
537
538 return std::move(self).DoQueue(request_ref);
539 }
540
QueueDMABuf(const std::vector<base::ScopedFD> & fds,V4L2RequestRef * request_ref)541 bool V4L2WritableBufferRef::QueueDMABuf(
542 const std::vector<base::ScopedFD>& fds,
543 V4L2RequestRef* request_ref) && {
544 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
545 DCHECK(buffer_data_);
546
547 // Move ourselves so our data gets freed no matter when we return
548 V4L2WritableBufferRef self(std::move(*this));
549
550 if (self.Memory() != V4L2_MEMORY_DMABUF) {
551 VLOGF(1) << "Called on invalid buffer type!";
552 return false;
553 }
554
555 if (!self.buffer_data_->CheckNumFDsForFormat(fds.size()))
556 return false;
557
558 size_t num_planes = self.PlanesCount();
559 for (size_t i = 0; i < num_planes; i++)
560 self.buffer_data_->v4l2_buffer_.m.planes[i].m.fd = fds[i].get();
561
562 return std::move(self).DoQueue(request_ref);
563 }
564
QueueDMABuf(const std::vector<gfx::NativePixmapPlane> & planes,V4L2RequestRef * request_ref)565 bool V4L2WritableBufferRef::QueueDMABuf(
566 const std::vector<gfx::NativePixmapPlane>& planes,
567 V4L2RequestRef* request_ref) && {
568 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
569 DCHECK(buffer_data_);
570
571 // Move ourselves so our data gets freed no matter when we return
572 V4L2WritableBufferRef self(std::move(*this));
573
574 if (self.Memory() != V4L2_MEMORY_DMABUF) {
575 VLOGF(1) << "Called on invalid buffer type!";
576 return false;
577 }
578
579 if (!self.buffer_data_->CheckNumFDsForFormat(planes.size()))
580 return false;
581
582 size_t num_planes = self.PlanesCount();
583 for (size_t i = 0; i < num_planes; i++)
584 self.buffer_data_->v4l2_buffer_.m.planes[i].m.fd = planes[i].fd.get();
585
586 return std::move(self).DoQueue(request_ref);
587 }
588
PlanesCount() const589 size_t V4L2WritableBufferRef::PlanesCount() const {
590 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
591 DCHECK(buffer_data_);
592
593 return buffer_data_->v4l2_buffer_.length;
594 }
595
GetPlaneSize(const size_t plane) const596 size_t V4L2WritableBufferRef::GetPlaneSize(const size_t plane) const {
597 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
598 DCHECK(buffer_data_);
599
600 if (plane >= PlanesCount()) {
601 VLOGF(1) << "Invalid plane " << plane << " requested.";
602 return 0;
603 }
604
605 return buffer_data_->v4l2_buffer_.m.planes[plane].length;
606 }
607
SetPlaneSize(const size_t plane,const size_t size)608 void V4L2WritableBufferRef::SetPlaneSize(const size_t plane,
609 const size_t size) {
610 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
611 DCHECK(buffer_data_);
612
613 enum v4l2_memory memory = Memory();
614 if (memory == V4L2_MEMORY_MMAP) {
615 DCHECK_EQ(buffer_data_->v4l2_buffer_.m.planes[plane].length, size);
616 return;
617 }
618 DCHECK(memory == V4L2_MEMORY_USERPTR || memory == V4L2_MEMORY_DMABUF);
619
620 if (plane >= PlanesCount()) {
621 VLOGF(1) << "Invalid plane " << plane << " requested.";
622 return;
623 }
624
625 buffer_data_->v4l2_buffer_.m.planes[plane].length = size;
626 }
627
GetPlaneMapping(const size_t plane)628 void* V4L2WritableBufferRef::GetPlaneMapping(const size_t plane) {
629 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
630 DCHECK(buffer_data_);
631
632 return buffer_data_->GetPlaneMapping(plane);
633 }
634
SetTimeStamp(const struct timeval & timestamp)635 void V4L2WritableBufferRef::SetTimeStamp(const struct timeval& timestamp) {
636 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
637 DCHECK(buffer_data_);
638
639 buffer_data_->v4l2_buffer_.timestamp = timestamp;
640 }
641
GetTimeStamp() const642 const struct timeval& V4L2WritableBufferRef::GetTimeStamp() const {
643 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
644 DCHECK(buffer_data_);
645
646 return buffer_data_->v4l2_buffer_.timestamp;
647 }
648
SetPlaneBytesUsed(const size_t plane,const size_t bytes_used)649 void V4L2WritableBufferRef::SetPlaneBytesUsed(const size_t plane,
650 const size_t bytes_used) {
651 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
652 DCHECK(buffer_data_);
653
654 if (plane >= PlanesCount()) {
655 VLOGF(1) << "Invalid plane " << plane << " requested.";
656 return;
657 }
658
659 if (bytes_used > GetPlaneSize(plane)) {
660 VLOGF(1) << "Set bytes used " << bytes_used << " larger than plane size "
661 << GetPlaneSize(plane) << ".";
662 return;
663 }
664
665 buffer_data_->v4l2_buffer_.m.planes[plane].bytesused = bytes_used;
666 }
667
GetPlaneBytesUsed(const size_t plane) const668 size_t V4L2WritableBufferRef::GetPlaneBytesUsed(const size_t plane) const {
669 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
670 DCHECK(buffer_data_);
671
672 if (plane >= PlanesCount()) {
673 VLOGF(1) << "Invalid plane " << plane << " requested.";
674 return 0;
675 }
676
677 return buffer_data_->v4l2_buffer_.m.planes[plane].bytesused;
678 }
679
SetPlaneDataOffset(const size_t plane,const size_t data_offset)680 void V4L2WritableBufferRef::SetPlaneDataOffset(const size_t plane,
681 const size_t data_offset) {
682 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
683 DCHECK(buffer_data_);
684
685 if (plane >= PlanesCount()) {
686 VLOGF(1) << "Invalid plane " << plane << " requested.";
687 return;
688 }
689
690 buffer_data_->v4l2_buffer_.m.planes[plane].data_offset = data_offset;
691 }
692
BufferId() const693 size_t V4L2WritableBufferRef::BufferId() const {
694 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
695 DCHECK(buffer_data_);
696
697 return buffer_data_->v4l2_buffer_.index;
698 }
699
SetConfigStore(uint32_t config_store)700 void V4L2WritableBufferRef::SetConfigStore(uint32_t config_store) {
701 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
702 DCHECK(buffer_data_);
703
704 buffer_data_->v4l2_buffer_.config_store = config_store;
705 }
706
V4L2ReadableBuffer(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)707 V4L2ReadableBuffer::V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer,
708 base::WeakPtr<V4L2Queue> queue)
709 : buffer_data_(
710 std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
711 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
712 }
713
GetVideoFrame()714 scoped_refptr<VideoFrame> V4L2ReadableBuffer::GetVideoFrame() {
715 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
716
717 return buffer_data_->GetVideoFrame();
718 }
719
~V4L2ReadableBuffer()720 V4L2ReadableBuffer::~V4L2ReadableBuffer() {
721 // This method is thread-safe. Since we are the destructor, we are guaranteed
722 // to be called from the only remaining reference to us. Also, we are just
723 // calling the destructor of buffer_data_, which is also thread-safe.
724 DCHECK(buffer_data_);
725 }
726
IsLast() const727 bool V4L2ReadableBuffer::IsLast() const {
728 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
729 DCHECK(buffer_data_);
730
731 return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_LAST;
732 }
733
IsKeyframe() const734 bool V4L2ReadableBuffer::IsKeyframe() const {
735 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
736 DCHECK(buffer_data_);
737
738 return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_KEYFRAME;
739 }
740
GetTimeStamp() const741 struct timeval V4L2ReadableBuffer::GetTimeStamp() const {
742 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
743 DCHECK(buffer_data_);
744
745 return buffer_data_->v4l2_buffer_.timestamp;
746 }
747
PlanesCount() const748 size_t V4L2ReadableBuffer::PlanesCount() const {
749 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
750 DCHECK(buffer_data_);
751
752 return buffer_data_->v4l2_buffer_.length;
753 }
754
GetPlaneMapping(const size_t plane) const755 const void* V4L2ReadableBuffer::GetPlaneMapping(const size_t plane) const {
756 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
757 DCHECK(buffer_data_);
758
759 return buffer_data_->GetPlaneMapping(plane);
760 }
761
GetPlaneBytesUsed(const size_t plane) const762 size_t V4L2ReadableBuffer::GetPlaneBytesUsed(const size_t plane) const {
763 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
764 DCHECK(buffer_data_);
765
766 if (plane >= PlanesCount()) {
767 VLOGF(1) << "Invalid plane " << plane << " requested.";
768 return 0;
769 }
770
771 return buffer_data_->v4l2_planes_[plane].bytesused;
772 }
773
GetPlaneDataOffset(const size_t plane) const774 size_t V4L2ReadableBuffer::GetPlaneDataOffset(const size_t plane) const {
775 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
776 DCHECK(buffer_data_);
777
778 if (plane >= PlanesCount()) {
779 VLOGF(1) << "Invalid plane " << plane << " requested.";
780 return 0;
781 }
782
783 return buffer_data_->v4l2_planes_[plane].data_offset;
784 }
785
BufferId() const786 size_t V4L2ReadableBuffer::BufferId() const {
787 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
788 DCHECK(buffer_data_);
789
790 return buffer_data_->v4l2_buffer_.index;
791 }
792
793 // This class is used to expose buffer reference classes constructors to
794 // this module. This is to ensure that nobody else can create buffer references.
795 class V4L2BufferRefFactory {
796 public:
CreateWritableRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)797 static V4L2WritableBufferRef CreateWritableRef(
798 const struct v4l2_buffer& v4l2_buffer,
799 base::WeakPtr<V4L2Queue> queue) {
800 return V4L2WritableBufferRef(v4l2_buffer, std::move(queue));
801 }
802
CreateReadableRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)803 static V4L2ReadableBufferRef CreateReadableRef(
804 const struct v4l2_buffer& v4l2_buffer,
805 base::WeakPtr<V4L2Queue> queue) {
806 return new V4L2ReadableBuffer(v4l2_buffer, std::move(queue));
807 }
808 };
809
810 // Helper macros that print the queue type with logs.
811 #define VPQLOGF(level) \
812 VPLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
813 #define VQLOGF(level) \
814 VLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
815 #define DVQLOGF(level) \
816 DVLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
817
V4L2Queue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroy_cb)818 V4L2Queue::V4L2Queue(scoped_refptr<V4L2Device> dev,
819 enum v4l2_buf_type type,
820 base::OnceClosure destroy_cb)
821 : type_(type),
822 device_(dev),
823 destroy_cb_(std::move(destroy_cb)),
824 weak_this_factory_(this) {
825 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
826
827 // Check if this queue support requests.
828 struct v4l2_requestbuffers reqbufs;
829 memset(&reqbufs, 0, sizeof(reqbufs));
830 reqbufs.count = 0;
831 reqbufs.type = type;
832 reqbufs.memory = V4L2_MEMORY_MMAP;
833 if (device_->Ioctl(VIDIOC_REQBUFS, &reqbufs) != 0) {
834 VPLOGF(1) << "Request support checks's VIDIOC_REQBUFS ioctl failed.";
835 return;
836 }
837
838 if (reqbufs.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) {
839 supports_requests_ = true;
840 DVLOGF(4) << "Queue supports request API.";
841 }
842 }
843
~V4L2Queue()844 V4L2Queue::~V4L2Queue() {
845 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
846
847 if (is_streaming_) {
848 VQLOGF(1) << "Queue is still streaming, trying to stop it...";
849 Streamoff();
850 }
851
852 DCHECK(queued_buffers_.empty());
853 DCHECK(!free_buffers_);
854
855 if (!buffers_.empty()) {
856 VQLOGF(1) << "Buffers are still allocated, trying to deallocate them...";
857 DeallocateBuffers();
858 }
859
860 std::move(destroy_cb_).Run();
861 }
862
SetFormat(uint32_t fourcc,const gfx::Size & size,size_t buffer_size)863 base::Optional<struct v4l2_format> V4L2Queue::SetFormat(uint32_t fourcc,
864 const gfx::Size& size,
865 size_t buffer_size) {
866 struct v4l2_format format = {};
867 format.type = type_;
868 format.fmt.pix_mp.pixelformat = fourcc;
869 format.fmt.pix_mp.width = size.width();
870 format.fmt.pix_mp.height = size.height();
871 format.fmt.pix_mp.num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(fourcc);
872 format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
873 if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
874 format.fmt.pix_mp.pixelformat != fourcc) {
875 VPQLOGF(2) << "Failed to set format (format_fourcc=0x" << std::hex << fourcc
876 << ")";
877 return base::nullopt;
878 }
879
880 current_format_ = format;
881 return current_format_;
882 }
883
AllocateBuffers(size_t count,enum v4l2_memory memory)884 size_t V4L2Queue::AllocateBuffers(size_t count, enum v4l2_memory memory) {
885 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
886 DCHECK(!free_buffers_);
887 DCHECK_EQ(queued_buffers_.size(), 0u);
888
889 if (IsStreaming()) {
890 VQLOGF(1) << "Cannot allocate buffers while streaming.";
891 return 0;
892 }
893
894 if (buffers_.size() != 0) {
895 VQLOGF(1)
896 << "Cannot allocate new buffers while others are still allocated.";
897 return 0;
898 }
899
900 if (count == 0) {
901 VQLOGF(1) << "Attempting to allocate 0 buffers.";
902 return 0;
903 }
904
905 // First query the number of planes in the buffers we are about to request.
906 // This should not be required, but Tegra's VIDIOC_QUERYBUF will fail on
907 // output buffers if the number of specified planes does not exactly match the
908 // format.
909 struct v4l2_format format = {.type = type_};
910 int ret = device_->Ioctl(VIDIOC_G_FMT, &format);
911 if (ret) {
912 VPQLOGF(1) << "VIDIOC_G_FMT failed";
913 return 0;
914 }
915 planes_count_ = format.fmt.pix_mp.num_planes;
916 DCHECK_LE(planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES));
917
918 struct v4l2_requestbuffers reqbufs = {};
919 reqbufs.count = count;
920 reqbufs.type = type_;
921 reqbufs.memory = memory;
922 DVQLOGF(3) << "Requesting " << count << " buffers.";
923
924 ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
925 if (ret) {
926 VPQLOGF(1) << "VIDIOC_REQBUFS failed";
927 return 0;
928 }
929 DVQLOGF(3) << "queue " << type_ << ": got " << reqbufs.count << " buffers.";
930
931 memory_ = memory;
932
933 free_buffers_ = new V4L2BuffersList();
934
935 // Now query all buffer information.
936 for (size_t i = 0; i < reqbufs.count; i++) {
937 auto buffer = V4L2Buffer::Create(device_, type_, memory_, format, i);
938
939 if (!buffer) {
940 DeallocateBuffers();
941
942 return 0;
943 }
944
945 buffers_.emplace_back(std::move(buffer));
946 free_buffers_->ReturnBuffer(i);
947 }
948
949 DCHECK(free_buffers_);
950 DCHECK_EQ(free_buffers_->size(), buffers_.size());
951 DCHECK_EQ(queued_buffers_.size(), 0u);
952
953 return buffers_.size();
954 }
955
DeallocateBuffers()956 bool V4L2Queue::DeallocateBuffers() {
957 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
958
959 if (IsStreaming()) {
960 VQLOGF(1) << "Cannot deallocate buffers while streaming.";
961 return false;
962 }
963
964 if (buffers_.size() == 0)
965 return true;
966
967 weak_this_factory_.InvalidateWeakPtrs();
968 buffers_.clear();
969 free_buffers_ = nullptr;
970
971 // Free all buffers.
972 struct v4l2_requestbuffers reqbufs = {};
973 reqbufs.count = 0;
974 reqbufs.type = type_;
975 reqbufs.memory = memory_;
976
977 int ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
978 if (ret) {
979 VPQLOGF(1) << "VIDIOC_REQBUFS failed";
980 return false;
981 }
982
983 DCHECK(!free_buffers_);
984 DCHECK_EQ(queued_buffers_.size(), 0u);
985
986 return true;
987 }
988
GetMemoryUsage() const989 size_t V4L2Queue::GetMemoryUsage() const {
990 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
991 size_t usage = 0;
992 for (const auto& buf : buffers_) {
993 usage += buf->GetMemoryUsage();
994 }
995 return usage;
996 }
997
GetMemoryType() const998 v4l2_memory V4L2Queue::GetMemoryType() const {
999 return memory_;
1000 }
1001
GetFreeBuffer()1002 base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer() {
1003 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1004
1005 // No buffers allocated at the moment?
1006 if (!free_buffers_)
1007 return base::nullopt;
1008
1009 auto buffer_id = free_buffers_->GetFreeBuffer();
1010 if (!buffer_id.has_value())
1011 return base::nullopt;
1012
1013 return V4L2BufferRefFactory::CreateWritableRef(
1014 buffers_[buffer_id.value()]->v4l2_buffer(),
1015 weak_this_factory_.GetWeakPtr());
1016 }
1017
QueueBuffer(struct v4l2_buffer * v4l2_buffer)1018 bool V4L2Queue::QueueBuffer(struct v4l2_buffer* v4l2_buffer) {
1019 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1020
1021 int ret = device_->Ioctl(VIDIOC_QBUF, v4l2_buffer);
1022 if (ret) {
1023 VPQLOGF(1) << "VIDIOC_QBUF failed";
1024 return false;
1025 }
1026
1027 auto inserted = queued_buffers_.emplace(v4l2_buffer->index);
1028 DCHECK_EQ(inserted.second, true);
1029
1030 device_->SchedulePoll();
1031
1032 return true;
1033 }
1034
DequeueBuffer()1035 std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::DequeueBuffer() {
1036 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1037
1038 // No need to dequeue if no buffers queued.
1039 if (QueuedBuffersCount() == 0)
1040 return std::make_pair(true, nullptr);
1041
1042 if (!IsStreaming()) {
1043 VQLOGF(1) << "Attempting to dequeue a buffer while not streaming.";
1044 return std::make_pair(true, nullptr);
1045 }
1046
1047 struct v4l2_buffer v4l2_buffer = {};
1048 // WARNING: do not change this to a vector or something smaller than
1049 // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
1050 // the number of allocated planes, resulting in memory corruption.
1051 struct v4l2_plane planes[VIDEO_MAX_PLANES] = {{}};
1052 v4l2_buffer.type = type_;
1053 v4l2_buffer.memory = memory_;
1054 v4l2_buffer.m.planes = planes;
1055 v4l2_buffer.length = planes_count_;
1056 int ret = device_->Ioctl(VIDIOC_DQBUF, &v4l2_buffer);
1057 if (ret) {
1058 // TODO(acourbot): we should not have to check for EPIPE as codec clients
1059 // should not call this method after the last buffer is dequeued.
1060 switch (errno) {
1061 case EAGAIN:
1062 case EPIPE:
1063 // This is not an error so we'll need to continue polling but won't
1064 // provide a buffer.
1065 device_->SchedulePoll();
1066 return std::make_pair(true, nullptr);
1067 default:
1068 VPQLOGF(1) << "VIDIOC_DQBUF failed";
1069 return std::make_pair(false, nullptr);
1070 }
1071 }
1072
1073 auto it = queued_buffers_.find(v4l2_buffer.index);
1074 DCHECK(it != queued_buffers_.end());
1075 queued_buffers_.erase(*it);
1076
1077 if (QueuedBuffersCount() > 0)
1078 device_->SchedulePoll();
1079
1080 DCHECK(free_buffers_);
1081 return std::make_pair(true,
1082 V4L2BufferRefFactory::CreateReadableRef(
1083 v4l2_buffer, weak_this_factory_.GetWeakPtr()));
1084 }
1085
IsStreaming() const1086 bool V4L2Queue::IsStreaming() const {
1087 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1088
1089 return is_streaming_;
1090 }
1091
Streamon()1092 bool V4L2Queue::Streamon() {
1093 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1094
1095 if (is_streaming_)
1096 return true;
1097
1098 int arg = static_cast<int>(type_);
1099 int ret = device_->Ioctl(VIDIOC_STREAMON, &arg);
1100 if (ret) {
1101 VPQLOGF(1) << "VIDIOC_STREAMON failed";
1102 return false;
1103 }
1104
1105 is_streaming_ = true;
1106
1107 return true;
1108 }
1109
Streamoff()1110 bool V4L2Queue::Streamoff() {
1111 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1112
1113 // We do not check the value of IsStreaming(), because we may have queued
1114 // buffers to the queue and wish to get them back - in such as case, we may
1115 // need to do a VIDIOC_STREAMOFF on a stopped queue.
1116
1117 int arg = static_cast<int>(type_);
1118 int ret = device_->Ioctl(VIDIOC_STREAMOFF, &arg);
1119 if (ret) {
1120 VPQLOGF(1) << "VIDIOC_STREAMOFF failed";
1121 return false;
1122 }
1123
1124 for (const auto& buffer_id : queued_buffers_) {
1125 DCHECK(free_buffers_);
1126 free_buffers_->ReturnBuffer(buffer_id);
1127 }
1128
1129 queued_buffers_.clear();
1130
1131 is_streaming_ = false;
1132
1133 return true;
1134 }
1135
AllocatedBuffersCount() const1136 size_t V4L2Queue::AllocatedBuffersCount() const {
1137 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1138
1139 return buffers_.size();
1140 }
1141
FreeBuffersCount() const1142 size_t V4L2Queue::FreeBuffersCount() const {
1143 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1144
1145 return free_buffers_ ? free_buffers_->size() : 0;
1146 }
1147
QueuedBuffersCount() const1148 size_t V4L2Queue::QueuedBuffersCount() const {
1149 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1150
1151 return queued_buffers_.size();
1152 }
1153
1154 #undef VDQLOGF
1155 #undef VPQLOGF
1156 #undef VQLOGF
1157
SupportsRequests()1158 bool V4L2Queue::SupportsRequests() {
1159 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1160
1161 return supports_requests_;
1162 }
1163
1164 // This class is used to expose V4L2Queue's constructor to this module. This is
1165 // to ensure that nobody else can create instances of it.
1166 class V4L2QueueFactory {
1167 public:
CreateQueue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroy_cb)1168 static scoped_refptr<V4L2Queue> CreateQueue(scoped_refptr<V4L2Device> dev,
1169 enum v4l2_buf_type type,
1170 base::OnceClosure destroy_cb) {
1171 return new V4L2Queue(std::move(dev), type, std::move(destroy_cb));
1172 }
1173 };
1174
V4L2Device()1175 V4L2Device::V4L2Device() {
1176 DETACH_FROM_SEQUENCE(client_sequence_checker_);
1177 }
1178
~V4L2Device()1179 V4L2Device::~V4L2Device() {}
1180
GetQueue(enum v4l2_buf_type type)1181 scoped_refptr<V4L2Queue> V4L2Device::GetQueue(enum v4l2_buf_type type) {
1182 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1183
1184 switch (type) {
1185 // Supported queue types.
1186 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1187 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1188 break;
1189 default:
1190 VLOGF(1) << "Unsupported V4L2 queue type: " << type;
1191 return nullptr;
1192 }
1193
1194 // TODO(acourbot): we should instead query the device for available queues,
1195 // and allocate them accordingly. This will do for now though.
1196 auto it = queues_.find(type);
1197 if (it != queues_.end())
1198 return scoped_refptr<V4L2Queue>(it->second);
1199
1200 scoped_refptr<V4L2Queue> queue = V4L2QueueFactory::CreateQueue(
1201 this, type, base::BindOnce(&V4L2Device::OnQueueDestroyed, this, type));
1202
1203 queues_[type] = queue.get();
1204 return queue;
1205 }
1206
OnQueueDestroyed(v4l2_buf_type buf_type)1207 void V4L2Device::OnQueueDestroyed(v4l2_buf_type buf_type) {
1208 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1209
1210 auto it = queues_.find(buf_type);
1211 DCHECK(it != queues_.end());
1212 queues_.erase(it);
1213 }
1214
1215 // static
Create()1216 scoped_refptr<V4L2Device> V4L2Device::Create() {
1217 DVLOGF(3);
1218
1219 scoped_refptr<V4L2Device> device;
1220
1221 #if defined(ARCH_CPU_ARMEL)
1222 device = new TegraV4L2Device();
1223 if (device->Initialize())
1224 return device;
1225 #endif
1226
1227 #if defined(AML_V4L2)
1228 device = new AmlV4L2Device();
1229 if (device->Initialize())
1230 return device;
1231 #endif
1232
1233 device = new GenericV4L2Device();
1234 if (device->Initialize())
1235 return device;
1236
1237 VLOGF(1) << "Failed to create a V4L2Device";
1238 return nullptr;
1239 }
1240
1241 // static
VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,bool slice_based)1242 uint32_t V4L2Device::VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
1243 bool slice_based) {
1244 if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
1245 if (slice_based)
1246 return V4L2_PIX_FMT_H264_SLICE;
1247 else
1248 return V4L2_PIX_FMT_H264;
1249 } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
1250 if (slice_based)
1251 return V4L2_PIX_FMT_VP8_FRAME;
1252 else
1253 return V4L2_PIX_FMT_VP8;
1254 } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
1255 if (slice_based)
1256 return V4L2_PIX_FMT_VP9_FRAME;
1257 else
1258 return V4L2_PIX_FMT_VP9;
1259 } else {
1260 LOG(ERROR) << "Unknown profile: " << GetProfileName(profile);
1261 return 0;
1262 }
1263 }
1264
1265 // static
V4L2ProfileToVideoCodecProfile(VideoCodec codec,uint32_t profile)1266 VideoCodecProfile V4L2Device::V4L2ProfileToVideoCodecProfile(VideoCodec codec,
1267 uint32_t profile) {
1268 switch (codec) {
1269 case kCodecH264:
1270 switch (profile) {
1271 case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
1272 case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
1273 return H264PROFILE_BASELINE;
1274 case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
1275 return H264PROFILE_MAIN;
1276 case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
1277 return H264PROFILE_EXTENDED;
1278 case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
1279 return H264PROFILE_HIGH;
1280 }
1281 break;
1282 case kCodecVP8:
1283 switch (profile) {
1284 case V4L2_MPEG_VIDEO_VP8_PROFILE_0:
1285 case V4L2_MPEG_VIDEO_VP8_PROFILE_1:
1286 case V4L2_MPEG_VIDEO_VP8_PROFILE_2:
1287 case V4L2_MPEG_VIDEO_VP8_PROFILE_3:
1288 return VP8PROFILE_ANY;
1289 }
1290 break;
1291 case kCodecVP9:
1292 switch (profile) {
1293 case V4L2_MPEG_VIDEO_VP9_PROFILE_0:
1294 return VP9PROFILE_PROFILE0;
1295 case V4L2_MPEG_VIDEO_VP9_PROFILE_1:
1296 return VP9PROFILE_PROFILE1;
1297 case V4L2_MPEG_VIDEO_VP9_PROFILE_2:
1298 return VP9PROFILE_PROFILE2;
1299 case V4L2_MPEG_VIDEO_VP9_PROFILE_3:
1300 return VP9PROFILE_PROFILE3;
1301 }
1302 break;
1303 default:
1304 VLOGF(2) << "Unknown codec: " << codec;
1305 }
1306 VLOGF(2) << "Unknown profile: " << profile;
1307 return VIDEO_CODEC_PROFILE_UNKNOWN;
1308 }
1309
V4L2PixFmtToVideoCodecProfiles(uint32_t pix_fmt,bool is_encoder)1310 std::vector<VideoCodecProfile> V4L2Device::V4L2PixFmtToVideoCodecProfiles(
1311 uint32_t pix_fmt,
1312 bool is_encoder) {
1313 auto get_supported_profiles = [this](
1314 VideoCodec codec,
1315 std::vector<VideoCodecProfile>* profiles) {
1316 uint32_t query_id = 0;
1317 switch (codec) {
1318 case kCodecH264:
1319 query_id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
1320 break;
1321 case kCodecVP8:
1322 query_id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
1323 break;
1324 case kCodecVP9:
1325 query_id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
1326 break;
1327 default:
1328 return false;
1329 }
1330
1331 v4l2_queryctrl query_ctrl = {};
1332 query_ctrl.id = query_id;
1333 if (Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) != 0) {
1334 return false;
1335 }
1336 v4l2_querymenu query_menu = {};
1337 query_menu.id = query_ctrl.id;
1338 for (query_menu.index = query_ctrl.minimum;
1339 static_cast<int>(query_menu.index) <= query_ctrl.maximum;
1340 query_menu.index++) {
1341 if (Ioctl(VIDIOC_QUERYMENU, &query_menu) == 0) {
1342 const VideoCodecProfile profile =
1343 V4L2Device::V4L2ProfileToVideoCodecProfile(codec, query_menu.index);
1344 if (profile != VIDEO_CODEC_PROFILE_UNKNOWN)
1345 profiles->push_back(profile);
1346 }
1347 }
1348 return true;
1349 };
1350
1351 std::vector<VideoCodecProfile> profiles;
1352 switch (pix_fmt) {
1353 case V4L2_PIX_FMT_H264:
1354 case V4L2_PIX_FMT_H264_SLICE:
1355 if (!get_supported_profiles(kCodecH264, &profiles)) {
1356 DLOG(WARNING) << "Driver doesn't support QUERY H264 profiles, "
1357 << "use default values, Base, Main, High";
1358 profiles = {
1359 H264PROFILE_BASELINE,
1360 H264PROFILE_MAIN,
1361 H264PROFILE_HIGH,
1362 };
1363 }
1364 break;
1365 case V4L2_PIX_FMT_VP8:
1366 case V4L2_PIX_FMT_VP8_FRAME:
1367 profiles = {VP8PROFILE_ANY};
1368 break;
1369 case V4L2_PIX_FMT_VP9:
1370 case V4L2_PIX_FMT_VP9_FRAME:
1371 if (!get_supported_profiles(kCodecVP9, &profiles)) {
1372 DLOG(WARNING) << "Driver doesn't support QUERY VP9 profiles, "
1373 << "use default values, Profile0";
1374 profiles = {VP9PROFILE_PROFILE0};
1375 }
1376 break;
1377 default:
1378 VLOGF(1) << "Unhandled pixelformat " << FourccToString(pix_fmt);
1379 return {};
1380 }
1381
1382 // Erase duplicated profiles.
1383 std::sort(profiles.begin(), profiles.end());
1384 profiles.erase(std::unique(profiles.begin(), profiles.end()), profiles.end());
1385 return profiles;
1386 }
1387
1388 // static
V4L2PixFmtToDrmFormat(uint32_t format)1389 uint32_t V4L2Device::V4L2PixFmtToDrmFormat(uint32_t format) {
1390 switch (format) {
1391 case V4L2_PIX_FMT_NV12:
1392 case V4L2_PIX_FMT_NV12M:
1393 return DRM_FORMAT_NV12;
1394
1395 case V4L2_PIX_FMT_YUV420:
1396 case V4L2_PIX_FMT_YUV420M:
1397 return DRM_FORMAT_YUV420;
1398
1399 case V4L2_PIX_FMT_YVU420:
1400 return DRM_FORMAT_YVU420;
1401
1402 case V4L2_PIX_FMT_RGB32:
1403 return DRM_FORMAT_ARGB8888;
1404
1405 default:
1406 DVLOGF(1) << "Unrecognized format " << FourccToString(format);
1407 return 0;
1408 }
1409 }
1410
1411 // static
VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile)1412 int32_t V4L2Device::VideoCodecProfileToV4L2H264Profile(
1413 VideoCodecProfile profile) {
1414 switch (profile) {
1415 case H264PROFILE_BASELINE:
1416 return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
1417 case H264PROFILE_MAIN:
1418 return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
1419 case H264PROFILE_EXTENDED:
1420 return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
1421 case H264PROFILE_HIGH:
1422 return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
1423 case H264PROFILE_HIGH10PROFILE:
1424 return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
1425 case H264PROFILE_HIGH422PROFILE:
1426 return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
1427 case H264PROFILE_HIGH444PREDICTIVEPROFILE:
1428 return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
1429 case H264PROFILE_SCALABLEBASELINE:
1430 return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
1431 case H264PROFILE_SCALABLEHIGH:
1432 return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
1433 case H264PROFILE_STEREOHIGH:
1434 return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
1435 case H264PROFILE_MULTIVIEWHIGH:
1436 return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
1437 default:
1438 DVLOGF(1) << "Add more cases as needed";
1439 return -1;
1440 }
1441 }
1442
1443 // static
H264LevelIdcToV4L2H264Level(uint8_t level_idc)1444 int32_t V4L2Device::H264LevelIdcToV4L2H264Level(uint8_t level_idc) {
1445 switch (level_idc) {
1446 case 10:
1447 return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
1448 case 9:
1449 return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
1450 case 11:
1451 return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
1452 case 12:
1453 return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
1454 case 13:
1455 return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
1456 case 20:
1457 return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
1458 case 21:
1459 return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
1460 case 22:
1461 return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
1462 case 30:
1463 return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
1464 case 31:
1465 return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
1466 case 32:
1467 return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
1468 case 40:
1469 return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
1470 case 41:
1471 return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
1472 case 42:
1473 return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
1474 case 50:
1475 return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
1476 case 51:
1477 return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
1478 default:
1479 DVLOGF(1) << "Unrecognized level_idc: " << static_cast<int>(level_idc);
1480 return -1;
1481 }
1482 }
1483
1484 // static
AllocatedSizeFromV4L2Format(const struct v4l2_format & format)1485 gfx::Size V4L2Device::AllocatedSizeFromV4L2Format(
1486 const struct v4l2_format& format) {
1487 gfx::Size coded_size;
1488 gfx::Size visible_size;
1489 VideoPixelFormat frame_format = PIXEL_FORMAT_UNKNOWN;
1490 size_t bytesperline = 0;
1491 // Total bytes in the frame.
1492 size_t sizeimage = 0;
1493
1494 if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1495 DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
1496 bytesperline =
1497 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
1498 for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
1499 sizeimage +=
1500 base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
1501 }
1502 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
1503 base::checked_cast<int>(format.fmt.pix_mp.height));
1504 const uint32_t pix_fmt = format.fmt.pix_mp.pixelformat;
1505 const auto frame_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1506 if (!frame_fourcc) {
1507 VLOGF(1) << "Unsupported format " << FourccToString(pix_fmt);
1508 return coded_size;
1509 }
1510 frame_format = frame_fourcc->ToVideoPixelFormat();
1511 } else {
1512 bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
1513 sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
1514 visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
1515 base::checked_cast<int>(format.fmt.pix.height));
1516 const uint32_t fourcc = format.fmt.pix.pixelformat;
1517 const auto frame_fourcc = Fourcc::FromV4L2PixFmt(fourcc);
1518 if (!frame_fourcc) {
1519 VLOGF(1) << "Unsupported format " << FourccToString(fourcc);
1520 return coded_size;
1521 }
1522 frame_format = frame_fourcc ? frame_fourcc->ToVideoPixelFormat()
1523 : PIXEL_FORMAT_UNKNOWN;
1524 }
1525
1526 // V4L2 does not provide per-plane bytesperline (bpl) when different
1527 // components are sharing one physical plane buffer. In this case, it only
1528 // provides bpl for the first component in the plane. So we can't depend on it
1529 // for calculating height, because bpl may vary within one physical plane
1530 // buffer. For example, YUV420 contains 3 components in one physical plane,
1531 // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
1532 // but we only get 8 pits per pixel from bytesperline in physical plane 0.
1533 // So we need to get total frame bpp from elsewhere to calculate coded height.
1534
1535 // We need bits per pixel for one component only to calculate
1536 // coded_width from bytesperline.
1537 int plane_horiz_bits_per_pixel =
1538 VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
1539
1540 // Adding up bpp for each component will give us total bpp for all components.
1541 int total_bpp = 0;
1542 for (size_t i = 0; i < VideoFrame::NumPlanes(frame_format); ++i)
1543 total_bpp += VideoFrame::PlaneBitsPerPixel(frame_format, i);
1544
1545 if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
1546 total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
1547 VLOGF(1) << "Invalid format provided";
1548 return coded_size;
1549 }
1550
1551 // Coded width can be calculated by taking the first component's bytesperline,
1552 // which in V4L2 always applies to the first component in physical plane
1553 // buffer.
1554 int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
1555 // Sizeimage is coded_width * coded_height * total_bpp. In the case that we
1556 // don't have exact alignment due to padding in the driver, round up so that
1557 // the buffer is large enough.
1558 std::div_t res = std::div(sizeimage * 8, coded_width * total_bpp);
1559 int coded_height = res.quot + std::min(res.rem, 1);
1560
1561 coded_size.SetSize(coded_width, coded_height);
1562 DVLOGF(3) << "coded_size=" << coded_size.ToString();
1563
1564 // Sanity checks. Calculated coded size has to contain given visible size
1565 // and fulfill buffer byte size requirements.
1566 DCHECK(gfx::Rect(coded_size).Contains(gfx::Rect(visible_size)));
1567 DCHECK_LE(sizeimage, VideoFrame::AllocationSize(frame_format, coded_size));
1568
1569 return coded_size;
1570 }
1571
1572 // static
V4L2MemoryToString(const v4l2_memory memory)1573 const char* V4L2Device::V4L2MemoryToString(const v4l2_memory memory) {
1574 switch (memory) {
1575 case V4L2_MEMORY_MMAP:
1576 return "V4L2_MEMORY_MMAP";
1577 case V4L2_MEMORY_USERPTR:
1578 return "V4L2_MEMORY_USERPTR";
1579 case V4L2_MEMORY_DMABUF:
1580 return "V4L2_MEMORY_DMABUF";
1581 case V4L2_MEMORY_OVERLAY:
1582 return "V4L2_MEMORY_OVERLAY";
1583 default:
1584 return "UNKNOWN";
1585 }
1586 }
1587
1588 // static
V4L2BufferTypeToString(const enum v4l2_buf_type buf_type)1589 const char* V4L2Device::V4L2BufferTypeToString(
1590 const enum v4l2_buf_type buf_type) {
1591 switch (buf_type) {
1592 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1593 return "OUTPUT";
1594 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1595 return "CAPTURE";
1596 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1597 return "OUTPUT_MPLANE";
1598 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1599 return "CAPTURE_MPLANE";
1600 default:
1601 return "UNKNOWN";
1602 }
1603 }
1604
1605 // static
V4L2FormatToString(const struct v4l2_format & format)1606 std::string V4L2Device::V4L2FormatToString(const struct v4l2_format& format) {
1607 std::ostringstream s;
1608 s << "v4l2_format type: " << format.type;
1609 if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1610 format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1611 // single-planar
1612 const struct v4l2_pix_format& pix = format.fmt.pix;
1613 s << ", width_height: " << gfx::Size(pix.width, pix.height).ToString()
1614 << ", pixelformat: " << FourccToString(pix.pixelformat)
1615 << ", field: " << pix.field << ", bytesperline: " << pix.bytesperline
1616 << ", sizeimage: " << pix.sizeimage;
1617 } else if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1618 const struct v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
1619 // As long as num_planes's type is uint8_t, ostringstream treats it as a
1620 // char instead of an integer, which is not what we want. Casting
1621 // pix_mp.num_planes unsigned int solves the issue.
1622 s << ", width_height: " << gfx::Size(pix_mp.width, pix_mp.height).ToString()
1623 << ", pixelformat: " << FourccToString(pix_mp.pixelformat)
1624 << ", field: " << pix_mp.field
1625 << ", num_planes: " << static_cast<unsigned int>(pix_mp.num_planes);
1626 for (size_t i = 0; i < pix_mp.num_planes; ++i) {
1627 const struct v4l2_plane_pix_format& plane_fmt = pix_mp.plane_fmt[i];
1628 s << ", plane_fmt[" << i << "].sizeimage: " << plane_fmt.sizeimage
1629 << ", plane_fmt[" << i << "].bytesperline: " << plane_fmt.bytesperline;
1630 }
1631 } else {
1632 s << " unsupported yet.";
1633 }
1634 return s.str();
1635 }
1636
1637 // static
V4L2BufferToString(const struct v4l2_buffer & buffer)1638 std::string V4L2Device::V4L2BufferToString(const struct v4l2_buffer& buffer) {
1639 std::ostringstream s;
1640 s << "v4l2_buffer type: " << buffer.type << ", memory: " << buffer.memory
1641 << ", index: " << buffer.index << " bytesused: " << buffer.bytesused
1642 << ", length: " << buffer.length;
1643 if (buffer.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1644 buffer.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1645 // single-planar
1646 if (buffer.memory == V4L2_MEMORY_MMAP) {
1647 s << ", m.offset: " << buffer.m.offset;
1648 } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1649 s << ", m.userptr: " << buffer.m.userptr;
1650 } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1651 s << ", m.fd: " << buffer.m.fd;
1652 }
1653 } else if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
1654 for (size_t i = 0; i < buffer.length; ++i) {
1655 const struct v4l2_plane& plane = buffer.m.planes[i];
1656 s << ", m.planes[" << i << "](bytesused: " << plane.bytesused
1657 << ", length: " << plane.length
1658 << ", data_offset: " << plane.data_offset;
1659 if (buffer.memory == V4L2_MEMORY_MMAP) {
1660 s << ", m.mem_offset: " << plane.m.mem_offset;
1661 } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1662 s << ", m.userptr: " << plane.m.userptr;
1663 } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1664 s << ", m.fd: " << plane.m.fd;
1665 }
1666 s << ")";
1667 }
1668 } else {
1669 s << " unsupported yet.";
1670 }
1671 return s.str();
1672 }
1673
1674 // static
V4L2FormatToVideoFrameLayout(const struct v4l2_format & format)1675 base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout(
1676 const struct v4l2_format& format) {
1677 if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1678 VLOGF(1) << "v4l2_buf_type is not multiplanar: " << std::hex << "0x"
1679 << format.type;
1680 return base::nullopt;
1681 }
1682 const v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
1683 const uint32_t& pix_fmt = pix_mp.pixelformat;
1684 const auto video_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1685 if (!video_fourcc) {
1686 VLOGF(1) << "Failed to convert pixel format to VideoPixelFormat: "
1687 << FourccToString(pix_fmt);
1688 return base::nullopt;
1689 }
1690 const VideoPixelFormat video_format = video_fourcc->ToVideoPixelFormat();
1691 const size_t num_buffers = pix_mp.num_planes;
1692 const size_t num_color_planes = VideoFrame::NumPlanes(video_format);
1693 if (num_color_planes == 0) {
1694 VLOGF(1) << "Unsupported video format for NumPlanes(): "
1695 << VideoPixelFormatToString(video_format);
1696 return base::nullopt;
1697 }
1698 if (num_buffers > num_color_planes) {
1699 VLOGF(1) << "pix_mp.num_planes: " << num_buffers
1700 << " should not be larger than NumPlanes("
1701 << VideoPixelFormatToString(video_format)
1702 << "): " << num_color_planes;
1703 return base::nullopt;
1704 }
1705 // Reserve capacity in advance to prevent unnecessary vector reallocation.
1706 std::vector<ColorPlaneLayout> planes;
1707 planes.reserve(num_color_planes);
1708 for (size_t i = 0; i < num_buffers; ++i) {
1709 const v4l2_plane_pix_format& plane_format = pix_mp.plane_fmt[i];
1710 planes.emplace_back(static_cast<int32_t>(plane_format.bytesperline), 0u,
1711 plane_format.sizeimage);
1712 }
1713 // For the case that #color planes > #buffers, it fills stride of color
1714 // plane which does not map to buffer.
1715 // Right now only some pixel formats are supported: NV12, YUV420, YVU420.
1716 if (num_color_planes > num_buffers) {
1717 const int32_t y_stride = planes[0].stride;
1718 // Note that y_stride is from v4l2 bytesperline and its type is uint32_t.
1719 // It is safe to cast to size_t.
1720 const size_t y_stride_abs = static_cast<size_t>(y_stride);
1721 switch (pix_fmt) {
1722 case V4L2_PIX_FMT_NV12:
1723 // The stride of UV is the same as Y in NV12.
1724 // The height is half of Y plane.
1725 planes.emplace_back(y_stride, y_stride_abs * pix_mp.height,
1726 y_stride_abs * pix_mp.height / 2);
1727 DCHECK_EQ(2u, planes.size());
1728 break;
1729 case V4L2_PIX_FMT_YUV420:
1730 case V4L2_PIX_FMT_YVU420: {
1731 // The spec claims that two Cx rows (including padding) is exactly as
1732 // long as one Y row (including padding). So stride of Y must be even
1733 // number.
1734 if (y_stride % 2 != 0 || pix_mp.height % 2 != 0) {
1735 VLOGF(1) << "Plane-Y stride and height should be even; stride: "
1736 << y_stride << ", height: " << pix_mp.height;
1737 return base::nullopt;
1738 }
1739 const int32_t half_stride = y_stride / 2;
1740 const size_t plane_0_area = y_stride_abs * pix_mp.height;
1741 const size_t plane_1_area = plane_0_area / 4;
1742 planes.emplace_back(half_stride, plane_0_area, plane_1_area);
1743 planes.emplace_back(half_stride, plane_0_area + plane_1_area,
1744 plane_1_area);
1745 DCHECK_EQ(3u, planes.size());
1746 break;
1747 }
1748 default:
1749 VLOGF(1) << "Cannot derive stride for each plane for pixel format "
1750 << FourccToString(pix_fmt);
1751 return base::nullopt;
1752 }
1753 }
1754
1755 // Some V4L2 devices expect buffers to be page-aligned. We cannot detect
1756 // such devices individually, so set this as a video frame layout property.
1757 constexpr size_t buffer_alignment = 0x1000;
1758 if (num_buffers == 1) {
1759 return VideoFrameLayout::CreateWithPlanes(
1760 video_format, gfx::Size(pix_mp.width, pix_mp.height), std::move(planes),
1761 buffer_alignment);
1762 } else {
1763 return VideoFrameLayout::CreateMultiPlanar(
1764 video_format, gfx::Size(pix_mp.width, pix_mp.height), std::move(planes),
1765 buffer_alignment);
1766 }
1767 }
1768
1769 // static
GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt)1770 size_t V4L2Device::GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt) {
1771 base::Optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1772 if (fourcc && fourcc->IsMultiPlanar()) {
1773 return VideoFrame::NumPlanes(fourcc->ToVideoPixelFormat());
1774 }
1775 return 1u;
1776 }
1777
GetSupportedResolution(uint32_t pixelformat,gfx::Size * min_resolution,gfx::Size * max_resolution)1778 void V4L2Device::GetSupportedResolution(uint32_t pixelformat,
1779 gfx::Size* min_resolution,
1780 gfx::Size* max_resolution) {
1781 max_resolution->SetSize(0, 0);
1782 min_resolution->SetSize(0, 0);
1783 v4l2_frmsizeenum frame_size;
1784 memset(&frame_size, 0, sizeof(frame_size));
1785 frame_size.pixel_format = pixelformat;
1786 for (; Ioctl(VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; ++frame_size.index) {
1787 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
1788 if (frame_size.discrete.width >=
1789 base::checked_cast<uint32_t>(max_resolution->width()) &&
1790 frame_size.discrete.height >=
1791 base::checked_cast<uint32_t>(max_resolution->height())) {
1792 max_resolution->SetSize(frame_size.discrete.width,
1793 frame_size.discrete.height);
1794 }
1795 if (min_resolution->IsEmpty() ||
1796 (frame_size.discrete.width <=
1797 base::checked_cast<uint32_t>(min_resolution->width()) &&
1798 frame_size.discrete.height <=
1799 base::checked_cast<uint32_t>(min_resolution->height()))) {
1800 min_resolution->SetSize(frame_size.discrete.width,
1801 frame_size.discrete.height);
1802 }
1803 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
1804 frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
1805 max_resolution->SetSize(frame_size.stepwise.max_width,
1806 frame_size.stepwise.max_height);
1807 min_resolution->SetSize(frame_size.stepwise.min_width,
1808 frame_size.stepwise.min_height);
1809 break;
1810 }
1811 }
1812 if (max_resolution->IsEmpty()) {
1813 max_resolution->SetSize(1920, 1088);
1814 VLOGF(1) << "GetSupportedResolution failed to get maximum resolution for "
1815 << "fourcc " << FourccToString(pixelformat) << ", fall back to "
1816 << max_resolution->ToString();
1817 }
1818 if (min_resolution->IsEmpty()) {
1819 min_resolution->SetSize(16, 16);
1820 VLOGF(1) << "GetSupportedResolution failed to get minimum resolution for "
1821 << "fourcc " << FourccToString(pixelformat) << ", fall back to "
1822 << min_resolution->ToString();
1823 }
1824 }
1825
EnumerateSupportedPixelformats(v4l2_buf_type buf_type)1826 std::vector<uint32_t> V4L2Device::EnumerateSupportedPixelformats(
1827 v4l2_buf_type buf_type) {
1828 std::vector<uint32_t> pixelformats;
1829
1830 v4l2_fmtdesc fmtdesc;
1831 memset(&fmtdesc, 0, sizeof(fmtdesc));
1832 fmtdesc.type = buf_type;
1833
1834 for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
1835 DVLOGF(3) << "Found " << fmtdesc.description << std::hex << " (0x"
1836 << fmtdesc.pixelformat << ")";
1837 pixelformats.push_back(fmtdesc.pixelformat);
1838 }
1839
1840 return pixelformats;
1841 }
1842
1843 VideoDecodeAccelerator::SupportedProfiles
EnumerateSupportedDecodeProfiles(const size_t num_formats,const uint32_t pixelformats[])1844 V4L2Device::EnumerateSupportedDecodeProfiles(const size_t num_formats,
1845 const uint32_t pixelformats[]) {
1846 VideoDecodeAccelerator::SupportedProfiles profiles;
1847
1848 const auto& supported_pixelformats =
1849 EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1850
1851 for (uint32_t pixelformat : supported_pixelformats) {
1852 if (std::find(pixelformats, pixelformats + num_formats, pixelformat) ==
1853 pixelformats + num_formats)
1854 continue;
1855
1856 VideoDecodeAccelerator::SupportedProfile profile;
1857 GetSupportedResolution(pixelformat, &profile.min_resolution,
1858 &profile.max_resolution);
1859
1860 const auto video_codec_profiles =
1861 V4L2PixFmtToVideoCodecProfiles(pixelformat, false);
1862
1863 for (const auto& video_codec_profile : video_codec_profiles) {
1864 profile.profile = video_codec_profile;
1865 profiles.push_back(profile);
1866
1867 DVLOGF(3) << "Found decoder profile " << GetProfileName(profile.profile)
1868 << ", resolutions: " << profile.min_resolution.ToString() << " "
1869 << profile.max_resolution.ToString();
1870 }
1871 }
1872
1873 return profiles;
1874 }
1875
1876 VideoEncodeAccelerator::SupportedProfiles
EnumerateSupportedEncodeProfiles()1877 V4L2Device::EnumerateSupportedEncodeProfiles() {
1878 VideoEncodeAccelerator::SupportedProfiles profiles;
1879
1880 const auto& supported_pixelformats =
1881 EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
1882
1883 for (const auto& pixelformat : supported_pixelformats) {
1884 VideoEncodeAccelerator::SupportedProfile profile;
1885 profile.max_framerate_numerator = 30;
1886 profile.max_framerate_denominator = 1;
1887 gfx::Size min_resolution;
1888 GetSupportedResolution(pixelformat, &min_resolution,
1889 &profile.max_resolution);
1890
1891 const auto video_codec_profiles =
1892 V4L2PixFmtToVideoCodecProfiles(pixelformat, true);
1893
1894 for (const auto& video_codec_profile : video_codec_profiles) {
1895 profile.profile = video_codec_profile;
1896 profiles.push_back(profile);
1897
1898 DVLOGF(3) << "Found encoder profile " << GetProfileName(profile.profile)
1899 << ", max resolution: " << profile.max_resolution.ToString();
1900 }
1901 }
1902
1903 return profiles;
1904 }
1905
StartPolling(V4L2DevicePoller::EventCallback event_callback,base::RepeatingClosure error_callback)1906 bool V4L2Device::StartPolling(V4L2DevicePoller::EventCallback event_callback,
1907 base::RepeatingClosure error_callback) {
1908 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1909
1910 if (!device_poller_) {
1911 device_poller_ =
1912 std::make_unique<V4L2DevicePoller>(this, "V4L2DeviceThreadPoller");
1913 }
1914
1915 bool ret = device_poller_->StartPolling(std::move(event_callback),
1916 std::move(error_callback));
1917
1918 if (!ret)
1919 device_poller_ = nullptr;
1920
1921 return ret;
1922 }
1923
StopPolling()1924 bool V4L2Device::StopPolling() {
1925 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1926
1927 return !device_poller_ || device_poller_->StopPolling();
1928 }
1929
SchedulePoll()1930 void V4L2Device::SchedulePoll() {
1931 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1932
1933 if (!device_poller_ || !device_poller_->IsPolling())
1934 return;
1935
1936 device_poller_->SchedulePoll();
1937 }
1938
GetRequestsQueue()1939 V4L2RequestsQueue* V4L2Device::GetRequestsQueue() {
1940 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1941
1942 if (requests_queue_creation_called_)
1943 return requests_queue_.get();
1944
1945 requests_queue_creation_called_ = true;
1946 int media_fd = open(REQUEST_DEVICE, O_RDWR, 0);
1947 if (media_fd < 0) {
1948 VPLOGF(1) << "Failed to open media device.";
1949 return nullptr;
1950 }
1951
1952 // Not using std::make_unique because constructor is private.
1953 std::unique_ptr<V4L2RequestsQueue> requests_queue(new V4L2RequestsQueue(
1954 base::ScopedFD(media_fd)));
1955 requests_queue_ = std::move(requests_queue);
1956
1957 return requests_queue_.get();
1958 }
1959
IsCtrlExposed(uint32_t ctrl_id)1960 bool V4L2Device::IsCtrlExposed(uint32_t ctrl_id) {
1961 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1962
1963 struct v4l2_queryctrl query_ctrl {};
1964 query_ctrl.id = ctrl_id;
1965
1966 return Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) == 0;
1967 }
1968
SetExtCtrls(uint32_t ctrl_class,std::vector<V4L2ExtCtrl> ctrls)1969 bool V4L2Device::SetExtCtrls(uint32_t ctrl_class,
1970 std::vector<V4L2ExtCtrl> ctrls) {
1971 DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1972
1973 if (ctrls.empty())
1974 return true;
1975
1976 struct v4l2_ext_controls ext_ctrls {};
1977 ext_ctrls.ctrl_class = ctrl_class;
1978 ext_ctrls.count = ctrls.size();
1979 ext_ctrls.controls = &ctrls[0].ctrl;
1980 return Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0;
1981 }
1982
1983 class V4L2Request {
1984 public:
1985 // Apply the passed controls to the request.
1986 bool ApplyCtrls(struct v4l2_ext_controls* ctrls);
1987 // Apply the passed buffer to the request..
1988 bool ApplyQueueBuffer(struct v4l2_buffer* buffer);
1989 // Submits the request to the driver.
1990 bool Submit();
1991 // Indicates if the request has completed.
1992 bool IsCompleted();
1993 // Waits for the request to complete for a determined timeout. Returns false
1994 // if the request is not ready or other error. Default timeout is 500ms.
1995 bool WaitForCompletion(int poll_timeout_ms = 500);
1996 // Resets the request.
1997 bool Reset();
1998
1999 private:
2000 V4L2RequestsQueue* request_queue_;
2001 int ref_counter_ = 0;
2002 base::ScopedFD request_fd_;
2003
2004 friend class V4L2RequestsQueue;
V4L2Request(base::ScopedFD && request_fd,V4L2RequestsQueue * request_queue)2005 V4L2Request(base::ScopedFD&& request_fd, V4L2RequestsQueue* request_queue) :
2006 request_queue_(request_queue), request_fd_(std::move(request_fd)) {}
2007
2008 friend class V4L2RequestRefBase;
2009 // Increases the number of request references.
2010 void IncRefCounter();
2011 // Decreases the number of request references.
2012 // When the counters reaches zero, the request is returned to the queue.
2013 int DecRefCounter();
2014
2015 SEQUENCE_CHECKER(sequence_checker_);
2016 DISALLOW_COPY_AND_ASSIGN(V4L2Request);
2017 };
2018
IncRefCounter()2019 void V4L2Request::IncRefCounter() {
2020 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2021
2022 ref_counter_++;
2023 }
2024
DecRefCounter()2025 int V4L2Request::DecRefCounter() {
2026 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2027
2028 ref_counter_--;
2029
2030 if (ref_counter_< 1)
2031 request_queue_->ReturnRequest(this);
2032
2033 return ref_counter_;
2034 }
2035
ApplyCtrls(struct v4l2_ext_controls * ctrls)2036 bool V4L2Request::ApplyCtrls(struct v4l2_ext_controls* ctrls) {
2037 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2038 DCHECK_NE(ctrls, nullptr);
2039
2040 if (!request_fd_.is_valid()) {
2041 VPLOGF(1) << "Invalid request";
2042 return false;
2043 }
2044
2045 ctrls->which = V4L2_CTRL_WHICH_REQUEST_VAL;
2046 ctrls->request_fd = request_fd_.get();
2047
2048 return true;
2049 }
2050
ApplyQueueBuffer(struct v4l2_buffer * buffer)2051 bool V4L2Request::ApplyQueueBuffer(struct v4l2_buffer* buffer) {
2052 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2053 DCHECK_NE(buffer, nullptr);
2054
2055 if (!request_fd_.is_valid()) {
2056 VPLOGF(1) << "Invalid request";
2057 return false;
2058 }
2059
2060 buffer->flags |= V4L2_BUF_FLAG_REQUEST_FD;
2061 buffer->request_fd = request_fd_.get();
2062
2063 return true;
2064 }
2065
Submit()2066 bool V4L2Request::Submit() {
2067 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2068
2069 if (!request_fd_.is_valid()) {
2070 VPLOGF(1) << "No valid request file descriptor to submit request.";
2071 return false;
2072 }
2073
2074 return HANDLE_EINTR(ioctl(request_fd_.get(), MEDIA_REQUEST_IOC_QUEUE)) == 0;
2075 }
2076
IsCompleted()2077 bool V4L2Request::IsCompleted() {
2078 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2079
2080 return WaitForCompletion(0);
2081 }
2082
WaitForCompletion(int poll_timeout_ms)2083 bool V4L2Request::WaitForCompletion(int poll_timeout_ms) {
2084 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2085 if (!request_fd_.is_valid()) {
2086 VPLOGF(1) << "Invalid request";
2087 return false;
2088 }
2089
2090 struct pollfd poll_fd = {request_fd_.get(), POLLPRI, 0};
2091
2092 // Poll the request to ensure its previous task is done
2093 switch (poll(&poll_fd, 1, poll_timeout_ms)) {
2094 case 1:
2095 return true;
2096 case 0:
2097 // Not an error - we just timed out.
2098 DVLOGF(4) << "Request poll(" << poll_timeout_ms << ") timed out";
2099 return false;
2100 case -1:
2101 VPLOGF(1) << "Failed to poll request";
2102 return false;
2103 default:
2104 NOTREACHED();
2105 return false;
2106 }
2107 }
2108
Reset()2109 bool V4L2Request::Reset() {
2110 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2111
2112 if (!request_fd_.is_valid()) {
2113 VPLOGF(1) << "Invalid request";
2114 return false;
2115 }
2116
2117 // Reinit the request to make sure we can use it for a new submission.
2118 if (HANDLE_EINTR(ioctl(request_fd_.get(), MEDIA_REQUEST_IOC_REINIT)) < 0) {
2119 VPLOGF(1) << "Failed to reinit request.";
2120 return false;
2121 }
2122
2123 return true;
2124 }
2125
V4L2RequestRefBase(V4L2RequestRefBase && req_base)2126 V4L2RequestRefBase::V4L2RequestRefBase(V4L2RequestRefBase&& req_base) {
2127 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2128
2129 request_ = req_base.request_;
2130 req_base.request_ = nullptr;
2131 }
2132
V4L2RequestRefBase(V4L2Request * request)2133 V4L2RequestRefBase::V4L2RequestRefBase(V4L2Request* request) {
2134 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2135
2136 if (request) {
2137 request_ = request;
2138 request_->IncRefCounter();
2139 }
2140 }
2141
~V4L2RequestRefBase()2142 V4L2RequestRefBase::~V4L2RequestRefBase() {
2143 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2144
2145 if (request_)
2146 request_->DecRefCounter();
2147 }
2148
ApplyCtrls(struct v4l2_ext_controls * ctrls) const2149 bool V4L2RequestRef::ApplyCtrls(struct v4l2_ext_controls* ctrls) const {
2150 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2151 DCHECK_NE(request_, nullptr);
2152
2153 return request_->ApplyCtrls(ctrls);
2154 }
2155
ApplyQueueBuffer(struct v4l2_buffer * buffer) const2156 bool V4L2RequestRef::ApplyQueueBuffer(struct v4l2_buffer* buffer) const {
2157 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2158 DCHECK_NE(request_, nullptr);
2159
2160 return request_->ApplyQueueBuffer(buffer);
2161 }
2162
Submit()2163 base::Optional<V4L2SubmittedRequestRef> V4L2RequestRef::Submit() && {
2164 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2165 DCHECK_NE(request_, nullptr);
2166
2167 V4L2RequestRef self(std::move(*this));
2168
2169 if (!self.request_->Submit())
2170 return base::nullopt;
2171
2172 return V4L2SubmittedRequestRef(self.request_);
2173 }
2174
IsCompleted()2175 bool V4L2SubmittedRequestRef::IsCompleted() {
2176 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2177 DCHECK_NE(request_, nullptr);
2178
2179 return request_->IsCompleted();
2180 }
2181
V4L2RequestsQueue(base::ScopedFD && media_fd)2182 V4L2RequestsQueue::V4L2RequestsQueue(base::ScopedFD&& media_fd) {
2183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2184
2185 media_fd_ = std::move(media_fd);
2186 }
2187
~V4L2RequestsQueue()2188 V4L2RequestsQueue::~V4L2RequestsQueue() {
2189 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2190
2191 requests_.clear();
2192 media_fd_.reset();
2193 }
2194
CreateRequestFD()2195 base::Optional<base::ScopedFD> V4L2RequestsQueue::CreateRequestFD() {
2196 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2197
2198 int request_fd;
2199 int ret = HANDLE_EINTR(
2200 ioctl(media_fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &request_fd));
2201 if (ret < 0) {
2202 VPLOGF(1) << "Failed to create request";
2203 return base::nullopt;
2204 }
2205
2206 return base::ScopedFD(request_fd);
2207 }
2208
GetFreeRequest()2209 base::Optional<V4L2RequestRef> V4L2RequestsQueue::GetFreeRequest() {
2210 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2211
2212 V4L2Request* request_ptr =
2213 free_requests_.empty() ? nullptr : free_requests_.front();
2214 if (request_ptr && request_ptr->IsCompleted()) {
2215 // Previous request is already completed, just recycle it.
2216 free_requests_.pop();
2217 } else if (requests_.size() < kMaxNumRequests) {
2218 // No request yet, or not completed, but we can allocate a new one.
2219 auto request_fd = CreateRequestFD();
2220 if (!request_fd.has_value()) {
2221 VLOGF(1) << "Error while creating a new request FD!";
2222 return base::nullopt;
2223 }
2224 // Not using std::make_unique because constructor is private.
2225 std::unique_ptr<V4L2Request> request(
2226 new V4L2Request(std::move(*request_fd), this));
2227 request_ptr = request.get();
2228 requests_.push_back(std::move(request));
2229 VLOGF(4) << "Allocated new request, total number: " << requests_.size();
2230 } else {
2231 // Request is not completed and we have reached the maximum number.
2232 // Wait for it to complete.
2233 VLOGF(1) << "Waiting for request completion. This probably means a "
2234 << "request is blocking.";
2235 if (!request_ptr->WaitForCompletion()) {
2236 VLOG(1) << "Timeout while waiting for request to complete.";
2237 return base::nullopt;
2238 }
2239 free_requests_.pop();
2240 }
2241
2242 DCHECK(request_ptr);
2243 if (!request_ptr->Reset()) {
2244 VPLOGF(1) << "Failed to reset request";
2245 return base::nullopt;
2246 }
2247
2248 return V4L2RequestRef(request_ptr);
2249 }
2250
ReturnRequest(V4L2Request * request)2251 void V4L2RequestsQueue::ReturnRequest(V4L2Request* request) {
2252 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
2253 DCHECK(request);
2254
2255 if (request)
2256 free_requests_.push(request);
2257 }
2258
2259 } // namespace media
2260