Home | History | Annotate | Download | only in 3_4
      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 "common.h"
     33 #include "stream_format.h"
     34 #include "v4l2_gralloc.h"
     35 
     36 namespace v4l2_camera_hal {
     37 
     38 const int32_t kStandardSizes[][2] = {{640, 480}, {320, 240}};
     39 
     40 V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
     41   std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
     42   if (!gralloc) {
     43     HAL_LOGE("Failed to initialize gralloc helper.");
     44     return nullptr;
     45   }
     46 
     47   return new V4L2Wrapper(device_path, std::move(gralloc));
     48 }
     49 
     50 V4L2Wrapper::V4L2Wrapper(const std::string device_path,
     51                          std::unique_ptr<V4L2Gralloc> gralloc)
     52     : device_path_(std::move(device_path)),
     53       gralloc_(std::move(gralloc)),
     54       connection_count_(0) {}
     55 
     56 V4L2Wrapper::~V4L2Wrapper() {}
     57 
     58 int V4L2Wrapper::Connect() {
     59   HAL_LOG_ENTER();
     60   std::lock_guard<std::mutex> lock(connection_lock_);
     61 
     62   if (connected()) {
     63     HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
     64     ++connection_count_;
     65     return 0;
     66   }
     67 
     68   // Open in nonblocking mode (DQBUF may return EAGAIN).
     69   int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
     70   if (fd < 0) {
     71     HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
     72     return -ENODEV;
     73   }
     74   device_fd_.reset(fd);
     75   ++connection_count_;
     76 
     77   // Check if this connection has the extended control query capability.
     78   v4l2_query_ext_ctrl query;
     79   query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
     80   extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
     81 
     82   // TODO(b/29185945): confirm this is a supported device.
     83   // This is checked by the HAL, but the device at device_path_ may
     84   // not be the same one that was there when the HAL was loaded.
     85   // (Alternatively, better hotplugging support may make this unecessary
     86   // by disabling cameras that get disconnected and checking newly connected
     87   // cameras, so Connect() is never called on an unsupported camera)
     88   return 0;
     89 }
     90 
     91 void V4L2Wrapper::Disconnect() {
     92   HAL_LOG_ENTER();
     93   std::lock_guard<std::mutex> lock(connection_lock_);
     94 
     95   if (connection_count_ == 0) {
     96     // Not connected.
     97     HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
     98              device_path_.c_str());
     99     return;
    100   }
    101 
    102   --connection_count_;
    103   if (connection_count_ > 0) {
    104     HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
    105              device_path_.c_str());
    106     return;
    107   }
    108 
    109   device_fd_.reset(-1);  // Includes close().
    110   format_.reset();
    111   buffers_.clear();
    112   // Closing the device releases all queued buffers back to the user.
    113   gralloc_->unlockAllBuffers();
    114 }
    115 
    116 // Helper function. Should be used instead of ioctl throughout this class.
    117 template <typename T>
    118 int V4L2Wrapper::IoctlLocked(int request, T data) {
    119   // Potentially called so many times logging entry is a bad idea.
    120   std::lock_guard<std::mutex> lock(device_lock_);
    121 
    122   if (!connected()) {
    123     HAL_LOGE("Device %s not connected.", device_path_.c_str());
    124     return -ENODEV;
    125   }
    126   return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
    127 }
    128 
    129 int V4L2Wrapper::StreamOn() {
    130   if (!format_) {
    131     HAL_LOGE("Stream format must be set before turning on stream.");
    132     return -EINVAL;
    133   }
    134 
    135   int32_t type = format_->type();
    136   if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
    137     HAL_LOGE("STREAMON fails: %s", strerror(errno));
    138     return -ENODEV;
    139   }
    140 
    141   HAL_LOGV("Stream turned on.");
    142   return 0;
    143 }
    144 
    145 int V4L2Wrapper::StreamOff() {
    146   if (!format_) {
    147     // Can't have turned on the stream without format being set,
    148     // so nothing to turn off here.
    149     return 0;
    150   }
    151 
    152   int32_t type = format_->type();
    153   int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
    154   // Calling STREAMOFF releases all queued buffers back to the user.
    155   int gralloc_res = gralloc_->unlockAllBuffers();
    156   // No buffers in flight.
    157   for (size_t i = 0; i < buffers_.size(); ++i) {
    158     buffers_[i] = false;
    159   }
    160   if (res < 0) {
    161     HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
    162     return -ENODEV;
    163   }
    164   if (gralloc_res < 0) {
    165     HAL_LOGE("Failed to unlock all buffers after turning stream off.");
    166     return gralloc_res;
    167   }
    168 
    169   HAL_LOGV("Stream turned off.");
    170   return 0;
    171 }
    172 
    173 int V4L2Wrapper::QueryControl(uint32_t control_id,
    174                               v4l2_query_ext_ctrl* result) {
    175   int res;
    176 
    177   memset(result, 0, sizeof(*result));
    178 
    179   if (extended_query_supported_) {
    180     result->id = control_id;
    181     res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
    182     // Assuming the operation was supported (not ENOTTY), no more to do.
    183     if (errno != ENOTTY) {
    184       if (res) {
    185         HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
    186         return -ENODEV;
    187       }
    188       return 0;
    189     }
    190   }
    191 
    192   // Extended control querying not supported, fall back to basic control query.
    193   v4l2_queryctrl query;
    194   query.id = control_id;
    195   if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
    196     HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
    197     return -ENODEV;
    198   }
    199 
    200   // Convert the basic result to the extended result.
    201   result->id = query.id;
    202   result->type = query.type;
    203   memcpy(result->name, query.name, sizeof(query.name));
    204   result->minimum = query.minimum;
    205   if (query.type == V4L2_CTRL_TYPE_BITMASK) {
    206     // According to the V4L2 documentation, when type is BITMASK,
    207     // max and default should be interpreted as __u32. Practically,
    208     // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
    209     result->maximum = static_cast<uint32_t>(query.maximum);
    210     result->default_value = static_cast<uint32_t>(query.default_value);
    211   } else {
    212     result->maximum = query.maximum;
    213     result->default_value = query.default_value;
    214   }
    215   result->step = static_cast<uint32_t>(query.step);
    216   result->flags = query.flags;
    217   result->elems = 1;
    218   switch (result->type) {
    219     case V4L2_CTRL_TYPE_INTEGER64:
    220       result->elem_size = sizeof(int64_t);
    221       break;
    222     case V4L2_CTRL_TYPE_STRING:
    223       result->elem_size = result->maximum + 1;
    224       break;
    225     default:
    226       result->elem_size = sizeof(int32_t);
    227       break;
    228   }
    229 
    230   return 0;
    231 }
    232 
    233 int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
    234   // For extended controls (any control class other than "user"),
    235   // G_EXT_CTRL must be used instead of G_CTRL.
    236   if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
    237     v4l2_ext_control control;
    238     v4l2_ext_controls controls;
    239     memset(&control, 0, sizeof(control));
    240     memset(&controls, 0, sizeof(controls));
    241 
    242     control.id = control_id;
    243     controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
    244     controls.count = 1;
    245     controls.controls = &control;
    246 
    247     if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
    248       HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
    249       return -ENODEV;
    250     }
    251     *value = control.value;
    252   } else {
    253     v4l2_control control{control_id, 0};
    254     if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
    255       HAL_LOGE("G_CTRL fails: %s", strerror(errno));
    256       return -ENODEV;
    257     }
    258     *value = control.value;
    259   }
    260   return 0;
    261 }
    262 
    263 int V4L2Wrapper::SetControl(uint32_t control_id,
    264                             int32_t desired,
    265                             int32_t* result) {
    266   int32_t result_value = 0;
    267 
    268   // TODO(b/29334616): When async, this may need to check if the stream
    269   // is on, and if so, lock it off while setting format. Need to look
    270   // into if V4L2 supports adjusting controls while the stream is on.
    271 
    272   // For extended controls (any control class other than "user"),
    273   // S_EXT_CTRL must be used instead of S_CTRL.
    274   if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
    275     v4l2_ext_control control;
    276     v4l2_ext_controls controls;
    277     memset(&control, 0, sizeof(control));
    278     memset(&controls, 0, sizeof(controls));
    279 
    280     control.id = control_id;
    281     control.value = desired;
    282     controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
    283     controls.count = 1;
    284     controls.controls = &control;
    285 
    286     if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
    287       HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
    288       return -ENODEV;
    289     }
    290     result_value = control.value;
    291   } else {
    292     v4l2_control control{control_id, desired};
    293     if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
    294       HAL_LOGE("S_CTRL fails: %s", strerror(errno));
    295       return -ENODEV;
    296     }
    297     result_value = control.value;
    298   }
    299 
    300   // If the caller wants to know the result, pass it back.
    301   if (result != nullptr) {
    302     *result = result_value;
    303   }
    304   return 0;
    305 }
    306 
    307 int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
    308   HAL_LOG_ENTER();
    309 
    310   v4l2_fmtdesc format_query;
    311   memset(&format_query, 0, sizeof(format_query));
    312   // TODO(b/30000211): multiplanar support.
    313   format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    314   while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
    315     v4l2_formats->insert(format_query.pixelformat);
    316     ++format_query.index;
    317   }
    318 
    319   if (errno != EINVAL) {
    320     HAL_LOGE(
    321         "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
    322     return -ENODEV;
    323   }
    324   return 0;
    325 }
    326 
    327 int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
    328                                      std::set<std::array<int32_t, 2>>* sizes) {
    329   v4l2_frmsizeenum size_query;
    330   memset(&size_query, 0, sizeof(size_query));
    331   size_query.pixel_format = v4l2_format;
    332   if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
    333     HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
    334     return -ENODEV;
    335   }
    336   if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
    337     // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
    338     // Assuming that a driver with discrete frame sizes has a reasonable number
    339     // of them.
    340     do {
    341       sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
    342                        static_cast<int32_t>(size_query.discrete.height)}}});
    343       ++size_query.index;
    344     } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
    345     if (errno != EINVAL) {
    346       HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
    347                size_query.index,
    348                strerror(errno));
    349       return -ENODEV;
    350     }
    351   } else {
    352     // Continuous/Step-wise: based on the stepwise struct returned by the query.
    353     // Fully listing all possible sizes, with large enough range/small enough
    354     // step size, may produce far too many potential sizes. Instead, find the
    355     // closest to a set of standard sizes.
    356     for (const auto size : kStandardSizes) {
    357       // Find the closest size, rounding up.
    358       uint32_t desired_width = size[0];
    359       uint32_t desired_height = size[1];
    360       if (desired_width < size_query.stepwise.min_width ||
    361           desired_height < size_query.stepwise.min_height) {
    362         HAL_LOGV("Standard size %u x %u is too small for format %d",
    363                  desired_width,
    364                  desired_height,
    365                  v4l2_format);
    366         continue;
    367       } else if (desired_width > size_query.stepwise.max_width &&
    368                  desired_height > size_query.stepwise.max_height) {
    369         HAL_LOGV("Standard size %u x %u is too big for format %d",
    370                  desired_width,
    371                  desired_height,
    372                  v4l2_format);
    373         continue;
    374       }
    375 
    376       // Round up.
    377       uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
    378                               size_query.stepwise.step_width - 1) /
    379                              size_query.stepwise.step_width;
    380       uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
    381                                size_query.stepwise.step_height - 1) /
    382                               size_query.stepwise.step_height;
    383       sizes->insert(
    384           {{{static_cast<int32_t>(size_query.stepwise.min_width +
    385                                   width_steps * size_query.stepwise.step_width),
    386              static_cast<int32_t>(size_query.stepwise.min_height +
    387                                   height_steps *
    388                                       size_query.stepwise.step_height)}}});
    389     }
    390   }
    391   return 0;
    392 }
    393 
    394 // Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
    395 inline int64_t FractToNs(const v4l2_fract& fract) {
    396   return (1000000000LL * fract.numerator) / fract.denominator;
    397 }
    398 
    399 int V4L2Wrapper::GetFormatFrameDurationRange(
    400     uint32_t v4l2_format,
    401     const std::array<int32_t, 2>& size,
    402     std::array<int64_t, 2>* duration_range) {
    403   // Potentially called so many times logging entry is a bad idea.
    404 
    405   v4l2_frmivalenum duration_query;
    406   memset(&duration_query, 0, sizeof(duration_query));
    407   duration_query.pixel_format = v4l2_format;
    408   duration_query.width = size[0];
    409   duration_query.height = size[1];
    410   if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
    411     HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
    412     return -ENODEV;
    413   }
    414 
    415   int64_t min = std::numeric_limits<int64_t>::max();
    416   int64_t max = std::numeric_limits<int64_t>::min();
    417   if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
    418     // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
    419     do {
    420       min = std::min(min, FractToNs(duration_query.discrete));
    421       max = std::max(max, FractToNs(duration_query.discrete));
    422       ++duration_query.index;
    423     } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
    424     if (errno != EINVAL) {
    425       HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
    426                duration_query.index,
    427                strerror(errno));
    428       return -ENODEV;
    429     }
    430   } else {
    431     // Continuous/Step-wise: simply convert the given min and max.
    432     min = FractToNs(duration_query.stepwise.min);
    433     max = FractToNs(duration_query.stepwise.max);
    434   }
    435   (*duration_range)[0] = min;
    436   (*duration_range)[1] = max;
    437   return 0;
    438 }
    439 
    440 int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
    441                            uint32_t* result_max_buffers) {
    442   HAL_LOG_ENTER();
    443 
    444   if (format_ && desired_format == *format_) {
    445     HAL_LOGV("Already in correct format, skipping format setting.");
    446     *result_max_buffers = buffers_.size();
    447     return 0;
    448   }
    449 
    450   // Not in the correct format, set the new one.
    451 
    452   if (format_) {
    453     // If we had an old format, first request 0 buffers to inform the device
    454     // we're no longer using any previously "allocated" buffers from the old
    455     // format. This seems like it shouldn't be necessary for USERPTR memory,
    456     // and/or should happen from turning the stream off, but the driver
    457     // complained. May be a driver issue, or may be intended behavior.
    458     int res = RequestBuffers(0);
    459     if (res) {
    460       return res;
    461     }
    462   }
    463 
    464   // Set the camera to the new format.
    465   v4l2_format new_format;
    466   desired_format.FillFormatRequest(&new_format);
    467   // TODO(b/29334616): When async, this will need to check if the stream
    468   // is on, and if so, lock it off while setting format.
    469 
    470   if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
    471     HAL_LOGE("S_FMT failed: %s", strerror(errno));
    472     return -ENODEV;
    473   }
    474 
    475   // Check that the driver actually set to the requested values.
    476   if (desired_format != new_format) {
    477     HAL_LOGE("Device doesn't support desired stream configuration.");
    478     return -EINVAL;
    479   }
    480 
    481   // Keep track of our new format.
    482   format_.reset(new StreamFormat(new_format));
    483 
    484   // Format changed, request new buffers.
    485   int res = RequestBuffers(1);
    486   if (res) {
    487     HAL_LOGE("Requesting buffers for new format failed.");
    488     return res;
    489   }
    490   *result_max_buffers = buffers_.size();
    491   return 0;
    492 }
    493 
    494 int V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
    495   v4l2_requestbuffers req_buffers;
    496   memset(&req_buffers, 0, sizeof(req_buffers));
    497   req_buffers.type = format_->type();
    498   req_buffers.memory = V4L2_MEMORY_USERPTR;
    499   req_buffers.count = num_requested;
    500 
    501   int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
    502   // Calling REQBUFS releases all queued buffers back to the user.
    503   int gralloc_res = gralloc_->unlockAllBuffers();
    504   if (res < 0) {
    505     HAL_LOGE("REQBUFS failed: %s", strerror(errno));
    506     return -ENODEV;
    507   }
    508   if (gralloc_res < 0) {
    509     HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
    510     return gralloc_res;
    511   }
    512 
    513   // V4L2 will set req_buffers.count to a number of buffers it can handle.
    514   if (num_requested > 0 && req_buffers.count < 1) {
    515     HAL_LOGE("REQBUFS claims it can't handle any buffers.");
    516     return -ENODEV;
    517   }
    518   buffers_.resize(req_buffers.count, false);
    519 
    520   return 0;
    521 }
    522 
    523 int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer,
    524                                uint32_t* enqueued_index) {
    525   if (!format_) {
    526     HAL_LOGE("Stream format must be set before enqueuing buffers.");
    527     return -ENODEV;
    528   }
    529 
    530   // Find a free buffer index. Could use some sort of persistent hinting
    531   // here to improve expected efficiency, but buffers_.size() is expected
    532   // to be low enough (<10 experimentally) that it's not worth it.
    533   int index = -1;
    534   {
    535     std::lock_guard<std::mutex> guard(buffer_queue_lock_);
    536     for (int i = 0; i < buffers_.size(); ++i) {
    537       if (!buffers_[i]) {
    538         index = i;
    539         break;
    540       }
    541     }
    542   }
    543   if (index < 0) {
    544     // Note: The HAL should be tracking the number of buffers in flight
    545     // for each stream, and should never overflow the device.
    546     HAL_LOGE("Cannot enqueue buffer: stream is already full.");
    547     return -ENODEV;
    548   }
    549 
    550   // Set up a v4l2 buffer struct.
    551   v4l2_buffer device_buffer;
    552   memset(&device_buffer, 0, sizeof(device_buffer));
    553   device_buffer.type = format_->type();
    554   device_buffer.index = index;
    555 
    556   // Use QUERYBUF to ensure our buffer/device is in good shape,
    557   // and fill out remaining fields.
    558   if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
    559     HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
    560     return -ENODEV;
    561   }
    562 
    563   // Lock the buffer for writing (fills in the user pointer field).
    564   int res =
    565       gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
    566   if (res) {
    567     HAL_LOGE("Gralloc failed to lock buffer.");
    568     return res;
    569   }
    570   if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
    571     HAL_LOGE("QBUF fails: %s", strerror(errno));
    572     gralloc_->unlock(&device_buffer);
    573     return -ENODEV;
    574   }
    575 
    576   // Mark the buffer as in flight.
    577   std::lock_guard<std::mutex> guard(buffer_queue_lock_);
    578   buffers_[index] = true;
    579 
    580   if (enqueued_index) {
    581     *enqueued_index = index;
    582   }
    583   return 0;
    584 }
    585 
    586 int V4L2Wrapper::DequeueBuffer(uint32_t* dequeued_index) {
    587   if (!format_) {
    588     HAL_LOGV(
    589         "Format not set, so stream can't be on, "
    590         "so no buffers available for dequeueing");
    591     return -EAGAIN;
    592   }
    593 
    594   v4l2_buffer buffer;
    595   memset(&buffer, 0, sizeof(buffer));
    596   buffer.type = format_->type();
    597   buffer.memory = V4L2_MEMORY_USERPTR;
    598   int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
    599   if (res) {
    600     if (errno == EAGAIN) {
    601       // Expected failure.
    602       return -EAGAIN;
    603     } else {
    604       // Unexpected failure.
    605       HAL_LOGE("DQBUF fails: %s", strerror(errno));
    606       return -ENODEV;
    607     }
    608   }
    609 
    610   // Mark the buffer as no longer in flight.
    611   {
    612     std::lock_guard<std::mutex> guard(buffer_queue_lock_);
    613     buffers_[buffer.index] = false;
    614   }
    615 
    616   // Now that we're done painting the buffer, we can unlock it.
    617   res = gralloc_->unlock(&buffer);
    618   if (res) {
    619     HAL_LOGE("Gralloc failed to unlock buffer after dequeueing.");
    620     return res;
    621   }
    622 
    623   if (dequeued_index) {
    624     *dequeued_index = buffer.index;
    625   }
    626   return 0;
    627 }
    628 
    629 }  // namespace v4l2_camera_hal
    630