xref: /aosp_15_r20/external/v4l2_codec2/v4l2/V4L2Device.cpp (revision 0ec5a0ec62797f775085659156625e7f1bdb369f)
1*0ec5a0ecSAndroid Build Coastguard Worker // Copyright 2014 The Chromium Authors. All rights reserved.
2*0ec5a0ecSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*0ec5a0ecSAndroid Build Coastguard Worker // found in the LICENSE file.
4*0ec5a0ecSAndroid Build Coastguard Worker // Note: ported from Chromium commit head: 2f13d62f0c0d
5*0ec5a0ecSAndroid Build Coastguard Worker // Note: Added some missing defines that are only defined in newer kernel
6*0ec5a0ecSAndroid Build Coastguard Worker //       versions (e.g. V4L2_PIX_FMT_VP8_FRAME)
7*0ec5a0ecSAndroid Build Coastguard Worker 
8*0ec5a0ecSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
9*0ec5a0ecSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_VIDEO
10*0ec5a0ecSAndroid Build Coastguard Worker #define LOG_TAG "V4L2Device"
11*0ec5a0ecSAndroid Build Coastguard Worker 
12*0ec5a0ecSAndroid Build Coastguard Worker #include <linux/v4l2-controls.h>
13*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/v4l2/V4L2Device.h>
14*0ec5a0ecSAndroid Build Coastguard Worker 
15*0ec5a0ecSAndroid Build Coastguard Worker #include <fcntl.h>
16*0ec5a0ecSAndroid Build Coastguard Worker #include <inttypes.h>
17*0ec5a0ecSAndroid Build Coastguard Worker #include <linux/media.h>
18*0ec5a0ecSAndroid Build Coastguard Worker #include <linux/videodev2.h>
19*0ec5a0ecSAndroid Build Coastguard Worker #include <poll.h>
20*0ec5a0ecSAndroid Build Coastguard Worker #include <string.h>
21*0ec5a0ecSAndroid Build Coastguard Worker #include <sys/eventfd.h>
22*0ec5a0ecSAndroid Build Coastguard Worker #include <sys/ioctl.h>
23*0ec5a0ecSAndroid Build Coastguard Worker #include <sys/mman.h>
24*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Trace.h>
25*0ec5a0ecSAndroid Build Coastguard Worker 
26*0ec5a0ecSAndroid Build Coastguard Worker #include <algorithm>
27*0ec5a0ecSAndroid Build Coastguard Worker #include <mutex>
28*0ec5a0ecSAndroid Build Coastguard Worker #include <set>
29*0ec5a0ecSAndroid Build Coastguard Worker #include <sstream>
30*0ec5a0ecSAndroid Build Coastguard Worker 
31*0ec5a0ecSAndroid Build Coastguard Worker #include <base/bind.h>
32*0ec5a0ecSAndroid Build Coastguard Worker #include <base/numerics/safe_conversions.h>
33*0ec5a0ecSAndroid Build Coastguard Worker #include <base/posix/eintr_wrapper.h>
34*0ec5a0ecSAndroid Build Coastguard Worker #include <base/strings/stringprintf.h>
35*0ec5a0ecSAndroid Build Coastguard Worker #include <base/thread_annotations.h>
36*0ec5a0ecSAndroid Build Coastguard Worker #include <utils/Log.h>
37*0ec5a0ecSAndroid Build Coastguard Worker 
38*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/Fourcc.h>
39*0ec5a0ecSAndroid Build Coastguard Worker #include <v4l2_codec2/common/VideoPixelFormat.h>
40*0ec5a0ecSAndroid Build Coastguard Worker 
41*0ec5a0ecSAndroid Build Coastguard Worker namespace android {
42*0ec5a0ecSAndroid Build Coastguard Worker 
isValidPixFmtForCodec(VideoCodec codec,uint32_t pixFmt)43*0ec5a0ecSAndroid Build Coastguard Worker bool isValidPixFmtForCodec(VideoCodec codec, uint32_t pixFmt) {
44*0ec5a0ecSAndroid Build Coastguard Worker     switch (pixFmt) {
45*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264:
46*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264_SLICE:
47*0ec5a0ecSAndroid Build Coastguard Worker         return codec == VideoCodec::H264;
48*0ec5a0ecSAndroid Build Coastguard Worker         break;
49*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8:
50*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8_FRAME:
51*0ec5a0ecSAndroid Build Coastguard Worker         return codec == VideoCodec::VP8;
52*0ec5a0ecSAndroid Build Coastguard Worker         break;
53*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9:
54*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9_FRAME:
55*0ec5a0ecSAndroid Build Coastguard Worker         return codec == VideoCodec::VP9;
56*0ec5a0ecSAndroid Build Coastguard Worker         break;
57*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC:
58*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC_SLICE:
59*0ec5a0ecSAndroid Build Coastguard Worker         return codec == VideoCodec::HEVC;
60*0ec5a0ecSAndroid Build Coastguard Worker         break;
61*0ec5a0ecSAndroid Build Coastguard Worker     default:
62*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unhandled pixelformat %s", fourccToString(pixFmt).c_str());
63*0ec5a0ecSAndroid Build Coastguard Worker         return false;
64*0ec5a0ecSAndroid Build Coastguard Worker     }
65*0ec5a0ecSAndroid Build Coastguard Worker }
66*0ec5a0ecSAndroid Build Coastguard Worker 
buildV4L2Format(const enum v4l2_buf_type type,uint32_t fourcc,const ui::Size & size,size_t buffer_size,uint32_t stride)67*0ec5a0ecSAndroid Build Coastguard Worker struct v4l2_format buildV4L2Format(const enum v4l2_buf_type type, uint32_t fourcc,
68*0ec5a0ecSAndroid Build Coastguard Worker                                    const ui::Size& size, size_t buffer_size, uint32_t stride) {
69*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format;
70*0ec5a0ecSAndroid Build Coastguard Worker     memset(&format, 0, sizeof(format));
71*0ec5a0ecSAndroid Build Coastguard Worker     format.type = type;
72*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.pixelformat = fourcc;
73*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.width = size.width;
74*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.height = size.height;
75*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.num_planes = V4L2Device::getNumPlanesOfV4L2PixFmt(fourcc);
76*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.plane_fmt[0].sizeimage = buffer_size;
77*0ec5a0ecSAndroid Build Coastguard Worker 
78*0ec5a0ecSAndroid Build Coastguard Worker     // When the image format is planar the bytesperline value applies to the first plane and is
79*0ec5a0ecSAndroid Build Coastguard Worker     // divided by the same factor as the width field for the other planes.
80*0ec5a0ecSAndroid Build Coastguard Worker     format.fmt.pix_mp.plane_fmt[0].bytesperline = stride;
81*0ec5a0ecSAndroid Build Coastguard Worker 
82*0ec5a0ecSAndroid Build Coastguard Worker     return format;
83*0ec5a0ecSAndroid Build Coastguard Worker }
84*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2ExtCtrl(uint32_t id)85*0ec5a0ecSAndroid Build Coastguard Worker V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id) {
86*0ec5a0ecSAndroid Build Coastguard Worker     memset(&ctrl, 0, sizeof(ctrl));
87*0ec5a0ecSAndroid Build Coastguard Worker     ctrl.id = id;
88*0ec5a0ecSAndroid Build Coastguard Worker }
89*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2ExtCtrl(uint32_t id,int32_t val)90*0ec5a0ecSAndroid Build Coastguard Worker V4L2ExtCtrl::V4L2ExtCtrl(uint32_t id, int32_t val) : V4L2ExtCtrl(id) {
91*0ec5a0ecSAndroid Build Coastguard Worker     ctrl.value = val;
92*0ec5a0ecSAndroid Build Coastguard Worker }
93*0ec5a0ecSAndroid Build Coastguard Worker 
94*0ec5a0ecSAndroid Build Coastguard Worker // Class used to store the state of a buffer that should persist between reference creations. This
95*0ec5a0ecSAndroid Build Coastguard Worker // includes:
96*0ec5a0ecSAndroid Build Coastguard Worker // * Result of initial VIDIOC_QUERYBUF ioctl,
97*0ec5a0ecSAndroid Build Coastguard Worker // * Plane mappings.
98*0ec5a0ecSAndroid Build Coastguard Worker //
99*0ec5a0ecSAndroid Build Coastguard Worker // Also provides helper functions.
100*0ec5a0ecSAndroid Build Coastguard Worker class V4L2Buffer {
101*0ec5a0ecSAndroid Build Coastguard Worker public:
102*0ec5a0ecSAndroid Build Coastguard Worker     static std::unique_ptr<V4L2Buffer> create(scoped_refptr<V4L2Device> device,
103*0ec5a0ecSAndroid Build Coastguard Worker                                               enum v4l2_buf_type type, enum v4l2_memory memory,
104*0ec5a0ecSAndroid Build Coastguard Worker                                               const struct v4l2_format& format, size_t bufferId);
105*0ec5a0ecSAndroid Build Coastguard Worker     ~V4L2Buffer();
106*0ec5a0ecSAndroid Build Coastguard Worker 
107*0ec5a0ecSAndroid Build Coastguard Worker     V4L2Buffer(const V4L2Buffer&) = delete;
108*0ec5a0ecSAndroid Build Coastguard Worker     V4L2Buffer& operator=(const V4L2Buffer&) = delete;
109*0ec5a0ecSAndroid Build Coastguard Worker 
110*0ec5a0ecSAndroid Build Coastguard Worker     void* getPlaneMapping(const size_t plane);
111*0ec5a0ecSAndroid Build Coastguard Worker     size_t getMemoryUsage() const;
v4l2_buffer() const112*0ec5a0ecSAndroid Build Coastguard Worker     const struct v4l2_buffer& v4l2_buffer() const { return mV4l2Buffer; }
113*0ec5a0ecSAndroid Build Coastguard Worker 
114*0ec5a0ecSAndroid Build Coastguard Worker private:
115*0ec5a0ecSAndroid Build Coastguard Worker     V4L2Buffer(scoped_refptr<V4L2Device> device, enum v4l2_buf_type type, enum v4l2_memory memory,
116*0ec5a0ecSAndroid Build Coastguard Worker                const struct v4l2_format& format, size_t bufferId);
117*0ec5a0ecSAndroid Build Coastguard Worker     bool query();
118*0ec5a0ecSAndroid Build Coastguard Worker 
119*0ec5a0ecSAndroid Build Coastguard Worker     scoped_refptr<V4L2Device> mDevice;
120*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<void*> mPlaneMappings;
121*0ec5a0ecSAndroid Build Coastguard Worker 
122*0ec5a0ecSAndroid Build Coastguard Worker     // V4L2 data as queried by QUERYBUF.
123*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_buffer mV4l2Buffer;
124*0ec5a0ecSAndroid Build Coastguard Worker     // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
125*0ec5a0ecSAndroid Build Coastguard Worker     // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
126*0ec5a0ecSAndroid Build Coastguard Worker     // corruption.
127*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_plane mV4l2Planes[VIDEO_MAX_PLANES];
128*0ec5a0ecSAndroid Build Coastguard Worker 
129*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format mFormat __attribute__((unused));
130*0ec5a0ecSAndroid Build Coastguard Worker };
131*0ec5a0ecSAndroid Build Coastguard Worker 
create(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t bufferId)132*0ec5a0ecSAndroid Build Coastguard Worker std::unique_ptr<V4L2Buffer> V4L2Buffer::create(scoped_refptr<V4L2Device> device,
133*0ec5a0ecSAndroid Build Coastguard Worker                                                enum v4l2_buf_type type, enum v4l2_memory memory,
134*0ec5a0ecSAndroid Build Coastguard Worker                                                const struct v4l2_format& format, size_t bufferId) {
135*0ec5a0ecSAndroid Build Coastguard Worker     // Not using std::make_unique because constructor is private.
136*0ec5a0ecSAndroid Build Coastguard Worker     std::unique_ptr<V4L2Buffer> buffer(new V4L2Buffer(device, type, memory, format, bufferId));
137*0ec5a0ecSAndroid Build Coastguard Worker 
138*0ec5a0ecSAndroid Build Coastguard Worker     if (!buffer->query()) return nullptr;
139*0ec5a0ecSAndroid Build Coastguard Worker 
140*0ec5a0ecSAndroid Build Coastguard Worker     return buffer;
141*0ec5a0ecSAndroid Build Coastguard Worker }
142*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2Buffer(scoped_refptr<V4L2Device> device,enum v4l2_buf_type type,enum v4l2_memory memory,const struct v4l2_format & format,size_t bufferId)143*0ec5a0ecSAndroid Build Coastguard Worker V4L2Buffer::V4L2Buffer(scoped_refptr<V4L2Device> device, enum v4l2_buf_type type,
144*0ec5a0ecSAndroid Build Coastguard Worker                        enum v4l2_memory memory, const struct v4l2_format& format, size_t bufferId)
145*0ec5a0ecSAndroid Build Coastguard Worker       : mDevice(device), mFormat(format) {
146*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(type));
147*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(format.fmt.pix_mp.num_planes <= base::size(mV4l2Planes));
148*0ec5a0ecSAndroid Build Coastguard Worker 
149*0ec5a0ecSAndroid Build Coastguard Worker     memset(mV4l2Planes, 0, sizeof(mV4l2Planes));
150*0ec5a0ecSAndroid Build Coastguard Worker     memset(&mV4l2Buffer, 0, sizeof(mV4l2Buffer));
151*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.m.planes = mV4l2Planes;
152*0ec5a0ecSAndroid Build Coastguard Worker     // Just in case we got more planes than we want.
153*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.length =
154*0ec5a0ecSAndroid Build Coastguard Worker             std::min(static_cast<size_t>(format.fmt.pix_mp.num_planes), base::size(mV4l2Planes));
155*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.index = bufferId;
156*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.type = type;
157*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.memory = memory;
158*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.memory = V4L2_MEMORY_DMABUF;
159*0ec5a0ecSAndroid Build Coastguard Worker     mPlaneMappings.resize(mV4l2Buffer.length);
160*0ec5a0ecSAndroid Build Coastguard Worker }
161*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2Buffer()162*0ec5a0ecSAndroid Build Coastguard Worker V4L2Buffer::~V4L2Buffer() {
163*0ec5a0ecSAndroid Build Coastguard Worker     if (mV4l2Buffer.memory == V4L2_MEMORY_MMAP) {
164*0ec5a0ecSAndroid Build Coastguard Worker         for (size_t i = 0; i < mPlaneMappings.size(); i++) {
165*0ec5a0ecSAndroid Build Coastguard Worker             if (mPlaneMappings[i] != nullptr) {
166*0ec5a0ecSAndroid Build Coastguard Worker                 mDevice->munmap(mPlaneMappings[i], mV4l2Buffer.m.planes[i].length);
167*0ec5a0ecSAndroid Build Coastguard Worker             }
168*0ec5a0ecSAndroid Build Coastguard Worker         }
169*0ec5a0ecSAndroid Build Coastguard Worker     }
170*0ec5a0ecSAndroid Build Coastguard Worker }
171*0ec5a0ecSAndroid Build Coastguard Worker 
query()172*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Buffer::query() {
173*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_QUERYBUF, &mV4l2Buffer);
174*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
175*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("VIDIOC_QUERYBUF failed");
176*0ec5a0ecSAndroid Build Coastguard Worker         return false;
177*0ec5a0ecSAndroid Build Coastguard Worker     }
178*0ec5a0ecSAndroid Build Coastguard Worker 
179*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK(mPlaneMappings.size() == mV4l2Buffer.length);
180*0ec5a0ecSAndroid Build Coastguard Worker 
181*0ec5a0ecSAndroid Build Coastguard Worker     return true;
182*0ec5a0ecSAndroid Build Coastguard Worker }
183*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneMapping(const size_t plane)184*0ec5a0ecSAndroid Build Coastguard Worker void* V4L2Buffer::getPlaneMapping(const size_t plane) {
185*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= mPlaneMappings.size()) {
186*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
187*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
188*0ec5a0ecSAndroid Build Coastguard Worker     }
189*0ec5a0ecSAndroid Build Coastguard Worker 
190*0ec5a0ecSAndroid Build Coastguard Worker     void* p = mPlaneMappings[plane];
191*0ec5a0ecSAndroid Build Coastguard Worker     if (p) {
192*0ec5a0ecSAndroid Build Coastguard Worker         return p;
193*0ec5a0ecSAndroid Build Coastguard Worker     }
194*0ec5a0ecSAndroid Build Coastguard Worker 
195*0ec5a0ecSAndroid Build Coastguard Worker     // Do this check here to avoid repeating it after a buffer has been successfully mapped (we know
196*0ec5a0ecSAndroid Build Coastguard Worker     // we are of MMAP type by then).
197*0ec5a0ecSAndroid Build Coastguard Worker     if (mV4l2Buffer.memory != V4L2_MEMORY_MMAP) {
198*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Cannot create mapping on non-MMAP buffer");
199*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
200*0ec5a0ecSAndroid Build Coastguard Worker     }
201*0ec5a0ecSAndroid Build Coastguard Worker 
202*0ec5a0ecSAndroid Build Coastguard Worker     p = mDevice->mmap(NULL, mV4l2Buffer.m.planes[plane].length, PROT_READ | PROT_WRITE, MAP_SHARED,
203*0ec5a0ecSAndroid Build Coastguard Worker                       mV4l2Buffer.m.planes[plane].m.mem_offset);
204*0ec5a0ecSAndroid Build Coastguard Worker     if (p == MAP_FAILED) {
205*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("mmap() failed: ");
206*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
207*0ec5a0ecSAndroid Build Coastguard Worker     }
208*0ec5a0ecSAndroid Build Coastguard Worker 
209*0ec5a0ecSAndroid Build Coastguard Worker     mPlaneMappings[plane] = p;
210*0ec5a0ecSAndroid Build Coastguard Worker     return p;
211*0ec5a0ecSAndroid Build Coastguard Worker }
212*0ec5a0ecSAndroid Build Coastguard Worker 
getMemoryUsage() const213*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Buffer::getMemoryUsage() const {
214*0ec5a0ecSAndroid Build Coastguard Worker     size_t usage = 0;
215*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < mV4l2Buffer.length; i++) {
216*0ec5a0ecSAndroid Build Coastguard Worker         usage += mV4l2Buffer.m.planes[i].length;
217*0ec5a0ecSAndroid Build Coastguard Worker     }
218*0ec5a0ecSAndroid Build Coastguard Worker     return usage;
219*0ec5a0ecSAndroid Build Coastguard Worker }
220*0ec5a0ecSAndroid Build Coastguard Worker 
221*0ec5a0ecSAndroid Build Coastguard Worker // A thread-safe pool of buffer indexes, allowing buffers to be obtained and returned from different
222*0ec5a0ecSAndroid Build Coastguard Worker // threads. All the methods of this class are thread-safe. Users should keep a scoped_refptr to
223*0ec5a0ecSAndroid Build Coastguard Worker // instances of this class in order to ensure the list remains alive as long as they need it.
224*0ec5a0ecSAndroid Build Coastguard Worker class V4L2BuffersList : public base::RefCountedThreadSafe<V4L2BuffersList> {
225*0ec5a0ecSAndroid Build Coastguard Worker public:
226*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BuffersList() = default;
227*0ec5a0ecSAndroid Build Coastguard Worker 
228*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BuffersList(const V4L2BuffersList&) = delete;
229*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BuffersList& operator=(const V4L2BuffersList&) = delete;
230*0ec5a0ecSAndroid Build Coastguard Worker 
231*0ec5a0ecSAndroid Build Coastguard Worker     // Return a buffer to this list. Also can be called to set the initial pool of buffers.
232*0ec5a0ecSAndroid Build Coastguard Worker     // Note that it is illegal to return the same buffer twice.
233*0ec5a0ecSAndroid Build Coastguard Worker     void returnBuffer(size_t bufferId);
234*0ec5a0ecSAndroid Build Coastguard Worker     // Get any of the buffers in the list. There is no order guarantee whatsoever.
235*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<size_t> getFreeBuffer();
236*0ec5a0ecSAndroid Build Coastguard Worker     // Get the buffer with specified index.
237*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<size_t> getFreeBuffer(size_t requestedBufferId);
238*0ec5a0ecSAndroid Build Coastguard Worker     // Number of buffers currently in this list.
239*0ec5a0ecSAndroid Build Coastguard Worker     size_t size() const;
240*0ec5a0ecSAndroid Build Coastguard Worker 
241*0ec5a0ecSAndroid Build Coastguard Worker private:
242*0ec5a0ecSAndroid Build Coastguard Worker     friend class base::RefCountedThreadSafe<V4L2BuffersList>;
243*0ec5a0ecSAndroid Build Coastguard Worker     ~V4L2BuffersList() = default;
244*0ec5a0ecSAndroid Build Coastguard Worker 
245*0ec5a0ecSAndroid Build Coastguard Worker     mutable std::mutex mLock;
246*0ec5a0ecSAndroid Build Coastguard Worker     std::set<size_t> mFreeBuffers GUARDED_BY(mLock);
247*0ec5a0ecSAndroid Build Coastguard Worker };
248*0ec5a0ecSAndroid Build Coastguard Worker 
returnBuffer(size_t bufferId)249*0ec5a0ecSAndroid Build Coastguard Worker void V4L2BuffersList::returnBuffer(size_t bufferId) {
250*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
251*0ec5a0ecSAndroid Build Coastguard Worker 
252*0ec5a0ecSAndroid Build Coastguard Worker     auto inserted = mFreeBuffers.emplace(bufferId);
253*0ec5a0ecSAndroid Build Coastguard Worker     if (!inserted.second) {
254*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Returning buffer failed");
255*0ec5a0ecSAndroid Build Coastguard Worker     }
256*0ec5a0ecSAndroid Build Coastguard Worker }
257*0ec5a0ecSAndroid Build Coastguard Worker 
getFreeBuffer()258*0ec5a0ecSAndroid Build Coastguard Worker std::optional<size_t> V4L2BuffersList::getFreeBuffer() {
259*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
260*0ec5a0ecSAndroid Build Coastguard Worker 
261*0ec5a0ecSAndroid Build Coastguard Worker     auto iter = mFreeBuffers.begin();
262*0ec5a0ecSAndroid Build Coastguard Worker     if (iter == mFreeBuffers.end()) {
263*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("No free buffer available!");
264*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
265*0ec5a0ecSAndroid Build Coastguard Worker     }
266*0ec5a0ecSAndroid Build Coastguard Worker 
267*0ec5a0ecSAndroid Build Coastguard Worker     size_t bufferId = *iter;
268*0ec5a0ecSAndroid Build Coastguard Worker     mFreeBuffers.erase(iter);
269*0ec5a0ecSAndroid Build Coastguard Worker 
270*0ec5a0ecSAndroid Build Coastguard Worker     return bufferId;
271*0ec5a0ecSAndroid Build Coastguard Worker }
272*0ec5a0ecSAndroid Build Coastguard Worker 
getFreeBuffer(size_t requestedBufferId)273*0ec5a0ecSAndroid Build Coastguard Worker std::optional<size_t> V4L2BuffersList::getFreeBuffer(size_t requestedBufferId) {
274*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
275*0ec5a0ecSAndroid Build Coastguard Worker 
276*0ec5a0ecSAndroid Build Coastguard Worker     return (mFreeBuffers.erase(requestedBufferId) > 0) ? std::make_optional(requestedBufferId)
277*0ec5a0ecSAndroid Build Coastguard Worker                                                        : std::nullopt;
278*0ec5a0ecSAndroid Build Coastguard Worker }
279*0ec5a0ecSAndroid Build Coastguard Worker 
size() const280*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2BuffersList::size() const {
281*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mLock);
282*0ec5a0ecSAndroid Build Coastguard Worker 
283*0ec5a0ecSAndroid Build Coastguard Worker     return mFreeBuffers.size();
284*0ec5a0ecSAndroid Build Coastguard Worker }
285*0ec5a0ecSAndroid Build Coastguard Worker 
286*0ec5a0ecSAndroid Build Coastguard Worker // Module-private class that let users query/write V4L2 buffer information. It also makes some
287*0ec5a0ecSAndroid Build Coastguard Worker // private V4L2Queue methods available to this module only.
288*0ec5a0ecSAndroid Build Coastguard Worker class V4L2BufferRefBase {
289*0ec5a0ecSAndroid Build Coastguard Worker public:
290*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BufferRefBase(const struct v4l2_buffer& v4l2Buffer, base::WeakPtr<V4L2Queue> queue);
291*0ec5a0ecSAndroid Build Coastguard Worker     ~V4L2BufferRefBase();
292*0ec5a0ecSAndroid Build Coastguard Worker 
293*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BufferRefBase(const V4L2BufferRefBase&) = delete;
294*0ec5a0ecSAndroid Build Coastguard Worker     V4L2BufferRefBase& operator=(const V4L2BufferRefBase&) = delete;
295*0ec5a0ecSAndroid Build Coastguard Worker 
296*0ec5a0ecSAndroid Build Coastguard Worker     bool queueBuffer();
297*0ec5a0ecSAndroid Build Coastguard Worker     void* getPlaneMapping(const size_t plane);
298*0ec5a0ecSAndroid Build Coastguard Worker 
299*0ec5a0ecSAndroid Build Coastguard Worker     // Checks that the number of passed FDs is adequate for the current format and buffer
300*0ec5a0ecSAndroid Build Coastguard Worker     // configuration. Only useful for DMABUF buffers.
301*0ec5a0ecSAndroid Build Coastguard Worker     bool checkNumFDsForFormat(const size_t numFds) const;
302*0ec5a0ecSAndroid Build Coastguard Worker 
303*0ec5a0ecSAndroid Build Coastguard Worker     // Data from the buffer, that users can query and/or write.
304*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_buffer mV4l2Buffer;
305*0ec5a0ecSAndroid Build Coastguard Worker     // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
306*0ec5a0ecSAndroid Build Coastguard Worker     // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
307*0ec5a0ecSAndroid Build Coastguard Worker     // corruption.
308*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_plane mV4l2Planes[VIDEO_MAX_PLANES];
309*0ec5a0ecSAndroid Build Coastguard Worker 
310*0ec5a0ecSAndroid Build Coastguard Worker private:
bufferId() const311*0ec5a0ecSAndroid Build Coastguard Worker     size_t bufferId() const { return mV4l2Buffer.index; }
312*0ec5a0ecSAndroid Build Coastguard Worker 
313*0ec5a0ecSAndroid Build Coastguard Worker     friend class V4L2WritableBufferRef;
314*0ec5a0ecSAndroid Build Coastguard Worker     // A weak pointer to the queue this buffer belongs to. Will remain valid as long as the
315*0ec5a0ecSAndroid Build Coastguard Worker     // underlying V4L2 buffer is valid too. This can only be accessed from the sequence protected by
316*0ec5a0ecSAndroid Build Coastguard Worker     // sequence_checker_. Thread-safe methods (like ~V4L2BufferRefBase) must *never* access this.
317*0ec5a0ecSAndroid Build Coastguard Worker     base::WeakPtr<V4L2Queue> mQueue;
318*0ec5a0ecSAndroid Build Coastguard Worker     // Where to return this buffer if it goes out of scope without being queued.
319*0ec5a0ecSAndroid Build Coastguard Worker     scoped_refptr<V4L2BuffersList> mReturnTo;
320*0ec5a0ecSAndroid Build Coastguard Worker     bool queued = false;
321*0ec5a0ecSAndroid Build Coastguard Worker 
322*0ec5a0ecSAndroid Build Coastguard Worker     SEQUENCE_CHECKER(mSequenceChecker);
323*0ec5a0ecSAndroid Build Coastguard Worker };
324*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2BufferRefBase(const struct v4l2_buffer & v4l2Buffer,base::WeakPtr<V4L2Queue> queue)325*0ec5a0ecSAndroid Build Coastguard Worker V4L2BufferRefBase::V4L2BufferRefBase(const struct v4l2_buffer& v4l2Buffer,
326*0ec5a0ecSAndroid Build Coastguard Worker                                      base::WeakPtr<V4L2Queue> queue)
327*0ec5a0ecSAndroid Build Coastguard Worker       : mQueue(std::move(queue)), mReturnTo(mQueue->mFreeBuffers) {
328*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
329*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(v4l2Buffer.type));
330*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(v4l2Buffer.length <= base::size(mV4l2Planes));
331*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mReturnTo);
332*0ec5a0ecSAndroid Build Coastguard Worker 
333*0ec5a0ecSAndroid Build Coastguard Worker     memcpy(&mV4l2Buffer, &v4l2Buffer, sizeof(mV4l2Buffer));
334*0ec5a0ecSAndroid Build Coastguard Worker     memcpy(mV4l2Planes, v4l2Buffer.m.planes, sizeof(struct v4l2_plane) * v4l2Buffer.length);
335*0ec5a0ecSAndroid Build Coastguard Worker     mV4l2Buffer.m.planes = mV4l2Planes;
336*0ec5a0ecSAndroid Build Coastguard Worker }
337*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2BufferRefBase()338*0ec5a0ecSAndroid Build Coastguard Worker V4L2BufferRefBase::~V4L2BufferRefBase() {
339*0ec5a0ecSAndroid Build Coastguard Worker     // We are the last reference and are only accessing the thread-safe mReturnTo, so we are safe
340*0ec5a0ecSAndroid Build Coastguard Worker     // to call from any sequence. If we have been queued, then the queue is our owner so we don't
341*0ec5a0ecSAndroid Build Coastguard Worker     // need to return to the free buffers list.
342*0ec5a0ecSAndroid Build Coastguard Worker     if (!queued) mReturnTo->returnBuffer(bufferId());
343*0ec5a0ecSAndroid Build Coastguard Worker }
344*0ec5a0ecSAndroid Build Coastguard Worker 
queueBuffer()345*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2BufferRefBase::queueBuffer() {
346*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
347*0ec5a0ecSAndroid Build Coastguard Worker 
348*0ec5a0ecSAndroid Build Coastguard Worker     if (!mQueue) return false;
349*0ec5a0ecSAndroid Build Coastguard Worker 
350*0ec5a0ecSAndroid Build Coastguard Worker     queued = mQueue->queueBuffer(&mV4l2Buffer);
351*0ec5a0ecSAndroid Build Coastguard Worker 
352*0ec5a0ecSAndroid Build Coastguard Worker     return queued;
353*0ec5a0ecSAndroid Build Coastguard Worker }
354*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneMapping(const size_t plane)355*0ec5a0ecSAndroid Build Coastguard Worker void* V4L2BufferRefBase::getPlaneMapping(const size_t plane) {
356*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
357*0ec5a0ecSAndroid Build Coastguard Worker 
358*0ec5a0ecSAndroid Build Coastguard Worker     if (!mQueue) return nullptr;
359*0ec5a0ecSAndroid Build Coastguard Worker 
360*0ec5a0ecSAndroid Build Coastguard Worker     return mQueue->mBuffers[bufferId()]->getPlaneMapping(plane);
361*0ec5a0ecSAndroid Build Coastguard Worker }
362*0ec5a0ecSAndroid Build Coastguard Worker 
checkNumFDsForFormat(const size_t numFds) const363*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2BufferRefBase::checkNumFDsForFormat(const size_t numFds) const {
364*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
365*0ec5a0ecSAndroid Build Coastguard Worker 
366*0ec5a0ecSAndroid Build Coastguard Worker     if (!mQueue) return false;
367*0ec5a0ecSAndroid Build Coastguard Worker 
368*0ec5a0ecSAndroid Build Coastguard Worker     // We have not used SetFormat(), assume this is ok.
369*0ec5a0ecSAndroid Build Coastguard Worker     // Hopefully we standardize SetFormat() in the future.
370*0ec5a0ecSAndroid Build Coastguard Worker     if (!mQueue->mCurrentFormat) return true;
371*0ec5a0ecSAndroid Build Coastguard Worker 
372*0ec5a0ecSAndroid Build Coastguard Worker     const size_t requiredFds = mQueue->mCurrentFormat->fmt.pix_mp.num_planes;
373*0ec5a0ecSAndroid Build Coastguard Worker     // Sanity check.
374*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mV4l2Buffer.length == requiredFds);
375*0ec5a0ecSAndroid Build Coastguard Worker     if (numFds < requiredFds) {
376*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Insufficient number of FDs given for the current format. "
377*0ec5a0ecSAndroid Build Coastguard Worker               "%zu provided, %zu required.",
378*0ec5a0ecSAndroid Build Coastguard Worker               numFds, requiredFds);
379*0ec5a0ecSAndroid Build Coastguard Worker         return false;
380*0ec5a0ecSAndroid Build Coastguard Worker     }
381*0ec5a0ecSAndroid Build Coastguard Worker 
382*0ec5a0ecSAndroid Build Coastguard Worker     const auto* planes = mV4l2Buffer.m.planes;
383*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = mV4l2Buffer.length - 1; i >= numFds; --i) {
384*0ec5a0ecSAndroid Build Coastguard Worker         // Assume that an fd is a duplicate of a previous plane's fd if offset != 0. Otherwise, if
385*0ec5a0ecSAndroid Build Coastguard Worker         // offset == 0, return error as it is likely pointing to a new plane.
386*0ec5a0ecSAndroid Build Coastguard Worker         if (planes[i].data_offset == 0) {
387*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Additional dmabuf fds point to a new buffer.");
388*0ec5a0ecSAndroid Build Coastguard Worker             return false;
389*0ec5a0ecSAndroid Build Coastguard Worker         }
390*0ec5a0ecSAndroid Build Coastguard Worker     }
391*0ec5a0ecSAndroid Build Coastguard Worker 
392*0ec5a0ecSAndroid Build Coastguard Worker     return true;
393*0ec5a0ecSAndroid Build Coastguard Worker }
394*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2WritableBufferRef(const struct v4l2_buffer & v4l2Buffer,base::WeakPtr<V4L2Queue> queue)395*0ec5a0ecSAndroid Build Coastguard Worker V4L2WritableBufferRef::V4L2WritableBufferRef(const struct v4l2_buffer& v4l2Buffer,
396*0ec5a0ecSAndroid Build Coastguard Worker                                              base::WeakPtr<V4L2Queue> queue)
397*0ec5a0ecSAndroid Build Coastguard Worker       : mBufferData(std::make_unique<V4L2BufferRefBase>(v4l2Buffer, std::move(queue))) {
398*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
399*0ec5a0ecSAndroid Build Coastguard Worker }
400*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2WritableBufferRef(V4L2WritableBufferRef && other)401*0ec5a0ecSAndroid Build Coastguard Worker V4L2WritableBufferRef::V4L2WritableBufferRef(V4L2WritableBufferRef&& other)
402*0ec5a0ecSAndroid Build Coastguard Worker       : mBufferData(std::move(other.mBufferData)) {
403*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
404*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(other.mSequenceChecker);
405*0ec5a0ecSAndroid Build Coastguard Worker }
406*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2WritableBufferRef()407*0ec5a0ecSAndroid Build Coastguard Worker V4L2WritableBufferRef::~V4L2WritableBufferRef() {
408*0ec5a0ecSAndroid Build Coastguard Worker     // Only valid references should be sequence-checked
409*0ec5a0ecSAndroid Build Coastguard Worker     if (mBufferData) {
410*0ec5a0ecSAndroid Build Coastguard Worker         DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
411*0ec5a0ecSAndroid Build Coastguard Worker     }
412*0ec5a0ecSAndroid Build Coastguard Worker }
413*0ec5a0ecSAndroid Build Coastguard Worker 
operator =(V4L2WritableBufferRef && other)414*0ec5a0ecSAndroid Build Coastguard Worker V4L2WritableBufferRef& V4L2WritableBufferRef::operator=(V4L2WritableBufferRef&& other) {
415*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
416*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(other.mSequenceChecker);
417*0ec5a0ecSAndroid Build Coastguard Worker 
418*0ec5a0ecSAndroid Build Coastguard Worker     if (this == &other) return *this;
419*0ec5a0ecSAndroid Build Coastguard Worker 
420*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData = std::move(other.mBufferData);
421*0ec5a0ecSAndroid Build Coastguard Worker 
422*0ec5a0ecSAndroid Build Coastguard Worker     return *this;
423*0ec5a0ecSAndroid Build Coastguard Worker }
424*0ec5a0ecSAndroid Build Coastguard Worker 
memory() const425*0ec5a0ecSAndroid Build Coastguard Worker enum v4l2_memory V4L2WritableBufferRef::memory() const {
426*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
427*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
428*0ec5a0ecSAndroid Build Coastguard Worker 
429*0ec5a0ecSAndroid Build Coastguard Worker     return static_cast<enum v4l2_memory>(mBufferData->mV4l2Buffer.memory);
430*0ec5a0ecSAndroid Build Coastguard Worker }
431*0ec5a0ecSAndroid Build Coastguard Worker 
doQueue()432*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2WritableBufferRef::doQueue() && {
433*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
434*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
435*0ec5a0ecSAndroid Build Coastguard Worker 
436*0ec5a0ecSAndroid Build Coastguard Worker     bool queued = mBufferData->queueBuffer();
437*0ec5a0ecSAndroid Build Coastguard Worker 
438*0ec5a0ecSAndroid Build Coastguard Worker     // Clear our own reference.
439*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData.reset();
440*0ec5a0ecSAndroid Build Coastguard Worker 
441*0ec5a0ecSAndroid Build Coastguard Worker     return queued;
442*0ec5a0ecSAndroid Build Coastguard Worker }
443*0ec5a0ecSAndroid Build Coastguard Worker 
queueMMap()444*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2WritableBufferRef::queueMMap() && {
445*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
446*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
447*0ec5a0ecSAndroid Build Coastguard Worker 
448*0ec5a0ecSAndroid Build Coastguard Worker     // Move ourselves so our data gets freed no matter when we return
449*0ec5a0ecSAndroid Build Coastguard Worker     V4L2WritableBufferRef self(std::move(*this));
450*0ec5a0ecSAndroid Build Coastguard Worker 
451*0ec5a0ecSAndroid Build Coastguard Worker     if (self.memory() != V4L2_MEMORY_MMAP) {
452*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Called on invalid buffer type!");
453*0ec5a0ecSAndroid Build Coastguard Worker         return false;
454*0ec5a0ecSAndroid Build Coastguard Worker     }
455*0ec5a0ecSAndroid Build Coastguard Worker 
456*0ec5a0ecSAndroid Build Coastguard Worker     return std::move(self).doQueue();
457*0ec5a0ecSAndroid Build Coastguard Worker }
458*0ec5a0ecSAndroid Build Coastguard Worker 
queueUserPtr(const std::vector<void * > & ptrs)459*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2WritableBufferRef::queueUserPtr(const std::vector<void*>& ptrs) && {
460*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
461*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
462*0ec5a0ecSAndroid Build Coastguard Worker 
463*0ec5a0ecSAndroid Build Coastguard Worker     // Move ourselves so our data gets freed no matter when we return
464*0ec5a0ecSAndroid Build Coastguard Worker     V4L2WritableBufferRef self(std::move(*this));
465*0ec5a0ecSAndroid Build Coastguard Worker 
466*0ec5a0ecSAndroid Build Coastguard Worker     if (self.memory() != V4L2_MEMORY_USERPTR) {
467*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Called on invalid buffer type!");
468*0ec5a0ecSAndroid Build Coastguard Worker         return false;
469*0ec5a0ecSAndroid Build Coastguard Worker     }
470*0ec5a0ecSAndroid Build Coastguard Worker 
471*0ec5a0ecSAndroid Build Coastguard Worker     if (ptrs.size() != self.planesCount()) {
472*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Provided %zu pointers while we require %u.", ptrs.size(),
473*0ec5a0ecSAndroid Build Coastguard Worker               self.mBufferData->mV4l2Buffer.length);
474*0ec5a0ecSAndroid Build Coastguard Worker         return false;
475*0ec5a0ecSAndroid Build Coastguard Worker     }
476*0ec5a0ecSAndroid Build Coastguard Worker 
477*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < ptrs.size(); i++) {
478*0ec5a0ecSAndroid Build Coastguard Worker         self.mBufferData->mV4l2Buffer.m.planes[i].m.userptr =
479*0ec5a0ecSAndroid Build Coastguard Worker                 reinterpret_cast<unsigned long>(ptrs[i]);
480*0ec5a0ecSAndroid Build Coastguard Worker     }
481*0ec5a0ecSAndroid Build Coastguard Worker 
482*0ec5a0ecSAndroid Build Coastguard Worker     return std::move(self).doQueue();
483*0ec5a0ecSAndroid Build Coastguard Worker }
484*0ec5a0ecSAndroid Build Coastguard Worker 
queueDMABuf(const std::vector<int> & fds)485*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2WritableBufferRef::queueDMABuf(const std::vector<int>& fds) && {
486*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
487*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
488*0ec5a0ecSAndroid Build Coastguard Worker 
489*0ec5a0ecSAndroid Build Coastguard Worker     // Move ourselves so our data gets freed no matter when we return
490*0ec5a0ecSAndroid Build Coastguard Worker     V4L2WritableBufferRef self(std::move(*this));
491*0ec5a0ecSAndroid Build Coastguard Worker 
492*0ec5a0ecSAndroid Build Coastguard Worker     if (self.memory() != V4L2_MEMORY_DMABUF) {
493*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Called on invalid buffer type!");
494*0ec5a0ecSAndroid Build Coastguard Worker         return false;
495*0ec5a0ecSAndroid Build Coastguard Worker     }
496*0ec5a0ecSAndroid Build Coastguard Worker 
497*0ec5a0ecSAndroid Build Coastguard Worker     if (!self.mBufferData->checkNumFDsForFormat(fds.size())) return false;
498*0ec5a0ecSAndroid Build Coastguard Worker 
499*0ec5a0ecSAndroid Build Coastguard Worker     size_t numPlanes = self.planesCount();
500*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < numPlanes; i++) self.mBufferData->mV4l2Buffer.m.planes[i].m.fd = fds[i];
501*0ec5a0ecSAndroid Build Coastguard Worker 
502*0ec5a0ecSAndroid Build Coastguard Worker     return std::move(self).doQueue();
503*0ec5a0ecSAndroid Build Coastguard Worker }
504*0ec5a0ecSAndroid Build Coastguard Worker 
planesCount() const505*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2WritableBufferRef::planesCount() const {
506*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
507*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
508*0ec5a0ecSAndroid Build Coastguard Worker 
509*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.length;
510*0ec5a0ecSAndroid Build Coastguard Worker }
511*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneSize(const size_t plane) const512*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2WritableBufferRef::getPlaneSize(const size_t plane) const {
513*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
514*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
515*0ec5a0ecSAndroid Build Coastguard Worker 
516*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
517*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
518*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
519*0ec5a0ecSAndroid Build Coastguard Worker     }
520*0ec5a0ecSAndroid Build Coastguard Worker 
521*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.m.planes[plane].length;
522*0ec5a0ecSAndroid Build Coastguard Worker }
523*0ec5a0ecSAndroid Build Coastguard Worker 
setPlaneSize(const size_t plane,const size_t size)524*0ec5a0ecSAndroid Build Coastguard Worker void V4L2WritableBufferRef::setPlaneSize(const size_t plane, const size_t size) {
525*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
526*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
527*0ec5a0ecSAndroid Build Coastguard Worker 
528*0ec5a0ecSAndroid Build Coastguard Worker     enum v4l2_memory mem = memory();
529*0ec5a0ecSAndroid Build Coastguard Worker     if (mem == V4L2_MEMORY_MMAP) {
530*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mBufferData->mV4l2Buffer.m.planes[plane].length == size);
531*0ec5a0ecSAndroid Build Coastguard Worker         return;
532*0ec5a0ecSAndroid Build Coastguard Worker     }
533*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mem == V4L2_MEMORY_USERPTR || mem == V4L2_MEMORY_DMABUF);
534*0ec5a0ecSAndroid Build Coastguard Worker 
535*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
536*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
537*0ec5a0ecSAndroid Build Coastguard Worker         return;
538*0ec5a0ecSAndroid Build Coastguard Worker     }
539*0ec5a0ecSAndroid Build Coastguard Worker 
540*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData->mV4l2Buffer.m.planes[plane].length = size;
541*0ec5a0ecSAndroid Build Coastguard Worker }
542*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneMapping(const size_t plane)543*0ec5a0ecSAndroid Build Coastguard Worker void* V4L2WritableBufferRef::getPlaneMapping(const size_t plane) {
544*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
545*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
546*0ec5a0ecSAndroid Build Coastguard Worker 
547*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->getPlaneMapping(plane);
548*0ec5a0ecSAndroid Build Coastguard Worker }
549*0ec5a0ecSAndroid Build Coastguard Worker 
setTimeStamp(const struct timeval & timestamp)550*0ec5a0ecSAndroid Build Coastguard Worker void V4L2WritableBufferRef::setTimeStamp(const struct timeval& timestamp) {
551*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
552*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
553*0ec5a0ecSAndroid Build Coastguard Worker 
554*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData->mV4l2Buffer.timestamp = timestamp;
555*0ec5a0ecSAndroid Build Coastguard Worker }
556*0ec5a0ecSAndroid Build Coastguard Worker 
getTimeStamp() const557*0ec5a0ecSAndroid Build Coastguard Worker const struct timeval& V4L2WritableBufferRef::getTimeStamp() const {
558*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
559*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
560*0ec5a0ecSAndroid Build Coastguard Worker 
561*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.timestamp;
562*0ec5a0ecSAndroid Build Coastguard Worker }
563*0ec5a0ecSAndroid Build Coastguard Worker 
setPlaneBytesUsed(const size_t plane,const size_t bytesUsed)564*0ec5a0ecSAndroid Build Coastguard Worker void V4L2WritableBufferRef::setPlaneBytesUsed(const size_t plane, const size_t bytesUsed) {
565*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
566*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
567*0ec5a0ecSAndroid Build Coastguard Worker 
568*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
569*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
570*0ec5a0ecSAndroid Build Coastguard Worker         return;
571*0ec5a0ecSAndroid Build Coastguard Worker     }
572*0ec5a0ecSAndroid Build Coastguard Worker 
573*0ec5a0ecSAndroid Build Coastguard Worker     if (bytesUsed > getPlaneSize(plane)) {
574*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Set bytes used %zu larger than plane size %zu.", bytesUsed, getPlaneSize(plane));
575*0ec5a0ecSAndroid Build Coastguard Worker         return;
576*0ec5a0ecSAndroid Build Coastguard Worker     }
577*0ec5a0ecSAndroid Build Coastguard Worker 
578*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData->mV4l2Buffer.m.planes[plane].bytesused = bytesUsed;
579*0ec5a0ecSAndroid Build Coastguard Worker }
580*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneBytesUsed(const size_t plane) const581*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2WritableBufferRef::getPlaneBytesUsed(const size_t plane) const {
582*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
583*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
584*0ec5a0ecSAndroid Build Coastguard Worker 
585*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
586*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
587*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
588*0ec5a0ecSAndroid Build Coastguard Worker     }
589*0ec5a0ecSAndroid Build Coastguard Worker 
590*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.m.planes[plane].bytesused;
591*0ec5a0ecSAndroid Build Coastguard Worker }
592*0ec5a0ecSAndroid Build Coastguard Worker 
setPlaneDataOffset(const size_t plane,const size_t dataOffset)593*0ec5a0ecSAndroid Build Coastguard Worker void V4L2WritableBufferRef::setPlaneDataOffset(const size_t plane, const size_t dataOffset) {
594*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
595*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
596*0ec5a0ecSAndroid Build Coastguard Worker 
597*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
598*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
599*0ec5a0ecSAndroid Build Coastguard Worker         return;
600*0ec5a0ecSAndroid Build Coastguard Worker     }
601*0ec5a0ecSAndroid Build Coastguard Worker 
602*0ec5a0ecSAndroid Build Coastguard Worker     mBufferData->mV4l2Buffer.m.planes[plane].data_offset = dataOffset;
603*0ec5a0ecSAndroid Build Coastguard Worker }
604*0ec5a0ecSAndroid Build Coastguard Worker 
bufferId() const605*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2WritableBufferRef::bufferId() const {
606*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
607*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
608*0ec5a0ecSAndroid Build Coastguard Worker 
609*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.index;
610*0ec5a0ecSAndroid Build Coastguard Worker }
611*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2ReadableBuffer(const struct v4l2_buffer & v4l2Buffer,base::WeakPtr<V4L2Queue> queue)612*0ec5a0ecSAndroid Build Coastguard Worker V4L2ReadableBuffer::V4L2ReadableBuffer(const struct v4l2_buffer& v4l2Buffer,
613*0ec5a0ecSAndroid Build Coastguard Worker                                        base::WeakPtr<V4L2Queue> queue)
614*0ec5a0ecSAndroid Build Coastguard Worker       : mBufferData(std::make_unique<V4L2BufferRefBase>(v4l2Buffer, std::move(queue))) {
615*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
616*0ec5a0ecSAndroid Build Coastguard Worker }
617*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2ReadableBuffer()618*0ec5a0ecSAndroid Build Coastguard Worker V4L2ReadableBuffer::~V4L2ReadableBuffer() {
619*0ec5a0ecSAndroid Build Coastguard Worker     // This method is thread-safe. Since we are the destructor, we are guaranteed to be called from
620*0ec5a0ecSAndroid Build Coastguard Worker     // the only remaining reference to us. Also, we are just calling the destructor of buffer_data_,
621*0ec5a0ecSAndroid Build Coastguard Worker     // which is also thread-safe.
622*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
623*0ec5a0ecSAndroid Build Coastguard Worker }
624*0ec5a0ecSAndroid Build Coastguard Worker 
isLast() const625*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2ReadableBuffer::isLast() const {
626*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
627*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
628*0ec5a0ecSAndroid Build Coastguard Worker 
629*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.flags & V4L2_BUF_FLAG_LAST;
630*0ec5a0ecSAndroid Build Coastguard Worker }
631*0ec5a0ecSAndroid Build Coastguard Worker 
isKeyframe() const632*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2ReadableBuffer::isKeyframe() const {
633*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
634*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
635*0ec5a0ecSAndroid Build Coastguard Worker 
636*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.flags & V4L2_BUF_FLAG_KEYFRAME;
637*0ec5a0ecSAndroid Build Coastguard Worker }
638*0ec5a0ecSAndroid Build Coastguard Worker 
getTimeStamp() const639*0ec5a0ecSAndroid Build Coastguard Worker struct timeval V4L2ReadableBuffer::getTimeStamp() const {
640*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
641*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
642*0ec5a0ecSAndroid Build Coastguard Worker 
643*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.timestamp;
644*0ec5a0ecSAndroid Build Coastguard Worker }
645*0ec5a0ecSAndroid Build Coastguard Worker 
planesCount() const646*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2ReadableBuffer::planesCount() const {
647*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
648*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
649*0ec5a0ecSAndroid Build Coastguard Worker 
650*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.length;
651*0ec5a0ecSAndroid Build Coastguard Worker }
652*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneMapping(const size_t plane) const653*0ec5a0ecSAndroid Build Coastguard Worker const void* V4L2ReadableBuffer::getPlaneMapping(const size_t plane) const {
654*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
655*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK(mBufferData);
656*0ec5a0ecSAndroid Build Coastguard Worker 
657*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->getPlaneMapping(plane);
658*0ec5a0ecSAndroid Build Coastguard Worker }
659*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneBytesUsed(const size_t plane) const660*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2ReadableBuffer::getPlaneBytesUsed(const size_t plane) const {
661*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
662*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
663*0ec5a0ecSAndroid Build Coastguard Worker 
664*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
665*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
666*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
667*0ec5a0ecSAndroid Build Coastguard Worker     }
668*0ec5a0ecSAndroid Build Coastguard Worker 
669*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Planes[plane].bytesused;
670*0ec5a0ecSAndroid Build Coastguard Worker }
671*0ec5a0ecSAndroid Build Coastguard Worker 
getPlaneDataOffset(const size_t plane) const672*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2ReadableBuffer::getPlaneDataOffset(const size_t plane) const {
673*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
674*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
675*0ec5a0ecSAndroid Build Coastguard Worker 
676*0ec5a0ecSAndroid Build Coastguard Worker     if (plane >= planesCount()) {
677*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid plane %zu requested.", plane);
678*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
679*0ec5a0ecSAndroid Build Coastguard Worker     }
680*0ec5a0ecSAndroid Build Coastguard Worker 
681*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Planes[plane].data_offset;
682*0ec5a0ecSAndroid Build Coastguard Worker }
683*0ec5a0ecSAndroid Build Coastguard Worker 
bufferId() const684*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2ReadableBuffer::bufferId() const {
685*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
686*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mBufferData);
687*0ec5a0ecSAndroid Build Coastguard Worker 
688*0ec5a0ecSAndroid Build Coastguard Worker     return mBufferData->mV4l2Buffer.index;
689*0ec5a0ecSAndroid Build Coastguard Worker }
690*0ec5a0ecSAndroid Build Coastguard Worker 
691*0ec5a0ecSAndroid Build Coastguard Worker // This class is used to expose buffer reference classes constructors to this module. This is to
692*0ec5a0ecSAndroid Build Coastguard Worker // ensure that nobody else can create buffer references.
693*0ec5a0ecSAndroid Build Coastguard Worker class V4L2BufferRefFactory {
694*0ec5a0ecSAndroid Build Coastguard Worker public:
CreateWritableRef(const struct v4l2_buffer & v4l2Buffer,base::WeakPtr<V4L2Queue> queue)695*0ec5a0ecSAndroid Build Coastguard Worker     static V4L2WritableBufferRef CreateWritableRef(const struct v4l2_buffer& v4l2Buffer,
696*0ec5a0ecSAndroid Build Coastguard Worker                                                    base::WeakPtr<V4L2Queue> queue) {
697*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2WritableBufferRef(v4l2Buffer, std::move(queue));
698*0ec5a0ecSAndroid Build Coastguard Worker     }
699*0ec5a0ecSAndroid Build Coastguard Worker 
CreateReadableRef(const struct v4l2_buffer & v4l2Buffer,base::WeakPtr<V4L2Queue> queue)700*0ec5a0ecSAndroid Build Coastguard Worker     static V4L2ReadableBufferRef CreateReadableRef(const struct v4l2_buffer& v4l2Buffer,
701*0ec5a0ecSAndroid Build Coastguard Worker                                                    base::WeakPtr<V4L2Queue> queue) {
702*0ec5a0ecSAndroid Build Coastguard Worker         return new V4L2ReadableBuffer(v4l2Buffer, std::move(queue));
703*0ec5a0ecSAndroid Build Coastguard Worker     }
704*0ec5a0ecSAndroid Build Coastguard Worker };
705*0ec5a0ecSAndroid Build Coastguard Worker 
706*0ec5a0ecSAndroid Build Coastguard Worker //// Helper macros that print the queue type with logs.
707*0ec5a0ecSAndroid Build Coastguard Worker #define ALOGEQ(fmt, ...) ALOGE("(%s)" fmt, V4L2Device::v4L2BufferTypeToString(mType), ##__VA_ARGS__)
708*0ec5a0ecSAndroid Build Coastguard Worker #define ALOGVQ(fmt, ...) ALOGD("(%s)" fmt, V4L2Device::v4L2BufferTypeToString(mType), ##__VA_ARGS__)
709*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2Queue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroyCb)710*0ec5a0ecSAndroid Build Coastguard Worker V4L2Queue::V4L2Queue(scoped_refptr<V4L2Device> dev, enum v4l2_buf_type type,
711*0ec5a0ecSAndroid Build Coastguard Worker                      base::OnceClosure destroyCb)
712*0ec5a0ecSAndroid Build Coastguard Worker       : mType(type), mDevice(dev), mDestroyCb(std::move(destroyCb)) {
713*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
714*0ec5a0ecSAndroid Build Coastguard Worker }
715*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2Queue()716*0ec5a0ecSAndroid Build Coastguard Worker V4L2Queue::~V4L2Queue() {
717*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
718*0ec5a0ecSAndroid Build Coastguard Worker 
719*0ec5a0ecSAndroid Build Coastguard Worker     if (mIsStreaming) {
720*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Queue is still streaming, trying to stop it...");
721*0ec5a0ecSAndroid Build Coastguard Worker         streamoff();
722*0ec5a0ecSAndroid Build Coastguard Worker     }
723*0ec5a0ecSAndroid Build Coastguard Worker 
724*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mQueuedBuffers.empty());
725*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mFreeBuffers);
726*0ec5a0ecSAndroid Build Coastguard Worker 
727*0ec5a0ecSAndroid Build Coastguard Worker     if (!mBuffers.empty()) {
728*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Buffers are still allocated, trying to deallocate them...");
729*0ec5a0ecSAndroid Build Coastguard Worker         deallocateBuffers();
730*0ec5a0ecSAndroid Build Coastguard Worker     }
731*0ec5a0ecSAndroid Build Coastguard Worker 
732*0ec5a0ecSAndroid Build Coastguard Worker     std::move(mDestroyCb).Run();
733*0ec5a0ecSAndroid Build Coastguard Worker }
734*0ec5a0ecSAndroid Build Coastguard Worker 
setFormat(uint32_t fourcc,const ui::Size & size,size_t bufferSize,uint32_t stride)735*0ec5a0ecSAndroid Build Coastguard Worker std::optional<struct v4l2_format> V4L2Queue::setFormat(uint32_t fourcc, const ui::Size& size,
736*0ec5a0ecSAndroid Build Coastguard Worker                                                        size_t bufferSize, uint32_t stride) {
737*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
738*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format = buildV4L2Format(mType, fourcc, size, bufferSize, stride);
739*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_S_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) {
740*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Failed to set format (format_fourcc=0x%" PRIx32 ")", fourcc);
741*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
742*0ec5a0ecSAndroid Build Coastguard Worker     }
743*0ec5a0ecSAndroid Build Coastguard Worker 
744*0ec5a0ecSAndroid Build Coastguard Worker     mCurrentFormat = format;
745*0ec5a0ecSAndroid Build Coastguard Worker     return mCurrentFormat;
746*0ec5a0ecSAndroid Build Coastguard Worker }
747*0ec5a0ecSAndroid Build Coastguard Worker 
tryFormat(uint32_t fourcc,const ui::Size & size,size_t bufferSize)748*0ec5a0ecSAndroid Build Coastguard Worker std::optional<struct v4l2_format> V4L2Queue::tryFormat(uint32_t fourcc, const ui::Size& size,
749*0ec5a0ecSAndroid Build Coastguard Worker                                                        size_t bufferSize) {
750*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format = buildV4L2Format(mType, fourcc, size, bufferSize, 0);
751*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_TRY_FMT, &format) != 0 || format.fmt.pix_mp.pixelformat != fourcc) {
752*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Tried format not supported (format_fourcc=0x%" PRIx32 ")", fourcc);
753*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
754*0ec5a0ecSAndroid Build Coastguard Worker     }
755*0ec5a0ecSAndroid Build Coastguard Worker 
756*0ec5a0ecSAndroid Build Coastguard Worker     return format;
757*0ec5a0ecSAndroid Build Coastguard Worker }
758*0ec5a0ecSAndroid Build Coastguard Worker 
getFormat()759*0ec5a0ecSAndroid Build Coastguard Worker std::pair<std::optional<struct v4l2_format>, int> V4L2Queue::getFormat() {
760*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format;
761*0ec5a0ecSAndroid Build Coastguard Worker     memset(&format, 0, sizeof(format));
762*0ec5a0ecSAndroid Build Coastguard Worker     format.type = mType;
763*0ec5a0ecSAndroid Build Coastguard Worker     if (mDevice->ioctl(VIDIOC_G_FMT, &format) != 0) {
764*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Failed to get format");
765*0ec5a0ecSAndroid Build Coastguard Worker         return std::make_pair(std::nullopt, errno);
766*0ec5a0ecSAndroid Build Coastguard Worker     }
767*0ec5a0ecSAndroid Build Coastguard Worker 
768*0ec5a0ecSAndroid Build Coastguard Worker     return std::make_pair(format, 0);
769*0ec5a0ecSAndroid Build Coastguard Worker }
770*0ec5a0ecSAndroid Build Coastguard Worker 
allocateBuffers(size_t count,enum v4l2_memory memory)771*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Queue::allocateBuffers(size_t count, enum v4l2_memory memory) {
772*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_CALL();
773*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
774*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mFreeBuffers);
775*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mQueuedBuffers.size() == 0u);
776*0ec5a0ecSAndroid Build Coastguard Worker 
777*0ec5a0ecSAndroid Build Coastguard Worker     if (isStreaming()) {
778*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Cannot allocate buffers while streaming.");
779*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
780*0ec5a0ecSAndroid Build Coastguard Worker     }
781*0ec5a0ecSAndroid Build Coastguard Worker 
782*0ec5a0ecSAndroid Build Coastguard Worker     if (mBuffers.size() != 0) {
783*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Cannot allocate new buffers while others are still allocated.");
784*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
785*0ec5a0ecSAndroid Build Coastguard Worker     }
786*0ec5a0ecSAndroid Build Coastguard Worker 
787*0ec5a0ecSAndroid Build Coastguard Worker     if (count == 0) {
788*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Attempting to allocate 0 buffers.");
789*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
790*0ec5a0ecSAndroid Build Coastguard Worker     }
791*0ec5a0ecSAndroid Build Coastguard Worker 
792*0ec5a0ecSAndroid Build Coastguard Worker     // First query the number of planes in the buffers we are about to request. This should not be
793*0ec5a0ecSAndroid Build Coastguard Worker     // required, but Tegra's VIDIOC_QUERYBUF will fail on output buffers if the number of specified
794*0ec5a0ecSAndroid Build Coastguard Worker     // planes does not exactly match the format.
795*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_format format = {.type = mType};
796*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_G_FMT, &format);
797*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
798*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_G_FMT failed");
799*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
800*0ec5a0ecSAndroid Build Coastguard Worker     }
801*0ec5a0ecSAndroid Build Coastguard Worker     mPlanesCount = format.fmt.pix_mp.num_planes;
802*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mPlanesCount <= static_cast<size_t>(VIDEO_MAX_PLANES));
803*0ec5a0ecSAndroid Build Coastguard Worker 
804*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_requestbuffers reqbufs;
805*0ec5a0ecSAndroid Build Coastguard Worker     memset(&reqbufs, 0, sizeof(reqbufs));
806*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.count = count;
807*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.type = mType;
808*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.memory = memory;
809*0ec5a0ecSAndroid Build Coastguard Worker     ALOGVQ("Requesting %zu buffers.", count);
810*0ec5a0ecSAndroid Build Coastguard Worker 
811*0ec5a0ecSAndroid Build Coastguard Worker     ret = mDevice->ioctl(VIDIOC_REQBUFS, &reqbufs);
812*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
813*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_REQBUFS failed");
814*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
815*0ec5a0ecSAndroid Build Coastguard Worker     }
816*0ec5a0ecSAndroid Build Coastguard Worker     ALOGVQ("Queue %u: got %u buffers.", mType, reqbufs.count);
817*0ec5a0ecSAndroid Build Coastguard Worker 
818*0ec5a0ecSAndroid Build Coastguard Worker     mMemory = memory;
819*0ec5a0ecSAndroid Build Coastguard Worker 
820*0ec5a0ecSAndroid Build Coastguard Worker     mFreeBuffers = new V4L2BuffersList();
821*0ec5a0ecSAndroid Build Coastguard Worker 
822*0ec5a0ecSAndroid Build Coastguard Worker     // Now query all buffer information.
823*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < reqbufs.count; i++) {
824*0ec5a0ecSAndroid Build Coastguard Worker         auto buffer = V4L2Buffer::create(mDevice, mType, mMemory, format, i);
825*0ec5a0ecSAndroid Build Coastguard Worker 
826*0ec5a0ecSAndroid Build Coastguard Worker         if (!buffer) {
827*0ec5a0ecSAndroid Build Coastguard Worker             deallocateBuffers();
828*0ec5a0ecSAndroid Build Coastguard Worker 
829*0ec5a0ecSAndroid Build Coastguard Worker             return 0;
830*0ec5a0ecSAndroid Build Coastguard Worker         }
831*0ec5a0ecSAndroid Build Coastguard Worker 
832*0ec5a0ecSAndroid Build Coastguard Worker         mBuffers.emplace_back(std::move(buffer));
833*0ec5a0ecSAndroid Build Coastguard Worker         mFreeBuffers->returnBuffer(i);
834*0ec5a0ecSAndroid Build Coastguard Worker     }
835*0ec5a0ecSAndroid Build Coastguard Worker 
836*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mFreeBuffers);
837*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mFreeBuffers->size() == mBuffers.size());
838*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mQueuedBuffers.size() == 0u);
839*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
840*0ec5a0ecSAndroid Build Coastguard Worker 
841*0ec5a0ecSAndroid Build Coastguard Worker     return mBuffers.size();
842*0ec5a0ecSAndroid Build Coastguard Worker }
843*0ec5a0ecSAndroid Build Coastguard Worker 
deallocateBuffers()844*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Queue::deallocateBuffers() {
845*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
846*0ec5a0ecSAndroid Build Coastguard Worker 
847*0ec5a0ecSAndroid Build Coastguard Worker     if (isStreaming()) {
848*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Cannot deallocate buffers while streaming.");
849*0ec5a0ecSAndroid Build Coastguard Worker         return false;
850*0ec5a0ecSAndroid Build Coastguard Worker     }
851*0ec5a0ecSAndroid Build Coastguard Worker 
852*0ec5a0ecSAndroid Build Coastguard Worker     if (mBuffers.size() == 0) return true;
853*0ec5a0ecSAndroid Build Coastguard Worker 
854*0ec5a0ecSAndroid Build Coastguard Worker     mWeakThisFactory.InvalidateWeakPtrs();
855*0ec5a0ecSAndroid Build Coastguard Worker     mBuffers.clear();
856*0ec5a0ecSAndroid Build Coastguard Worker     mFreeBuffers = nullptr;
857*0ec5a0ecSAndroid Build Coastguard Worker 
858*0ec5a0ecSAndroid Build Coastguard Worker     // Free all buffers.
859*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_requestbuffers reqbufs;
860*0ec5a0ecSAndroid Build Coastguard Worker     memset(&reqbufs, 0, sizeof(reqbufs));
861*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.count = 0;
862*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.type = mType;
863*0ec5a0ecSAndroid Build Coastguard Worker     reqbufs.memory = mMemory;
864*0ec5a0ecSAndroid Build Coastguard Worker 
865*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_REQBUFS, &reqbufs);
866*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
867*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_REQBUFS failed");
868*0ec5a0ecSAndroid Build Coastguard Worker         return false;
869*0ec5a0ecSAndroid Build Coastguard Worker     }
870*0ec5a0ecSAndroid Build Coastguard Worker 
871*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mFreeBuffers);
872*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mQueuedBuffers.size() == 0u);
873*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
874*0ec5a0ecSAndroid Build Coastguard Worker 
875*0ec5a0ecSAndroid Build Coastguard Worker     return true;
876*0ec5a0ecSAndroid Build Coastguard Worker }
877*0ec5a0ecSAndroid Build Coastguard Worker 
getMemoryUsage() const878*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Queue::getMemoryUsage() const {
879*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
880*0ec5a0ecSAndroid Build Coastguard Worker     size_t usage = 0;
881*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& buf : mBuffers) {
882*0ec5a0ecSAndroid Build Coastguard Worker         usage += buf->getMemoryUsage();
883*0ec5a0ecSAndroid Build Coastguard Worker     }
884*0ec5a0ecSAndroid Build Coastguard Worker     return usage;
885*0ec5a0ecSAndroid Build Coastguard Worker }
886*0ec5a0ecSAndroid Build Coastguard Worker 
getMemoryType() const887*0ec5a0ecSAndroid Build Coastguard Worker v4l2_memory V4L2Queue::getMemoryType() const {
888*0ec5a0ecSAndroid Build Coastguard Worker     return mMemory;
889*0ec5a0ecSAndroid Build Coastguard Worker }
890*0ec5a0ecSAndroid Build Coastguard Worker 
getFreeBuffer()891*0ec5a0ecSAndroid Build Coastguard Worker std::optional<V4L2WritableBufferRef> V4L2Queue::getFreeBuffer() {
892*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
893*0ec5a0ecSAndroid Build Coastguard Worker 
894*0ec5a0ecSAndroid Build Coastguard Worker     // No buffers allocated at the moment?
895*0ec5a0ecSAndroid Build Coastguard Worker     if (!mFreeBuffers) return std::nullopt;
896*0ec5a0ecSAndroid Build Coastguard Worker 
897*0ec5a0ecSAndroid Build Coastguard Worker     auto bufferId = mFreeBuffers->getFreeBuffer();
898*0ec5a0ecSAndroid Build Coastguard Worker     if (!bufferId.has_value()) return std::nullopt;
899*0ec5a0ecSAndroid Build Coastguard Worker 
900*0ec5a0ecSAndroid Build Coastguard Worker     return V4L2BufferRefFactory::CreateWritableRef(mBuffers[bufferId.value()]->v4l2_buffer(),
901*0ec5a0ecSAndroid Build Coastguard Worker                                                    mWeakThisFactory.GetWeakPtr());
902*0ec5a0ecSAndroid Build Coastguard Worker }
903*0ec5a0ecSAndroid Build Coastguard Worker 
getFreeBuffer(size_t requestedBufferIid)904*0ec5a0ecSAndroid Build Coastguard Worker std::optional<V4L2WritableBufferRef> V4L2Queue::getFreeBuffer(size_t requestedBufferIid) {
905*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
906*0ec5a0ecSAndroid Build Coastguard Worker 
907*0ec5a0ecSAndroid Build Coastguard Worker     // No buffers allocated at the moment?
908*0ec5a0ecSAndroid Build Coastguard Worker     if (!mFreeBuffers) return std::nullopt;
909*0ec5a0ecSAndroid Build Coastguard Worker 
910*0ec5a0ecSAndroid Build Coastguard Worker     auto bufferId = mFreeBuffers->getFreeBuffer(requestedBufferIid);
911*0ec5a0ecSAndroid Build Coastguard Worker     if (!bufferId.has_value()) return std::nullopt;
912*0ec5a0ecSAndroid Build Coastguard Worker 
913*0ec5a0ecSAndroid Build Coastguard Worker     return V4L2BufferRefFactory::CreateWritableRef(mBuffers[bufferId.value()]->v4l2_buffer(),
914*0ec5a0ecSAndroid Build Coastguard Worker                                                    mWeakThisFactory.GetWeakPtr());
915*0ec5a0ecSAndroid Build Coastguard Worker }
916*0ec5a0ecSAndroid Build Coastguard Worker 
reportTraceMetrics()917*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Queue::reportTraceMetrics() {
918*0ec5a0ecSAndroid Build Coastguard Worker     // Don't printf labels if ATrace is not enabled
919*0ec5a0ecSAndroid Build Coastguard Worker     if (!ATRACE_ENABLED()) return;
920*0ec5a0ecSAndroid Build Coastguard Worker 
921*0ec5a0ecSAndroid Build Coastguard Worker     std::string atraceLabel;
922*0ec5a0ecSAndroid Build Coastguard Worker 
923*0ec5a0ecSAndroid Build Coastguard Worker     atraceLabel =
924*0ec5a0ecSAndroid Build Coastguard Worker             V4L2Device::v4L2BufferTypeToATraceLabel(mDevice->getDebugStreamId(), mType, "streamon");
925*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_INT(atraceLabel.c_str(), isStreaming());
926*0ec5a0ecSAndroid Build Coastguard Worker 
927*0ec5a0ecSAndroid Build Coastguard Worker     atraceLabel = V4L2Device::v4L2BufferTypeToATraceLabel(mDevice->getDebugStreamId(), mType,
928*0ec5a0ecSAndroid Build Coastguard Worker                                                           "buffers free");
929*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_INT64(atraceLabel.c_str(), freeBuffersCount());
930*0ec5a0ecSAndroid Build Coastguard Worker 
931*0ec5a0ecSAndroid Build Coastguard Worker     atraceLabel = V4L2Device::v4L2BufferTypeToATraceLabel(mDevice->getDebugStreamId(), mType,
932*0ec5a0ecSAndroid Build Coastguard Worker                                                           "buffers queued");
933*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_INT64(atraceLabel.c_str(), queuedBuffersCount());
934*0ec5a0ecSAndroid Build Coastguard Worker 
935*0ec5a0ecSAndroid Build Coastguard Worker     atraceLabel = V4L2Device::v4L2BufferTypeToATraceLabel(mDevice->getDebugStreamId(), mType,
936*0ec5a0ecSAndroid Build Coastguard Worker                                                           "buffers allocated");
937*0ec5a0ecSAndroid Build Coastguard Worker     ATRACE_INT64(atraceLabel.c_str(), allocatedBuffersCount());
938*0ec5a0ecSAndroid Build Coastguard Worker }
939*0ec5a0ecSAndroid Build Coastguard Worker 
queueBuffer(struct v4l2_buffer * v4l2Buffer)940*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Queue::queueBuffer(struct v4l2_buffer* v4l2Buffer) {
941*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
942*0ec5a0ecSAndroid Build Coastguard Worker 
943*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_QBUF, v4l2Buffer);
944*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
945*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_QBUF failed");
946*0ec5a0ecSAndroid Build Coastguard Worker         return false;
947*0ec5a0ecSAndroid Build Coastguard Worker     }
948*0ec5a0ecSAndroid Build Coastguard Worker 
949*0ec5a0ecSAndroid Build Coastguard Worker     if (ATRACE_ENABLED()) {
950*0ec5a0ecSAndroid Build Coastguard Worker         std::string atraceLabel = V4L2Device::v4L2BufferTypeToATraceLabel(
951*0ec5a0ecSAndroid Build Coastguard Worker                 mDevice->getDebugStreamId(), mType, "enqueued buffer");
952*0ec5a0ecSAndroid Build Coastguard Worker         ATRACE_ASYNC_BEGIN(atraceLabel.c_str(), v4l2Buffer->index);
953*0ec5a0ecSAndroid Build Coastguard Worker     }
954*0ec5a0ecSAndroid Build Coastguard Worker 
955*0ec5a0ecSAndroid Build Coastguard Worker     auto inserted = mQueuedBuffers.emplace(v4l2Buffer->index);
956*0ec5a0ecSAndroid Build Coastguard Worker     if (!inserted.second) {
957*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Queuing buffer failed");
958*0ec5a0ecSAndroid Build Coastguard Worker         return false;
959*0ec5a0ecSAndroid Build Coastguard Worker     }
960*0ec5a0ecSAndroid Build Coastguard Worker 
961*0ec5a0ecSAndroid Build Coastguard Worker     mDevice->schedulePoll();
962*0ec5a0ecSAndroid Build Coastguard Worker 
963*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
964*0ec5a0ecSAndroid Build Coastguard Worker 
965*0ec5a0ecSAndroid Build Coastguard Worker     return true;
966*0ec5a0ecSAndroid Build Coastguard Worker }
967*0ec5a0ecSAndroid Build Coastguard Worker 
dequeueBuffer()968*0ec5a0ecSAndroid Build Coastguard Worker std::pair<bool, V4L2ReadableBufferRef> V4L2Queue::dequeueBuffer() {
969*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
970*0ec5a0ecSAndroid Build Coastguard Worker 
971*0ec5a0ecSAndroid Build Coastguard Worker     // No need to dequeue if no buffers queued.
972*0ec5a0ecSAndroid Build Coastguard Worker     if (queuedBuffersCount() == 0) return std::make_pair(true, nullptr);
973*0ec5a0ecSAndroid Build Coastguard Worker 
974*0ec5a0ecSAndroid Build Coastguard Worker     if (!isStreaming()) {
975*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("Attempting to dequeue a buffer while not streaming.");
976*0ec5a0ecSAndroid Build Coastguard Worker         return std::make_pair(true, nullptr);
977*0ec5a0ecSAndroid Build Coastguard Worker     }
978*0ec5a0ecSAndroid Build Coastguard Worker 
979*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_buffer v4l2Buffer;
980*0ec5a0ecSAndroid Build Coastguard Worker     memset(&v4l2Buffer, 0, sizeof(v4l2Buffer));
981*0ec5a0ecSAndroid Build Coastguard Worker     // WARNING: do not change this to a vector or something smaller than VIDEO_MAX_PLANES, otherwise
982*0ec5a0ecSAndroid Build Coastguard Worker     // the Tegra libv4l2 will write data beyond the number of allocated planes, resulting in memory
983*0ec5a0ecSAndroid Build Coastguard Worker     // corruption.
984*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_plane planes[VIDEO_MAX_PLANES];
985*0ec5a0ecSAndroid Build Coastguard Worker     memset(planes, 0, sizeof(planes));
986*0ec5a0ecSAndroid Build Coastguard Worker     v4l2Buffer.type = mType;
987*0ec5a0ecSAndroid Build Coastguard Worker     v4l2Buffer.memory = mMemory;
988*0ec5a0ecSAndroid Build Coastguard Worker     v4l2Buffer.m.planes = planes;
989*0ec5a0ecSAndroid Build Coastguard Worker     v4l2Buffer.length = mPlanesCount;
990*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_DQBUF, &v4l2Buffer);
991*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
992*0ec5a0ecSAndroid Build Coastguard Worker         // TODO(acourbot): we should not have to check for EPIPE as codec clients should not call
993*0ec5a0ecSAndroid Build Coastguard Worker         // this method after the last buffer is dequeued.
994*0ec5a0ecSAndroid Build Coastguard Worker         switch (errno) {
995*0ec5a0ecSAndroid Build Coastguard Worker         case EAGAIN:
996*0ec5a0ecSAndroid Build Coastguard Worker         case EPIPE:
997*0ec5a0ecSAndroid Build Coastguard Worker             // This is not an error so we'll need to continue polling but won't provide a buffer.
998*0ec5a0ecSAndroid Build Coastguard Worker             mDevice->schedulePoll();
999*0ec5a0ecSAndroid Build Coastguard Worker             return std::make_pair(true, nullptr);
1000*0ec5a0ecSAndroid Build Coastguard Worker         default:
1001*0ec5a0ecSAndroid Build Coastguard Worker             ALOGEQ("VIDIOC_DQBUF failed");
1002*0ec5a0ecSAndroid Build Coastguard Worker             return std::make_pair(false, nullptr);
1003*0ec5a0ecSAndroid Build Coastguard Worker         }
1004*0ec5a0ecSAndroid Build Coastguard Worker     }
1005*0ec5a0ecSAndroid Build Coastguard Worker 
1006*0ec5a0ecSAndroid Build Coastguard Worker     if (ATRACE_ENABLED()) {
1007*0ec5a0ecSAndroid Build Coastguard Worker         std::string atraceLabel = V4L2Device::v4L2BufferTypeToATraceLabel(
1008*0ec5a0ecSAndroid Build Coastguard Worker                 mDevice->getDebugStreamId(), mType, "enqueued buffer");
1009*0ec5a0ecSAndroid Build Coastguard Worker         ATRACE_ASYNC_END(atraceLabel.c_str(), v4l2Buffer.index);
1010*0ec5a0ecSAndroid Build Coastguard Worker     }
1011*0ec5a0ecSAndroid Build Coastguard Worker 
1012*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mQueuedBuffers.find(v4l2Buffer.index);
1013*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(it != mQueuedBuffers.end());
1014*0ec5a0ecSAndroid Build Coastguard Worker     mQueuedBuffers.erase(*it);
1015*0ec5a0ecSAndroid Build Coastguard Worker 
1016*0ec5a0ecSAndroid Build Coastguard Worker     if (queuedBuffersCount() > 0) mDevice->schedulePoll();
1017*0ec5a0ecSAndroid Build Coastguard Worker 
1018*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
1019*0ec5a0ecSAndroid Build Coastguard Worker 
1020*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mFreeBuffers);
1021*0ec5a0ecSAndroid Build Coastguard Worker     return std::make_pair(true, V4L2BufferRefFactory::CreateReadableRef(
1022*0ec5a0ecSAndroid Build Coastguard Worker                                         v4l2Buffer, mWeakThisFactory.GetWeakPtr()));
1023*0ec5a0ecSAndroid Build Coastguard Worker }
1024*0ec5a0ecSAndroid Build Coastguard Worker 
isStreaming() const1025*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Queue::isStreaming() const {
1026*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1027*0ec5a0ecSAndroid Build Coastguard Worker 
1028*0ec5a0ecSAndroid Build Coastguard Worker     return mIsStreaming;
1029*0ec5a0ecSAndroid Build Coastguard Worker }
1030*0ec5a0ecSAndroid Build Coastguard Worker 
streamon()1031*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Queue::streamon() {
1032*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1033*0ec5a0ecSAndroid Build Coastguard Worker 
1034*0ec5a0ecSAndroid Build Coastguard Worker     if (mIsStreaming) return true;
1035*0ec5a0ecSAndroid Build Coastguard Worker 
1036*0ec5a0ecSAndroid Build Coastguard Worker     int arg = static_cast<int>(mType);
1037*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_STREAMON, &arg);
1038*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
1039*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_STREAMON failed");
1040*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1041*0ec5a0ecSAndroid Build Coastguard Worker     }
1042*0ec5a0ecSAndroid Build Coastguard Worker 
1043*0ec5a0ecSAndroid Build Coastguard Worker     mIsStreaming = true;
1044*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
1045*0ec5a0ecSAndroid Build Coastguard Worker 
1046*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1047*0ec5a0ecSAndroid Build Coastguard Worker }
1048*0ec5a0ecSAndroid Build Coastguard Worker 
streamoff()1049*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Queue::streamoff() {
1050*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1051*0ec5a0ecSAndroid Build Coastguard Worker 
1052*0ec5a0ecSAndroid Build Coastguard Worker     // We do not check the value of IsStreaming(), because we may have queued buffers to the queue
1053*0ec5a0ecSAndroid Build Coastguard Worker     // and wish to get them back - in such as case, we may need to do a VIDIOC_STREAMOFF on a
1054*0ec5a0ecSAndroid Build Coastguard Worker     // stopped queue.
1055*0ec5a0ecSAndroid Build Coastguard Worker 
1056*0ec5a0ecSAndroid Build Coastguard Worker     int arg = static_cast<int>(mType);
1057*0ec5a0ecSAndroid Build Coastguard Worker     int ret = mDevice->ioctl(VIDIOC_STREAMOFF, &arg);
1058*0ec5a0ecSAndroid Build Coastguard Worker     if (ret) {
1059*0ec5a0ecSAndroid Build Coastguard Worker         ALOGEQ("VIDIOC_STREAMOFF failed");
1060*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1061*0ec5a0ecSAndroid Build Coastguard Worker     }
1062*0ec5a0ecSAndroid Build Coastguard Worker 
1063*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& bufferId : mQueuedBuffers) {
1064*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(mFreeBuffers);
1065*0ec5a0ecSAndroid Build Coastguard Worker         mFreeBuffers->returnBuffer(bufferId);
1066*0ec5a0ecSAndroid Build Coastguard Worker     }
1067*0ec5a0ecSAndroid Build Coastguard Worker 
1068*0ec5a0ecSAndroid Build Coastguard Worker     mQueuedBuffers.clear();
1069*0ec5a0ecSAndroid Build Coastguard Worker 
1070*0ec5a0ecSAndroid Build Coastguard Worker     mIsStreaming = false;
1071*0ec5a0ecSAndroid Build Coastguard Worker 
1072*0ec5a0ecSAndroid Build Coastguard Worker     reportTraceMetrics();
1073*0ec5a0ecSAndroid Build Coastguard Worker 
1074*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1075*0ec5a0ecSAndroid Build Coastguard Worker }
1076*0ec5a0ecSAndroid Build Coastguard Worker 
allocatedBuffersCount() const1077*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Queue::allocatedBuffersCount() const {
1078*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1079*0ec5a0ecSAndroid Build Coastguard Worker 
1080*0ec5a0ecSAndroid Build Coastguard Worker     return mBuffers.size();
1081*0ec5a0ecSAndroid Build Coastguard Worker }
1082*0ec5a0ecSAndroid Build Coastguard Worker 
freeBuffersCount() const1083*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Queue::freeBuffersCount() const {
1084*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1085*0ec5a0ecSAndroid Build Coastguard Worker 
1086*0ec5a0ecSAndroid Build Coastguard Worker     return mFreeBuffers ? mFreeBuffers->size() : 0;
1087*0ec5a0ecSAndroid Build Coastguard Worker }
1088*0ec5a0ecSAndroid Build Coastguard Worker 
queuedBuffersCount() const1089*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Queue::queuedBuffersCount() const {
1090*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mSequenceChecker);
1091*0ec5a0ecSAndroid Build Coastguard Worker 
1092*0ec5a0ecSAndroid Build Coastguard Worker     return mQueuedBuffers.size();
1093*0ec5a0ecSAndroid Build Coastguard Worker }
1094*0ec5a0ecSAndroid Build Coastguard Worker 
1095*0ec5a0ecSAndroid Build Coastguard Worker #undef ALOGEQ
1096*0ec5a0ecSAndroid Build Coastguard Worker #undef ALOGVQ
1097*0ec5a0ecSAndroid Build Coastguard Worker 
1098*0ec5a0ecSAndroid Build Coastguard Worker // This class is used to expose V4L2Queue's constructor to this module. This is to ensure that
1099*0ec5a0ecSAndroid Build Coastguard Worker // nobody else can create instances of it.
1100*0ec5a0ecSAndroid Build Coastguard Worker class V4L2QueueFactory {
1101*0ec5a0ecSAndroid Build Coastguard Worker public:
createQueue(scoped_refptr<V4L2Device> dev,enum v4l2_buf_type type,base::OnceClosure destroyCb)1102*0ec5a0ecSAndroid Build Coastguard Worker     static scoped_refptr<V4L2Queue> createQueue(scoped_refptr<V4L2Device> dev,
1103*0ec5a0ecSAndroid Build Coastguard Worker                                                 enum v4l2_buf_type type,
1104*0ec5a0ecSAndroid Build Coastguard Worker                                                 base::OnceClosure destroyCb) {
1105*0ec5a0ecSAndroid Build Coastguard Worker         return new V4L2Queue(std::move(dev), type, std::move(destroyCb));
1106*0ec5a0ecSAndroid Build Coastguard Worker     }
1107*0ec5a0ecSAndroid Build Coastguard Worker };
1108*0ec5a0ecSAndroid Build Coastguard Worker 
V4L2Device(uint32_t debugStreamId)1109*0ec5a0ecSAndroid Build Coastguard Worker V4L2Device::V4L2Device(uint32_t debugStreamId) : mDebugStreamId(debugStreamId) {
1110*0ec5a0ecSAndroid Build Coastguard Worker     DETACH_FROM_SEQUENCE(mClientSequenceChecker);
1111*0ec5a0ecSAndroid Build Coastguard Worker }
1112*0ec5a0ecSAndroid Build Coastguard Worker 
~V4L2Device()1113*0ec5a0ecSAndroid Build Coastguard Worker V4L2Device::~V4L2Device() {
1114*0ec5a0ecSAndroid Build Coastguard Worker     closeDevice();
1115*0ec5a0ecSAndroid Build Coastguard Worker }
1116*0ec5a0ecSAndroid Build Coastguard Worker 
getQueue(enum v4l2_buf_type type)1117*0ec5a0ecSAndroid Build Coastguard Worker scoped_refptr<V4L2Queue> V4L2Device::getQueue(enum v4l2_buf_type type) {
1118*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
1119*0ec5a0ecSAndroid Build Coastguard Worker 
1120*0ec5a0ecSAndroid Build Coastguard Worker     switch (type) {
1121*0ec5a0ecSAndroid Build Coastguard Worker     // Supported queue types.
1122*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1123*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1124*0ec5a0ecSAndroid Build Coastguard Worker         break;
1125*0ec5a0ecSAndroid Build Coastguard Worker     default:
1126*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unsupported V4L2 queue type: %u", type);
1127*0ec5a0ecSAndroid Build Coastguard Worker         return nullptr;
1128*0ec5a0ecSAndroid Build Coastguard Worker     }
1129*0ec5a0ecSAndroid Build Coastguard Worker 
1130*0ec5a0ecSAndroid Build Coastguard Worker     // TODO(acourbot): we should instead query the device for available queues, and allocate them
1131*0ec5a0ecSAndroid Build Coastguard Worker     // accordingly. This will do for now though.
1132*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mQueues.find(type);
1133*0ec5a0ecSAndroid Build Coastguard Worker     if (it != mQueues.end()) return scoped_refptr<V4L2Queue>(it->second);
1134*0ec5a0ecSAndroid Build Coastguard Worker 
1135*0ec5a0ecSAndroid Build Coastguard Worker     scoped_refptr<V4L2Queue> queue = V4L2QueueFactory::createQueue(
1136*0ec5a0ecSAndroid Build Coastguard Worker             this, type, base::BindOnce(&V4L2Device::onQueueDestroyed, this, type));
1137*0ec5a0ecSAndroid Build Coastguard Worker 
1138*0ec5a0ecSAndroid Build Coastguard Worker     mQueues[type] = queue.get();
1139*0ec5a0ecSAndroid Build Coastguard Worker     return queue;
1140*0ec5a0ecSAndroid Build Coastguard Worker }
1141*0ec5a0ecSAndroid Build Coastguard Worker 
onQueueDestroyed(v4l2_buf_type bufType)1142*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Device::onQueueDestroyed(v4l2_buf_type bufType) {
1143*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
1144*0ec5a0ecSAndroid Build Coastguard Worker 
1145*0ec5a0ecSAndroid Build Coastguard Worker     auto it = mQueues.find(bufType);
1146*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(it != mQueues.end());
1147*0ec5a0ecSAndroid Build Coastguard Worker     mQueues.erase(it);
1148*0ec5a0ecSAndroid Build Coastguard Worker }
1149*0ec5a0ecSAndroid Build Coastguard Worker 
1150*0ec5a0ecSAndroid Build Coastguard Worker // static
create(uint32_t debugStreamId)1151*0ec5a0ecSAndroid Build Coastguard Worker scoped_refptr<V4L2Device> V4L2Device::create(uint32_t debugStreamId) {
1152*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1153*0ec5a0ecSAndroid Build Coastguard Worker     return scoped_refptr<V4L2Device>(new V4L2Device(debugStreamId));
1154*0ec5a0ecSAndroid Build Coastguard Worker }
1155*0ec5a0ecSAndroid Build Coastguard Worker 
open(Type type,uint32_t v4l2PixFmt)1156*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::open(Type type, uint32_t v4l2PixFmt) {
1157*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1158*0ec5a0ecSAndroid Build Coastguard Worker 
1159*0ec5a0ecSAndroid Build Coastguard Worker     std::string path = getDevicePathFor(type, v4l2PixFmt);
1160*0ec5a0ecSAndroid Build Coastguard Worker 
1161*0ec5a0ecSAndroid Build Coastguard Worker     if (path.empty()) {
1162*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("No devices supporting %s for type: %u", fourccToString(v4l2PixFmt).c_str(),
1163*0ec5a0ecSAndroid Build Coastguard Worker               static_cast<uint32_t>(type));
1164*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1165*0ec5a0ecSAndroid Build Coastguard Worker     }
1166*0ec5a0ecSAndroid Build Coastguard Worker 
1167*0ec5a0ecSAndroid Build Coastguard Worker     if (!openDevicePath(path, type)) {
1168*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed opening %s", path.c_str());
1169*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1170*0ec5a0ecSAndroid Build Coastguard Worker     }
1171*0ec5a0ecSAndroid Build Coastguard Worker 
1172*0ec5a0ecSAndroid Build Coastguard Worker     mDevicePollInterruptFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
1173*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevicePollInterruptFd.is_valid()) {
1174*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed creating a poll interrupt fd");
1175*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1176*0ec5a0ecSAndroid Build Coastguard Worker     }
1177*0ec5a0ecSAndroid Build Coastguard Worker 
1178*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1179*0ec5a0ecSAndroid Build Coastguard Worker }
1180*0ec5a0ecSAndroid Build Coastguard Worker 
ioctl(int request,void * arg)1181*0ec5a0ecSAndroid Build Coastguard Worker int V4L2Device::ioctl(int request, void* arg) {
1182*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(mDeviceFd.is_valid());
1183*0ec5a0ecSAndroid Build Coastguard Worker     return HANDLE_EINTR(::ioctl(mDeviceFd.get(), request, arg));
1184*0ec5a0ecSAndroid Build Coastguard Worker }
1185*0ec5a0ecSAndroid Build Coastguard Worker 
poll(bool pollDevice,bool pollBuffers,bool * eventPending,bool * buffersPending)1186*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::poll(bool pollDevice, bool pollBuffers, bool* eventPending, bool* buffersPending) {
1187*0ec5a0ecSAndroid Build Coastguard Worker     struct pollfd pollfds[2];
1188*0ec5a0ecSAndroid Build Coastguard Worker     nfds_t nfds;
1189*0ec5a0ecSAndroid Build Coastguard Worker     int pollfd = -1;
1190*0ec5a0ecSAndroid Build Coastguard Worker 
1191*0ec5a0ecSAndroid Build Coastguard Worker     pollfds[0].fd = mDevicePollInterruptFd.get();
1192*0ec5a0ecSAndroid Build Coastguard Worker     pollfds[0].events = POLLIN | POLLERR;
1193*0ec5a0ecSAndroid Build Coastguard Worker     nfds = 1;
1194*0ec5a0ecSAndroid Build Coastguard Worker 
1195*0ec5a0ecSAndroid Build Coastguard Worker     if (pollDevice) {
1196*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("adding device fd to poll() set");
1197*0ec5a0ecSAndroid Build Coastguard Worker         pollfds[nfds].fd = mDeviceFd.get();
1198*0ec5a0ecSAndroid Build Coastguard Worker         pollfds[nfds].events = POLLERR | POLLPRI;
1199*0ec5a0ecSAndroid Build Coastguard Worker         if (pollBuffers) {
1200*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("will poll buffers");
1201*0ec5a0ecSAndroid Build Coastguard Worker             pollfds[nfds].events |= POLLIN | POLLOUT;
1202*0ec5a0ecSAndroid Build Coastguard Worker         }
1203*0ec5a0ecSAndroid Build Coastguard Worker         pollfd = nfds;
1204*0ec5a0ecSAndroid Build Coastguard Worker         nfds++;
1205*0ec5a0ecSAndroid Build Coastguard Worker     }
1206*0ec5a0ecSAndroid Build Coastguard Worker 
1207*0ec5a0ecSAndroid Build Coastguard Worker     if (HANDLE_EINTR(::poll(pollfds, nfds, -1)) == -1) {
1208*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("poll() failed");
1209*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1210*0ec5a0ecSAndroid Build Coastguard Worker     }
1211*0ec5a0ecSAndroid Build Coastguard Worker     *eventPending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
1212*0ec5a0ecSAndroid Build Coastguard Worker     *buffersPending = (pollfd != -1 && pollfds[pollfd].revents & (POLLIN | POLLOUT));
1213*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1214*0ec5a0ecSAndroid Build Coastguard Worker }
1215*0ec5a0ecSAndroid Build Coastguard Worker 
mmap(void * addr,unsigned int len,int prot,int flags,unsigned int offset)1216*0ec5a0ecSAndroid Build Coastguard Worker void* V4L2Device::mmap(void* addr, unsigned int len, int prot, int flags, unsigned int offset) {
1217*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK(mDeviceFd.is_valid());
1218*0ec5a0ecSAndroid Build Coastguard Worker     return ::mmap(addr, len, prot, flags, mDeviceFd.get(), offset);
1219*0ec5a0ecSAndroid Build Coastguard Worker }
1220*0ec5a0ecSAndroid Build Coastguard Worker 
munmap(void * addr,unsigned int len)1221*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Device::munmap(void* addr, unsigned int len) {
1222*0ec5a0ecSAndroid Build Coastguard Worker     ::munmap(addr, len);
1223*0ec5a0ecSAndroid Build Coastguard Worker }
1224*0ec5a0ecSAndroid Build Coastguard Worker 
setDevicePollInterrupt()1225*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::setDevicePollInterrupt() {
1226*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1227*0ec5a0ecSAndroid Build Coastguard Worker 
1228*0ec5a0ecSAndroid Build Coastguard Worker     const uint64_t buf = 1;
1229*0ec5a0ecSAndroid Build Coastguard Worker     if (HANDLE_EINTR(write(mDevicePollInterruptFd.get(), &buf, sizeof(buf))) == -1) {
1230*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("write() failed");
1231*0ec5a0ecSAndroid Build Coastguard Worker         return false;
1232*0ec5a0ecSAndroid Build Coastguard Worker     }
1233*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1234*0ec5a0ecSAndroid Build Coastguard Worker }
1235*0ec5a0ecSAndroid Build Coastguard Worker 
clearDevicePollInterrupt()1236*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::clearDevicePollInterrupt() {
1237*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1238*0ec5a0ecSAndroid Build Coastguard Worker 
1239*0ec5a0ecSAndroid Build Coastguard Worker     uint64_t buf;
1240*0ec5a0ecSAndroid Build Coastguard Worker     if (HANDLE_EINTR(read(mDevicePollInterruptFd.get(), &buf, sizeof(buf))) == -1) {
1241*0ec5a0ecSAndroid Build Coastguard Worker         if (errno == EAGAIN) {
1242*0ec5a0ecSAndroid Build Coastguard Worker             // No interrupt flag set, and we're reading nonblocking.  Not an error.
1243*0ec5a0ecSAndroid Build Coastguard Worker             return true;
1244*0ec5a0ecSAndroid Build Coastguard Worker         } else {
1245*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("read() failed");
1246*0ec5a0ecSAndroid Build Coastguard Worker             return false;
1247*0ec5a0ecSAndroid Build Coastguard Worker         }
1248*0ec5a0ecSAndroid Build Coastguard Worker     }
1249*0ec5a0ecSAndroid Build Coastguard Worker     return true;
1250*0ec5a0ecSAndroid Build Coastguard Worker }
1251*0ec5a0ecSAndroid Build Coastguard Worker 
getDmabufsForV4L2Buffer(int index,size_t numPlanes,enum v4l2_buf_type bufType)1252*0ec5a0ecSAndroid Build Coastguard Worker std::vector<base::ScopedFD> V4L2Device::getDmabufsForV4L2Buffer(int index, size_t numPlanes,
1253*0ec5a0ecSAndroid Build Coastguard Worker                                                                 enum v4l2_buf_type bufType) {
1254*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
1255*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(V4L2_TYPE_IS_MULTIPLANAR(bufType));
1256*0ec5a0ecSAndroid Build Coastguard Worker 
1257*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<base::ScopedFD> dmabufFds;
1258*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < numPlanes; ++i) {
1259*0ec5a0ecSAndroid Build Coastguard Worker         struct v4l2_exportbuffer expbuf;
1260*0ec5a0ecSAndroid Build Coastguard Worker         memset(&expbuf, 0, sizeof(expbuf));
1261*0ec5a0ecSAndroid Build Coastguard Worker         expbuf.type = bufType;
1262*0ec5a0ecSAndroid Build Coastguard Worker         expbuf.index = index;
1263*0ec5a0ecSAndroid Build Coastguard Worker         expbuf.plane = i;
1264*0ec5a0ecSAndroid Build Coastguard Worker         expbuf.flags = O_CLOEXEC;
1265*0ec5a0ecSAndroid Build Coastguard Worker         if (ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
1266*0ec5a0ecSAndroid Build Coastguard Worker             dmabufFds.clear();
1267*0ec5a0ecSAndroid Build Coastguard Worker             break;
1268*0ec5a0ecSAndroid Build Coastguard Worker         }
1269*0ec5a0ecSAndroid Build Coastguard Worker 
1270*0ec5a0ecSAndroid Build Coastguard Worker         dmabufFds.push_back(base::ScopedFD(expbuf.fd));
1271*0ec5a0ecSAndroid Build Coastguard Worker     }
1272*0ec5a0ecSAndroid Build Coastguard Worker 
1273*0ec5a0ecSAndroid Build Coastguard Worker     return dmabufFds;
1274*0ec5a0ecSAndroid Build Coastguard Worker }
1275*0ec5a0ecSAndroid Build Coastguard Worker 
preferredInputFormat(Type type)1276*0ec5a0ecSAndroid Build Coastguard Worker std::vector<uint32_t> V4L2Device::preferredInputFormat(Type type) {
1277*0ec5a0ecSAndroid Build Coastguard Worker     if (type == Type::kEncoder) return {V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_NV12};
1278*0ec5a0ecSAndroid Build Coastguard Worker 
1279*0ec5a0ecSAndroid Build Coastguard Worker     return {};
1280*0ec5a0ecSAndroid Build Coastguard Worker }
1281*0ec5a0ecSAndroid Build Coastguard Worker 
1282*0ec5a0ecSAndroid Build Coastguard Worker // static
c2ProfileToV4L2PixFmt(C2Config::profile_t profile,bool sliceBased)1283*0ec5a0ecSAndroid Build Coastguard Worker uint32_t V4L2Device::c2ProfileToV4L2PixFmt(C2Config::profile_t profile, bool sliceBased) {
1284*0ec5a0ecSAndroid Build Coastguard Worker     if (profile >= C2Config::PROFILE_AVC_BASELINE &&
1285*0ec5a0ecSAndroid Build Coastguard Worker         profile <= C2Config::PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH) {
1286*0ec5a0ecSAndroid Build Coastguard Worker         if (sliceBased) {
1287*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_H264_SLICE;
1288*0ec5a0ecSAndroid Build Coastguard Worker         } else {
1289*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_H264;
1290*0ec5a0ecSAndroid Build Coastguard Worker         }
1291*0ec5a0ecSAndroid Build Coastguard Worker     } else if (profile >= C2Config::PROFILE_VP8_0 && profile <= C2Config::PROFILE_VP8_3) {
1292*0ec5a0ecSAndroid Build Coastguard Worker         if (sliceBased) {
1293*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_VP8_FRAME;
1294*0ec5a0ecSAndroid Build Coastguard Worker         } else {
1295*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_VP8;
1296*0ec5a0ecSAndroid Build Coastguard Worker         }
1297*0ec5a0ecSAndroid Build Coastguard Worker     } else if (profile >= C2Config::PROFILE_VP9_0 && profile <= C2Config::PROFILE_VP9_3) {
1298*0ec5a0ecSAndroid Build Coastguard Worker         if (sliceBased) {
1299*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_VP9_FRAME;
1300*0ec5a0ecSAndroid Build Coastguard Worker         } else {
1301*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_VP9;
1302*0ec5a0ecSAndroid Build Coastguard Worker         }
1303*0ec5a0ecSAndroid Build Coastguard Worker     } else if (profile >= C2Config::PROFILE_HEVC_MAIN &&
1304*0ec5a0ecSAndroid Build Coastguard Worker                profile <= C2Config::PROFILE_HEVC_3D_MAIN) {
1305*0ec5a0ecSAndroid Build Coastguard Worker         if (sliceBased) {
1306*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_HEVC_SLICE;
1307*0ec5a0ecSAndroid Build Coastguard Worker         } else {
1308*0ec5a0ecSAndroid Build Coastguard Worker             return V4L2_PIX_FMT_HEVC;
1309*0ec5a0ecSAndroid Build Coastguard Worker         }
1310*0ec5a0ecSAndroid Build Coastguard Worker     } else {
1311*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unknown profile: %s", profileToString(profile));
1312*0ec5a0ecSAndroid Build Coastguard Worker         return 0;
1313*0ec5a0ecSAndroid Build Coastguard Worker     }
1314*0ec5a0ecSAndroid Build Coastguard Worker }
1315*0ec5a0ecSAndroid Build Coastguard Worker 
1316*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2LevelToC2Level(VideoCodec codec,uint32_t level)1317*0ec5a0ecSAndroid Build Coastguard Worker C2Config::level_t V4L2Device::v4L2LevelToC2Level(VideoCodec codec, uint32_t level) {
1318*0ec5a0ecSAndroid Build Coastguard Worker     switch (codec) {
1319*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264:
1320*0ec5a0ecSAndroid Build Coastguard Worker         switch (level) {
1321*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
1322*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_1;
1323*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
1324*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_1B;
1325*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
1326*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_1_1;
1327*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
1328*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_1_2;
1329*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
1330*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_1_3;
1331*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
1332*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_2;
1333*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
1334*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_2_1;
1335*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
1336*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_2_2;
1337*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
1338*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_3;
1339*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
1340*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_3_1;
1341*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
1342*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_3_2;
1343*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
1344*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_4;
1345*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
1346*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_4_1;
1347*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
1348*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_4_2;
1349*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
1350*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_5;
1351*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_H264_LEVEL_5_1
1352*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
1353*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_5_1;
1354*0ec5a0ecSAndroid Build Coastguard Worker #endif
1355*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_H264_LEVEL_5_2
1356*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_5_2:
1357*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_5_2;
1358*0ec5a0ecSAndroid Build Coastguard Worker #endif
1359*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_H264_LEVEL_6_0
1360*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_6_0:
1361*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_6;
1362*0ec5a0ecSAndroid Build Coastguard Worker #endif
1363*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_H264_LEVEL_6_1
1364*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_6_1:
1365*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_6_1;
1366*0ec5a0ecSAndroid Build Coastguard Worker #endif
1367*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_H264_LEVEL_6_2
1368*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_LEVEL_6_2:
1369*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_AVC_6_2;
1370*0ec5a0ecSAndroid Build Coastguard Worker #endif
1371*0ec5a0ecSAndroid Build Coastguard Worker         }
1372*0ec5a0ecSAndroid Build Coastguard Worker         break;
1373*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP8:
1374*0ec5a0ecSAndroid Build Coastguard Worker         return C2Config::LEVEL_UNUSED;
1375*0ec5a0ecSAndroid Build Coastguard Worker         break;
1376*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
1377*0ec5a0ecSAndroid Build Coastguard Worker         switch (level) {
1378*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_1_0
1379*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_1_0:
1380*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_1;
1381*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_1_1:
1382*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_1_1;
1383*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_2_0:
1384*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_2;
1385*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_2_1:
1386*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_2_1;
1387*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_3_0:
1388*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_3;
1389*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_3_1:
1390*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_3_1;
1391*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_4_0:
1392*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_4;
1393*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_4_1:
1394*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_4_1;
1395*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_5_0
1396*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_5_0:
1397*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_5;
1398*0ec5a0ecSAndroid Build Coastguard Worker #endif
1399*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_5_1
1400*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_5_1:
1401*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_5_1;
1402*0ec5a0ecSAndroid Build Coastguard Worker #endif
1403*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_5_2
1404*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_5_2:
1405*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_5_2;
1406*0ec5a0ecSAndroid Build Coastguard Worker #endif
1407*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_6_0
1408*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_6_0:
1409*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_6;
1410*0ec5a0ecSAndroid Build Coastguard Worker #endif
1411*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_6_1
1412*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_6_1:
1413*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_6_1;
1414*0ec5a0ecSAndroid Build Coastguard Worker #endif
1415*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_MPEG_VIDEO_VP9_LEVEL_6_2
1416*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_LEVEL_6_2:
1417*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_VP9_6_2;
1418*0ec5a0ecSAndroid Build Coastguard Worker #endif
1419*0ec5a0ecSAndroid Build Coastguard Worker #endif
1420*0ec5a0ecSAndroid Build Coastguard Worker         default:
1421*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_UNUSED;
1422*0ec5a0ecSAndroid Build Coastguard Worker         }
1423*0ec5a0ecSAndroid Build Coastguard Worker         break;
1424*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC:
1425*0ec5a0ecSAndroid Build Coastguard Worker         switch (level) {
1426*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
1427*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_1;
1428*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
1429*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_2;
1430*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
1431*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_2_1;
1432*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
1433*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_3;
1434*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
1435*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_3_1;
1436*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
1437*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_4;
1438*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
1439*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_4_1;
1440*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
1441*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_5;
1442*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
1443*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_5_1;
1444*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
1445*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_5_2;
1446*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_6:
1447*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_6;
1448*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1:
1449*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_6_1;
1450*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2:
1451*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::LEVEL_HEVC_MAIN_6_2;
1452*0ec5a0ecSAndroid Build Coastguard Worker         }
1453*0ec5a0ecSAndroid Build Coastguard Worker         break;
1454*0ec5a0ecSAndroid Build Coastguard Worker     default:
1455*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unknown codec: %u", codec);
1456*0ec5a0ecSAndroid Build Coastguard Worker     }
1457*0ec5a0ecSAndroid Build Coastguard Worker     ALOGE("Unknown level: %u", level);
1458*0ec5a0ecSAndroid Build Coastguard Worker     return C2Config::LEVEL_UNUSED;
1459*0ec5a0ecSAndroid Build Coastguard Worker }
1460*0ec5a0ecSAndroid Build Coastguard Worker 
1461*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2ProfileToC2Profile(VideoCodec codec,uint32_t profile)1462*0ec5a0ecSAndroid Build Coastguard Worker C2Config::profile_t V4L2Device::v4L2ProfileToC2Profile(VideoCodec codec, uint32_t profile) {
1463*0ec5a0ecSAndroid Build Coastguard Worker     switch (codec) {
1464*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264:
1465*0ec5a0ecSAndroid Build Coastguard Worker         switch (profile) {
1466*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
1467*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_AVC_BASELINE;
1468*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
1469*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_AVC_CONSTRAINED_BASELINE;
1470*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
1471*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_AVC_MAIN;
1472*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
1473*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_AVC_EXTENDED;
1474*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
1475*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_AVC_HIGH;
1476*0ec5a0ecSAndroid Build Coastguard Worker         }
1477*0ec5a0ecSAndroid Build Coastguard Worker         break;
1478*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP8:
1479*0ec5a0ecSAndroid Build Coastguard Worker         switch (profile) {
1480*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP8_PROFILE_0:
1481*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP8_0;
1482*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP8_PROFILE_1:
1483*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP8_1;
1484*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP8_PROFILE_2:
1485*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP8_2;
1486*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP8_PROFILE_3:
1487*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP8_3;
1488*0ec5a0ecSAndroid Build Coastguard Worker         }
1489*0ec5a0ecSAndroid Build Coastguard Worker         break;
1490*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
1491*0ec5a0ecSAndroid Build Coastguard Worker         switch (profile) {
1492*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_PROFILE_0:
1493*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP9_0;
1494*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_PROFILE_1:
1495*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP9_1;
1496*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_PROFILE_2:
1497*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP9_2;
1498*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_VP9_PROFILE_3:
1499*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_VP9_3;
1500*0ec5a0ecSAndroid Build Coastguard Worker         }
1501*0ec5a0ecSAndroid Build Coastguard Worker         break;
1502*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC:
1503*0ec5a0ecSAndroid Build Coastguard Worker         switch (profile) {
1504*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
1505*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_HEVC_MAIN;
1506*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
1507*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_HEVC_MAIN_STILL;
1508*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
1509*0ec5a0ecSAndroid Build Coastguard Worker             return C2Config::PROFILE_HEVC_MAIN_10;
1510*0ec5a0ecSAndroid Build Coastguard Worker         }
1511*0ec5a0ecSAndroid Build Coastguard Worker         break;
1512*0ec5a0ecSAndroid Build Coastguard Worker     default:
1513*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unknown codec: %u", codec);
1514*0ec5a0ecSAndroid Build Coastguard Worker     }
1515*0ec5a0ecSAndroid Build Coastguard Worker     ALOGE("Unknown profile: %u", profile);
1516*0ec5a0ecSAndroid Build Coastguard Worker     return C2Config::PROFILE_UNUSED;
1517*0ec5a0ecSAndroid Build Coastguard Worker }
1518*0ec5a0ecSAndroid Build Coastguard Worker 
1519*0ec5a0ecSAndroid Build Coastguard Worker // static
videoCodecToPixFmt(VideoCodec codec)1520*0ec5a0ecSAndroid Build Coastguard Worker uint32_t V4L2Device::videoCodecToPixFmt(VideoCodec codec) {
1521*0ec5a0ecSAndroid Build Coastguard Worker     switch (codec) {
1522*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264:
1523*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_PIX_FMT_H264;
1524*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP8:
1525*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_PIX_FMT_VP8;
1526*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
1527*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_PIX_FMT_VP9;
1528*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC:
1529*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_PIX_FMT_HEVC;
1530*0ec5a0ecSAndroid Build Coastguard Worker     }
1531*0ec5a0ecSAndroid Build Coastguard Worker }
1532*0ec5a0ecSAndroid Build Coastguard Worker 
queryC2Levels(uint32_t pixFmt)1533*0ec5a0ecSAndroid Build Coastguard Worker std::vector<C2Config::level_t> V4L2Device::queryC2Levels(uint32_t pixFmt) {
1534*0ec5a0ecSAndroid Build Coastguard Worker     auto getSupportedLevels = [this](VideoCodec codec, std::vector<C2Config::level_t>* levels) {
1535*0ec5a0ecSAndroid Build Coastguard Worker         uint32_t queryId = 0;
1536*0ec5a0ecSAndroid Build Coastguard Worker         switch (codec) {
1537*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::H264:
1538*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
1539*0ec5a0ecSAndroid Build Coastguard Worker             break;
1540*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_CID_MPEG_VIDEO_VP9_LEVEL
1541*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::VP9:
1542*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_VP9_LEVEL;
1543*0ec5a0ecSAndroid Build Coastguard Worker             break;
1544*0ec5a0ecSAndroid Build Coastguard Worker #endif
1545*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::HEVC:
1546*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL;
1547*0ec5a0ecSAndroid Build Coastguard Worker             break;
1548*0ec5a0ecSAndroid Build Coastguard Worker         default:
1549*0ec5a0ecSAndroid Build Coastguard Worker             return false;
1550*0ec5a0ecSAndroid Build Coastguard Worker         }
1551*0ec5a0ecSAndroid Build Coastguard Worker 
1552*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_queryctrl queryCtrl = {};
1553*0ec5a0ecSAndroid Build Coastguard Worker         queryCtrl.id = queryId;
1554*0ec5a0ecSAndroid Build Coastguard Worker         if (ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
1555*0ec5a0ecSAndroid Build Coastguard Worker             return false;
1556*0ec5a0ecSAndroid Build Coastguard Worker         }
1557*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_querymenu queryMenu = {};
1558*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.id = queryCtrl.id;
1559*0ec5a0ecSAndroid Build Coastguard Worker         for (queryMenu.index = queryCtrl.minimum;
1560*0ec5a0ecSAndroid Build Coastguard Worker              static_cast<int>(queryMenu.index) <= queryCtrl.maximum; queryMenu.index++) {
1561*0ec5a0ecSAndroid Build Coastguard Worker             if (ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
1562*0ec5a0ecSAndroid Build Coastguard Worker                 const C2Config::level_t level =
1563*0ec5a0ecSAndroid Build Coastguard Worker                         V4L2Device::v4L2LevelToC2Level(codec, queryMenu.index);
1564*0ec5a0ecSAndroid Build Coastguard Worker                 if (level != C2Config::LEVEL_UNUSED) levels->push_back(level);
1565*0ec5a0ecSAndroid Build Coastguard Worker             }
1566*0ec5a0ecSAndroid Build Coastguard Worker         }
1567*0ec5a0ecSAndroid Build Coastguard Worker         return true;
1568*0ec5a0ecSAndroid Build Coastguard Worker     };
1569*0ec5a0ecSAndroid Build Coastguard Worker 
1570*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<C2Config::level_t> levels;
1571*0ec5a0ecSAndroid Build Coastguard Worker     switch (pixFmt) {
1572*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264:
1573*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264_SLICE:
1574*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedLevels(VideoCodec::H264, &levels)) {
1575*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY H264 levels, "
1576*0ec5a0ecSAndroid Build Coastguard Worker                   "use default values, 1-5_2");
1577*0ec5a0ecSAndroid Build Coastguard Worker             levels = {C2Config::LEVEL_AVC_1,   C2Config::LEVEL_AVC_1B,  C2Config::LEVEL_AVC_1_1,
1578*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2,
1579*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2, C2Config::LEVEL_AVC_3,
1580*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4,
1581*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2, C2Config::LEVEL_AVC_5,
1582*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_AVC_5_1, C2Config::LEVEL_AVC_5_2};
1583*0ec5a0ecSAndroid Build Coastguard Worker         }
1584*0ec5a0ecSAndroid Build Coastguard Worker         break;
1585*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8:
1586*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8_FRAME:
1587*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedLevels(VideoCodec::VP8, &levels)) {
1588*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY VP8 levels, use default values, unused");
1589*0ec5a0ecSAndroid Build Coastguard Worker             levels = {C2Config::LEVEL_UNUSED};
1590*0ec5a0ecSAndroid Build Coastguard Worker         }
1591*0ec5a0ecSAndroid Build Coastguard Worker         break;
1592*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9:
1593*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9_FRAME:
1594*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedLevels(VideoCodec::VP9, &levels)) {
1595*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY VP9 levels, use default values, 1-5");
1596*0ec5a0ecSAndroid Build Coastguard Worker             levels = {C2Config::LEVEL_VP9_1,   C2Config::LEVEL_VP9_1_1, C2Config::LEVEL_VP9_2,
1597*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_VP9_2_1, C2Config::LEVEL_VP9_3,   C2Config::LEVEL_VP9_3_1,
1598*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_VP9_4,   C2Config::LEVEL_VP9_4_1, C2Config::LEVEL_VP9_5};
1599*0ec5a0ecSAndroid Build Coastguard Worker         }
1600*0ec5a0ecSAndroid Build Coastguard Worker         break;
1601*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC:
1602*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC_SLICE:
1603*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedLevels(VideoCodec::VP9, &levels)) {
1604*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY HEVC levels, use default values");
1605*0ec5a0ecSAndroid Build Coastguard Worker             levels = {C2Config::LEVEL_HEVC_MAIN_1,   C2Config::LEVEL_HEVC_MAIN_2,
1606*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_2_1, C2Config::LEVEL_HEVC_MAIN_3,
1607*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_3_1, C2Config::LEVEL_HEVC_MAIN_4,
1608*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_4_1, C2Config::LEVEL_HEVC_MAIN_5,
1609*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_5_1, C2Config::LEVEL_HEVC_MAIN_5_2,
1610*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_6,   C2Config::LEVEL_HEVC_MAIN_6_1,
1611*0ec5a0ecSAndroid Build Coastguard Worker                       C2Config::LEVEL_HEVC_MAIN_6_2};
1612*0ec5a0ecSAndroid Build Coastguard Worker         }
1613*0ec5a0ecSAndroid Build Coastguard Worker         break;
1614*0ec5a0ecSAndroid Build Coastguard Worker     default:
1615*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unhandled pixelformat %s", fourccToString(pixFmt).c_str());
1616*0ec5a0ecSAndroid Build Coastguard Worker         return {};
1617*0ec5a0ecSAndroid Build Coastguard Worker     }
1618*0ec5a0ecSAndroid Build Coastguard Worker 
1619*0ec5a0ecSAndroid Build Coastguard Worker     std::sort(levels.begin(), levels.end());
1620*0ec5a0ecSAndroid Build Coastguard Worker     levels.erase(std::unique(levels.begin(), levels.end()), levels.end());
1621*0ec5a0ecSAndroid Build Coastguard Worker     return levels;
1622*0ec5a0ecSAndroid Build Coastguard Worker }
1623*0ec5a0ecSAndroid Build Coastguard Worker 
queryC2Profiles(uint32_t pixFmt)1624*0ec5a0ecSAndroid Build Coastguard Worker std::vector<C2Config::profile_t> V4L2Device::queryC2Profiles(uint32_t pixFmt) {
1625*0ec5a0ecSAndroid Build Coastguard Worker     auto getSupportedProfiles = [this](VideoCodec codec,
1626*0ec5a0ecSAndroid Build Coastguard Worker                                        std::vector<C2Config::profile_t>* profiles) {
1627*0ec5a0ecSAndroid Build Coastguard Worker         uint32_t queryId = 0;
1628*0ec5a0ecSAndroid Build Coastguard Worker         switch (codec) {
1629*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::H264:
1630*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
1631*0ec5a0ecSAndroid Build Coastguard Worker             break;
1632*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::VP8:
1633*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
1634*0ec5a0ecSAndroid Build Coastguard Worker             break;
1635*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::VP9:
1636*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
1637*0ec5a0ecSAndroid Build Coastguard Worker             break;
1638*0ec5a0ecSAndroid Build Coastguard Worker         case VideoCodec::HEVC:
1639*0ec5a0ecSAndroid Build Coastguard Worker             queryId = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE;
1640*0ec5a0ecSAndroid Build Coastguard Worker             break;
1641*0ec5a0ecSAndroid Build Coastguard Worker         default:
1642*0ec5a0ecSAndroid Build Coastguard Worker             return false;
1643*0ec5a0ecSAndroid Build Coastguard Worker         }
1644*0ec5a0ecSAndroid Build Coastguard Worker 
1645*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_queryctrl queryCtrl = {};
1646*0ec5a0ecSAndroid Build Coastguard Worker         queryCtrl.id = queryId;
1647*0ec5a0ecSAndroid Build Coastguard Worker         if (ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
1648*0ec5a0ecSAndroid Build Coastguard Worker             return false;
1649*0ec5a0ecSAndroid Build Coastguard Worker         }
1650*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_querymenu queryMenu = {};
1651*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.id = queryCtrl.id;
1652*0ec5a0ecSAndroid Build Coastguard Worker         for (queryMenu.index = queryCtrl.minimum;
1653*0ec5a0ecSAndroid Build Coastguard Worker              static_cast<int>(queryMenu.index) <= queryCtrl.maximum; queryMenu.index++) {
1654*0ec5a0ecSAndroid Build Coastguard Worker             if (ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
1655*0ec5a0ecSAndroid Build Coastguard Worker                 const C2Config::profile_t profile =
1656*0ec5a0ecSAndroid Build Coastguard Worker                         V4L2Device::v4L2ProfileToC2Profile(codec, queryMenu.index);
1657*0ec5a0ecSAndroid Build Coastguard Worker                 if (profile != C2Config::PROFILE_UNUSED) profiles->push_back(profile);
1658*0ec5a0ecSAndroid Build Coastguard Worker             }
1659*0ec5a0ecSAndroid Build Coastguard Worker         }
1660*0ec5a0ecSAndroid Build Coastguard Worker         return true;
1661*0ec5a0ecSAndroid Build Coastguard Worker     };
1662*0ec5a0ecSAndroid Build Coastguard Worker 
1663*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<C2Config::profile_t> profiles;
1664*0ec5a0ecSAndroid Build Coastguard Worker     switch (pixFmt) {
1665*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264:
1666*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_H264_SLICE:
1667*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedProfiles(VideoCodec::H264, &profiles)) {
1668*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY H264 profiles, "
1669*0ec5a0ecSAndroid Build Coastguard Worker                   "use default values, Base, Main, High");
1670*0ec5a0ecSAndroid Build Coastguard Worker             profiles = {
1671*0ec5a0ecSAndroid Build Coastguard Worker                     C2Config::PROFILE_AVC_BASELINE,
1672*0ec5a0ecSAndroid Build Coastguard Worker                     C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
1673*0ec5a0ecSAndroid Build Coastguard Worker                     C2Config::PROFILE_AVC_MAIN,
1674*0ec5a0ecSAndroid Build Coastguard Worker                     C2Config::PROFILE_AVC_HIGH,
1675*0ec5a0ecSAndroid Build Coastguard Worker             };
1676*0ec5a0ecSAndroid Build Coastguard Worker         }
1677*0ec5a0ecSAndroid Build Coastguard Worker         break;
1678*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8:
1679*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP8_FRAME:
1680*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedProfiles(VideoCodec::VP8, &profiles)) {
1681*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY VP8 profiles, use default values, Profile0");
1682*0ec5a0ecSAndroid Build Coastguard Worker             profiles = {C2Config::PROFILE_VP8_0};
1683*0ec5a0ecSAndroid Build Coastguard Worker         }
1684*0ec5a0ecSAndroid Build Coastguard Worker         break;
1685*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9:
1686*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_VP9_FRAME:
1687*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedProfiles(VideoCodec::VP9, &profiles)) {
1688*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY VP9 profiles, use default values, Profile0");
1689*0ec5a0ecSAndroid Build Coastguard Worker             profiles = {C2Config::PROFILE_VP9_0};
1690*0ec5a0ecSAndroid Build Coastguard Worker         }
1691*0ec5a0ecSAndroid Build Coastguard Worker         break;
1692*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC:
1693*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_PIX_FMT_HEVC_SLICE:
1694*0ec5a0ecSAndroid Build Coastguard Worker         if (!getSupportedProfiles(VideoCodec::HEVC, &profiles)) {
1695*0ec5a0ecSAndroid Build Coastguard Worker             ALOGW("Driver doesn't support QUERY HEVC profiles, "
1696*0ec5a0ecSAndroid Build Coastguard Worker                   "use default values, Main");
1697*0ec5a0ecSAndroid Build Coastguard Worker             profiles = {
1698*0ec5a0ecSAndroid Build Coastguard Worker                     C2Config::PROFILE_HEVC_MAIN,
1699*0ec5a0ecSAndroid Build Coastguard Worker             };
1700*0ec5a0ecSAndroid Build Coastguard Worker         }
1701*0ec5a0ecSAndroid Build Coastguard Worker         break;
1702*0ec5a0ecSAndroid Build Coastguard Worker     default:
1703*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unhandled pixelformat %s", fourccToString(pixFmt).c_str());
1704*0ec5a0ecSAndroid Build Coastguard Worker         return {};
1705*0ec5a0ecSAndroid Build Coastguard Worker     }
1706*0ec5a0ecSAndroid Build Coastguard Worker 
1707*0ec5a0ecSAndroid Build Coastguard Worker     // Erase duplicated profiles.
1708*0ec5a0ecSAndroid Build Coastguard Worker     std::sort(profiles.begin(), profiles.end());
1709*0ec5a0ecSAndroid Build Coastguard Worker     profiles.erase(std::unique(profiles.begin(), profiles.end()), profiles.end());
1710*0ec5a0ecSAndroid Build Coastguard Worker     return profiles;
1711*0ec5a0ecSAndroid Build Coastguard Worker }
1712*0ec5a0ecSAndroid Build Coastguard Worker 
1713*0ec5a0ecSAndroid Build Coastguard Worker // static
c2ProfileToV4L2H264Profile(C2Config::profile_t profile)1714*0ec5a0ecSAndroid Build Coastguard Worker int32_t V4L2Device::c2ProfileToV4L2H264Profile(C2Config::profile_t profile) {
1715*0ec5a0ecSAndroid Build Coastguard Worker     switch (profile) {
1716*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_BASELINE:
1717*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
1718*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_CONSTRAINED_BASELINE:
1719*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
1720*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_MAIN:
1721*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
1722*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_EXTENDED:
1723*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
1724*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_HIGH:
1725*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
1726*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_HIGH_10:
1727*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
1728*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_HIGH_422:
1729*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
1730*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_HIGH_444_PREDICTIVE:
1731*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
1732*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_SCALABLE_BASELINE:
1733*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE;
1734*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_SCALABLE_HIGH:
1735*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH;
1736*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_STEREO_HIGH:
1737*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH;
1738*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::PROFILE_AVC_MULTIVIEW_HIGH:
1739*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH;
1740*0ec5a0ecSAndroid Build Coastguard Worker     default:
1741*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Add more cases as needed");
1742*0ec5a0ecSAndroid Build Coastguard Worker         return -1;
1743*0ec5a0ecSAndroid Build Coastguard Worker     }
1744*0ec5a0ecSAndroid Build Coastguard Worker }
1745*0ec5a0ecSAndroid Build Coastguard Worker 
1746*0ec5a0ecSAndroid Build Coastguard Worker // static
h264LevelIdcToV4L2H264Level(uint8_t levelIdc)1747*0ec5a0ecSAndroid Build Coastguard Worker int32_t V4L2Device::h264LevelIdcToV4L2H264Level(uint8_t levelIdc) {
1748*0ec5a0ecSAndroid Build Coastguard Worker     switch (levelIdc) {
1749*0ec5a0ecSAndroid Build Coastguard Worker     case 10:
1750*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
1751*0ec5a0ecSAndroid Build Coastguard Worker     case 9:
1752*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
1753*0ec5a0ecSAndroid Build Coastguard Worker     case 11:
1754*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
1755*0ec5a0ecSAndroid Build Coastguard Worker     case 12:
1756*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
1757*0ec5a0ecSAndroid Build Coastguard Worker     case 13:
1758*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
1759*0ec5a0ecSAndroid Build Coastguard Worker     case 20:
1760*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
1761*0ec5a0ecSAndroid Build Coastguard Worker     case 21:
1762*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
1763*0ec5a0ecSAndroid Build Coastguard Worker     case 22:
1764*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
1765*0ec5a0ecSAndroid Build Coastguard Worker     case 30:
1766*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
1767*0ec5a0ecSAndroid Build Coastguard Worker     case 31:
1768*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
1769*0ec5a0ecSAndroid Build Coastguard Worker     case 32:
1770*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
1771*0ec5a0ecSAndroid Build Coastguard Worker     case 40:
1772*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
1773*0ec5a0ecSAndroid Build Coastguard Worker     case 41:
1774*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
1775*0ec5a0ecSAndroid Build Coastguard Worker     case 42:
1776*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
1777*0ec5a0ecSAndroid Build Coastguard Worker     case 50:
1778*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
1779*0ec5a0ecSAndroid Build Coastguard Worker     case 51:
1780*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
1781*0ec5a0ecSAndroid Build Coastguard Worker     default:
1782*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unrecognized levelIdc: %u", static_cast<uint32_t>(levelIdc));
1783*0ec5a0ecSAndroid Build Coastguard Worker         return -1;
1784*0ec5a0ecSAndroid Build Coastguard Worker     }
1785*0ec5a0ecSAndroid Build Coastguard Worker }
1786*0ec5a0ecSAndroid Build Coastguard Worker 
1787*0ec5a0ecSAndroid Build Coastguard Worker // static
c2BitrateModeToV4L2BitrateMode(C2Config::bitrate_mode_t bitrateMode)1788*0ec5a0ecSAndroid Build Coastguard Worker v4l2_mpeg_video_bitrate_mode V4L2Device::c2BitrateModeToV4L2BitrateMode(
1789*0ec5a0ecSAndroid Build Coastguard Worker         C2Config::bitrate_mode_t bitrateMode) {
1790*0ec5a0ecSAndroid Build Coastguard Worker     switch (bitrateMode) {
1791*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::bitrate_mode_t::BITRATE_CONST_SKIP_ALLOWED:
1792*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("BITRATE_CONST_SKIP_ALLOWED not supported, defaulting to BITRATE_CONST");
1793*0ec5a0ecSAndroid Build Coastguard Worker         FALLTHROUGH;
1794*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::bitrate_mode_t::BITRATE_CONST:
1795*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
1796*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::bitrate_mode_t::BITRATE_VARIABLE_SKIP_ALLOWED:
1797*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("BITRATE_VARIABLE_SKIP_ALLOWED not supported, defaulting to BITRATE_VARIABLE");
1798*0ec5a0ecSAndroid Build Coastguard Worker         FALLTHROUGH;
1799*0ec5a0ecSAndroid Build Coastguard Worker     case C2Config::bitrate_mode_t::BITRATE_VARIABLE:
1800*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
1801*0ec5a0ecSAndroid Build Coastguard Worker     default:
1802*0ec5a0ecSAndroid Build Coastguard Worker         ALOGW("Unsupported bitrate mode %u, defaulting to BITRATE_VARIABLE",
1803*0ec5a0ecSAndroid Build Coastguard Worker               static_cast<uint32_t>(bitrateMode));
1804*0ec5a0ecSAndroid Build Coastguard Worker         return V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
1805*0ec5a0ecSAndroid Build Coastguard Worker     }
1806*0ec5a0ecSAndroid Build Coastguard Worker }
1807*0ec5a0ecSAndroid Build Coastguard Worker 
1808*0ec5a0ecSAndroid Build Coastguard Worker // static
allocatedSizeFromV4L2Format(const struct v4l2_format & format)1809*0ec5a0ecSAndroid Build Coastguard Worker ui::Size V4L2Device::allocatedSizeFromV4L2Format(const struct v4l2_format& format) {
1810*0ec5a0ecSAndroid Build Coastguard Worker     ui::Size codedSize;
1811*0ec5a0ecSAndroid Build Coastguard Worker     ui::Size visibleSize;
1812*0ec5a0ecSAndroid Build Coastguard Worker     VideoPixelFormat frameFormat = VideoPixelFormat::UNKNOWN;
1813*0ec5a0ecSAndroid Build Coastguard Worker     size_t bytesPerLine = 0;
1814*0ec5a0ecSAndroid Build Coastguard Worker     // Total bytes in the frame.
1815*0ec5a0ecSAndroid Build Coastguard Worker     size_t sizeimage = 0;
1816*0ec5a0ecSAndroid Build Coastguard Worker 
1817*0ec5a0ecSAndroid Build Coastguard Worker     if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1818*0ec5a0ecSAndroid Build Coastguard Worker         ALOG_ASSERT(format.fmt.pix_mp.num_planes > 0);
1819*0ec5a0ecSAndroid Build Coastguard Worker         bytesPerLine = base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[0].bytesperline);
1820*0ec5a0ecSAndroid Build Coastguard Worker         for (size_t i = 0; i < format.fmt.pix_mp.num_planes; ++i) {
1821*0ec5a0ecSAndroid Build Coastguard Worker             sizeimage += base::checked_cast<int>(format.fmt.pix_mp.plane_fmt[i].sizeimage);
1822*0ec5a0ecSAndroid Build Coastguard Worker         }
1823*0ec5a0ecSAndroid Build Coastguard Worker         visibleSize.set(base::checked_cast<int>(format.fmt.pix_mp.width),
1824*0ec5a0ecSAndroid Build Coastguard Worker                         base::checked_cast<int>(format.fmt.pix_mp.height));
1825*0ec5a0ecSAndroid Build Coastguard Worker         const uint32_t pixFmt = format.fmt.pix_mp.pixelformat;
1826*0ec5a0ecSAndroid Build Coastguard Worker         const auto frameFourcc = Fourcc::fromV4L2PixFmt(pixFmt);
1827*0ec5a0ecSAndroid Build Coastguard Worker         if (!frameFourcc) {
1828*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unsupported format %s", fourccToString(pixFmt).c_str());
1829*0ec5a0ecSAndroid Build Coastguard Worker             return codedSize;
1830*0ec5a0ecSAndroid Build Coastguard Worker         }
1831*0ec5a0ecSAndroid Build Coastguard Worker         frameFormat = frameFourcc->toVideoPixelFormat();
1832*0ec5a0ecSAndroid Build Coastguard Worker     } else {
1833*0ec5a0ecSAndroid Build Coastguard Worker         bytesPerLine = base::checked_cast<int>(format.fmt.pix.bytesperline);
1834*0ec5a0ecSAndroid Build Coastguard Worker         sizeimage = base::checked_cast<int>(format.fmt.pix.sizeimage);
1835*0ec5a0ecSAndroid Build Coastguard Worker         visibleSize.set(base::checked_cast<int>(format.fmt.pix.width),
1836*0ec5a0ecSAndroid Build Coastguard Worker                         base::checked_cast<int>(format.fmt.pix.height));
1837*0ec5a0ecSAndroid Build Coastguard Worker         const uint32_t fourcc = format.fmt.pix.pixelformat;
1838*0ec5a0ecSAndroid Build Coastguard Worker         const auto frameFourcc = Fourcc::fromV4L2PixFmt(fourcc);
1839*0ec5a0ecSAndroid Build Coastguard Worker         if (!frameFourcc) {
1840*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Unsupported format %s", fourccToString(fourcc).c_str());
1841*0ec5a0ecSAndroid Build Coastguard Worker             return codedSize;
1842*0ec5a0ecSAndroid Build Coastguard Worker         }
1843*0ec5a0ecSAndroid Build Coastguard Worker         frameFormat = frameFourcc ? frameFourcc->toVideoPixelFormat() : VideoPixelFormat::UNKNOWN;
1844*0ec5a0ecSAndroid Build Coastguard Worker     }
1845*0ec5a0ecSAndroid Build Coastguard Worker 
1846*0ec5a0ecSAndroid Build Coastguard Worker     // V4L2 does not provide per-plane bytesperline (bpl) when different components are sharing one
1847*0ec5a0ecSAndroid Build Coastguard Worker     // physical plane buffer. In this case, it only provides bpl for the first component in the
1848*0ec5a0ecSAndroid Build Coastguard Worker     // plane. So we can't depend on it for calculating height, because bpl may vary within one
1849*0ec5a0ecSAndroid Build Coastguard Worker     // physical plane buffer. For example, YUV420 contains 3 components in one physical plane, with
1850*0ec5a0ecSAndroid Build Coastguard Worker     // Y at 8 bits per pixel, and Cb/Cr at 4 bits per pixel per component, but we only get 8 pits
1851*0ec5a0ecSAndroid Build Coastguard Worker     // per pixel from bytesperline in physical plane 0. So we need to get total frame bpp from
1852*0ec5a0ecSAndroid Build Coastguard Worker     // elsewhere to calculate coded height.
1853*0ec5a0ecSAndroid Build Coastguard Worker 
1854*0ec5a0ecSAndroid Build Coastguard Worker     // We need bits per pixel for one component only to calculate the coded width from bytesperline.
1855*0ec5a0ecSAndroid Build Coastguard Worker     int planeHorizBitsPerPixel = planeHorizontalBitsPerPixel(frameFormat, 0);
1856*0ec5a0ecSAndroid Build Coastguard Worker 
1857*0ec5a0ecSAndroid Build Coastguard Worker     // Adding up bpp for each component will give us total bpp for all components.
1858*0ec5a0ecSAndroid Build Coastguard Worker     int totalBpp = 0;
1859*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < numPlanes(frameFormat); ++i)
1860*0ec5a0ecSAndroid Build Coastguard Worker         totalBpp += planeBitsPerPixel(frameFormat, i);
1861*0ec5a0ecSAndroid Build Coastguard Worker 
1862*0ec5a0ecSAndroid Build Coastguard Worker     if (sizeimage == 0 || bytesPerLine == 0 || planeHorizBitsPerPixel == 0 || totalBpp == 0 ||
1863*0ec5a0ecSAndroid Build Coastguard Worker         (bytesPerLine * 8) % planeHorizBitsPerPixel != 0) {
1864*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Invalid format provided");
1865*0ec5a0ecSAndroid Build Coastguard Worker         return codedSize;
1866*0ec5a0ecSAndroid Build Coastguard Worker     }
1867*0ec5a0ecSAndroid Build Coastguard Worker 
1868*0ec5a0ecSAndroid Build Coastguard Worker     // Coded width can be calculated by taking the first component's bytesperline, which in V4L2
1869*0ec5a0ecSAndroid Build Coastguard Worker     // always applies to the first component in physical plane buffer.
1870*0ec5a0ecSAndroid Build Coastguard Worker     int codedWidth = bytesPerLine * 8 / planeHorizBitsPerPixel;
1871*0ec5a0ecSAndroid Build Coastguard Worker     // Sizeimage is codedWidth * codedHeight * totalBpp.
1872*0ec5a0ecSAndroid Build Coastguard Worker     int codedHeight = sizeimage * 8 / codedWidth / totalBpp;
1873*0ec5a0ecSAndroid Build Coastguard Worker 
1874*0ec5a0ecSAndroid Build Coastguard Worker     codedSize.set(codedWidth, codedHeight);
1875*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("codedSize=%s", toString(codedSize).c_str());
1876*0ec5a0ecSAndroid Build Coastguard Worker 
1877*0ec5a0ecSAndroid Build Coastguard Worker     // Sanity checks. Calculated coded size has to contain given visible size and fulfill buffer
1878*0ec5a0ecSAndroid Build Coastguard Worker     // byte size requirements.
1879*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(contains(Rect(codedSize), Rect(visibleSize)));
1880*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(sizeimage <= allocationSize(frameFormat, codedSize));
1881*0ec5a0ecSAndroid Build Coastguard Worker 
1882*0ec5a0ecSAndroid Build Coastguard Worker     return codedSize;
1883*0ec5a0ecSAndroid Build Coastguard Worker }
1884*0ec5a0ecSAndroid Build Coastguard Worker 
1885*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2MemoryToString(const v4l2_memory memory)1886*0ec5a0ecSAndroid Build Coastguard Worker const char* V4L2Device::v4L2MemoryToString(const v4l2_memory memory) {
1887*0ec5a0ecSAndroid Build Coastguard Worker     switch (memory) {
1888*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_MEMORY_MMAP:
1889*0ec5a0ecSAndroid Build Coastguard Worker         return "V4L2_MEMORY_MMAP";
1890*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_MEMORY_USERPTR:
1891*0ec5a0ecSAndroid Build Coastguard Worker         return "V4L2_MEMORY_USERPTR";
1892*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_MEMORY_DMABUF:
1893*0ec5a0ecSAndroid Build Coastguard Worker         return "V4L2_MEMORY_DMABUF";
1894*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_MEMORY_OVERLAY:
1895*0ec5a0ecSAndroid Build Coastguard Worker         return "V4L2_MEMORY_OVERLAY";
1896*0ec5a0ecSAndroid Build Coastguard Worker     default:
1897*0ec5a0ecSAndroid Build Coastguard Worker         return "UNKNOWN";
1898*0ec5a0ecSAndroid Build Coastguard Worker     }
1899*0ec5a0ecSAndroid Build Coastguard Worker }
1900*0ec5a0ecSAndroid Build Coastguard Worker 
1901*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2BufferTypeToString(const enum v4l2_buf_type bufType)1902*0ec5a0ecSAndroid Build Coastguard Worker const char* V4L2Device::v4L2BufferTypeToString(const enum v4l2_buf_type bufType) {
1903*0ec5a0ecSAndroid Build Coastguard Worker     switch (bufType) {
1904*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1905*0ec5a0ecSAndroid Build Coastguard Worker         return "OUTPUT";
1906*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1907*0ec5a0ecSAndroid Build Coastguard Worker         return "CAPTURE";
1908*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1909*0ec5a0ecSAndroid Build Coastguard Worker         return "OUTPUT_MPLANE";
1910*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1911*0ec5a0ecSAndroid Build Coastguard Worker         return "CAPTURE_MPLANE";
1912*0ec5a0ecSAndroid Build Coastguard Worker     default:
1913*0ec5a0ecSAndroid Build Coastguard Worker         return "UNKNOWN";
1914*0ec5a0ecSAndroid Build Coastguard Worker     }
1915*0ec5a0ecSAndroid Build Coastguard Worker }
1916*0ec5a0ecSAndroid Build Coastguard Worker 
1917*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2BufferTypeToATraceLabel(uint32_t debugStreamId,const enum v4l2_buf_type type,const char * label)1918*0ec5a0ecSAndroid Build Coastguard Worker std::string V4L2Device::v4L2BufferTypeToATraceLabel(uint32_t debugStreamId,
1919*0ec5a0ecSAndroid Build Coastguard Worker                                                     const enum v4l2_buf_type type,
1920*0ec5a0ecSAndroid Build Coastguard Worker                                                     const char* label) {
1921*0ec5a0ecSAndroid Build Coastguard Worker     const char* queueName;
1922*0ec5a0ecSAndroid Build Coastguard Worker     switch (type) {
1923*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1924*0ec5a0ecSAndroid Build Coastguard Worker         FALLTHROUGH;
1925*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1926*0ec5a0ecSAndroid Build Coastguard Worker         queueName = "CAPTURE";
1927*0ec5a0ecSAndroid Build Coastguard Worker         break;
1928*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1929*0ec5a0ecSAndroid Build Coastguard Worker         FALLTHROUGH;
1930*0ec5a0ecSAndroid Build Coastguard Worker     case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
1931*0ec5a0ecSAndroid Build Coastguard Worker         queueName = "OUTPUT";
1932*0ec5a0ecSAndroid Build Coastguard Worker         break;
1933*0ec5a0ecSAndroid Build Coastguard Worker     default:
1934*0ec5a0ecSAndroid Build Coastguard Worker         queueName = "";
1935*0ec5a0ecSAndroid Build Coastguard Worker         break;
1936*0ec5a0ecSAndroid Build Coastguard Worker     }
1937*0ec5a0ecSAndroid Build Coastguard Worker 
1938*0ec5a0ecSAndroid Build Coastguard Worker     return base::StringPrintf("#%u V4L2 %s %s", debugStreamId, queueName, label);
1939*0ec5a0ecSAndroid Build Coastguard Worker }
1940*0ec5a0ecSAndroid Build Coastguard Worker 
1941*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2FormatToString(const struct v4l2_format & format)1942*0ec5a0ecSAndroid Build Coastguard Worker std::string V4L2Device::v4L2FormatToString(const struct v4l2_format& format) {
1943*0ec5a0ecSAndroid Build Coastguard Worker     std::ostringstream s;
1944*0ec5a0ecSAndroid Build Coastguard Worker     s << "v4l2_format type: " << format.type;
1945*0ec5a0ecSAndroid Build Coastguard Worker     if (format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1946*0ec5a0ecSAndroid Build Coastguard Worker         //  single-planar
1947*0ec5a0ecSAndroid Build Coastguard Worker         const struct v4l2_pix_format& pix = format.fmt.pix;
1948*0ec5a0ecSAndroid Build Coastguard Worker         s << ", width_height: " << toString(ui::Size(pix.width, pix.height))
1949*0ec5a0ecSAndroid Build Coastguard Worker           << ", pixelformat: " << fourccToString(pix.pixelformat) << ", field: " << pix.field
1950*0ec5a0ecSAndroid Build Coastguard Worker           << ", bytesperline: " << pix.bytesperline << ", sizeimage: " << pix.sizeimage;
1951*0ec5a0ecSAndroid Build Coastguard Worker     } else if (V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
1952*0ec5a0ecSAndroid Build Coastguard Worker         const struct v4l2_pix_format_mplane& pixMp = format.fmt.pix_mp;
1953*0ec5a0ecSAndroid Build Coastguard Worker         // As long as num_planes's type is uint8_t, ostringstream treats it as a char instead of an
1954*0ec5a0ecSAndroid Build Coastguard Worker         // integer, which is not what we want. Casting pix_mp.num_planes unsigned int solves the
1955*0ec5a0ecSAndroid Build Coastguard Worker         // issue.
1956*0ec5a0ecSAndroid Build Coastguard Worker         s << ", width_height: " << toString(ui::Size(pixMp.width, pixMp.height))
1957*0ec5a0ecSAndroid Build Coastguard Worker           << ", pixelformat: " << fourccToString(pixMp.pixelformat) << ", field: " << pixMp.field
1958*0ec5a0ecSAndroid Build Coastguard Worker           << ", num_planes: " << static_cast<unsigned int>(pixMp.num_planes);
1959*0ec5a0ecSAndroid Build Coastguard Worker         for (size_t i = 0; i < pixMp.num_planes; ++i) {
1960*0ec5a0ecSAndroid Build Coastguard Worker             const struct v4l2_plane_pix_format& plane_fmt = pixMp.plane_fmt[i];
1961*0ec5a0ecSAndroid Build Coastguard Worker             s << ", plane_fmt[" << i << "].sizeimage: " << plane_fmt.sizeimage << ", plane_fmt["
1962*0ec5a0ecSAndroid Build Coastguard Worker               << i << "].bytesperline: " << plane_fmt.bytesperline;
1963*0ec5a0ecSAndroid Build Coastguard Worker         }
1964*0ec5a0ecSAndroid Build Coastguard Worker     } else {
1965*0ec5a0ecSAndroid Build Coastguard Worker         s << " unsupported yet.";
1966*0ec5a0ecSAndroid Build Coastguard Worker     }
1967*0ec5a0ecSAndroid Build Coastguard Worker     return s.str();
1968*0ec5a0ecSAndroid Build Coastguard Worker }
1969*0ec5a0ecSAndroid Build Coastguard Worker 
1970*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2BufferToString(const struct v4l2_buffer & buffer)1971*0ec5a0ecSAndroid Build Coastguard Worker std::string V4L2Device::v4L2BufferToString(const struct v4l2_buffer& buffer) {
1972*0ec5a0ecSAndroid Build Coastguard Worker     std::ostringstream s;
1973*0ec5a0ecSAndroid Build Coastguard Worker     s << "v4l2_buffer type: " << buffer.type << ", memory: " << buffer.memory
1974*0ec5a0ecSAndroid Build Coastguard Worker       << ", index: " << buffer.index << " bytesused: " << buffer.bytesused
1975*0ec5a0ecSAndroid Build Coastguard Worker       << ", length: " << buffer.length;
1976*0ec5a0ecSAndroid Build Coastguard Worker     if (buffer.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || buffer.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
1977*0ec5a0ecSAndroid Build Coastguard Worker         //  single-planar
1978*0ec5a0ecSAndroid Build Coastguard Worker         if (buffer.memory == V4L2_MEMORY_MMAP) {
1979*0ec5a0ecSAndroid Build Coastguard Worker             s << ", m.offset: " << buffer.m.offset;
1980*0ec5a0ecSAndroid Build Coastguard Worker         } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1981*0ec5a0ecSAndroid Build Coastguard Worker             s << ", m.userptr: " << buffer.m.userptr;
1982*0ec5a0ecSAndroid Build Coastguard Worker         } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1983*0ec5a0ecSAndroid Build Coastguard Worker             s << ", m.fd: " << buffer.m.fd;
1984*0ec5a0ecSAndroid Build Coastguard Worker         };
1985*0ec5a0ecSAndroid Build Coastguard Worker     } else if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
1986*0ec5a0ecSAndroid Build Coastguard Worker         for (size_t i = 0; i < buffer.length; ++i) {
1987*0ec5a0ecSAndroid Build Coastguard Worker             const struct v4l2_plane& plane = buffer.m.planes[i];
1988*0ec5a0ecSAndroid Build Coastguard Worker             s << ", m.planes[" << i << "](bytesused: " << plane.bytesused
1989*0ec5a0ecSAndroid Build Coastguard Worker               << ", length: " << plane.length << ", data_offset: " << plane.data_offset;
1990*0ec5a0ecSAndroid Build Coastguard Worker             if (buffer.memory == V4L2_MEMORY_MMAP) {
1991*0ec5a0ecSAndroid Build Coastguard Worker                 s << ", m.mem_offset: " << plane.m.mem_offset;
1992*0ec5a0ecSAndroid Build Coastguard Worker             } else if (buffer.memory == V4L2_MEMORY_USERPTR) {
1993*0ec5a0ecSAndroid Build Coastguard Worker                 s << ", m.userptr: " << plane.m.userptr;
1994*0ec5a0ecSAndroid Build Coastguard Worker             } else if (buffer.memory == V4L2_MEMORY_DMABUF) {
1995*0ec5a0ecSAndroid Build Coastguard Worker                 s << ", m.fd: " << plane.m.fd;
1996*0ec5a0ecSAndroid Build Coastguard Worker             }
1997*0ec5a0ecSAndroid Build Coastguard Worker             s << ")";
1998*0ec5a0ecSAndroid Build Coastguard Worker         }
1999*0ec5a0ecSAndroid Build Coastguard Worker     } else {
2000*0ec5a0ecSAndroid Build Coastguard Worker         s << " unsupported yet.";
2001*0ec5a0ecSAndroid Build Coastguard Worker     }
2002*0ec5a0ecSAndroid Build Coastguard Worker     return s.str();
2003*0ec5a0ecSAndroid Build Coastguard Worker }
2004*0ec5a0ecSAndroid Build Coastguard Worker 
2005*0ec5a0ecSAndroid Build Coastguard Worker // static
v4L2FormatToVideoFrameLayout(const struct v4l2_format & format)2006*0ec5a0ecSAndroid Build Coastguard Worker std::optional<VideoFrameLayout> V4L2Device::v4L2FormatToVideoFrameLayout(
2007*0ec5a0ecSAndroid Build Coastguard Worker         const struct v4l2_format& format) {
2008*0ec5a0ecSAndroid Build Coastguard Worker     if (!V4L2_TYPE_IS_MULTIPLANAR(format.type)) {
2009*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("v4l2_buf_type is not multiplanar: 0x%" PRIx32, format.type);
2010*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
2011*0ec5a0ecSAndroid Build Coastguard Worker     }
2012*0ec5a0ecSAndroid Build Coastguard Worker     const v4l2_pix_format_mplane& pixMp = format.fmt.pix_mp;
2013*0ec5a0ecSAndroid Build Coastguard Worker     const uint32_t& pixFmt = pixMp.pixelformat;
2014*0ec5a0ecSAndroid Build Coastguard Worker     const auto videoFourcc = Fourcc::fromV4L2PixFmt(pixFmt);
2015*0ec5a0ecSAndroid Build Coastguard Worker     if (!videoFourcc) {
2016*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to convert pixel format to VideoPixelFormat: %s",
2017*0ec5a0ecSAndroid Build Coastguard Worker               fourccToString(pixFmt).c_str());
2018*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
2019*0ec5a0ecSAndroid Build Coastguard Worker     }
2020*0ec5a0ecSAndroid Build Coastguard Worker     const VideoPixelFormat videoFormat = videoFourcc->toVideoPixelFormat();
2021*0ec5a0ecSAndroid Build Coastguard Worker     const size_t numBuffers = pixMp.num_planes;
2022*0ec5a0ecSAndroid Build Coastguard Worker     const size_t numColorPlanes = numPlanes(videoFormat);
2023*0ec5a0ecSAndroid Build Coastguard Worker     if (numColorPlanes == 0) {
2024*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Unsupported video format for NumPlanes(): %s",
2025*0ec5a0ecSAndroid Build Coastguard Worker               videoPixelFormatToString(videoFormat).c_str());
2026*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
2027*0ec5a0ecSAndroid Build Coastguard Worker     }
2028*0ec5a0ecSAndroid Build Coastguard Worker     if (numBuffers > numColorPlanes) {
2029*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("pix_mp.num_planes: %zu should not be larger than NumPlanes(%s): %zu", numBuffers,
2030*0ec5a0ecSAndroid Build Coastguard Worker               videoPixelFormatToString(videoFormat).c_str(), numColorPlanes);
2031*0ec5a0ecSAndroid Build Coastguard Worker         return std::nullopt;
2032*0ec5a0ecSAndroid Build Coastguard Worker     }
2033*0ec5a0ecSAndroid Build Coastguard Worker     // Reserve capacity in advance to prevent unnecessary vector reallocation.
2034*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<VideoFramePlane> planes;
2035*0ec5a0ecSAndroid Build Coastguard Worker     planes.reserve(numColorPlanes);
2036*0ec5a0ecSAndroid Build Coastguard Worker     for (size_t i = 0; i < numBuffers; ++i) {
2037*0ec5a0ecSAndroid Build Coastguard Worker         const v4l2_plane_pix_format& planeFormat = pixMp.plane_fmt[i];
2038*0ec5a0ecSAndroid Build Coastguard Worker         planes.push_back(VideoFramePlane{planeFormat.bytesperline, 0u, planeFormat.sizeimage});
2039*0ec5a0ecSAndroid Build Coastguard Worker     }
2040*0ec5a0ecSAndroid Build Coastguard Worker     // For the case that #color planes > #buffers, it fills stride of color plane which does not map
2041*0ec5a0ecSAndroid Build Coastguard Worker     // to buffer. Right now only some pixel formats are supported: NV12, YUV420, YVU420.
2042*0ec5a0ecSAndroid Build Coastguard Worker     if (numColorPlanes > numBuffers) {
2043*0ec5a0ecSAndroid Build Coastguard Worker         const uint32_t yStride = planes[0].mStride;
2044*0ec5a0ecSAndroid Build Coastguard Worker         // Note that y_stride is from v4l2 bytesperline and its type is uint32_t. It is safe to cast
2045*0ec5a0ecSAndroid Build Coastguard Worker         // to size_t.
2046*0ec5a0ecSAndroid Build Coastguard Worker         const size_t yStrideAbs = static_cast<size_t>(yStride);
2047*0ec5a0ecSAndroid Build Coastguard Worker         switch (pixFmt) {
2048*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_PIX_FMT_NV12:
2049*0ec5a0ecSAndroid Build Coastguard Worker             // The stride of UV is the same as Y in NV12. The height is half of Y plane.
2050*0ec5a0ecSAndroid Build Coastguard Worker             planes.push_back(VideoFramePlane{yStride, yStrideAbs * pixMp.height,
2051*0ec5a0ecSAndroid Build Coastguard Worker                                              yStrideAbs * pixMp.height / 2});
2052*0ec5a0ecSAndroid Build Coastguard Worker             ALOG_ASSERT(2u == planes.size());
2053*0ec5a0ecSAndroid Build Coastguard Worker             break;
2054*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_PIX_FMT_YUV420:
2055*0ec5a0ecSAndroid Build Coastguard Worker         case V4L2_PIX_FMT_YVU420: {
2056*0ec5a0ecSAndroid Build Coastguard Worker             // The spec claims that two Cx rows (including padding) is exactly as long as one Y row
2057*0ec5a0ecSAndroid Build Coastguard Worker             // (including padding). So stride of Y must be even number.
2058*0ec5a0ecSAndroid Build Coastguard Worker             if (yStride % 2 != 0 || pixMp.height % 2 != 0) {
2059*0ec5a0ecSAndroid Build Coastguard Worker                 ALOGE("Plane-Y stride and height should be even; stride: %u, height: %u", yStride,
2060*0ec5a0ecSAndroid Build Coastguard Worker                       pixMp.height);
2061*0ec5a0ecSAndroid Build Coastguard Worker                 return std::nullopt;
2062*0ec5a0ecSAndroid Build Coastguard Worker             }
2063*0ec5a0ecSAndroid Build Coastguard Worker             const uint32_t halfStride = yStride / 2;
2064*0ec5a0ecSAndroid Build Coastguard Worker             const size_t plane0Area = yStrideAbs * pixMp.height;
2065*0ec5a0ecSAndroid Build Coastguard Worker             const size_t plane1Area = plane0Area / 4;
2066*0ec5a0ecSAndroid Build Coastguard Worker             planes.push_back(VideoFramePlane{halfStride, plane0Area, plane1Area});
2067*0ec5a0ecSAndroid Build Coastguard Worker             planes.push_back(VideoFramePlane{halfStride, plane0Area + plane1Area, plane1Area});
2068*0ec5a0ecSAndroid Build Coastguard Worker             ALOG_ASSERT(3u == planes.size());
2069*0ec5a0ecSAndroid Build Coastguard Worker             break;
2070*0ec5a0ecSAndroid Build Coastguard Worker         }
2071*0ec5a0ecSAndroid Build Coastguard Worker         default:
2072*0ec5a0ecSAndroid Build Coastguard Worker             ALOGE("Cannot derive stride for each plane for pixel format %s",
2073*0ec5a0ecSAndroid Build Coastguard Worker                   fourccToString(pixFmt).c_str());
2074*0ec5a0ecSAndroid Build Coastguard Worker             return std::nullopt;
2075*0ec5a0ecSAndroid Build Coastguard Worker         }
2076*0ec5a0ecSAndroid Build Coastguard Worker     }
2077*0ec5a0ecSAndroid Build Coastguard Worker 
2078*0ec5a0ecSAndroid Build Coastguard Worker     return VideoFrameLayout{videoFormat, ui::Size(pixMp.width, pixMp.height), std::move(planes),
2079*0ec5a0ecSAndroid Build Coastguard Worker                             (numBuffers > 1)};
2080*0ec5a0ecSAndroid Build Coastguard Worker }
2081*0ec5a0ecSAndroid Build Coastguard Worker 
2082*0ec5a0ecSAndroid Build Coastguard Worker // static
getNumPlanesOfV4L2PixFmt(uint32_t pixFmt)2083*0ec5a0ecSAndroid Build Coastguard Worker size_t V4L2Device::getNumPlanesOfV4L2PixFmt(uint32_t pixFmt) {
2084*0ec5a0ecSAndroid Build Coastguard Worker     std::optional<Fourcc> fourcc = Fourcc::fromV4L2PixFmt(pixFmt);
2085*0ec5a0ecSAndroid Build Coastguard Worker     if (fourcc && fourcc->isMultiPlanar()) {
2086*0ec5a0ecSAndroid Build Coastguard Worker         return numPlanes(fourcc->toVideoPixelFormat());
2087*0ec5a0ecSAndroid Build Coastguard Worker     }
2088*0ec5a0ecSAndroid Build Coastguard Worker     return 1u;
2089*0ec5a0ecSAndroid Build Coastguard Worker }
2090*0ec5a0ecSAndroid Build Coastguard Worker 
getSupportedResolution(uint32_t pixelFormat,ui::Size * minResolution,ui::Size * maxResolution)2091*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Device::getSupportedResolution(uint32_t pixelFormat, ui::Size* minResolution,
2092*0ec5a0ecSAndroid Build Coastguard Worker                                         ui::Size* maxResolution) {
2093*0ec5a0ecSAndroid Build Coastguard Worker     maxResolution->set(0, 0);
2094*0ec5a0ecSAndroid Build Coastguard Worker     minResolution->set(0, 0);
2095*0ec5a0ecSAndroid Build Coastguard Worker     v4l2_frmsizeenum frameSize;
2096*0ec5a0ecSAndroid Build Coastguard Worker     memset(&frameSize, 0, sizeof(frameSize));
2097*0ec5a0ecSAndroid Build Coastguard Worker     frameSize.pixel_format = pixelFormat;
2098*0ec5a0ecSAndroid Build Coastguard Worker     for (; ioctl(VIDIOC_ENUM_FRAMESIZES, &frameSize) == 0; ++frameSize.index) {
2099*0ec5a0ecSAndroid Build Coastguard Worker         if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
2100*0ec5a0ecSAndroid Build Coastguard Worker             if (frameSize.discrete.width >= base::checked_cast<uint32_t>(maxResolution->width) &&
2101*0ec5a0ecSAndroid Build Coastguard Worker                 frameSize.discrete.height >= base::checked_cast<uint32_t>(maxResolution->height)) {
2102*0ec5a0ecSAndroid Build Coastguard Worker                 maxResolution->set(frameSize.discrete.width, frameSize.discrete.height);
2103*0ec5a0ecSAndroid Build Coastguard Worker             }
2104*0ec5a0ecSAndroid Build Coastguard Worker             if (isEmpty(*minResolution) ||
2105*0ec5a0ecSAndroid Build Coastguard Worker                 (frameSize.discrete.width <= base::checked_cast<uint32_t>(minResolution->width) &&
2106*0ec5a0ecSAndroid Build Coastguard Worker                  frameSize.discrete.height <=
2107*0ec5a0ecSAndroid Build Coastguard Worker                          base::checked_cast<uint32_t>(minResolution->height))) {
2108*0ec5a0ecSAndroid Build Coastguard Worker                 minResolution->set(frameSize.discrete.width, frameSize.discrete.height);
2109*0ec5a0ecSAndroid Build Coastguard Worker             }
2110*0ec5a0ecSAndroid Build Coastguard Worker         } else if (frameSize.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
2111*0ec5a0ecSAndroid Build Coastguard Worker                    frameSize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
2112*0ec5a0ecSAndroid Build Coastguard Worker             maxResolution->set(frameSize.stepwise.max_width, frameSize.stepwise.max_height);
2113*0ec5a0ecSAndroid Build Coastguard Worker             minResolution->set(frameSize.stepwise.min_width, frameSize.stepwise.min_height);
2114*0ec5a0ecSAndroid Build Coastguard Worker             break;
2115*0ec5a0ecSAndroid Build Coastguard Worker         }
2116*0ec5a0ecSAndroid Build Coastguard Worker     }
2117*0ec5a0ecSAndroid Build Coastguard Worker     if (isEmpty(*maxResolution)) {
2118*0ec5a0ecSAndroid Build Coastguard Worker         maxResolution->set(1920, 1088);
2119*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("GetSupportedResolution failed to get maximum resolution for fourcc %s, "
2120*0ec5a0ecSAndroid Build Coastguard Worker               "fall back to %s",
2121*0ec5a0ecSAndroid Build Coastguard Worker               fourccToString(pixelFormat).c_str(), toString(*maxResolution).c_str());
2122*0ec5a0ecSAndroid Build Coastguard Worker     }
2123*0ec5a0ecSAndroid Build Coastguard Worker     if (isEmpty(*minResolution)) {
2124*0ec5a0ecSAndroid Build Coastguard Worker         minResolution->set(16, 16);
2125*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("GetSupportedResolution failed to get minimum resolution for fourcc %s, "
2126*0ec5a0ecSAndroid Build Coastguard Worker               "fall back to %s",
2127*0ec5a0ecSAndroid Build Coastguard Worker               fourccToString(pixelFormat).c_str(), toString(*minResolution).c_str());
2128*0ec5a0ecSAndroid Build Coastguard Worker     }
2129*0ec5a0ecSAndroid Build Coastguard Worker }
2130*0ec5a0ecSAndroid Build Coastguard Worker 
enumerateSupportedPixelformats(v4l2_buf_type bufType)2131*0ec5a0ecSAndroid Build Coastguard Worker std::vector<uint32_t> V4L2Device::enumerateSupportedPixelformats(v4l2_buf_type bufType) {
2132*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<uint32_t> pixelFormats;
2133*0ec5a0ecSAndroid Build Coastguard Worker 
2134*0ec5a0ecSAndroid Build Coastguard Worker     v4l2_fmtdesc fmtDesc;
2135*0ec5a0ecSAndroid Build Coastguard Worker     memset(&fmtDesc, 0, sizeof(fmtDesc));
2136*0ec5a0ecSAndroid Build Coastguard Worker     fmtDesc.type = bufType;
2137*0ec5a0ecSAndroid Build Coastguard Worker 
2138*0ec5a0ecSAndroid Build Coastguard Worker     for (; ioctl(VIDIOC_ENUM_FMT, &fmtDesc) == 0; ++fmtDesc.index) {
2139*0ec5a0ecSAndroid Build Coastguard Worker         ALOGV("Found %s (0x%" PRIx32 ")", fmtDesc.description, fmtDesc.pixelformat);
2140*0ec5a0ecSAndroid Build Coastguard Worker         pixelFormats.push_back(fmtDesc.pixelformat);
2141*0ec5a0ecSAndroid Build Coastguard Worker     }
2142*0ec5a0ecSAndroid Build Coastguard Worker 
2143*0ec5a0ecSAndroid Build Coastguard Worker     return pixelFormats;
2144*0ec5a0ecSAndroid Build Coastguard Worker }
2145*0ec5a0ecSAndroid Build Coastguard Worker 
2146*0ec5a0ecSAndroid Build Coastguard Worker // static
getSupportedDecodeLevels(VideoCodec videoCodecType)2147*0ec5a0ecSAndroid Build Coastguard Worker std::vector<C2Config::level_t> V4L2Device::getSupportedDecodeLevels(VideoCodec videoCodecType) {
2148*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<C2Config::level_t> supportedLevels;
2149*0ec5a0ecSAndroid Build Coastguard Worker     Type type = Type::kDecoder;
2150*0ec5a0ecSAndroid Build Coastguard Worker 
2151*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& info : getDeviceInfosForType(type)) {
2152*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<V4L2Device> device = V4L2Device::create();
2153*0ec5a0ecSAndroid Build Coastguard Worker         if (!device->openDevicePath(info.first, type)) {
2154*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Failed opening %s", info.first.c_str());
2155*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2156*0ec5a0ecSAndroid Build Coastguard Worker         }
2157*0ec5a0ecSAndroid Build Coastguard Worker 
2158*0ec5a0ecSAndroid Build Coastguard Worker         const auto& levels = device->enumerateSupportedDecodeLevels(videoCodecType);
2159*0ec5a0ecSAndroid Build Coastguard Worker         supportedLevels.insert(supportedLevels.end(), levels.begin(), levels.end());
2160*0ec5a0ecSAndroid Build Coastguard Worker         device->closeDevice();
2161*0ec5a0ecSAndroid Build Coastguard Worker     }
2162*0ec5a0ecSAndroid Build Coastguard Worker 
2163*0ec5a0ecSAndroid Build Coastguard Worker     return supportedLevels;
2164*0ec5a0ecSAndroid Build Coastguard Worker }
2165*0ec5a0ecSAndroid Build Coastguard Worker 
2166*0ec5a0ecSAndroid Build Coastguard Worker // static
getSupportedProfiles(V4L2Device::Type type,const std::vector<uint32_t> & pixelFormats)2167*0ec5a0ecSAndroid Build Coastguard Worker SupportedProfiles V4L2Device::getSupportedProfiles(V4L2Device::Type type,
2168*0ec5a0ecSAndroid Build Coastguard Worker                                                    const std::vector<uint32_t>& pixelFormats) {
2169*0ec5a0ecSAndroid Build Coastguard Worker     SupportedProfiles supportedProfiles;
2170*0ec5a0ecSAndroid Build Coastguard Worker 
2171*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& info : getDeviceInfosForType(type)) {
2172*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<V4L2Device> device = V4L2Device::create();
2173*0ec5a0ecSAndroid Build Coastguard Worker         if (!device->openDevicePath(info.first, type)) {
2174*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Failed opening %s", info.first.c_str());
2175*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2176*0ec5a0ecSAndroid Build Coastguard Worker         }
2177*0ec5a0ecSAndroid Build Coastguard Worker 
2178*0ec5a0ecSAndroid Build Coastguard Worker         const auto& profiles = device->enumerateSupportedProfiles(type, pixelFormats);
2179*0ec5a0ecSAndroid Build Coastguard Worker         supportedProfiles.insert(supportedProfiles.end(), profiles.begin(), profiles.end());
2180*0ec5a0ecSAndroid Build Coastguard Worker 
2181*0ec5a0ecSAndroid Build Coastguard Worker         device->closeDevice();
2182*0ec5a0ecSAndroid Build Coastguard Worker     }
2183*0ec5a0ecSAndroid Build Coastguard Worker 
2184*0ec5a0ecSAndroid Build Coastguard Worker     return supportedProfiles;
2185*0ec5a0ecSAndroid Build Coastguard Worker }
2186*0ec5a0ecSAndroid Build Coastguard Worker 
2187*0ec5a0ecSAndroid Build Coastguard Worker // static
getDefaultProfile(VideoCodec codec)2188*0ec5a0ecSAndroid Build Coastguard Worker C2Config::profile_t V4L2Device::getDefaultProfile(VideoCodec codec) {
2189*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t queryId = 0;
2190*0ec5a0ecSAndroid Build Coastguard Worker 
2191*0ec5a0ecSAndroid Build Coastguard Worker     switch (codec) {
2192*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264:
2193*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_H264_PROFILE;
2194*0ec5a0ecSAndroid Build Coastguard Worker         break;
2195*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP8:
2196*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_VP8_PROFILE;
2197*0ec5a0ecSAndroid Build Coastguard Worker         break;
2198*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
2199*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_VP9_PROFILE;
2200*0ec5a0ecSAndroid Build Coastguard Worker         break;
2201*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC:
2202*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE;
2203*0ec5a0ecSAndroid Build Coastguard Worker         break;
2204*0ec5a0ecSAndroid Build Coastguard Worker     default:
2205*0ec5a0ecSAndroid Build Coastguard Worker         return C2Config::PROFILE_UNUSED;
2206*0ec5a0ecSAndroid Build Coastguard Worker     }
2207*0ec5a0ecSAndroid Build Coastguard Worker 
2208*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& info : getDeviceInfosForType(Type::kDecoder)) {
2209*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<V4L2Device> device = V4L2Device::create();
2210*0ec5a0ecSAndroid Build Coastguard Worker         if (!device->openDevicePath(info.first, Type::kDecoder)) {
2211*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Failed opening %s", info.first.c_str());
2212*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2213*0ec5a0ecSAndroid Build Coastguard Worker         }
2214*0ec5a0ecSAndroid Build Coastguard Worker 
2215*0ec5a0ecSAndroid Build Coastguard Worker         // Call to query control which will return structure including
2216*0ec5a0ecSAndroid Build Coastguard Worker         // index of default profile
2217*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_queryctrl queryCtrl = {};
2218*0ec5a0ecSAndroid Build Coastguard Worker         queryCtrl.id = queryId;
2219*0ec5a0ecSAndroid Build Coastguard Worker         if (device->ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
2220*0ec5a0ecSAndroid Build Coastguard Worker             device->closeDevice();
2221*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2222*0ec5a0ecSAndroid Build Coastguard Worker         }
2223*0ec5a0ecSAndroid Build Coastguard Worker 
2224*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_querymenu queryMenu = {};
2225*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.id = queryCtrl.id;
2226*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.index = queryCtrl.default_value;
2227*0ec5a0ecSAndroid Build Coastguard Worker         if (device->ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
2228*0ec5a0ecSAndroid Build Coastguard Worker             device->closeDevice();
2229*0ec5a0ecSAndroid Build Coastguard Worker             return v4L2ProfileToC2Profile(codec, queryMenu.index);
2230*0ec5a0ecSAndroid Build Coastguard Worker         }
2231*0ec5a0ecSAndroid Build Coastguard Worker 
2232*0ec5a0ecSAndroid Build Coastguard Worker         device->closeDevice();
2233*0ec5a0ecSAndroid Build Coastguard Worker     }
2234*0ec5a0ecSAndroid Build Coastguard Worker     return C2Config::PROFILE_UNUSED;
2235*0ec5a0ecSAndroid Build Coastguard Worker }
2236*0ec5a0ecSAndroid Build Coastguard Worker 
2237*0ec5a0ecSAndroid Build Coastguard Worker // static
getDefaultLevel(VideoCodec codec)2238*0ec5a0ecSAndroid Build Coastguard Worker C2Config::level_t V4L2Device::getDefaultLevel(VideoCodec codec) {
2239*0ec5a0ecSAndroid Build Coastguard Worker     uint32_t queryId = 0;
2240*0ec5a0ecSAndroid Build Coastguard Worker 
2241*0ec5a0ecSAndroid Build Coastguard Worker     switch (codec) {
2242*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::H264:
2243*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_H264_LEVEL;
2244*0ec5a0ecSAndroid Build Coastguard Worker         break;
2245*0ec5a0ecSAndroid Build Coastguard Worker #ifdef V4L2_CID_MPEG_VIDEO_VP9_LEVEL
2246*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::VP9:
2247*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_VP9_LEVEL;
2248*0ec5a0ecSAndroid Build Coastguard Worker         break;
2249*0ec5a0ecSAndroid Build Coastguard Worker #endif
2250*0ec5a0ecSAndroid Build Coastguard Worker     case VideoCodec::HEVC:
2251*0ec5a0ecSAndroid Build Coastguard Worker         queryId = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL;
2252*0ec5a0ecSAndroid Build Coastguard Worker         break;
2253*0ec5a0ecSAndroid Build Coastguard Worker     default:
2254*0ec5a0ecSAndroid Build Coastguard Worker         return C2Config::LEVEL_UNUSED;
2255*0ec5a0ecSAndroid Build Coastguard Worker     }
2256*0ec5a0ecSAndroid Build Coastguard Worker 
2257*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& info : getDeviceInfosForType(Type::kDecoder)) {
2258*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<V4L2Device> device = V4L2Device::create();
2259*0ec5a0ecSAndroid Build Coastguard Worker         if (!device->openDevicePath(info.first, Type::kDecoder)) {
2260*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Failed opening %s", info.first.c_str());
2261*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2262*0ec5a0ecSAndroid Build Coastguard Worker         }
2263*0ec5a0ecSAndroid Build Coastguard Worker 
2264*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_queryctrl queryCtrl = {};
2265*0ec5a0ecSAndroid Build Coastguard Worker         queryCtrl.id = queryId;
2266*0ec5a0ecSAndroid Build Coastguard Worker         if (device->ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {  // gets index of default profile
2267*0ec5a0ecSAndroid Build Coastguard Worker             device->closeDevice();
2268*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2269*0ec5a0ecSAndroid Build Coastguard Worker         }
2270*0ec5a0ecSAndroid Build Coastguard Worker 
2271*0ec5a0ecSAndroid Build Coastguard Worker         v4l2_querymenu queryMenu = {};
2272*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.id = queryCtrl.id;
2273*0ec5a0ecSAndroid Build Coastguard Worker         queryMenu.index = queryCtrl.default_value;
2274*0ec5a0ecSAndroid Build Coastguard Worker         if (device->ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
2275*0ec5a0ecSAndroid Build Coastguard Worker             device->closeDevice();
2276*0ec5a0ecSAndroid Build Coastguard Worker             return v4L2LevelToC2Level(codec, queryMenu.index);
2277*0ec5a0ecSAndroid Build Coastguard Worker         }
2278*0ec5a0ecSAndroid Build Coastguard Worker 
2279*0ec5a0ecSAndroid Build Coastguard Worker         device->closeDevice();
2280*0ec5a0ecSAndroid Build Coastguard Worker     }
2281*0ec5a0ecSAndroid Build Coastguard Worker 
2282*0ec5a0ecSAndroid Build Coastguard Worker     return C2Config::LEVEL_UNUSED;
2283*0ec5a0ecSAndroid Build Coastguard Worker }
2284*0ec5a0ecSAndroid Build Coastguard Worker 
2285*0ec5a0ecSAndroid Build Coastguard Worker // static
queryDecodingCapabilities(VideoCodec codec)2286*0ec5a0ecSAndroid Build Coastguard Worker SupportedCapabilities V4L2Device::queryDecodingCapabilities(VideoCodec codec) {
2287*0ec5a0ecSAndroid Build Coastguard Worker     SupportedCapabilities caps;
2288*0ec5a0ecSAndroid Build Coastguard Worker     caps.codec = codec;
2289*0ec5a0ecSAndroid Build Coastguard Worker     caps.supportedLevels = V4L2Device::getSupportedDecodeLevels(codec);
2290*0ec5a0ecSAndroid Build Coastguard Worker     caps.defaultLevel = V4L2Device::getDefaultLevel(codec);
2291*0ec5a0ecSAndroid Build Coastguard Worker     caps.supportedProfiles = V4L2Device::getSupportedProfiles(
2292*0ec5a0ecSAndroid Build Coastguard Worker             V4L2Device::Type::kDecoder, {V4L2Device::videoCodecToPixFmt(codec)});
2293*0ec5a0ecSAndroid Build Coastguard Worker     caps.defaultLevel = V4L2Device::getDefaultLevel(codec);
2294*0ec5a0ecSAndroid Build Coastguard Worker 
2295*0ec5a0ecSAndroid Build Coastguard Worker     return caps;
2296*0ec5a0ecSAndroid Build Coastguard Worker }
2297*0ec5a0ecSAndroid Build Coastguard Worker 
2298*0ec5a0ecSAndroid Build Coastguard Worker // static
queryEncodingCapabilities(VideoCodec codec)2299*0ec5a0ecSAndroid Build Coastguard Worker SupportedCapabilities V4L2Device::queryEncodingCapabilities(VideoCodec codec) {
2300*0ec5a0ecSAndroid Build Coastguard Worker     SupportedCapabilities caps;
2301*0ec5a0ecSAndroid Build Coastguard Worker     caps.codec = codec;
2302*0ec5a0ecSAndroid Build Coastguard Worker     caps.supportedProfiles = V4L2Device::getSupportedProfiles(
2303*0ec5a0ecSAndroid Build Coastguard Worker             V4L2Device::Type::kEncoder, {V4L2Device::videoCodecToPixFmt(codec)});
2304*0ec5a0ecSAndroid Build Coastguard Worker     return caps;
2305*0ec5a0ecSAndroid Build Coastguard Worker }
2306*0ec5a0ecSAndroid Build Coastguard Worker 
enumerateSupportedDecodeLevels(VideoCodec videoCodecType)2307*0ec5a0ecSAndroid Build Coastguard Worker std::vector<C2Config::level_t> V4L2Device::enumerateSupportedDecodeLevels(
2308*0ec5a0ecSAndroid Build Coastguard Worker         VideoCodec videoCodecType) {
2309*0ec5a0ecSAndroid Build Coastguard Worker     std::vector<C2Config::level_t> supportedLevels;
2310*0ec5a0ecSAndroid Build Coastguard Worker 
2311*0ec5a0ecSAndroid Build Coastguard Worker     const auto& supportedPixelformats =
2312*0ec5a0ecSAndroid Build Coastguard Worker             enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
2313*0ec5a0ecSAndroid Build Coastguard Worker 
2314*0ec5a0ecSAndroid Build Coastguard Worker     for (uint32_t pixelFormat : supportedPixelformats) {
2315*0ec5a0ecSAndroid Build Coastguard Worker         if (isValidPixFmtForCodec(videoCodecType, pixelFormat)) {
2316*0ec5a0ecSAndroid Build Coastguard Worker             std::vector<C2Config::level_t> levels = queryC2Levels(pixelFormat);
2317*0ec5a0ecSAndroid Build Coastguard Worker             supportedLevels.insert(supportedLevels.end(), levels.begin(), levels.end());
2318*0ec5a0ecSAndroid Build Coastguard Worker         }
2319*0ec5a0ecSAndroid Build Coastguard Worker     }
2320*0ec5a0ecSAndroid Build Coastguard Worker 
2321*0ec5a0ecSAndroid Build Coastguard Worker     return supportedLevels;
2322*0ec5a0ecSAndroid Build Coastguard Worker }
2323*0ec5a0ecSAndroid Build Coastguard Worker 
enumerateSupportedProfiles(V4L2Device::Type type,const std::vector<uint32_t> & pixelFormats)2324*0ec5a0ecSAndroid Build Coastguard Worker SupportedProfiles V4L2Device::enumerateSupportedProfiles(
2325*0ec5a0ecSAndroid Build Coastguard Worker         V4L2Device::Type type, const std::vector<uint32_t>& pixelFormats) {
2326*0ec5a0ecSAndroid Build Coastguard Worker     SupportedProfiles profiles;
2327*0ec5a0ecSAndroid Build Coastguard Worker 
2328*0ec5a0ecSAndroid Build Coastguard Worker     v4l2_buf_type bufType;
2329*0ec5a0ecSAndroid Build Coastguard Worker     switch (type) {
2330*0ec5a0ecSAndroid Build Coastguard Worker     case Type::kDecoder:
2331*0ec5a0ecSAndroid Build Coastguard Worker         bufType = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
2332*0ec5a0ecSAndroid Build Coastguard Worker         break;
2333*0ec5a0ecSAndroid Build Coastguard Worker     case Type::kEncoder:
2334*0ec5a0ecSAndroid Build Coastguard Worker         bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
2335*0ec5a0ecSAndroid Build Coastguard Worker         break;
2336*0ec5a0ecSAndroid Build Coastguard Worker     }
2337*0ec5a0ecSAndroid Build Coastguard Worker 
2338*0ec5a0ecSAndroid Build Coastguard Worker     const auto& supportedPixelformats = enumerateSupportedPixelformats(bufType);
2339*0ec5a0ecSAndroid Build Coastguard Worker 
2340*0ec5a0ecSAndroid Build Coastguard Worker     for (uint32_t pixelFormat : supportedPixelformats) {
2341*0ec5a0ecSAndroid Build Coastguard Worker         if (std::find(pixelFormats.begin(), pixelFormats.end(), pixelFormat) == pixelFormats.end())
2342*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2343*0ec5a0ecSAndroid Build Coastguard Worker 
2344*0ec5a0ecSAndroid Build Coastguard Worker         SupportedProfile profile;
2345*0ec5a0ecSAndroid Build Coastguard Worker         if (type == Type::kEncoder) {
2346*0ec5a0ecSAndroid Build Coastguard Worker             profile.max_framerate_numerator = 30;
2347*0ec5a0ecSAndroid Build Coastguard Worker             profile.max_framerate_denominator = 1;
2348*0ec5a0ecSAndroid Build Coastguard Worker         }
2349*0ec5a0ecSAndroid Build Coastguard Worker 
2350*0ec5a0ecSAndroid Build Coastguard Worker         getSupportedResolution(pixelFormat, &profile.min_resolution, &profile.max_resolution);
2351*0ec5a0ecSAndroid Build Coastguard Worker 
2352*0ec5a0ecSAndroid Build Coastguard Worker         const auto videoCodecProfiles = queryC2Profiles(pixelFormat);
2353*0ec5a0ecSAndroid Build Coastguard Worker 
2354*0ec5a0ecSAndroid Build Coastguard Worker         for (const auto& videoCodecProfile : videoCodecProfiles) {
2355*0ec5a0ecSAndroid Build Coastguard Worker             profile.profile = videoCodecProfile;
2356*0ec5a0ecSAndroid Build Coastguard Worker             profiles.push_back(profile);
2357*0ec5a0ecSAndroid Build Coastguard Worker 
2358*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Found profile %s, resolutions: %s %s", profileToString(profile.profile),
2359*0ec5a0ecSAndroid Build Coastguard Worker                   toString(profile.min_resolution).c_str(),
2360*0ec5a0ecSAndroid Build Coastguard Worker                   toString(profile.max_resolution).c_str());
2361*0ec5a0ecSAndroid Build Coastguard Worker         }
2362*0ec5a0ecSAndroid Build Coastguard Worker     }
2363*0ec5a0ecSAndroid Build Coastguard Worker 
2364*0ec5a0ecSAndroid Build Coastguard Worker     return profiles;
2365*0ec5a0ecSAndroid Build Coastguard Worker }
2366*0ec5a0ecSAndroid Build Coastguard Worker 
startPolling(scoped_refptr<base::SequencedTaskRunner> taskRunner,android::V4L2DevicePoller::EventCallback eventCallback,base::RepeatingClosure errorCallback)2367*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::startPolling(scoped_refptr<base::SequencedTaskRunner> taskRunner,
2368*0ec5a0ecSAndroid Build Coastguard Worker                               android::V4L2DevicePoller::EventCallback eventCallback,
2369*0ec5a0ecSAndroid Build Coastguard Worker                               base::RepeatingClosure errorCallback) {
2370*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2371*0ec5a0ecSAndroid Build Coastguard Worker 
2372*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevicePoller) {
2373*0ec5a0ecSAndroid Build Coastguard Worker         mDevicePoller = std::make_unique<android::V4L2DevicePoller>(this, "V4L2DeviceThreadPoller",
2374*0ec5a0ecSAndroid Build Coastguard Worker                                                                     std::move(taskRunner));
2375*0ec5a0ecSAndroid Build Coastguard Worker     }
2376*0ec5a0ecSAndroid Build Coastguard Worker 
2377*0ec5a0ecSAndroid Build Coastguard Worker     bool ret = mDevicePoller->startPolling(std::move(eventCallback), std::move(errorCallback));
2378*0ec5a0ecSAndroid Build Coastguard Worker 
2379*0ec5a0ecSAndroid Build Coastguard Worker     if (!ret) mDevicePoller = nullptr;
2380*0ec5a0ecSAndroid Build Coastguard Worker 
2381*0ec5a0ecSAndroid Build Coastguard Worker     return ret;
2382*0ec5a0ecSAndroid Build Coastguard Worker }
2383*0ec5a0ecSAndroid Build Coastguard Worker 
stopPolling()2384*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::stopPolling() {
2385*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2386*0ec5a0ecSAndroid Build Coastguard Worker 
2387*0ec5a0ecSAndroid Build Coastguard Worker     return !mDevicePoller || mDevicePoller->stopPolling();
2388*0ec5a0ecSAndroid Build Coastguard Worker }
2389*0ec5a0ecSAndroid Build Coastguard Worker 
schedulePoll()2390*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Device::schedulePoll() {
2391*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2392*0ec5a0ecSAndroid Build Coastguard Worker 
2393*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDevicePoller || !mDevicePoller->isPolling()) return;
2394*0ec5a0ecSAndroid Build Coastguard Worker 
2395*0ec5a0ecSAndroid Build Coastguard Worker     mDevicePoller->schedulePoll();
2396*0ec5a0ecSAndroid Build Coastguard Worker }
2397*0ec5a0ecSAndroid Build Coastguard Worker 
isCtrlExposed(uint32_t ctrlId)2398*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::isCtrlExposed(uint32_t ctrlId) {
2399*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2400*0ec5a0ecSAndroid Build Coastguard Worker 
2401*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_queryctrl queryCtrl;
2402*0ec5a0ecSAndroid Build Coastguard Worker     memset(&queryCtrl, 0, sizeof(queryCtrl));
2403*0ec5a0ecSAndroid Build Coastguard Worker     queryCtrl.id = ctrlId;
2404*0ec5a0ecSAndroid Build Coastguard Worker 
2405*0ec5a0ecSAndroid Build Coastguard Worker     return ioctl(VIDIOC_QUERYCTRL, &queryCtrl) == 0;
2406*0ec5a0ecSAndroid Build Coastguard Worker }
2407*0ec5a0ecSAndroid Build Coastguard Worker 
setExtCtrls(uint32_t ctrlClass,std::vector<V4L2ExtCtrl> ctrls)2408*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::setExtCtrls(uint32_t ctrlClass, std::vector<V4L2ExtCtrl> ctrls) {
2409*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2410*0ec5a0ecSAndroid Build Coastguard Worker 
2411*0ec5a0ecSAndroid Build Coastguard Worker     if (ctrls.empty()) return true;
2412*0ec5a0ecSAndroid Build Coastguard Worker 
2413*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_ext_controls extCtrls;
2414*0ec5a0ecSAndroid Build Coastguard Worker     memset(&extCtrls, 0, sizeof(extCtrls));
2415*0ec5a0ecSAndroid Build Coastguard Worker     extCtrls.ctrl_class = ctrlClass;
2416*0ec5a0ecSAndroid Build Coastguard Worker     extCtrls.count = ctrls.size();
2417*0ec5a0ecSAndroid Build Coastguard Worker     extCtrls.controls = &ctrls[0].ctrl;
2418*0ec5a0ecSAndroid Build Coastguard Worker     return ioctl(VIDIOC_S_EXT_CTRLS, &extCtrls) == 0;
2419*0ec5a0ecSAndroid Build Coastguard Worker }
2420*0ec5a0ecSAndroid Build Coastguard Worker 
isCommandSupported(uint32_t commandId)2421*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::isCommandSupported(uint32_t commandId) {
2422*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2423*0ec5a0ecSAndroid Build Coastguard Worker 
2424*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_encoder_cmd cmd;
2425*0ec5a0ecSAndroid Build Coastguard Worker     memset(&cmd, 0, sizeof(cmd));
2426*0ec5a0ecSAndroid Build Coastguard Worker     cmd.cmd = commandId;
2427*0ec5a0ecSAndroid Build Coastguard Worker 
2428*0ec5a0ecSAndroid Build Coastguard Worker     return ioctl(VIDIOC_TRY_ENCODER_CMD, &cmd) == 0;
2429*0ec5a0ecSAndroid Build Coastguard Worker }
2430*0ec5a0ecSAndroid Build Coastguard Worker 
hasCapabilities(uint32_t capabilities)2431*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::hasCapabilities(uint32_t capabilities) {
2432*0ec5a0ecSAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(mClientSequenceChecker);
2433*0ec5a0ecSAndroid Build Coastguard Worker 
2434*0ec5a0ecSAndroid Build Coastguard Worker     struct v4l2_capability caps;
2435*0ec5a0ecSAndroid Build Coastguard Worker     memset(&caps, 0, sizeof(caps));
2436*0ec5a0ecSAndroid Build Coastguard Worker     if (ioctl(VIDIOC_QUERYCAP, &caps) != 0) {
2437*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Failed to query capabilities");
2438*0ec5a0ecSAndroid Build Coastguard Worker         return false;
2439*0ec5a0ecSAndroid Build Coastguard Worker     }
2440*0ec5a0ecSAndroid Build Coastguard Worker 
2441*0ec5a0ecSAndroid Build Coastguard Worker     return (caps.capabilities & capabilities) == capabilities;
2442*0ec5a0ecSAndroid Build Coastguard Worker }
2443*0ec5a0ecSAndroid Build Coastguard Worker 
openDevicePath(const std::string & path,Type)2444*0ec5a0ecSAndroid Build Coastguard Worker bool V4L2Device::openDevicePath(const std::string& path, Type /*type*/) {
2445*0ec5a0ecSAndroid Build Coastguard Worker     ALOG_ASSERT(!mDeviceFd.is_valid());
2446*0ec5a0ecSAndroid Build Coastguard Worker 
2447*0ec5a0ecSAndroid Build Coastguard Worker     mDeviceFd.reset(HANDLE_EINTR(::open(path.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC)));
2448*0ec5a0ecSAndroid Build Coastguard Worker     if (!mDeviceFd.is_valid()) return false;
2449*0ec5a0ecSAndroid Build Coastguard Worker 
2450*0ec5a0ecSAndroid Build Coastguard Worker     return true;
2451*0ec5a0ecSAndroid Build Coastguard Worker }
2452*0ec5a0ecSAndroid Build Coastguard Worker 
closeDevice()2453*0ec5a0ecSAndroid Build Coastguard Worker void V4L2Device::closeDevice() {
2454*0ec5a0ecSAndroid Build Coastguard Worker     ALOGV("%s()", __func__);
2455*0ec5a0ecSAndroid Build Coastguard Worker 
2456*0ec5a0ecSAndroid Build Coastguard Worker     mDeviceFd.reset();
2457*0ec5a0ecSAndroid Build Coastguard Worker }
2458*0ec5a0ecSAndroid Build Coastguard Worker 
2459*0ec5a0ecSAndroid Build Coastguard Worker // static
getDeviceInfosForType(V4L2Device::Type type)2460*0ec5a0ecSAndroid Build Coastguard Worker const V4L2Device::DeviceInfos& V4L2Device::getDeviceInfosForType(V4L2Device::Type type) {
2461*0ec5a0ecSAndroid Build Coastguard Worker     // video input/output devices are registered as /dev/videoX in V4L2.
2462*0ec5a0ecSAndroid Build Coastguard Worker     static constexpr const char* kVideoDevicePattern = "/dev/video";
2463*0ec5a0ecSAndroid Build Coastguard Worker     static const DeviceInfos sNoDevices = {};
2464*0ec5a0ecSAndroid Build Coastguard Worker     static std::mutex sDeviceInfosCacheLock;
2465*0ec5a0ecSAndroid Build Coastguard Worker     static std::map<Type, DeviceInfos> sDeviceInfosCache;
2466*0ec5a0ecSAndroid Build Coastguard Worker 
2467*0ec5a0ecSAndroid Build Coastguard Worker     std::lock_guard lock(sDeviceInfosCacheLock);
2468*0ec5a0ecSAndroid Build Coastguard Worker     if (sDeviceInfosCache.find(type) != sDeviceInfosCache.end()) {
2469*0ec5a0ecSAndroid Build Coastguard Worker         return sDeviceInfosCache[type];
2470*0ec5a0ecSAndroid Build Coastguard Worker     }
2471*0ec5a0ecSAndroid Build Coastguard Worker 
2472*0ec5a0ecSAndroid Build Coastguard Worker     v4l2_buf_type bufType;
2473*0ec5a0ecSAndroid Build Coastguard Worker     switch (type) {
2474*0ec5a0ecSAndroid Build Coastguard Worker     case Type::kDecoder:
2475*0ec5a0ecSAndroid Build Coastguard Worker         bufType = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
2476*0ec5a0ecSAndroid Build Coastguard Worker         break;
2477*0ec5a0ecSAndroid Build Coastguard Worker     case Type::kEncoder:
2478*0ec5a0ecSAndroid Build Coastguard Worker         bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
2479*0ec5a0ecSAndroid Build Coastguard Worker         break;
2480*0ec5a0ecSAndroid Build Coastguard Worker     default:
2481*0ec5a0ecSAndroid Build Coastguard Worker         ALOGE("Only decoder and encoder types are supported!!");
2482*0ec5a0ecSAndroid Build Coastguard Worker         return sNoDevices;
2483*0ec5a0ecSAndroid Build Coastguard Worker     }
2484*0ec5a0ecSAndroid Build Coastguard Worker 
2485*0ec5a0ecSAndroid Build Coastguard Worker     DeviceInfos deviceInfos;
2486*0ec5a0ecSAndroid Build Coastguard Worker     for (int i = 0; i < 10; ++i) {
2487*0ec5a0ecSAndroid Build Coastguard Worker         std::string path = base::StringPrintf("%s%d", kVideoDevicePattern, i);
2488*0ec5a0ecSAndroid Build Coastguard Worker 
2489*0ec5a0ecSAndroid Build Coastguard Worker         scoped_refptr<V4L2Device> device = V4L2Device::create();
2490*0ec5a0ecSAndroid Build Coastguard Worker         if (!device->openDevicePath(path, type)) {
2491*0ec5a0ecSAndroid Build Coastguard Worker             continue;
2492*0ec5a0ecSAndroid Build Coastguard Worker         }
2493*0ec5a0ecSAndroid Build Coastguard Worker 
2494*0ec5a0ecSAndroid Build Coastguard Worker         const auto& supportedPixelformats = device->enumerateSupportedPixelformats(bufType);
2495*0ec5a0ecSAndroid Build Coastguard Worker         if (!supportedPixelformats.empty()) {
2496*0ec5a0ecSAndroid Build Coastguard Worker             ALOGV("Found device: %s", path.c_str());
2497*0ec5a0ecSAndroid Build Coastguard Worker             deviceInfos.push_back(std::make_pair(path, supportedPixelformats));
2498*0ec5a0ecSAndroid Build Coastguard Worker         }
2499*0ec5a0ecSAndroid Build Coastguard Worker 
2500*0ec5a0ecSAndroid Build Coastguard Worker         device->closeDevice();
2501*0ec5a0ecSAndroid Build Coastguard Worker     }
2502*0ec5a0ecSAndroid Build Coastguard Worker 
2503*0ec5a0ecSAndroid Build Coastguard Worker     sDeviceInfosCache[type] = deviceInfos;
2504*0ec5a0ecSAndroid Build Coastguard Worker 
2505*0ec5a0ecSAndroid Build Coastguard Worker     return sDeviceInfosCache[type];
2506*0ec5a0ecSAndroid Build Coastguard Worker }
2507*0ec5a0ecSAndroid Build Coastguard Worker 
getDevicePathFor(Type type,uint32_t pixFmt)2508*0ec5a0ecSAndroid Build Coastguard Worker std::string V4L2Device::getDevicePathFor(Type type, uint32_t pixFmt) {
2509*0ec5a0ecSAndroid Build Coastguard Worker     for (const auto& info : getDeviceInfosForType(type)) {
2510*0ec5a0ecSAndroid Build Coastguard Worker         if (std::find(info.second.begin(), info.second.end(), pixFmt) != info.second.end())
2511*0ec5a0ecSAndroid Build Coastguard Worker             return info.first;
2512*0ec5a0ecSAndroid Build Coastguard Worker     }
2513*0ec5a0ecSAndroid Build Coastguard Worker 
2514*0ec5a0ecSAndroid Build Coastguard Worker     return std::string();
2515*0ec5a0ecSAndroid Build Coastguard Worker }
2516*0ec5a0ecSAndroid Build Coastguard Worker 
2517*0ec5a0ecSAndroid Build Coastguard Worker }  // namespace android
2518