• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Note: ported from Chromium commit head: 2f13d62f0c0d
5 // Note: Added some missing defines that are only defined in newer kernel
6 //       versions (e.g. V4L2_PIX_FMT_VP8_FRAME)
7 
8 #include "v4l2_device.h"
9 
10 #include <fcntl.h>
11 #include <linux/media.h>
12 #include <linux/videodev2.h>
13 #include <poll.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
17 
18 #include <algorithm>
19 #include <set>
20 #include <sstream>
21 
22 #include "base/bind.h"
23 #include "base/logging.h"
24 #include "base/numerics/safe_conversions.h"
25 #include "base/posix/eintr_wrapper.h"
26 
27 #include "color_plane_layout.h"
28 #include "generic_v4l2_device.h"
29 #include "macros.h"
30 #include "video_pixel_format.h"
31 
32 // VP8 parsed frames
33 #ifndef V4L2_PIX_FMT_VP8_FRAME
34 #define V4L2_PIX_FMT_VP8_FRAME v4l2_fourcc('V', 'P', '8', 'F')
35 #endif
36 
37 // VP9 parsed frames
38 #ifndef V4L2_PIX_FMT_VP9_FRAME
39 #define V4L2_PIX_FMT_VP9_FRAME v4l2_fourcc('V', 'P', '9', 'F')
40 #endif
41 
42 // H264 parsed slices
43 #ifndef V4L2_PIX_FMT_H264_SLICE
44 #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4')
45 #endif
46 
47 #define REQUEST_DEVICE "/dev/media-dec0"
48 
49 namespace media {
50 
V4L2ExtCtrl(uint32_t id)51 V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id) {
52   memset(&ctrl, 0, sizeof(ctrl));
53   ctrl.id = id;
54 }
55 
V4L2ExtCtrl(uint32_t id,int32_t val)56 V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id, int32_t val) : V4L2ExtCtrl(id) {
57   ctrl.value = val;
58 }
59 
60 // Class used to store the state of a buffer that should persist between
61 // reference creations. This includes:
62 // * Result of initial VIDIOC_QUERYBUF ioctl,
63 // * Plane mappings.
64 //
65 // Also provides helper functions.
66 class V4L2Buffer {
67  public:
68   static std::unique_ptr<V4L2Buffer> Create(scoped_refptr<V4L2Device> device,
69                                             enum v4l2_buf_type type,
70                                             enum v4l2_memory memory,
71                                             const struct v4l2_format& format,
72                                             size_t buffer_id);
73   ~V4L2Buffer();
74 
75   void* GetPlaneMapping(const size_t plane);
76   size_t GetMemoryUsage() const;
v4l2_buffer() const77   const struct v4l2_buffer& v4l2_buffer() const { return v4l2_buffer_; }
78 
79  private:
80   V4L2Buffer(scoped_refptr<V4L2Device> device,
81              enum v4l2_buf_type type,
82              enum v4l2_memory memory,
83              const struct v4l2_format& format,
84              size_t buffer_id);
85   bool Query();
86 
87   scoped_refptr<V4L2Device> device_;
88   std::vector<void*> plane_mappings_;
89 
90   // V4L2 data as queried by QUERYBUF.
91   struct v4l2_buffer v4l2_buffer_;
92   // WARNING: do not change this to a vector or something smaller than
93   // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
94   // the number of allocated planes, resulting in memory corruption.
95   struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
96 
97   struct v4l2_format format_ __attribute__((unused));
98   scoped_refptr<VideoFrame> video_frame_;
99 
100   DISALLOW_COPY_AND_ASSIGN(V4L2Buffer);
101 };
102 
Create(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t buffer_id)103 std::unique_ptr<V4L2Buffer> V4L2Buffer::Create(scoped_refptr<V4L2Device> device,
104                                                enum v4l2_buf_type type,
105                                                enum v4l2_memory memory,
106                                                const struct v4l2_format& format,
107                                                size_t buffer_id) {
108   // Not using std::make_unique because constructor is private.
109   std::unique_ptr<V4L2Buffer> buffer(
110       new V4L2Buffer(device, type, memory, format, buffer_id));
111 
112   if (!buffer->Query())
113     return nullptr;
114 
115   return buffer;
116 }
117 
V4L2Buffer(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t buffer_id)118 V4L2Buffer::V4L2Buffer(scoped_refptr<V4L2Device> device,
119                        enum v4l2_buf_type type,
120                        enum v4l2_memory memory,
121                        const struct v4l2_format& format,
122                        size_t buffer_id)
123     : device_(device), format_(format) {
124   DCHECK(V4L2_TYPE_IS_MULTIPLANAR(type));
125   DCHECK_LE(format.fmt.pix_mp.num_planes, base::size(v4l2_planes_));
126 
127   memset(v4l2_planes_, 0, sizeof(v4l2_planes_));
128   memset(&v4l2_buffer_, 0, sizeof(v4l2_buffer_));
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 
197 // A thread-safe pool of buffer indexes, allowing buffers to be obtained and
198 // returned from different threads. All the methods of this class are
199 // thread-safe. Users should keep a scoped_refptr to instances of this class
200 // in order to ensure the list remains alive as long as they need it.
201 class V4L2BuffersList : public base::RefCountedThreadSafe<V4L2BuffersList> {
202  public:
203   V4L2BuffersList() = default;
204   // Return a buffer to this list. Also can be called to set the initial pool
205   // of buffers.
206   // Note that it is illegal to return the same buffer twice.
207   void ReturnBuffer(size_t buffer_id);
208   // Get any of the buffers in the list. There is no order guarantee whatsoever.
209   base::Optional<size_t> GetFreeBuffer();
210   // Get the buffer with specified index.
211   base::Optional<size_t> GetFreeBuffer(size_t requested_buffer_id);
212   // Number of buffers currently in this list.
213   size_t size() const;
214 
215  private:
216   friend class base::RefCountedThreadSafe<V4L2BuffersList>;
217   ~V4L2BuffersList() = default;
218 
219   mutable base::Lock lock_;
220   std::set<size_t> free_buffers_ GUARDED_BY(lock_);
221   DISALLOW_COPY_AND_ASSIGN(V4L2BuffersList);
222 };
223 
ReturnBuffer(size_t buffer_id)224 void V4L2BuffersList::ReturnBuffer(size_t buffer_id) {
225   base::AutoLock auto_lock(lock_);
226 
227   auto inserted = free_buffers_.emplace(buffer_id);
228   DCHECK(inserted.second);
229 }
230 
GetFreeBuffer()231 base::Optional<size_t> V4L2BuffersList::GetFreeBuffer() {
232   base::AutoLock auto_lock(lock_);
233 
234   auto iter = free_buffers_.begin();
235   if (iter == free_buffers_.end()) {
236     DVLOGF(4) << "No free buffer available!";
237     return base::nullopt;
238   }
239 
240   size_t buffer_id = *iter;
241   free_buffers_.erase(iter);
242 
243   return buffer_id;
244 }
245 
GetFreeBuffer(size_t requested_buffer_id)246 base::Optional<size_t> V4L2BuffersList::GetFreeBuffer(
247     size_t requested_buffer_id) {
248   base::AutoLock auto_lock(lock_);
249 
250   return (free_buffers_.erase(requested_buffer_id) > 0)
251              ? base::make_optional(requested_buffer_id)
252              : base::nullopt;
253 }
254 
size() const255 size_t V4L2BuffersList::size() const {
256   base::AutoLock auto_lock(lock_);
257 
258   return free_buffers_.size();
259 }
260 
261 // Module-private class that let users query/write V4L2 buffer information.
262 // It also makes some private V4L2Queue methods available to this module only.
263 class V4L2BufferRefBase {
264  public:
265   V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
266                     base::WeakPtr<V4L2Queue> queue);
267   ~V4L2BufferRefBase();
268 
269   bool QueueBuffer();
270   void* GetPlaneMapping(const size_t plane);
271 
272   // Checks that the number of passed FDs is adequate for the current format
273   // and buffer configuration. Only useful for DMABUF buffers.
274   bool CheckNumFDsForFormat(const size_t num_fds) const;
275 
276   // Data from the buffer, that users can query and/or write.
277   struct v4l2_buffer v4l2_buffer_;
278   // WARNING: do not change this to a vector or something smaller than
279   // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
280   // the number of allocated planes, resulting in memory corruption.
281   struct v4l2_plane v4l2_planes_[VIDEO_MAX_PLANES];
282 
283  private:
BufferId() const284   size_t BufferId() const { return v4l2_buffer_.index; }
285 
286   friend class V4L2WritableBufferRef;
287   // A weak pointer to the queue this buffer belongs to. Will remain valid as
288   // long as the underlying V4L2 buffer is valid too.
289   // This can only be accessed from the sequence protected by sequence_checker_.
290   // Thread-safe methods (like ~V4L2BufferRefBase) must *never* access this.
291   base::WeakPtr<V4L2Queue> queue_;
292   // Where to return this buffer if it goes out of scope without being queued.
293   scoped_refptr<V4L2BuffersList> return_to_;
294   bool queued = false;
295 
296   SEQUENCE_CHECKER(sequence_checker_);
297   DISALLOW_COPY_AND_ASSIGN(V4L2BufferRefBase);
298 };
299 
V4L2BufferRefBase(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)300 V4L2BufferRefBase::V4L2BufferRefBase(const struct v4l2_buffer& v4l2_buffer,
301                                      base::WeakPtr<V4L2Queue> queue)
302     : queue_(std::move(queue)), return_to_(queue_->free_buffers_) {
303   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
304   DCHECK(V4L2_TYPE_IS_MULTIPLANAR(v4l2_buffer.type));
305   DCHECK_LE(v4l2_buffer.length, base::size(v4l2_planes_));
306   DCHECK(return_to_);
307 
308   memcpy(&v4l2_buffer_, &v4l2_buffer, sizeof(v4l2_buffer_));
309   memcpy(v4l2_planes_, v4l2_buffer.m.planes,
310          sizeof(struct v4l2_plane) * v4l2_buffer.length);
311   v4l2_buffer_.m.planes = v4l2_planes_;
312 }
313 
~V4L2BufferRefBase()314 V4L2BufferRefBase::~V4L2BufferRefBase() {
315   // We are the last reference and are only accessing the thread-safe
316   // return_to_, so we are safe to call from any sequence.
317   // If we have been queued, then the queue is our owner so we don't need to
318   // return to the free buffers list.
319   if (!queued)
320     return_to_->ReturnBuffer(BufferId());
321 }
322 
QueueBuffer()323 bool V4L2BufferRefBase::QueueBuffer() {
324   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
325 
326   if (!queue_)
327     return false;
328 
329   queued = queue_->QueueBuffer(&v4l2_buffer_);
330 
331   return queued;
332 }
333 
GetPlaneMapping(const size_t plane)334 void* V4L2BufferRefBase::GetPlaneMapping(const size_t plane) {
335   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
336 
337   if (!queue_)
338     return nullptr;
339 
340   return queue_->buffers_[BufferId()]->GetPlaneMapping(plane);
341 }
342 
CheckNumFDsForFormat(const size_t num_fds) const343 bool V4L2BufferRefBase::CheckNumFDsForFormat(const size_t num_fds) const {
344   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
345 
346   if (!queue_)
347     return false;
348 
349   // We have not used SetFormat(), assume this is ok.
350   // Hopefully we standardize SetFormat() in the future.
351   if (!queue_->current_format_)
352     return true;
353 
354   const size_t required_fds = queue_->current_format_->fmt.pix_mp.num_planes;
355   // Sanity check.
356   DCHECK_EQ(v4l2_buffer_.length, required_fds);
357   if (num_fds < required_fds) {
358     VLOGF(1) << "Insufficient number of FDs given for the current format. "
359              << num_fds << " provided, " << required_fds << " required.";
360     return false;
361   }
362 
363   const auto* planes = v4l2_buffer_.m.planes;
364   for (size_t i = v4l2_buffer_.length - 1; i >= num_fds; --i) {
365     // Assume that an fd is a duplicate of a previous plane's fd if offset != 0.
366     // Otherwise, if offset == 0, return error as it is likely pointing to
367     // a new plane.
368     if (planes[i].data_offset == 0) {
369       VLOGF(1) << "Additional dmabuf fds point to a new buffer.";
370       return false;
371     }
372   }
373 
374   return true;
375 }
376 
V4L2WritableBufferRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)377 V4L2WritableBufferRef::V4L2WritableBufferRef(
378     const struct v4l2_buffer& v4l2_buffer,
379     base::WeakPtr<V4L2Queue> queue)
380     : buffer_data_(
381           std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
382   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
383 }
384 
V4L2WritableBufferRef(V4L2WritableBufferRef && other)385 V4L2WritableBufferRef::V4L2WritableBufferRef(V4L2WritableBufferRef&& other)
386     : buffer_data_(std::move(other.buffer_data_)) {
387   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
388   DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
389 }
390 
~V4L2WritableBufferRef()391 V4L2WritableBufferRef::~V4L2WritableBufferRef() {
392   // Only valid references should be sequence-checked
393   if (buffer_data_) {
394     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
395   }
396 }
397 
operator =(V4L2WritableBufferRef && other)398 V4L2WritableBufferRef& V4L2WritableBufferRef::operator=(
399     V4L2WritableBufferRef&& other) {
400   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
401   DCHECK_CALLED_ON_VALID_SEQUENCE(other.sequence_checker_);
402 
403   if (this == &other)
404     return *this;
405 
406   buffer_data_ = std::move(other.buffer_data_);
407 
408   return *this;
409 }
410 
Memory() const411 enum v4l2_memory V4L2WritableBufferRef::Memory() const {
412   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
413   DCHECK(buffer_data_);
414 
415   return static_cast<enum v4l2_memory>(buffer_data_->v4l2_buffer_.memory);
416 }
417 
DoQueue(V4L2RequestRef *)418 bool V4L2WritableBufferRef::DoQueue(V4L2RequestRef* /*request_ref*/) && {
419   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
420   DCHECK(buffer_data_);
421 
422   bool queued = buffer_data_->QueueBuffer();
423 
424   // Clear our own reference.
425   buffer_data_.reset();
426 
427   return queued;
428 }
429 
QueueMMap(V4L2RequestRef * request_ref)430 bool V4L2WritableBufferRef::QueueMMap(V4L2RequestRef* request_ref) && {
431   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
432   DCHECK(buffer_data_);
433 
434   // Move ourselves so our data gets freed no matter when we return
435   V4L2WritableBufferRef self(std::move(*this));
436 
437   if (self.Memory() != V4L2_MEMORY_MMAP) {
438     VLOGF(1) << "Called on invalid buffer type!";
439     return false;
440   }
441 
442   return std::move(self).DoQueue(request_ref);
443 }
444 
QueueUserPtr(const std::vector<void * > & ptrs,V4L2RequestRef * request_ref)445 bool V4L2WritableBufferRef::QueueUserPtr(const std::vector<void*>& ptrs,
446                                          V4L2RequestRef* request_ref) && {
447   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
448   DCHECK(buffer_data_);
449 
450   // Move ourselves so our data gets freed no matter when we return
451   V4L2WritableBufferRef self(std::move(*this));
452 
453   if (self.Memory() != V4L2_MEMORY_USERPTR) {
454     VLOGF(1) << "Called on invalid buffer type!";
455     return false;
456   }
457 
458   if (ptrs.size() != self.PlanesCount()) {
459     VLOGF(1) << "Provided " << ptrs.size() << " pointers while we require "
460              << self.buffer_data_->v4l2_buffer_.length << ".";
461     return false;
462   }
463 
464   for (size_t i = 0; i < ptrs.size(); i++)
465     self.buffer_data_->v4l2_buffer_.m.planes[i].m.userptr =
466         reinterpret_cast<unsigned long>(ptrs[i]);
467 
468   return std::move(self).DoQueue(request_ref);
469 }
470 
QueueDMABuf(const std::vector<base::ScopedFD> & scoped_fds,V4L2RequestRef * request_ref)471 bool V4L2WritableBufferRef::QueueDMABuf(const std::vector<base::ScopedFD>& scoped_fds,
472                                         V4L2RequestRef* request_ref) && {
473   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
474 
475   std::vector<int> fds;
476   fds.reserve(scoped_fds.size());
477   for (const base::ScopedFD& scoped_fd : scoped_fds)
478     fds.push_back(scoped_fd.get());
479 
480   return std::move(*this).QueueDMABuf(fds, request_ref);
481 }
482 
QueueDMABuf(const std::vector<int> & fds,V4L2RequestRef * request_ref)483 bool V4L2WritableBufferRef::QueueDMABuf(const std::vector<int>& fds,
484                                         V4L2RequestRef* request_ref) && {
485   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
486   DCHECK(buffer_data_);
487 
488   // Move ourselves so our data gets freed no matter when we return
489   V4L2WritableBufferRef self(std::move(*this));
490 
491   if (self.Memory() != V4L2_MEMORY_DMABUF) {
492     VLOGF(1) << "Called on invalid buffer type!";
493     return false;
494   }
495 
496   if (!self.buffer_data_->CheckNumFDsForFormat(fds.size()))
497     return false;
498 
499   size_t num_planes = self.PlanesCount();
500   for (size_t i = 0; i < num_planes; i++)
501     self.buffer_data_->v4l2_buffer_.m.planes[i].m.fd = fds[i];
502 
503   return std::move(self).DoQueue(request_ref);
504 }
505 
PlanesCount() const506 size_t V4L2WritableBufferRef::PlanesCount() const {
507   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
508   DCHECK(buffer_data_);
509 
510   return buffer_data_->v4l2_buffer_.length;
511 }
512 
GetPlaneSize(const size_t plane) const513 size_t V4L2WritableBufferRef::GetPlaneSize(const size_t plane) const {
514   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
515   DCHECK(buffer_data_);
516 
517   if (plane >= PlanesCount()) {
518     VLOGF(1) << "Invalid plane " << plane << " requested.";
519     return 0;
520   }
521 
522   return buffer_data_->v4l2_buffer_.m.planes[plane].length;
523 }
524 
SetPlaneSize(const size_t plane,const size_t size)525 void V4L2WritableBufferRef::SetPlaneSize(const size_t plane,
526                                          const size_t size) {
527   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
528   DCHECK(buffer_data_);
529 
530   enum v4l2_memory memory = Memory();
531   if (memory == V4L2_MEMORY_MMAP) {
532     DCHECK_EQ(buffer_data_->v4l2_buffer_.m.planes[plane].length, size);
533     return;
534   }
535   DCHECK(memory == V4L2_MEMORY_USERPTR || memory == V4L2_MEMORY_DMABUF);
536 
537   if (plane >= PlanesCount()) {
538     VLOGF(1) << "Invalid plane " << plane << " requested.";
539     return;
540   }
541 
542   buffer_data_->v4l2_buffer_.m.planes[plane].length = size;
543 }
544 
GetPlaneMapping(const size_t plane)545 void* V4L2WritableBufferRef::GetPlaneMapping(const size_t plane) {
546   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
547   DCHECK(buffer_data_);
548 
549   return buffer_data_->GetPlaneMapping(plane);
550 }
551 
SetTimeStamp(const struct timeval & timestamp)552 void V4L2WritableBufferRef::SetTimeStamp(const struct timeval& timestamp) {
553   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
554   DCHECK(buffer_data_);
555 
556   buffer_data_->v4l2_buffer_.timestamp = timestamp;
557 }
558 
GetTimeStamp() const559 const struct timeval& V4L2WritableBufferRef::GetTimeStamp() const {
560   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
561   DCHECK(buffer_data_);
562 
563   return buffer_data_->v4l2_buffer_.timestamp;
564 }
565 
SetPlaneBytesUsed(const size_t plane,const size_t bytes_used)566 void V4L2WritableBufferRef::SetPlaneBytesUsed(const size_t plane,
567                                               const size_t bytes_used) {
568   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
569   DCHECK(buffer_data_);
570 
571   if (plane >= PlanesCount()) {
572     VLOGF(1) << "Invalid plane " << plane << " requested.";
573     return;
574   }
575 
576   if (bytes_used > GetPlaneSize(plane)) {
577     VLOGF(1) << "Set bytes used " << bytes_used << " larger than plane size "
578              << GetPlaneSize(plane) << ".";
579     return;
580   }
581 
582   buffer_data_->v4l2_buffer_.m.planes[plane].bytesused = bytes_used;
583 }
584 
GetPlaneBytesUsed(const size_t plane) const585 size_t V4L2WritableBufferRef::GetPlaneBytesUsed(const size_t plane) const {
586   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
587   DCHECK(buffer_data_);
588 
589   if (plane >= PlanesCount()) {
590     VLOGF(1) << "Invalid plane " << plane << " requested.";
591     return 0;
592   }
593 
594   return buffer_data_->v4l2_buffer_.m.planes[plane].bytesused;
595 }
596 
SetPlaneDataOffset(const size_t plane,const size_t data_offset)597 void V4L2WritableBufferRef::SetPlaneDataOffset(const size_t plane,
598                                                const size_t data_offset) {
599   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
600   DCHECK(buffer_data_);
601 
602   if (plane >= PlanesCount()) {
603     VLOGF(1) << "Invalid plane " << plane << " requested.";
604     return;
605   }
606 
607   buffer_data_->v4l2_buffer_.m.planes[plane].data_offset = data_offset;
608 }
609 
BufferId() const610 size_t V4L2WritableBufferRef::BufferId() const {
611   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
612   DCHECK(buffer_data_);
613 
614   return buffer_data_->v4l2_buffer_.index;
615 }
616 
V4L2ReadableBuffer(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)617 V4L2ReadableBuffer::V4L2ReadableBuffer(const struct v4l2_buffer& v4l2_buffer,
618                                        base::WeakPtr<V4L2Queue> queue)
619     : buffer_data_(
620           std::make_unique<V4L2BufferRefBase>(v4l2_buffer, std::move(queue))) {
621   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622 }
623 
~V4L2ReadableBuffer()624 V4L2ReadableBuffer::~V4L2ReadableBuffer() {
625   // This method is thread-safe. Since we are the destructor, we are guaranteed
626   // to be called from the only remaining reference to us. Also, we are just
627   // calling the destructor of buffer_data_, which is also thread-safe.
628   DCHECK(buffer_data_);
629 }
630 
IsLast() const631 bool V4L2ReadableBuffer::IsLast() const {
632   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
633   DCHECK(buffer_data_);
634 
635   return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_LAST;
636 }
637 
IsKeyframe() const638 bool V4L2ReadableBuffer::IsKeyframe() const {
639   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
640   DCHECK(buffer_data_);
641 
642   return buffer_data_->v4l2_buffer_.flags & V4L2_BUF_FLAG_KEYFRAME;
643 }
644 
GetTimeStamp() const645 struct timeval V4L2ReadableBuffer::GetTimeStamp() const {
646   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
647   DCHECK(buffer_data_);
648 
649   return buffer_data_->v4l2_buffer_.timestamp;
650 }
651 
PlanesCount() const652 size_t V4L2ReadableBuffer::PlanesCount() const {
653   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
654   DCHECK(buffer_data_);
655 
656   return buffer_data_->v4l2_buffer_.length;
657 }
658 
GetPlaneMapping(const size_t plane) const659 const void* V4L2ReadableBuffer::GetPlaneMapping(const size_t plane) const {
660   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
661   DCHECK(buffer_data_);
662 
663   return buffer_data_->GetPlaneMapping(plane);
664 }
665 
GetPlaneBytesUsed(const size_t plane) const666 size_t V4L2ReadableBuffer::GetPlaneBytesUsed(const size_t plane) const {
667   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
668   DCHECK(buffer_data_);
669 
670   if (plane >= PlanesCount()) {
671     VLOGF(1) << "Invalid plane " << plane << " requested.";
672     return 0;
673   }
674 
675   return buffer_data_->v4l2_planes_[plane].bytesused;
676 }
677 
GetPlaneDataOffset(const size_t plane) const678 size_t V4L2ReadableBuffer::GetPlaneDataOffset(const size_t plane) const {
679   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
680   DCHECK(buffer_data_);
681 
682   if (plane >= PlanesCount()) {
683     VLOGF(1) << "Invalid plane " << plane << " requested.";
684     return 0;
685   }
686 
687   return buffer_data_->v4l2_planes_[plane].data_offset;
688 }
689 
BufferId() const690 size_t V4L2ReadableBuffer::BufferId() const {
691   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
692   DCHECK(buffer_data_);
693 
694   return buffer_data_->v4l2_buffer_.index;
695 }
696 
697 // This class is used to expose buffer reference classes constructors to
698 // this module. This is to ensure that nobody else can create buffer references.
699 class V4L2BufferRefFactory {
700  public:
CreateWritableRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)701   static V4L2WritableBufferRef CreateWritableRef(
702       const struct v4l2_buffer& v4l2_buffer,
703       base::WeakPtr<V4L2Queue> queue) {
704     return V4L2WritableBufferRef(v4l2_buffer, std::move(queue));
705   }
706 
CreateReadableRef(const struct v4l2_buffer & v4l2_buffer,base::WeakPtr<V4L2Queue> queue)707   static V4L2ReadableBufferRef CreateReadableRef(
708       const struct v4l2_buffer& v4l2_buffer,
709       base::WeakPtr<V4L2Queue> queue) {
710     return new V4L2ReadableBuffer(v4l2_buffer, std::move(queue));
711   }
712 };
713 
714 // Helper macros that print the queue type with logs.
715 #define VPQLOGF(level) \
716   VPLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
717 #define VQLOGF(level) \
718   VLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
719 #define DVQLOGF(level) \
720   DVLOGF(level) << "(" << V4L2Device::V4L2BufferTypeToString(type_) << ") "
721 
V4L2Queue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroy_cb)722 V4L2Queue::V4L2Queue(scoped_refptr<V4L2Device> dev,
723                      enum v4l2_buf_type type,
724                      base::OnceClosure destroy_cb)
725     : type_(type),
726       device_(dev),
727       destroy_cb_(std::move(destroy_cb)),
728       weak_this_factory_(this) {
729   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
730 }
731 
~V4L2Queue()732 V4L2Queue::~V4L2Queue() {
733   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
734 
735   if (is_streaming_) {
736     VQLOGF(1) << "Queue is still streaming, trying to stop it...";
737     Streamoff();
738   }
739 
740   DCHECK(queued_buffers_.empty());
741   DCHECK(!free_buffers_);
742 
743   if (!buffers_.empty()) {
744     VQLOGF(1) << "Buffers are still allocated, trying to deallocate them...";
745     DeallocateBuffers();
746   }
747 
748   std::move(destroy_cb_).Run();
749 }
750 
SetFormat(uint32_t fourcc,const Size & size,size_t buffer_size)751 base::Optional<struct v4l2_format> V4L2Queue::SetFormat(uint32_t fourcc,
752                                                         const Size& size,
753                                                         size_t buffer_size) {
754   struct v4l2_format format;
755   memset(&format, 0, sizeof(format));
756   format.type = type_;
757   format.fmt.pix_mp.pixelformat = fourcc;
758   format.fmt.pix_mp.width = size.width();
759   format.fmt.pix_mp.height = size.height();
760   format.fmt.pix_mp.num_planes = V4L2Device::GetNumPlanesOfV4L2PixFmt(fourcc);
761   format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
762   if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 ||
763       format.fmt.pix_mp.pixelformat != fourcc) {
764     VPQLOGF(2) << "Failed to set format on queue " << type_
765                << ". format_fourcc=0x" << std::hex << fourcc;
766     return base::nullopt;
767   }
768 
769   current_format_ = format;
770   return current_format_;
771 }
772 
AllocateBuffers(size_t count,enum v4l2_memory memory)773 size_t V4L2Queue::AllocateBuffers(size_t count, enum v4l2_memory memory) {
774   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
775   DCHECK(!free_buffers_);
776   DCHECK_EQ(queued_buffers_.size(), 0u);
777 
778   if (IsStreaming()) {
779     VQLOGF(1) << "Cannot allocate buffers while streaming.";
780     return 0;
781   }
782 
783   if (buffers_.size() != 0) {
784     VQLOGF(1)
785         << "Cannot allocate new buffers while others are still allocated.";
786     return 0;
787   }
788 
789   if (count == 0) {
790     VQLOGF(1) << "Attempting to allocate 0 buffers.";
791     return 0;
792   }
793 
794   // First query the number of planes in the buffers we are about to request.
795   // This should not be required, but Tegra's VIDIOC_QUERYBUF will fail on
796   // output buffers if the number of specified planes does not exactly match the
797   // format.
798   struct v4l2_format format = {.type = type_};
799   int ret = device_->Ioctl(VIDIOC_G_FMT, &format);
800   if (ret) {
801     VPQLOGF(1) << "VIDIOC_G_FMT failed";
802     return 0;
803   }
804   planes_count_ = format.fmt.pix_mp.num_planes;
805   DCHECK_LE(planes_count_, static_cast<size_t>(VIDEO_MAX_PLANES));
806 
807   struct v4l2_requestbuffers reqbufs;
808   memset(&reqbufs, 0, sizeof(reqbufs));
809   reqbufs.count = count;
810   reqbufs.type = type_;
811   reqbufs.memory = memory;
812   DVQLOGF(3) << "Requesting " << count << " buffers.";
813 
814   ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
815   if (ret) {
816     VPQLOGF(1) << "VIDIOC_REQBUFS failed";
817     return 0;
818   }
819   DVQLOGF(3) << "queue " << type_ << ": got " << reqbufs.count << " buffers.";
820 
821   memory_ = memory;
822 
823   free_buffers_ = new V4L2BuffersList();
824 
825   // Now query all buffer information.
826   for (size_t i = 0; i < reqbufs.count; i++) {
827     auto buffer = V4L2Buffer::Create(device_, type_, memory_, format, i);
828 
829     if (!buffer) {
830       DeallocateBuffers();
831 
832       return 0;
833     }
834 
835     buffers_.emplace_back(std::move(buffer));
836     free_buffers_->ReturnBuffer(i);
837   }
838 
839   DCHECK(free_buffers_);
840   DCHECK_EQ(free_buffers_->size(), buffers_.size());
841   DCHECK_EQ(queued_buffers_.size(), 0u);
842 
843   return buffers_.size();
844 }
845 
DeallocateBuffers()846 bool V4L2Queue::DeallocateBuffers() {
847   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
848 
849   if (IsStreaming()) {
850     VQLOGF(1) << "Cannot deallocate buffers while streaming.";
851     return false;
852   }
853 
854   if (buffers_.size() == 0)
855     return true;
856 
857   weak_this_factory_.InvalidateWeakPtrs();
858   buffers_.clear();
859   free_buffers_ = nullptr;
860 
861   // Free all buffers.
862   struct v4l2_requestbuffers reqbufs;
863   memset(&reqbufs, 0, sizeof(reqbufs));
864   reqbufs.count = 0;
865   reqbufs.type = type_;
866   reqbufs.memory = memory_;
867 
868   int ret = device_->Ioctl(VIDIOC_REQBUFS, &reqbufs);
869   if (ret) {
870     VPQLOGF(1) << "VIDIOC_REQBUFS failed";
871     return false;
872   }
873 
874   DCHECK(!free_buffers_);
875   DCHECK_EQ(queued_buffers_.size(), 0u);
876 
877   return true;
878 }
879 
GetMemoryUsage() const880 size_t V4L2Queue::GetMemoryUsage() const {
881   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
882   size_t usage = 0;
883   for (const auto& buf : buffers_) {
884     usage += buf->GetMemoryUsage();
885   }
886   return usage;
887 }
888 
GetMemoryType() const889 v4l2_memory V4L2Queue::GetMemoryType() const {
890   return memory_;
891 }
892 
GetFreeBuffer()893 base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer() {
894   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
895 
896   // No buffers allocated at the moment?
897   if (!free_buffers_)
898     return base::nullopt;
899 
900   auto buffer_id = free_buffers_->GetFreeBuffer();
901   if (!buffer_id.has_value())
902     return base::nullopt;
903 
904   return V4L2BufferRefFactory::CreateWritableRef(
905       buffers_[buffer_id.value()]->v4l2_buffer(),
906       weak_this_factory_.GetWeakPtr());
907 }
908 
GetFreeBuffer(size_t requested_buffer_id)909 base::Optional<V4L2WritableBufferRef> V4L2Queue::GetFreeBuffer(
910     size_t requested_buffer_id) {
911   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
912 
913   // No buffers allocated at the moment?
914   if (!free_buffers_)
915     return base::nullopt;
916 
917   auto buffer_id = free_buffers_->GetFreeBuffer(requested_buffer_id);
918   if (!buffer_id.has_value())
919     return base::nullopt;
920 
921   return V4L2BufferRefFactory::CreateWritableRef(
922       buffers_[buffer_id.value()]->v4l2_buffer(),
923       weak_this_factory_.GetWeakPtr());
924 }
925 
QueueBuffer(struct v4l2_buffer * v4l2_buffer)926 bool V4L2Queue::QueueBuffer(struct v4l2_buffer* v4l2_buffer) {
927   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
928 
929   int ret = device_->Ioctl(VIDIOC_QBUF, v4l2_buffer);
930   if (ret) {
931     VPQLOGF(1) << "VIDIOC_QBUF failed";
932     return false;
933   }
934 
935   auto inserted = queued_buffers_.emplace(v4l2_buffer->index);
936   DCHECK_EQ(inserted.second, true);
937 
938   device_->SchedulePoll();
939 
940   return true;
941 }
942 
DequeueBuffer()943 std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::DequeueBuffer() {
944   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
945 
946   // No need to dequeue if no buffers queued.
947   if (QueuedBuffersCount() == 0)
948     return std::make_pair(true, nullptr);
949 
950   if (!IsStreaming()) {
951     VQLOGF(1) << "Attempting to dequeue a buffer while not streaming.";
952     return std::make_pair(true, nullptr);
953   }
954 
955   struct v4l2_buffer v4l2_buffer;
956   memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
957   // WARNING: do not change this to a vector or something smaller than
958   // VIDEO_MAX_PLANES, otherwise the Tegra libv4l2 will write data beyond
959   // the number of allocated planes, resulting in memory corruption.
960   struct v4l2_plane planes[VIDEO_MAX_PLANES];
961   memset(planes, 0, sizeof(planes));
962   v4l2_buffer.type = type_;
963   v4l2_buffer.memory = memory_;
964   v4l2_buffer.m.planes = planes;
965   v4l2_buffer.length = planes_count_;
966   int ret = device_->Ioctl(VIDIOC_DQBUF, &v4l2_buffer);
967   if (ret) {
968     // TODO(acourbot): we should not have to check for EPIPE as codec clients
969     // should not call this method after the last buffer is dequeued.
970     switch (errno) {
971       case EAGAIN:
972       case EPIPE:
973         // This is not an error so we'll need to continue polling but won't
974         // provide a buffer.
975         device_->SchedulePoll();
976         return std::make_pair(true, nullptr);
977       default:
978         VPQLOGF(1) << "VIDIOC_DQBUF failed";
979         return std::make_pair(false, nullptr);
980     }
981   }
982 
983   auto it = queued_buffers_.find(v4l2_buffer.index);
984   DCHECK(it != queued_buffers_.end());
985   queued_buffers_.erase(*it);
986 
987   if (QueuedBuffersCount() > 0)
988     device_->SchedulePoll();
989 
990   DCHECK(free_buffers_);
991   return std::make_pair(true,
992                         V4L2BufferRefFactory::CreateReadableRef(
993                             v4l2_buffer, weak_this_factory_.GetWeakPtr()));
994 }
995 
IsStreaming() const996 bool V4L2Queue::IsStreaming() const {
997   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
998 
999   return is_streaming_;
1000 }
1001 
Streamon()1002 bool V4L2Queue::Streamon() {
1003   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1004 
1005   if (is_streaming_)
1006     return true;
1007 
1008   int arg = static_cast<int>(type_);
1009   int ret = device_->Ioctl(VIDIOC_STREAMON, &arg);
1010   if (ret) {
1011     VPQLOGF(1) << "VIDIOC_STREAMON failed";
1012     return false;
1013   }
1014 
1015   is_streaming_ = true;
1016 
1017   return true;
1018 }
1019 
Streamoff()1020 bool V4L2Queue::Streamoff() {
1021   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1022 
1023   // We do not check the value of IsStreaming(), because we may have queued
1024   // buffers to the queue and wish to get them back - in such as case, we may
1025   // need to do a VIDIOC_STREAMOFF on a stopped queue.
1026 
1027   int arg = static_cast<int>(type_);
1028   int ret = device_->Ioctl(VIDIOC_STREAMOFF, &arg);
1029   if (ret) {
1030     VPQLOGF(1) << "VIDIOC_STREAMOFF failed";
1031     return false;
1032   }
1033 
1034   for (const auto& buffer_id : queued_buffers_) {
1035     DCHECK(free_buffers_);
1036     free_buffers_->ReturnBuffer(buffer_id);
1037   }
1038 
1039   queued_buffers_.clear();
1040 
1041   is_streaming_ = false;
1042 
1043   return true;
1044 }
1045 
AllocatedBuffersCount() const1046 size_t V4L2Queue::AllocatedBuffersCount() const {
1047   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1048 
1049   return buffers_.size();
1050 }
1051 
FreeBuffersCount() const1052 size_t V4L2Queue::FreeBuffersCount() const {
1053   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1054 
1055   return free_buffers_ ? free_buffers_->size() : 0;
1056 }
1057 
QueuedBuffersCount() const1058 size_t V4L2Queue::QueuedBuffersCount() const {
1059   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1060 
1061   return queued_buffers_.size();
1062 }
1063 
1064 #undef VDQLOGF
1065 #undef VPQLOGF
1066 #undef VQLOGF
1067 
SupportsRequests()1068 bool V4L2Queue::SupportsRequests() {
1069   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1070 
1071   return supports_requests_;
1072 }
1073 
1074 // This class is used to expose V4L2Queue's constructor to this module. This is
1075 // to ensure that nobody else can create instances of it.
1076 class V4L2QueueFactory {
1077  public:
CreateQueue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroy_cb)1078   static scoped_refptr<V4L2Queue> CreateQueue(scoped_refptr<V4L2Device> dev,
1079                                               enum v4l2_buf_type type,
1080                                               base::OnceClosure destroy_cb) {
1081     return new V4L2Queue(std::move(dev), type, std::move(destroy_cb));
1082   }
1083 };
1084 
V4L2Device()1085 V4L2Device::V4L2Device() {
1086   DETACH_FROM_SEQUENCE(client_sequence_checker_);
1087 }
1088 
~V4L2Device()1089 V4L2Device::~V4L2Device() {}
1090 
GetQueue(enum v4l2_buf_type type)1091 scoped_refptr<V4L2Queue> V4L2Device::GetQueue(enum v4l2_buf_type type) {
1092   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1093 
1094   switch (type) {
1095     // Supported queue types.
1096     case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1097     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1098       break;
1099     default:
1100       VLOGF(1) << "Unsupported V4L2 queue type: " << type;
1101       return nullptr;
1102   }
1103 
1104   // TODO(acourbot): we should instead query the device for available queues,
1105   // and allocate them accordingly. This will do for now though.
1106   auto it = queues_.find(type);
1107   if (it != queues_.end())
1108     return scoped_refptr<V4L2Queue>(it->second);
1109 
1110   scoped_refptr<V4L2Queue> queue = V4L2QueueFactory::CreateQueue(
1111       this, type, base::BindOnce(&V4L2Device::OnQueueDestroyed, this, type));
1112 
1113   queues_[type] = queue.get();
1114   return queue;
1115 }
1116 
OnQueueDestroyed(v4l2_buf_type buf_type)1117 void V4L2Device::OnQueueDestroyed(v4l2_buf_type buf_type) {
1118   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1119 
1120   auto it = queues_.find(buf_type);
1121   DCHECK(it != queues_.end());
1122   queues_.erase(it);
1123 }
1124 
1125 // static
Create()1126 scoped_refptr<V4L2Device> V4L2Device::Create() {
1127   DVLOGF(3);
1128 
1129   scoped_refptr<V4L2Device> device;
1130 
1131   device = new GenericV4L2Device();
1132   if (device->Initialize())
1133     return device;
1134 
1135   VLOGF(1) << "Failed to create a V4L2Device";
1136   return nullptr;
1137 }
1138 
1139 // static
VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,bool slice_based)1140 uint32_t V4L2Device::VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile,
1141                                                    bool slice_based) {
1142   if (profile >= H264PROFILE_MIN && profile <= H264PROFILE_MAX) {
1143     if (slice_based)
1144       return V4L2_PIX_FMT_H264_SLICE;
1145     else
1146       return V4L2_PIX_FMT_H264;
1147   } else if (profile >= VP8PROFILE_MIN && profile <= VP8PROFILE_MAX) {
1148     if (slice_based)
1149       return V4L2_PIX_FMT_VP8_FRAME;
1150     else
1151       return V4L2_PIX_FMT_VP8;
1152   } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
1153     if (slice_based)
1154       return V4L2_PIX_FMT_VP9_FRAME;
1155     else
1156       return V4L2_PIX_FMT_VP9;
1157   } else {
1158     LOG(ERROR) << "Unknown profile: " << GetProfileName(profile);
1159     return 0;
1160   }
1161 }
1162 
1163 // static
V4L2ProfileToVideoCodecProfile(VideoCodec codec,uint32_t profile)1164 VideoCodecProfile V4L2Device::V4L2ProfileToVideoCodecProfile(VideoCodec codec,
1165                                                              uint32_t profile) {
1166   switch (codec) {
1167     case kCodecH264:
1168       switch (profile) {
1169         case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
1170         case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
1171           return H264PROFILE_BASELINE;
1172         case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
1173           return H264PROFILE_MAIN;
1174         case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
1175           return H264PROFILE_EXTENDED;
1176         case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
1177           return H264PROFILE_HIGH;
1178       }
1179       break;
1180     case kCodecVP8:
1181       switch (profile) {
1182         case V4L2_MPEG_VIDEO_VP8_PROFILE_0:
1183         case V4L2_MPEG_VIDEO_VP8_PROFILE_1:
1184         case V4L2_MPEG_VIDEO_VP8_PROFILE_2:
1185         case V4L2_MPEG_VIDEO_VP8_PROFILE_3:
1186           return VP8PROFILE_ANY;
1187       }
1188       break;
1189     case kCodecVP9:
1190       switch (profile) {
1191         case V4L2_MPEG_VIDEO_VP9_PROFILE_0:
1192           return VP9PROFILE_PROFILE0;
1193         case V4L2_MPEG_VIDEO_VP9_PROFILE_1:
1194           return VP9PROFILE_PROFILE1;
1195         case V4L2_MPEG_VIDEO_VP9_PROFILE_2:
1196           return VP9PROFILE_PROFILE2;
1197         case V4L2_MPEG_VIDEO_VP9_PROFILE_3:
1198           return VP9PROFILE_PROFILE3;
1199       }
1200       break;
1201     default:
1202       VLOGF(2) << "Unknown codec: " << codec;
1203   }
1204   VLOGF(2) << "Unknown profile: " << profile;
1205   return VIDEO_CODEC_PROFILE_UNKNOWN;
1206 }
1207 
V4L2PixFmtToVideoCodecProfiles(uint32_t pix_fmt,bool is_encoder)1208 std::vector<VideoCodecProfile> V4L2Device::V4L2PixFmtToVideoCodecProfiles(
1209     uint32_t pix_fmt,
1210     bool is_encoder) {
1211   auto get_supported_profiles = [this](
1212                                     VideoCodec codec,
1213                                     std::vector<VideoCodecProfile>* profiles) {
1214     uint32_t query_id = 0;
1215     switch (codec) {
1216       case kCodecH264:
1217         query_id = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
1218         break;
1219       case kCodecVP8:
1220         query_id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
1221         break;
1222       case kCodecVP9:
1223         query_id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
1224         break;
1225       default:
1226         return false;
1227     }
1228 
1229     v4l2_queryctrl query_ctrl = {};
1230     query_ctrl.id = query_id;
1231     if (Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) != 0) {
1232       return false;
1233     }
1234     v4l2_querymenu query_menu = {};
1235     query_menu.id = query_ctrl.id;
1236     for (query_menu.index = query_ctrl.minimum;
1237          static_cast<int>(query_menu.index) <= query_ctrl.maximum;
1238          query_menu.index++) {
1239       if (Ioctl(VIDIOC_QUERYMENU, &query_menu) == 0) {
1240         const VideoCodecProfile profile =
1241             V4L2Device::V4L2ProfileToVideoCodecProfile(codec, query_menu.index);
1242         if (profile != VIDEO_CODEC_PROFILE_UNKNOWN)
1243           profiles->push_back(profile);
1244       }
1245     }
1246     return true;
1247   };
1248 
1249   std::vector<VideoCodecProfile> profiles;
1250   switch (pix_fmt) {
1251     case V4L2_PIX_FMT_H264:
1252     case V4L2_PIX_FMT_H264_SLICE:
1253       if (!get_supported_profiles(kCodecH264, &profiles)) {
1254         DLOG(WARNING) << "Driver doesn't support QUERY H264 profiles, "
1255                       << "use default values, Base, Main, High";
1256         profiles = {
1257             H264PROFILE_BASELINE,
1258             H264PROFILE_MAIN,
1259             H264PROFILE_HIGH,
1260         };
1261       }
1262       break;
1263     case V4L2_PIX_FMT_VP8:
1264     case V4L2_PIX_FMT_VP8_FRAME:
1265       profiles = {VP8PROFILE_ANY};
1266       break;
1267     case V4L2_PIX_FMT_VP9:
1268     case V4L2_PIX_FMT_VP9_FRAME:
1269       if (!get_supported_profiles(kCodecVP9, &profiles)) {
1270         DLOG(WARNING) << "Driver doesn't support QUERY VP9 profiles, "
1271                       << "use default values, Profile0";
1272         profiles = {VP9PROFILE_PROFILE0};
1273       }
1274       break;
1275     default:
1276       VLOGF(1) << "Unhandled pixelformat " << FourccToString(pix_fmt);
1277       return {};
1278   }
1279 
1280   // Erase duplicated profiles.
1281   std::sort(profiles.begin(), profiles.end());
1282   profiles.erase(std::unique(profiles.begin(), profiles.end()), profiles.end());
1283   return profiles;
1284 }
1285 
1286 // static
VideoCodecProfileToV4L2H264Profile(VideoCodecProfile profile)1287 int32_t V4L2Device::VideoCodecProfileToV4L2H264Profile(
1288     VideoCodecProfile profile) {
1289   switch (profile) {
1290     case H264PROFILE_BASELINE:
1291       return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
1292     case H264PROFILE_MAIN:
1293       return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
1294     case H264PROFILE_EXTENDED:
1295       return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
1296     case H264PROFILE_HIGH:
1297       return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
1298     case H264PROFILE_HIGH10PROFILE:
1299       return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
1300     case H264PROFILE_HIGH422PROFILE:
1301       return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
1302     case H264PROFILE_HIGH444PREDICTIVEPROFILE:
1303       return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
1304     case H264PROFILE_SCALABLEBASELINE:
1305       return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
1306     case H264PROFILE_SCALABLEHIGH:
1307       return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
1308     case H264PROFILE_STEREOHIGH:
1309       return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
1310     case H264PROFILE_MULTIVIEWHIGH:
1311       return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
1312     default:
1313       DVLOGF(1) << "Add more cases as needed";
1314       return -1;
1315   }
1316 }
1317 
1318 // static
H264LevelIdcToV4L2H264Level(uint8_t level_idc)1319 int32_t V4L2Device::H264LevelIdcToV4L2H264Level(uint8_t level_idc) {
1320   switch (level_idc) {
1321     case 10:
1322       return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
1323     case 9:
1324       return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
1325     case 11:
1326       return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
1327     case 12:
1328       return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
1329     case 13:
1330       return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
1331     case 20:
1332       return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
1333     case 21:
1334       return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
1335     case 22:
1336       return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
1337     case 30:
1338       return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
1339     case 31:
1340       return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
1341     case 32:
1342       return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
1343     case 40:
1344       return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
1345     case 41:
1346       return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
1347     case 42:
1348       return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
1349     case 50:
1350       return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
1351     case 51:
1352       return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
1353     default:
1354       DVLOGF(1) << "Unrecognized level_idc: " << static_cast<int>(level_idc);
1355       return -1;
1356   }
1357 }
1358 
1359 // static
AllocatedSizeFromV4L2Format(const struct v4l2_format & format)1360 Size V4L2Device::AllocatedSizeFromV4L2Format(const struct v4l2_format& format) {
1361   Size coded_size;
1362   Size visible_size;
1363   VideoPixelFormat frame_format = PIXEL_FORMAT_UNKNOWN;
1364   size_t bytesperline = 0;
1365   // Total bytes in the frame.
1366   size_t sizeimage = 0;
1367 
1368   if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1369     DCHECK_GT(format.fmt.pix_mp.num_planes, 0);
1370     bytesperline =
1371         base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
1372     for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
1373       sizeimage +=
1374           base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
1375     }
1376     visible_size.SetSize(base::checked_cast<int>(format.fmt.pix_mp.width),
1377                          base::checked_cast<int>(format.fmt.pix_mp.height));
1378     const uint32_t pix_fmt = format.fmt.pix_mp.pixelformat;
1379     const auto frame_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1380     if (!frame_fourcc) {
1381       VLOGF(1) << "Unsupported format " << FourccToString(pix_fmt);
1382       return coded_size;
1383     }
1384     frame_format = frame_fourcc->ToVideoPixelFormat();
1385   } else {
1386     bytesperline = base::checked_cast<int>(format.fmt.pix.bytesperline);
1387     sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
1388     visible_size.SetSize(base::checked_cast<int>(format.fmt.pix.width),
1389                          base::checked_cast<int>(format.fmt.pix.height));
1390     const uint32_t fourcc = format.fmt.pix.pixelformat;
1391     const auto frame_fourcc = Fourcc::FromV4L2PixFmt(fourcc);
1392     if (!frame_fourcc) {
1393       VLOGF(1) << "Unsupported format " << FourccToString(fourcc);
1394       return coded_size;
1395     }
1396     frame_format = frame_fourcc ? frame_fourcc->ToVideoPixelFormat()
1397                                 : PIXEL_FORMAT_UNKNOWN;
1398   }
1399 
1400   // V4L2 does not provide per-plane bytesperline (bpl) when different
1401   // components are sharing one physical plane buffer. In this case, it only
1402   // provides bpl for the first component in the plane. So we can't depend on it
1403   // for calculating height, because bpl may vary within one physical plane
1404   // buffer. For example, YUV420 contains 3 components in one physical plane,
1405   // with Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component,
1406   // but we only get 8 pits per pixel from bytesperline in physical plane 0.
1407   // So we need to get total frame bpp from elsewhere to calculate coded height.
1408 
1409   // We need bits per pixel for one component only to calculate
1410   // coded_width from bytesperline.
1411   int plane_horiz_bits_per_pixel =
1412       VideoFrame::PlaneHorizontalBitsPerPixel(frame_format, 0);
1413 
1414   // Adding up bpp for each component will give us total bpp for all components.
1415   int total_bpp = 0;
1416   for (size_t i = 0; i < VideoFrame::NumPlanes(frame_format); ++i)
1417     total_bpp += VideoFrame::PlaneBitsPerPixel(frame_format, i);
1418 
1419   if (sizeimage == 0 || bytesperline == 0 || plane_horiz_bits_per_pixel == 0 ||
1420       total_bpp == 0 || (bytesperline * 8) % plane_horiz_bits_per_pixel != 0) {
1421     VLOGF(1) << "Invalid format provided";
1422     return coded_size;
1423   }
1424 
1425   // Coded width can be calculated by taking the first component's bytesperline,
1426   // which in V4L2 always applies to the first component in physical plane
1427   // buffer.
1428   int coded_width = bytesperline * 8 / plane_horiz_bits_per_pixel;
1429   // Sizeimage is coded_width * coded_height * total_bpp.
1430   int coded_height = sizeimage * 8 / coded_width / total_bpp;
1431 
1432   coded_size.SetSize(coded_width, coded_height);
1433   DVLOGF(3) << "coded_size=" << coded_size.ToString();
1434 
1435   // Sanity checks. Calculated coded size has to contain given visible size
1436   // and fulfill buffer byte size requirements.
1437   DCHECK(Rect(coded_size).Contains(Rect(visible_size)));
1438   DCHECK_LE(sizeimage, VideoFrame::AllocationSize(frame_format, coded_size));
1439 
1440   return coded_size;
1441 }
1442 
1443 // static
V4L2MemoryToString(const v4l2_memory memory)1444 const char* V4L2Device::V4L2MemoryToString(const v4l2_memory memory) {
1445   switch (memory) {
1446     case V4L2_MEMORY_MMAP:
1447       return "V4L2_MEMORY_MMAP";
1448     case V4L2_MEMORY_USERPTR:
1449       return "V4L2_MEMORY_USERPTR";
1450     case V4L2_MEMORY_DMABUF:
1451       return "V4L2_MEMORY_DMABUF";
1452     case V4L2_MEMORY_OVERLAY:
1453       return "V4L2_MEMORY_OVERLAY";
1454     default:
1455       return "UNKNOWN";
1456   }
1457 }
1458 
1459 // static
V4L2BufferTypeToString(const enum v4l2_buf_type buf_type)1460 const char* V4L2Device::V4L2BufferTypeToString(
1461     const enum v4l2_buf_type buf_type) {
1462   switch (buf_type) {
1463     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1464       return "OUTPUT";
1465     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1466       return "CAPTURE";
1467     case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1468       return "OUTPUT_MPLANE";
1469     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1470       return "CAPTURE_MPLANE";
1471     default:
1472       return "UNKNOWN";
1473   }
1474 }
1475 
1476 // static
V4L2FormatToString(const struct v4l2_format & format)1477 std::string V4L2Device::V4L2FormatToString(const struct v4l2_format& format) {
1478   std::ostringstream s;
1479   s << "v4l2_format type: " << format.type;
1480   if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1481       format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1482     //  single-planar
1483     const struct v4l2_pix_format& pix = format.fmt.pix;
1484     s << ", width_height: " << Size(pix.width, pix.height).ToString()
1485       << ", pixelformat: " << FourccToString(pix.pixelformat)
1486       << ", field: " << pix.field << ", bytesperline: " << pix.bytesperline
1487       << ", sizeimage: " << pix.sizeimage;
1488   } else if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1489     const struct v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
1490     // As long as num_planes's type is uint8_t, ostringstream treats it as a
1491     // char instead of an integer, which is not what we want. Casting
1492     // pix_mp.num_planes unsigned int solves the issue.
1493     s << ", width_height: " << Size(pix_mp.width, pix_mp.height).ToString()
1494       << ", pixelformat: " << FourccToString(pix_mp.pixelformat)
1495       << ", field: " << pix_mp.field
1496       << ", num_planes: " << static_cast<unsigned int>(pix_mp.num_planes);
1497     for (size_t i = 0; i < pix_mp.num_planes; ++i) {
1498       const struct v4l2_plane_pix_format& plane_fmt = pix_mp.plane_fmt[i];
1499       s << ", plane_fmt[" << i << "].sizeimage: " << plane_fmt.sizeimage
1500         << ", plane_fmt[" << i << "].bytesperline: " << plane_fmt.bytesperline;
1501     }
1502   } else {
1503     s << " unsupported yet.";
1504   }
1505   return s.str();
1506 }
1507 
1508 // static
V4L2BufferToString(const struct v4l2_buffer & buffer)1509 std::string V4L2Device::V4L2BufferToString(const struct v4l2_buffer& buffer) {
1510   std::ostringstream s;
1511   s << "v4l2_buffer type: " << buffer.type << ", memory: " << buffer.memory
1512     << ", index: " << buffer.index << " bytesused: " << buffer.bytesused
1513     << ", length: " << buffer.length;
1514   if (buffer.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
1515       buffer.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1516     //  single-planar
1517     if (buffer.memory == V4L2_MEMORY_MMAP) {
1518       s << ", m.offset: " << buffer.m.offset;
1519     } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1520       s << ", m.userptr: " << buffer.m.userptr;
1521     } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1522       s << ", m.fd: " << buffer.m.fd;
1523     }
1524   } else if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
1525     for (size_t i = 0; i < buffer.length; ++i) {
1526       const struct v4l2_plane& plane = buffer.m.planes[i];
1527       s << ", m.planes[" << i << "](bytesused: " << plane.bytesused
1528         << ", length: " << plane.length
1529         << ", data_offset: " << plane.data_offset;
1530       if (buffer.memory == V4L2_MEMORY_MMAP) {
1531         s << ", m.mem_offset: " << plane.m.mem_offset;
1532       } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1533         s << ", m.userptr: " << plane.m.userptr;
1534       } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1535         s << ", m.fd: " << plane.m.fd;
1536       }
1537       s << ")";
1538     }
1539   } else {
1540     s << " unsupported yet.";
1541   }
1542   return s.str();
1543 }
1544 
1545 // static
V4L2FormatToVideoFrameLayout(const struct v4l2_format & format)1546 base::Optional<VideoFrameLayout> V4L2Device::V4L2FormatToVideoFrameLayout(
1547     const struct v4l2_format& format) {
1548   if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1549     VLOGF(1) << "v4l2_buf_type is not multiplanar: " << std::hex << "0x"
1550              << format.type;
1551     return base::nullopt;
1552   }
1553   const v4l2_pix_format_mplane& pix_mp = format.fmt.pix_mp;
1554   const uint32_t& pix_fmt = pix_mp.pixelformat;
1555   const auto video_fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1556   if (!video_fourcc) {
1557     VLOGF(1) << "Failed to convert pixel format to VideoPixelFormat: "
1558              << FourccToString(pix_fmt);
1559     return base::nullopt;
1560   }
1561   const VideoPixelFormat video_format = video_fourcc->ToVideoPixelFormat();
1562   const size_t num_buffers = pix_mp.num_planes;
1563   const size_t num_color_planes = VideoFrame::NumPlanes(video_format);
1564   if (num_color_planes == 0) {
1565     VLOGF(1) << "Unsupported video format for NumPlanes(): "
1566              << VideoPixelFormatToString(video_format);
1567     return base::nullopt;
1568   }
1569   if (num_buffers > num_color_planes) {
1570     VLOGF(1) << "pix_mp.num_planes: " << num_buffers
1571              << " should not be larger than NumPlanes("
1572              << VideoPixelFormatToString(video_format)
1573              << "): " << num_color_planes;
1574     return base::nullopt;
1575   }
1576   // Reserve capacity in advance to prevent unnecessary vector reallocation.
1577   std::vector<ColorPlaneLayout> planes;
1578   planes.reserve(num_color_planes);
1579   for (size_t i = 0; i < num_buffers; ++i) {
1580     const v4l2_plane_pix_format& plane_format = pix_mp.plane_fmt[i];
1581     planes.emplace_back(static_cast<int32_t>(plane_format.bytesperline), 0u,
1582                         plane_format.sizeimage);
1583   }
1584   // For the case that #color planes > #buffers, it fills stride of color
1585   // plane which does not map to buffer.
1586   // Right now only some pixel formats are supported: NV12, YUV420, YVU420.
1587   if (num_color_planes > num_buffers) {
1588     const int32_t y_stride = planes[0].stride;
1589     // Note that y_stride is from v4l2 bytesperline and its type is uint32_t.
1590     // It is safe to cast to size_t.
1591     const size_t y_stride_abs = static_cast<size_t>(y_stride);
1592     switch (pix_fmt) {
1593       case V4L2_PIX_FMT_NV12:
1594         // The stride of UV is the same as Y in NV12.
1595         // The height is half of Y plane.
1596         planes.emplace_back(y_stride, y_stride_abs * pix_mp.height,
1597                             y_stride_abs * pix_mp.height / 2);
1598         DCHECK_EQ(2u, planes.size());
1599         break;
1600       case V4L2_PIX_FMT_YUV420:
1601       case V4L2_PIX_FMT_YVU420: {
1602         // The spec claims that two Cx rows (including padding) is exactly as
1603         // long as one Y row (including padding). So stride of Y must be even
1604         // number.
1605         if (y_stride % 2 != 0 || pix_mp.height % 2 != 0) {
1606           VLOGF(1) << "Plane-Y stride and height should be even; stride: "
1607                    << y_stride << ", height: " << pix_mp.height;
1608           return base::nullopt;
1609         }
1610         const int32_t half_stride = y_stride / 2;
1611         const size_t plane_0_area = y_stride_abs * pix_mp.height;
1612         const size_t plane_1_area = plane_0_area / 4;
1613         planes.emplace_back(half_stride, plane_0_area, plane_1_area);
1614         planes.emplace_back(half_stride, plane_0_area + plane_1_area,
1615                             plane_1_area);
1616         DCHECK_EQ(3u, planes.size());
1617         break;
1618       }
1619       default:
1620         VLOGF(1) << "Cannot derive stride for each plane for pixel format "
1621                  << FourccToString(pix_fmt);
1622         return base::nullopt;
1623     }
1624   }
1625 
1626   // Some V4L2 devices expect buffers to be page-aligned. We cannot detect
1627   // such devices individually, so set this as a video frame layout property.
1628   constexpr size_t buffer_alignment = 0x1000;
1629   if (num_buffers == 1) {
1630     return VideoFrameLayout::CreateWithPlanes(
1631         video_format, Size(pix_mp.width, pix_mp.height), std::move(planes),
1632         buffer_alignment);
1633   } else {
1634     return VideoFrameLayout::CreateMultiPlanar(
1635         video_format, Size(pix_mp.width, pix_mp.height), std::move(planes),
1636         buffer_alignment);
1637   }
1638 }
1639 
1640 // static
GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt)1641 size_t V4L2Device::GetNumPlanesOfV4L2PixFmt(uint32_t pix_fmt) {
1642   base::Optional<Fourcc> fourcc = Fourcc::FromV4L2PixFmt(pix_fmt);
1643   if (fourcc && fourcc->IsMultiPlanar()) {
1644     return VideoFrame::NumPlanes(fourcc->ToVideoPixelFormat());
1645   }
1646   return 1u;
1647 }
1648 
GetSupportedResolution(uint32_t pixelformat,Size * min_resolution,Size * max_resolution)1649 void V4L2Device::GetSupportedResolution(uint32_t pixelformat,
1650                                         Size* min_resolution,
1651                                         Size* max_resolution) {
1652   max_resolution->SetSize(0, 0);
1653   min_resolution->SetSize(0, 0);
1654   v4l2_frmsizeenum frame_size;
1655   memset(&frame_size, 0, sizeof(frame_size));
1656   frame_size.pixel_format = pixelformat;
1657   for (; Ioctl(VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; ++frame_size.index) {
1658     if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
1659       if (frame_size.discrete.width >=
1660               base::checked_cast<uint32_t>(max_resolution->width()) &&
1661           frame_size.discrete.height >=
1662               base::checked_cast<uint32_t>(max_resolution->height())) {
1663         max_resolution->SetSize(frame_size.discrete.width,
1664                                 frame_size.discrete.height);
1665       }
1666       if (min_resolution->IsEmpty() ||
1667           (frame_size.discrete.width <=
1668                base::checked_cast<uint32_t>(min_resolution->width()) &&
1669            frame_size.discrete.height <=
1670                base::checked_cast<uint32_t>(min_resolution->height()))) {
1671         min_resolution->SetSize(frame_size.discrete.width,
1672                                 frame_size.discrete.height);
1673       }
1674     } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
1675                frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
1676       max_resolution->SetSize(frame_size.stepwise.max_width,
1677                               frame_size.stepwise.max_height);
1678       min_resolution->SetSize(frame_size.stepwise.min_width,
1679                               frame_size.stepwise.min_height);
1680       break;
1681     }
1682   }
1683   if (max_resolution->IsEmpty()) {
1684     max_resolution->SetSize(1920, 1088);
1685     VLOGF(1) << "GetSupportedResolution failed to get maximum resolution for "
1686              << "fourcc " << FourccToString(pixelformat) << ", fall back to "
1687              << max_resolution->ToString();
1688   }
1689   if (min_resolution->IsEmpty()) {
1690     min_resolution->SetSize(16, 16);
1691     VLOGF(1) << "GetSupportedResolution failed to get minimum resolution for "
1692              << "fourcc " << FourccToString(pixelformat) << ", fall back to "
1693              << min_resolution->ToString();
1694   }
1695 }
1696 
EnumerateSupportedPixelformats(v4l2_buf_type buf_type)1697 std::vector<uint32_t> V4L2Device::EnumerateSupportedPixelformats(
1698     v4l2_buf_type buf_type) {
1699   std::vector<uint32_t> pixelformats;
1700 
1701   v4l2_fmtdesc fmtdesc;
1702   memset(&fmtdesc, 0, sizeof(fmtdesc));
1703   fmtdesc.type = buf_type;
1704 
1705   for (; Ioctl(VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) {
1706     DVLOGF(3) << "Found " << fmtdesc.description << std::hex << " (0x"
1707               << fmtdesc.pixelformat << ")";
1708     pixelformats.push_back(fmtdesc.pixelformat);
1709   }
1710 
1711   return pixelformats;
1712 }
1713 
1714 VideoDecodeAccelerator::SupportedProfiles
EnumerateSupportedDecodeProfiles(const size_t num_formats,const uint32_t pixelformats[])1715 V4L2Device::EnumerateSupportedDecodeProfiles(const size_t num_formats,
1716                                              const uint32_t pixelformats[]) {
1717   VideoDecodeAccelerator::SupportedProfiles profiles;
1718 
1719   const auto& supported_pixelformats =
1720       EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
1721 
1722   for (uint32_t pixelformat : supported_pixelformats) {
1723     if (std::find(pixelformats, pixelformats + num_formats, pixelformat) ==
1724         pixelformats + num_formats)
1725       continue;
1726 
1727     VideoDecodeAccelerator::SupportedProfile profile;
1728     GetSupportedResolution(pixelformat, &profile.min_resolution,
1729                            &profile.max_resolution);
1730 
1731     const auto video_codec_profiles =
1732         V4L2PixFmtToVideoCodecProfiles(pixelformat, false);
1733 
1734     for (const auto& video_codec_profile : video_codec_profiles) {
1735       profile.profile = video_codec_profile;
1736       profiles.push_back(profile);
1737 
1738       DVLOGF(3) << "Found decoder profile " << GetProfileName(profile.profile)
1739                 << ", resolutions: " << profile.min_resolution.ToString() << " "
1740                 << profile.max_resolution.ToString();
1741     }
1742   }
1743 
1744   return profiles;
1745 }
1746 
1747 VideoEncodeAccelerator::SupportedProfiles
EnumerateSupportedEncodeProfiles()1748 V4L2Device::EnumerateSupportedEncodeProfiles() {
1749   VideoEncodeAccelerator::SupportedProfiles profiles;
1750 
1751   const auto& supported_pixelformats =
1752       EnumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
1753 
1754   for (const auto& pixelformat : supported_pixelformats) {
1755     VideoEncodeAccelerator::SupportedProfile profile;
1756     profile.max_framerate_numerator = 30;
1757     profile.max_framerate_denominator = 1;
1758     Size min_resolution;
1759     GetSupportedResolution(pixelformat, &min_resolution,
1760                            &profile.max_resolution);
1761 
1762     const auto video_codec_profiles =
1763         V4L2PixFmtToVideoCodecProfiles(pixelformat, true);
1764 
1765     for (const auto& video_codec_profile : video_codec_profiles) {
1766       profile.profile = video_codec_profile;
1767       profiles.push_back(profile);
1768 
1769       DVLOGF(3) << "Found encoder profile " << GetProfileName(profile.profile)
1770                 << ", max resolution: " << profile.max_resolution.ToString();
1771     }
1772   }
1773 
1774   return profiles;
1775 }
1776 
StartPolling(V4L2DevicePoller::EventCallback event_callback,base::RepeatingClosure error_callback)1777 bool V4L2Device::StartPolling(V4L2DevicePoller::EventCallback event_callback,
1778                               base::RepeatingClosure error_callback) {
1779   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1780 
1781   if (!device_poller_) {
1782     device_poller_ =
1783         std::make_unique<V4L2DevicePoller>(this, "V4L2DeviceThreadPoller");
1784   }
1785 
1786   bool ret = device_poller_->StartPolling(std::move(event_callback),
1787                                           std::move(error_callback));
1788 
1789   if (!ret)
1790     device_poller_ = nullptr;
1791 
1792   return ret;
1793 }
1794 
StopPolling()1795 bool V4L2Device::StopPolling() {
1796   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1797 
1798   return !device_poller_ || device_poller_->StopPolling();
1799 }
1800 
SchedulePoll()1801 void V4L2Device::SchedulePoll() {
1802   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1803 
1804   if (!device_poller_ || !device_poller_->IsPolling())
1805     return;
1806 
1807   device_poller_->SchedulePoll();
1808 }
1809 
IsCtrlExposed(uint32_t ctrl_id)1810 bool V4L2Device::IsCtrlExposed(uint32_t ctrl_id) {
1811   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1812 
1813   struct v4l2_queryctrl query_ctrl;
1814   memset(&query_ctrl, 0, sizeof(query_ctrl));
1815   query_ctrl.id = ctrl_id;
1816 
1817   return Ioctl(VIDIOC_QUERYCTRL, &query_ctrl) == 0;
1818 }
1819 
SetExtCtrls(uint32_t ctrl_class,std::vector<V4L2ExtCtrl> ctrls)1820 bool V4L2Device::SetExtCtrls(uint32_t ctrl_class,
1821                              std::vector<V4L2ExtCtrl> ctrls) {
1822   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1823 
1824   if (ctrls.empty())
1825     return true;
1826 
1827   struct v4l2_ext_controls ext_ctrls;
1828   memset(&ext_ctrls, 0, sizeof(ext_ctrls));
1829   ext_ctrls.ctrl_class = ctrl_class;
1830   ext_ctrls.count = ctrls.size();
1831   ext_ctrls.controls = &ctrls[0].ctrl;
1832   return Ioctl(VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0;
1833 }
1834 
IsCommandSupported(uint32_t command_id)1835 bool V4L2Device::IsCommandSupported(uint32_t command_id) {
1836   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1837 
1838   struct v4l2_encoder_cmd cmd;
1839   memset(&cmd, 0, sizeof(cmd));
1840   cmd.cmd = command_id;
1841 
1842   return Ioctl(VIDIOC_TRY_ENCODER_CMD, &cmd) == 0;
1843 }
1844 
HasCapabilities(uint32_t capabilities)1845 bool V4L2Device::HasCapabilities(uint32_t capabilities) {
1846   DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
1847 
1848   struct v4l2_capability caps;
1849   memset(&caps, 0, sizeof(caps));
1850   if (Ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
1851     LOG(ERROR) << "Failed to query capabilities";
1852     return false;
1853   }
1854 
1855   return (caps.capabilities & capabilities) == capabilities;
1856 }
1857 
1858 }  //  namespace media
1859