1 /*
2  * Copyright 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "v4l2_wrapper.h"
18 
19 #include <algorithm>
20 #include <array>
21 #include <limits>
22 #include <mutex>
23 #include <vector>
24 
25 #include <fcntl.h>
26 #include <linux/videodev2.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 
30 #include <android-base/unique_fd.h>
31 
32 #include "arc/cached_frame.h"
33 
34 namespace v4l2_camera_hal {
35 
36 using arc::AllocatedFrameBuffer;
37 using arc::SupportedFormat;
38 using arc::SupportedFormats;
39 using default_camera_hal::CaptureRequest;
40 
41 const int32_t kStandardSizes[][2] = {
42   {4096, 2160}, // 4KDCI (for USB camera)
43   {3840, 2160}, // 4KUHD (for USB camera)
44   {3280, 2464}, // 8MP
45   {2560, 1440}, // QHD
46   {1920, 1080}, // HD1080
47   {1640, 1232}, // 2MP
48   {1280,  720}, // HD
49   {1024,  768}, // XGA
50   { 640,  480}, // VGA
51   { 320,  240}, // QVGA
52   { 176,  144}  // QCIF
53 };
54 
NewV4L2Wrapper(const std::string device_path)55 V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
56   return new V4L2Wrapper(device_path);
57 }
58 
V4L2Wrapper(const std::string device_path)59 V4L2Wrapper::V4L2Wrapper(const std::string device_path)
60     : device_path_(std::move(device_path)), connection_count_(0) {}
61 
~V4L2Wrapper()62 V4L2Wrapper::~V4L2Wrapper() {}
63 
Connect()64 int V4L2Wrapper::Connect() {
65   HAL_LOG_ENTER();
66   std::lock_guard<std::mutex> lock(connection_lock_);
67 
68   if (connected()) {
69     HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
70     ++connection_count_;
71     return 0;
72   }
73 
74   // Open in nonblocking mode (DQBUF may return EAGAIN).
75   int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
76   if (fd < 0) {
77     HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
78     return -ENODEV;
79   }
80   device_fd_.reset(fd);
81   ++connection_count_;
82 
83   // Check if this connection has the extended control query capability.
84   v4l2_query_ext_ctrl query;
85   query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
86   extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
87 
88   // TODO(b/29185945): confirm this is a supported device.
89   // This is checked by the HAL, but the device at device_path_ may
90   // not be the same one that was there when the HAL was loaded.
91   // (Alternatively, better hotplugging support may make this unecessary
92   // by disabling cameras that get disconnected and checking newly connected
93   // cameras, so Connect() is never called on an unsupported camera)
94 
95   supported_formats_ = GetSupportedFormats();
96   qualified_formats_ = StreamFormat::GetQualifiedFormats(supported_formats_);
97 
98   return 0;
99 }
100 
Disconnect()101 void V4L2Wrapper::Disconnect() {
102   HAL_LOG_ENTER();
103   std::lock_guard<std::mutex> lock(connection_lock_);
104 
105   if (connection_count_ == 0) {
106     // Not connected.
107     HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
108              device_path_.c_str());
109     return;
110   }
111 
112   --connection_count_;
113   if (connection_count_ > 0) {
114     HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
115              device_path_.c_str(), connection_count_);
116     return;
117   }
118 
119   device_fd_.reset(-1);  // Includes close().
120   format_.reset();
121   {
122     std::lock_guard<std::mutex> buffer_lock(buffer_queue_lock_);
123     buffers_.clear();
124   }
125 }
126 
127 // Helper function. Should be used instead of ioctl throughout this class.
128 template <typename T>
IoctlLocked(int request,T data)129 int V4L2Wrapper::IoctlLocked(int request, T data) {
130   // Potentially called so many times logging entry is a bad idea.
131   std::lock_guard<std::mutex> lock(device_lock_);
132 
133   if (!connected()) {
134     HAL_LOGE("Device %s not connected.", device_path_.c_str());
135     return -ENODEV;
136   }
137   return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
138 }
139 
StreamOn()140 int V4L2Wrapper::StreamOn() {
141   if (!format_) {
142     HAL_LOGE("Stream format must be set before turning on stream.");
143     return -EINVAL;
144   }
145 
146   int32_t type = format_->type();
147   if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
148     HAL_LOGE("STREAMON fails (%d): %s", errno, strerror(errno));
149     return -ENODEV;
150   }
151 
152   HAL_LOGV("Stream turned on.");
153   return 0;
154 }
155 
StreamOff()156 int V4L2Wrapper::StreamOff() {
157   if (!format_) {
158     // Can't have turned on the stream without format being set,
159     // so nothing to turn off here.
160     return 0;
161   }
162 
163   int32_t type = format_->type();
164   int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
165   // Calling STREAMOFF releases all queued buffers back to the user.
166   // No buffers in flight.
167   if (res < 0) {
168     HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
169     return -ENODEV;
170   }
171   std::lock_guard<std::mutex> lock(buffer_queue_lock_);
172   for (auto& buffer : buffers_) {
173     buffer.active = false;
174     buffer.request.reset();
175   }
176   HAL_LOGV("Stream turned off.");
177   return 0;
178 }
179 
QueryControl(uint32_t control_id,v4l2_query_ext_ctrl * result)180 int V4L2Wrapper::QueryControl(uint32_t control_id,
181                               v4l2_query_ext_ctrl* result) {
182   int res;
183 
184   memset(result, 0, sizeof(*result));
185 
186   if (extended_query_supported_) {
187     result->id = control_id;
188     res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
189     // Assuming the operation was supported (not ENOTTY), no more to do.
190     if (errno != ENOTTY) {
191       if (res) {
192         HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
193         return -ENODEV;
194       }
195       return 0;
196     }
197   }
198 
199   // Extended control querying not supported, fall back to basic control query.
200   v4l2_queryctrl query;
201   query.id = control_id;
202   if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
203     HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
204     return -ENODEV;
205   }
206 
207   // Convert the basic result to the extended result.
208   result->id = query.id;
209   result->type = query.type;
210   memcpy(result->name, query.name, sizeof(query.name));
211   result->minimum = query.minimum;
212   if (query.type == V4L2_CTRL_TYPE_BITMASK) {
213     // According to the V4L2 documentation, when type is BITMASK,
214     // max and default should be interpreted as __u32. Practically,
215     // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
216     result->maximum = static_cast<uint32_t>(query.maximum);
217     result->default_value = static_cast<uint32_t>(query.default_value);
218   } else {
219     result->maximum = query.maximum;
220     result->default_value = query.default_value;
221   }
222   result->step = static_cast<uint32_t>(query.step);
223   result->flags = query.flags;
224   result->elems = 1;
225   switch (result->type) {
226     case V4L2_CTRL_TYPE_INTEGER64:
227       result->elem_size = sizeof(int64_t);
228       break;
229     case V4L2_CTRL_TYPE_STRING:
230       result->elem_size = result->maximum + 1;
231       break;
232     default:
233       result->elem_size = sizeof(int32_t);
234       break;
235   }
236 
237   return 0;
238 }
239 
GetControl(uint32_t control_id,int32_t * value)240 int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
241   // For extended controls (any control class other than "user"),
242   // G_EXT_CTRL must be used instead of G_CTRL.
243   if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
244     v4l2_ext_control control;
245     v4l2_ext_controls controls;
246     memset(&control, 0, sizeof(control));
247     memset(&controls, 0, sizeof(controls));
248 
249     control.id = control_id;
250     controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
251     controls.count = 1;
252     controls.controls = &control;
253 
254     if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
255       HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
256       return -ENODEV;
257     }
258     *value = control.value;
259   } else {
260     v4l2_control control{control_id, 0};
261     if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
262       HAL_LOGE("G_CTRL fails: %s", strerror(errno));
263       return -ENODEV;
264     }
265     *value = control.value;
266   }
267   return 0;
268 }
269 
SetControl(uint32_t control_id,int32_t desired,int32_t * result)270 int V4L2Wrapper::SetControl(uint32_t control_id,
271                             int32_t desired,
272                             int32_t* result) {
273   int32_t result_value = 0;
274 
275   // TODO(b/29334616): When async, this may need to check if the stream
276   // is on, and if so, lock it off while setting format. Need to look
277   // into if V4L2 supports adjusting controls while the stream is on.
278 
279   // For extended controls (any control class other than "user"),
280   // S_EXT_CTRL must be used instead of S_CTRL.
281   if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
282     v4l2_ext_control control;
283     v4l2_ext_controls controls;
284     memset(&control, 0, sizeof(control));
285     memset(&controls, 0, sizeof(controls));
286 
287     control.id = control_id;
288     control.value = desired;
289     controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
290     controls.count = 1;
291     controls.controls = &control;
292 
293     if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
294       HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
295       return -ENODEV;
296     }
297     result_value = control.value;
298   } else {
299     v4l2_control control{control_id, desired};
300     if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
301       HAL_LOGE("S_CTRL fails: %s", strerror(errno));
302       return -ENODEV;
303     }
304     result_value = control.value;
305   }
306 
307   // If the caller wants to know the result, pass it back.
308   if (result != nullptr) {
309     *result = result_value;
310   }
311   return 0;
312 }
313 
GetSupportedFormats()314 const SupportedFormats V4L2Wrapper::GetSupportedFormats() {
315   SupportedFormats formats;
316   std::set<uint32_t> pixel_formats;
317   int res = GetFormats(&pixel_formats);
318   if (res) {
319     HAL_LOGE("Failed to get device formats.");
320     return formats;
321   }
322 
323   arc::SupportedFormat supported_format;
324   std::set<std::array<int32_t, 2>> frame_sizes;
325 
326   for (auto pixel_format : pixel_formats) {
327     supported_format.fourcc = pixel_format;
328 
329     frame_sizes.clear();
330     res = GetFormatFrameSizes(pixel_format, &frame_sizes);
331     if (res) {
332       HAL_LOGE("Failed to get frame sizes for format: 0x%x", pixel_format);
333       continue;
334     }
335     for (auto frame_size : frame_sizes) {
336       supported_format.width = frame_size[0];
337       supported_format.height = frame_size[1];
338       formats.push_back(supported_format);
339     }
340   }
341   return formats;
342 }
343 
GetFormats(std::set<uint32_t> * v4l2_formats)344 int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
345   HAL_LOG_ENTER();
346 
347   v4l2_fmtdesc format_query;
348   memset(&format_query, 0, sizeof(format_query));
349   // TODO(b/30000211): multiplanar support.
350   format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
351   while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
352     v4l2_formats->insert(format_query.pixelformat);
353     ++format_query.index;
354   }
355 
356   if (errno != EINVAL) {
357     HAL_LOGE(
358         "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
359     return -ENODEV;
360   }
361   return 0;
362 }
363 
GetQualifiedFormats(std::vector<uint32_t> * v4l2_formats)364 int V4L2Wrapper::GetQualifiedFormats(std::vector<uint32_t>* v4l2_formats) {
365   HAL_LOG_ENTER();
366   if (!connected()) {
367     HAL_LOGE(
368         "Device is not connected, qualified formats may not have been set.");
369     return -EINVAL;
370   }
371   v4l2_formats->clear();
372   std::set<uint32_t> unique_fourccs;
373   for (auto& format : qualified_formats_) {
374     unique_fourccs.insert(format.fourcc);
375   }
376   v4l2_formats->assign(unique_fourccs.begin(), unique_fourccs.end());
377   return 0;
378 }
379 
GetFormatFrameSizes(uint32_t v4l2_format,std::set<std::array<int32_t,2>> * sizes)380 int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
381                                      std::set<std::array<int32_t, 2>>* sizes) {
382   v4l2_frmsizeenum size_query;
383   memset(&size_query, 0, sizeof(size_query));
384   size_query.pixel_format = v4l2_format;
385   if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
386     HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
387     return -ENODEV;
388   }
389   if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
390     // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
391     // Assuming that a driver with discrete frame sizes has a reasonable number
392     // of them.
393     do {
394       sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
395                        static_cast<int32_t>(size_query.discrete.height)}}});
396       ++size_query.index;
397     } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
398     if (errno != EINVAL) {
399       HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
400                size_query.index,
401                strerror(errno));
402       return -ENODEV;
403     }
404   } else {
405     // Continuous/Step-wise: based on the stepwise struct returned by the query.
406     // Fully listing all possible sizes, with large enough range/small enough
407     // step size, may produce far too many potential sizes. Instead, find the
408     // closest to a set of standard sizes.
409     for (const auto size : kStandardSizes) {
410       // Find the closest size, rounding up.
411       uint32_t desired_width = size[0];
412       uint32_t desired_height = size[1];
413       if (desired_width < size_query.stepwise.min_width ||
414           desired_height < size_query.stepwise.min_height) {
415         HAL_LOGV("Standard size %u x %u is too small for format %d",
416                  desired_width,
417                  desired_height,
418                  v4l2_format);
419         continue;
420       } else if (desired_width > size_query.stepwise.max_width ||
421                  desired_height > size_query.stepwise.max_height) {
422         HAL_LOGV("Standard size %u x %u is too big for format %d",
423                  desired_width,
424                  desired_height,
425                  v4l2_format);
426         continue;
427       }
428 
429       // Round up.
430       uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
431                               size_query.stepwise.step_width - 1) /
432                              size_query.stepwise.step_width;
433       uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
434                                size_query.stepwise.step_height - 1) /
435                               size_query.stepwise.step_height;
436       sizes->insert(
437           {{{static_cast<int32_t>(size_query.stepwise.min_width +
438                                   width_steps * size_query.stepwise.step_width),
439              static_cast<int32_t>(size_query.stepwise.min_height +
440                                   height_steps *
441                                       size_query.stepwise.step_height)}}});
442     }
443   }
444   return 0;
445 }
446 
447 // Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
FractToNs(const v4l2_fract & fract)448 inline int64_t FractToNs(const v4l2_fract& fract) {
449   return (1000000000LL * fract.numerator) / fract.denominator;
450 }
451 
GetFormatFrameDurationRange(uint32_t v4l2_format,const std::array<int32_t,2> & size,std::array<int64_t,2> * duration_range)452 int V4L2Wrapper::GetFormatFrameDurationRange(
453     uint32_t v4l2_format,
454     const std::array<int32_t, 2>& size,
455     std::array<int64_t, 2>* duration_range) {
456   // Potentially called so many times logging entry is a bad idea.
457 
458   v4l2_frmivalenum duration_query;
459   memset(&duration_query, 0, sizeof(duration_query));
460   duration_query.pixel_format = v4l2_format;
461   duration_query.width = size[0];
462   duration_query.height = size[1];
463   if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
464     HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
465     return -ENODEV;
466   }
467 
468   int64_t min = std::numeric_limits<int64_t>::max();
469   int64_t max = std::numeric_limits<int64_t>::min();
470   if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
471     // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
472     do {
473       min = std::min(min, FractToNs(duration_query.discrete));
474       max = std::max(max, FractToNs(duration_query.discrete));
475       ++duration_query.index;
476     } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
477     if (errno != EINVAL) {
478       HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
479                duration_query.index,
480                strerror(errno));
481       return -ENODEV;
482     }
483   } else {
484     // Continuous/Step-wise: simply convert the given min and max.
485     min = FractToNs(duration_query.stepwise.min);
486     max = FractToNs(duration_query.stepwise.max);
487   }
488   (*duration_range)[0] = min;
489   (*duration_range)[1] = max;
490   return 0;
491 }
492 
SetFormat(const StreamFormat & desired_format,uint32_t * result_max_buffers)493 int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
494                            uint32_t* result_max_buffers) {
495   HAL_LOG_ENTER();
496 
497   if (format_ && desired_format == *format_) {
498     HAL_LOGV("Already in correct format, skipping format setting.");
499     *result_max_buffers = buffers_.size();
500     return 0;
501   }
502 
503   if (format_) {
504     // If we had an old format, first request 0 buffers to inform the device
505     // we're no longer using any previously "allocated" buffers from the old
506     // format. This seems like it shouldn't be necessary for USERPTR memory,
507     // and/or should happen from turning the stream off, but the driver
508     // complained. May be a driver issue, or may be intended behavior.
509     int res = RequestBuffers(0);
510     if (res) {
511       return res;
512     }
513   }
514 
515   // Select the matching format, or if not available, select a qualified format
516   // we can convert from.
517   SupportedFormat format;
518   if (!StreamFormat::FindBestFitFormat(supported_formats_, qualified_formats_,
519                                        desired_format.v4l2_pixel_format(),
520                                        desired_format.width(),
521                                        desired_format.height(), &format)) {
522     HAL_LOGE(
523         "Unable to find supported resolution in list, "
524         "width: %d, height: %d",
525         desired_format.width(), desired_format.height());
526     return -EINVAL;
527   }
528 
529   // Set the camera to the new format.
530   v4l2_format new_format;
531   const StreamFormat resolved_format(format);
532   resolved_format.FillFormatRequest(&new_format);
533 
534   // TODO(b/29334616): When async, this will need to check if the stream
535   // is on, and if so, lock it off while setting format.
536   if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
537     HAL_LOGE("S_FMT failed: %s", strerror(errno));
538     return -ENODEV;
539   }
540 
541   // Check that the driver actually set to the requested values.
542   if (resolved_format != new_format) {
543     HAL_LOGE("Device doesn't support desired stream configuration.");
544     return -EINVAL;
545   }
546 
547   // Keep track of our new format.
548   format_.reset(new StreamFormat(new_format));
549 
550   // Format changed, request new buffers.
551   int res = RequestBuffers(1);
552   if (res) {
553     HAL_LOGE("Requesting buffers for new format failed.");
554     return res;
555   }
556   *result_max_buffers = buffers_.size();
557   return 0;
558 }
559 
RequestBuffers(uint32_t num_requested)560 int V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
561   v4l2_requestbuffers req_buffers;
562   memset(&req_buffers, 0, sizeof(req_buffers));
563   req_buffers.type = format_->type();
564   req_buffers.memory = V4L2_MEMORY_USERPTR;
565   req_buffers.count = num_requested;
566 
567   int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
568   // Calling REQBUFS releases all queued buffers back to the user.
569   if (res < 0) {
570     HAL_LOGE("REQBUFS failed: %s", strerror(errno));
571     return -ENODEV;
572   }
573 
574   // V4L2 will set req_buffers.count to a number of buffers it can handle.
575   if (num_requested > 0 && req_buffers.count < 1) {
576     HAL_LOGE("REQBUFS claims it can't handle any buffers.");
577     return -ENODEV;
578   }
579   buffers_.resize(req_buffers.count);
580   return 0;
581 }
582 
EnqueueRequest(std::shared_ptr<default_camera_hal::CaptureRequest> request)583 int V4L2Wrapper::EnqueueRequest(
584     std::shared_ptr<default_camera_hal::CaptureRequest> request) {
585   if (!format_) {
586     HAL_LOGE("Stream format must be set before enqueuing buffers.");
587     return -ENODEV;
588   }
589 
590   // Find a free buffer index. Could use some sort of persistent hinting
591   // here to improve expected efficiency, but buffers_.size() is expected
592   // to be low enough (<10 experimentally) that it's not worth it.
593   int index = -1;
594   {
595     std::lock_guard<std::mutex> guard(buffer_queue_lock_);
596     for (size_t i = 0; i < buffers_.size(); ++i) {
597       if (!buffers_[i].active) {
598         index = i;
599         break;
600       }
601     }
602   }
603   if (index < 0) {
604     // Note: The HAL should be tracking the number of buffers in flight
605     // for each stream, and should never overflow the device.
606     HAL_LOGE("Cannot enqueue buffer: stream is already full.");
607     return -ENODEV;
608   }
609 
610   // Set up a v4l2 buffer struct.
611   v4l2_buffer device_buffer;
612   memset(&device_buffer, 0, sizeof(device_buffer));
613   device_buffer.type = format_->type();
614   device_buffer.index = index;
615 
616   // Use QUERYBUF to ensure our buffer/device is in good shape,
617   // and fill out remaining fields.
618   if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
619     HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
620     // Return buffer index.
621     std::lock_guard<std::mutex> guard(buffer_queue_lock_);
622     buffers_[index].active = false;
623     return -ENODEV;
624   }
625 
626   // Setup our request context and fill in the user pointer field.
627   RequestContext* request_context;
628   void* data;
629   {
630     std::lock_guard<std::mutex> guard(buffer_queue_lock_);
631     request_context = &buffers_[index];
632     request_context->camera_buffer->SetDataSize(device_buffer.length);
633     request_context->camera_buffer->Reset();
634     request_context->camera_buffer->SetFourcc(format_->v4l2_pixel_format());
635     request_context->camera_buffer->SetWidth(format_->width());
636     request_context->camera_buffer->SetHeight(format_->height());
637     request_context->request = request;
638     data = request_context->camera_buffer->GetData();
639   }
640   device_buffer.m.userptr = reinterpret_cast<unsigned long>(data);
641 
642   // Pass the buffer to the camera.
643   if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
644     HAL_LOGE("QBUF fails: %s", strerror(errno));
645     return -ENODEV;
646   }
647 
648   // Mark the buffer as in flight.
649   std::lock_guard<std::mutex> guard(buffer_queue_lock_);
650   request_context->active = true;
651 
652   return 0;
653 }
654 
DequeueRequest(std::shared_ptr<CaptureRequest> * request)655 int V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request) {
656   if (!format_) {
657     HAL_LOGV(
658         "Format not set, so stream can't be on, "
659         "so no buffers available for dequeueing");
660     return -EAGAIN;
661   }
662 
663   v4l2_buffer buffer;
664   memset(&buffer, 0, sizeof(buffer));
665   buffer.type = format_->type();
666   buffer.memory = V4L2_MEMORY_USERPTR;
667   int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
668   if (res) {
669     if (errno == EAGAIN) {
670       // Expected failure.
671       return -EAGAIN;
672     } else {
673       // Unexpected failure.
674       HAL_LOGE("DQBUF fails: %s", strerror(errno));
675       return -ENODEV;
676     }
677   }
678 
679   std::lock_guard<std::mutex> guard(buffer_queue_lock_);
680   RequestContext* request_context = &buffers_[buffer.index];
681 
682   // Lock the camera stream buffer for painting.
683   const camera3_stream_buffer_t* stream_buffer =
684       &request_context->request->output_buffers[0];
685   uint32_t fourcc =
686       StreamFormat::HalToV4L2PixelFormat(stream_buffer->stream->format);
687 
688   if (request) {
689     *request = request_context->request;
690   }
691 
692   // Note that the device buffer length is passed to the output frame. If the
693   // GrallocFrameBuffer does not have support for the transformation to
694   // |fourcc|, it will assume that the amount of data to lock is based on
695   // |buffer.length|, otherwise it will use the ImageProcessor::ConvertedSize.
696   arc::GrallocFrameBuffer output_frame(
697       *stream_buffer->buffer, stream_buffer->stream->width,
698       stream_buffer->stream->height, fourcc, buffer.length,
699       stream_buffer->stream->usage);
700   res = output_frame.Map();
701   if (res) {
702     HAL_LOGE("Failed to map output frame.");
703     request_context->request.reset();
704     return -EINVAL;
705   }
706   if (request_context->camera_buffer->GetFourcc() == fourcc &&
707       request_context->camera_buffer->GetWidth() ==
708           stream_buffer->stream->width &&
709       request_context->camera_buffer->GetHeight() ==
710           stream_buffer->stream->height) {
711     // If no format conversion needs to be applied, directly copy the data over.
712     memcpy(output_frame.GetData(), request_context->camera_buffer->GetData(),
713            request_context->camera_buffer->GetDataSize());
714   } else {
715     // Perform the format conversion.
716     arc::CachedFrame cached_frame;
717     cached_frame.SetSource(request_context->camera_buffer.get(), 0);
718     cached_frame.Convert(request_context->request->settings, &output_frame);
719   }
720 
721   request_context->request.reset();
722   // Mark the buffer as not in flight.
723   request_context->active = false;
724   return 0;
725 }
726 
GetInFlightBufferCount()727 int V4L2Wrapper::GetInFlightBufferCount() {
728   int count = 0;
729   std::lock_guard<std::mutex> guard(buffer_queue_lock_);
730   for (auto& buffer : buffers_) {
731     if (buffer.active) {
732       count++;
733     }
734   }
735   return count;
736 }
737 
738 }  // namespace v4l2_camera_hal
739