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