1c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen/*
2c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * Copyright 2016 The Android Open Source Project
3c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen *
4c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * Licensed under the Apache License, Version 2.0 (the "License");
5c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * you may not use this file except in compliance with the License.
6c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * You may obtain a copy of the License at
7c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen *
8c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen *      http://www.apache.org/licenses/LICENSE-2.0
9c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen *
10c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * Unless required by applicable law or agreed to in writing, software
11c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * distributed under the License is distributed on an "AS IS" BASIS,
12c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * See the License for the specific language governing permissions and
14c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen * limitations under the License.
15c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen */
16c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
173841a7f4951fe1498bf5ba88466def3ea18f8867Ari Hausman-Cohen#include "v4l2_wrapper.h"
18c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
199e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen#include <algorithm>
20abbf9cc0bd4160642c36f7bd47c0277a8bf17adfAri Hausman-Cohen#include <array>
219e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen#include <limits>
222d1ea3a164de3d5908b2f3c127b8979e906d37b9Ari Hausman-Cohen#include <mutex>
239e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen#include <vector>
249e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
25c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen#include <fcntl.h>
26c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen#include <linux/videodev2.h>
27c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen#include <sys/stat.h>
28c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen#include <sys/types.h>
29c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
302d1ea3a164de3d5908b2f3c127b8979e906d37b9Ari Hausman-Cohen#include <android-base/unique_fd.h>
31c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
3228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan#include "arc/cached_frame.h"
33c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
34c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohennamespace v4l2_camera_hal {
35c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
3628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanusing arc::AllocatedFrameBuffer;
3728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanusing arc::SupportedFormat;
3828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanusing arc::SupportedFormats;
3928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanusing default_camera_hal::CaptureRequest;
4028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
41932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chungconst int32_t kStandardSizes[][2] = {
42932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {4096, 2160}, // 4KDCI (for USB camera)
43932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {3840, 2160}, // 4KUHD (for USB camera)
44932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {3280, 2464}, // 8MP
45932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {2560, 1440}, // QHD
46932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {1920, 1080}, // HD1080
47932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {1640, 1232}, // 2MP
48932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {1280,  720}, // HD
49932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  {1024,  768}, // XGA
50932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  { 640,  480}, // VGA
51932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  { 320,  240}, // QVGA
52932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung  { 176,  144}  // QCIF
53932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung};
549e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
554ab49624207319ac99a75d7272d968c172064422Ari Hausman-CohenV4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
5628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  return new V4L2Wrapper(device_path);
574ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen}
584ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
5928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth SwaminathanV4L2Wrapper::V4L2Wrapper(const std::string device_path)
6028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    : device_path_(std::move(device_path)), connection_count_(0) {}
61c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
62ad6fe2b033997ab0401b0a519b18cea6e957dac0Ari Hausman-CohenV4L2Wrapper::~V4L2Wrapper() {}
63c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
64c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::Connect() {
65c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  HAL_LOG_ENTER();
669e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  std::lock_guard<std::mutex> lock(connection_lock_);
67c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
68c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (connected()) {
699e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
709e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    ++connection_count_;
719e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return 0;
72c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
73c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
74c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  // Open in nonblocking mode (DQBUF may return EAGAIN).
75c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
76c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (fd < 0) {
77c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
789e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return -ENODEV;
79c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
80c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  device_fd_.reset(fd);
819e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  ++connection_count_;
82c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
83c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // Check if this connection has the extended control query capability.
84c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  v4l2_query_ext_ctrl query;
85c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
869e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
87c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
88c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // TODO(b/29185945): confirm this is a supported device.
89c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // This is checked by the HAL, but the device at device_path_ may
90c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // not be the same one that was there when the HAL was loaded.
91c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // (Alternatively, better hotplugging support may make this unecessary
92c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // by disabling cameras that get disconnected and checking newly connected
93c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // cameras, so Connect() is never called on an unsupported camera)
9428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
9528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  supported_formats_ = GetSupportedFormats();
9628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  qualified_formats_ = StreamFormat::GetQualifiedFormats(supported_formats_);
9728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
98c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
99c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
100c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
101c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenvoid V4L2Wrapper::Disconnect() {
102c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  HAL_LOG_ENTER();
1039e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  std::lock_guard<std::mutex> lock(connection_lock_);
1049e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
1059e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (connection_count_ == 0) {
1069e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Not connected.
1079e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
108abbf9cc0bd4160642c36f7bd47c0277a8bf17adfAri Hausman-Cohen             device_path_.c_str());
1099e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return;
1109e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
1119e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
1129e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  --connection_count_;
1139e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (connection_count_ > 0) {
1149e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
11528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan             device_path_.c_str(), connection_count_);
1169e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return;
1179e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
118c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
1192d1ea3a164de3d5908b2f3c127b8979e906d37b9Ari Hausman-Cohen  device_fd_.reset(-1);  // Includes close().
120c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  format_.reset();
12128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  {
12228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    std::lock_guard<std::mutex> buffer_lock(buffer_queue_lock_);
12328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    buffers_.clear();
12428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
125c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
126c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
127c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen// Helper function. Should be used instead of ioctl throughout this class.
128c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohentemplate <typename T>
129c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::IoctlLocked(int request, T data) {
1309e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  // Potentially called so many times logging entry is a bad idea.
131c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  std::lock_guard<std::mutex> lock(device_lock_);
132c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
133c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (!connected()) {
134c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("Device %s not connected.", device_path_.c_str());
135c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
136c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
137c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
138c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
139c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
140c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::StreamOn() {
141c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (!format_) {
142c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("Stream format must be set before turning on stream.");
143c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -EINVAL;
144c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
145c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
1464ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  int32_t type = format_->type();
147c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
14828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    HAL_LOGE("STREAMON fails (%d): %s", errno, strerror(errno));
149c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
150c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
151c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
152ad6fe2b033997ab0401b0a519b18cea6e957dac0Ari Hausman-Cohen  HAL_LOGV("Stream turned on.");
153c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
154c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
155c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
156c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::StreamOff() {
157660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  if (!format_) {
158ad6fe2b033997ab0401b0a519b18cea6e957dac0Ari Hausman-Cohen    // Can't have turned on the stream without format being set,
15971cb874e349b296312e6cfb15d419977340b7e94Ari Hausman-Cohen    // so nothing to turn off here.
16071cb874e349b296312e6cfb15d419977340b7e94Ari Hausman-Cohen    return 0;
161660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  }
162660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen
1634ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  int32_t type = format_->type();
1644ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
1654ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  // Calling STREAMOFF releases all queued buffers back to the user.
166c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  // No buffers in flight.
1674ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  if (res < 0) {
168c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
169c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
170c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
17128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::lock_guard<std::mutex> lock(buffer_queue_lock_);
17228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  for (auto& buffer : buffers_) {
17328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    buffer.active = false;
17428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    buffer.request.reset();
1754ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  }
176ad6fe2b033997ab0401b0a519b18cea6e957dac0Ari Hausman-Cohen  HAL_LOGV("Stream turned off.");
177c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
178c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
179c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
180c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::QueryControl(uint32_t control_id,
181c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen                              v4l2_query_ext_ctrl* result) {
182c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  int res;
183c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
184c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  memset(result, 0, sizeof(*result));
185c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
186c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (extended_query_supported_) {
187c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    result->id = control_id;
188c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
189c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    // Assuming the operation was supported (not ENOTTY), no more to do.
190c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    if (errno != ENOTTY) {
191c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      if (res) {
192c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen        HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
193c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen        return -ENODEV;
194c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      }
195c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      return 0;
196c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    }
197c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
198c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
199c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // Extended control querying not supported, fall back to basic control query.
200c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  v4l2_queryctrl query;
201c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  query.id = control_id;
202c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
203c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
204c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
205c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
206c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
207c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // Convert the basic result to the extended result.
208c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->id = query.id;
209c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->type = query.type;
210c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  memcpy(result->name, query.name, sizeof(query.name));
211c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->minimum = query.minimum;
212c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (query.type == V4L2_CTRL_TYPE_BITMASK) {
213c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    // According to the V4L2 documentation, when type is BITMASK,
214c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    // max and default should be interpreted as __u32. Practically,
215c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
216c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    result->maximum = static_cast<uint32_t>(query.maximum);
217c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    result->default_value = static_cast<uint32_t>(query.default_value);
218c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  } else {
219c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    result->maximum = query.maximum;
220c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    result->default_value = query.default_value;
221c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
222c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->step = static_cast<uint32_t>(query.step);
223c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->flags = query.flags;
224c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  result->elems = 1;
225c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  switch (result->type) {
226c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    case V4L2_CTRL_TYPE_INTEGER64:
227c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      result->elem_size = sizeof(int64_t);
228c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      break;
229c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    case V4L2_CTRL_TYPE_STRING:
230c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      result->elem_size = result->maximum + 1;
231c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      break;
232c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    default:
233c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      result->elem_size = sizeof(int32_t);
234c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen      break;
235c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
236c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
237c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
238c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
239c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
240c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohenint V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
2417a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  // For extended controls (any control class other than "user"),
2427a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  // G_EXT_CTRL must be used instead of G_CTRL.
2437a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
2447a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_ext_control control;
2457a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_ext_controls controls;
2467a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    memset(&control, 0, sizeof(control));
2477a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    memset(&controls, 0, sizeof(controls));
2487a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen
2497a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    control.id = control_id;
2507a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
2517a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.count = 1;
2527a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.controls = &control;
2537a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen
2547a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
2557a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
2567a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      return -ENODEV;
2577a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    }
2587a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    *value = control.value;
2597a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  } else {
2607a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_control control{control_id, 0};
2617a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
2627a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      HAL_LOGE("G_CTRL fails: %s", strerror(errno));
2637a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      return -ENODEV;
2647a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    }
2657a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    *value = control.value;
266c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
267c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
268c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
269c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
2705d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohenint V4L2Wrapper::SetControl(uint32_t control_id,
2715d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                            int32_t desired,
272c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen                            int32_t* result) {
2737a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  int32_t result_value = 0;
274c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
27599f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  // TODO(b/29334616): When async, this may need to check if the stream
27699f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  // is on, and if so, lock it off while setting format. Need to look
27799f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  // into if V4L2 supports adjusting controls while the stream is on.
27899f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen
2797a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  // For extended controls (any control class other than "user"),
2807a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  // S_EXT_CTRL must be used instead of S_CTRL.
2817a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
2827a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_ext_control control;
2837a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_ext_controls controls;
2847a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    memset(&control, 0, sizeof(control));
2857a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    memset(&controls, 0, sizeof(controls));
2867a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen
2877a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    control.id = control_id;
2887a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    control.value = desired;
2897a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
2907a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.count = 1;
2917a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    controls.controls = &control;
2927a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen
2937a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
2947a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
2957a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      return -ENODEV;
2967a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    }
2977a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    result_value = control.value;
2987a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen  } else {
2997a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    v4l2_control control{control_id, desired};
3007a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
3017a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      HAL_LOGE("S_CTRL fails: %s", strerror(errno));
3027a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen      return -ENODEV;
3037a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    }
3047a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    result_value = control.value;
305c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
3067a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen
30799f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  // If the caller wants to know the result, pass it back.
30899f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  if (result != nullptr) {
3097a1fba6127333481259d88fd3764e1660e60398bAri Hausman-Cohen    *result = result_value;
31099f3ea02d08d5263214ad3667d7929daa7c6ce27Ari Hausman-Cohen  }
311c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
312c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
313c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
31428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanconst SupportedFormats V4L2Wrapper::GetSupportedFormats() {
31528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  SupportedFormats formats;
31628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::set<uint32_t> pixel_formats;
31728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  int res = GetFormats(&pixel_formats);
31828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (res) {
31928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    HAL_LOGE("Failed to get device formats.");
32028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    return formats;
32128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
32228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
32328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  arc::SupportedFormat supported_format;
32428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::set<std::array<int32_t, 2>> frame_sizes;
32528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
32628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  for (auto pixel_format : pixel_formats) {
32728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    supported_format.fourcc = pixel_format;
32828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
32928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    frame_sizes.clear();
33028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    res = GetFormatFrameSizes(pixel_format, &frame_sizes);
33128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    if (res) {
33228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      HAL_LOGE("Failed to get frame sizes for format: 0x%x", pixel_format);
33328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      continue;
33428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    }
33528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    for (auto frame_size : frame_sizes) {
33628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      supported_format.width = frame_size[0];
33728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      supported_format.height = frame_size[1];
33828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      formats.push_back(supported_format);
33928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    }
34028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
34128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  return formats;
34228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan}
34328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
3449e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohenint V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
3459e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  HAL_LOG_ENTER();
3469e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
3479e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  v4l2_fmtdesc format_query;
3489e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  memset(&format_query, 0, sizeof(format_query));
3499e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  // TODO(b/30000211): multiplanar support.
3509e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3519e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
3529e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    v4l2_formats->insert(format_query.pixelformat);
3539e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    ++format_query.index;
3549e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
3559e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
3569e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (errno != EINVAL) {
3575d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen    HAL_LOGE(
3585d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen        "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
3599e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return -ENODEV;
3609e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
3619e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  return 0;
3629e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen}
3639e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
36428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanint V4L2Wrapper::GetQualifiedFormats(std::vector<uint32_t>* v4l2_formats) {
36528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  HAL_LOG_ENTER();
36628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (!connected()) {
36728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    HAL_LOGE(
36828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan        "Device is not connected, qualified formats may not have been set.");
36928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    return -EINVAL;
37028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
37128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  v4l2_formats->clear();
37228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::set<uint32_t> unique_fourccs;
37328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  for (auto& format : qualified_formats_) {
37428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    unique_fourccs.insert(format.fourcc);
37528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
37628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  v4l2_formats->assign(unique_fourccs.begin(), unique_fourccs.end());
37728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  return 0;
37828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan}
37928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
3809e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohenint V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
3819e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                                     std::set<std::array<int32_t, 2>>* sizes) {
3829e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  v4l2_frmsizeenum size_query;
3839e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  memset(&size_query, 0, sizeof(size_query));
3849e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  size_query.pixel_format = v4l2_format;
3859e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
3869e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
3879e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return -ENODEV;
3889e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
3899e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
3909e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
3919e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Assuming that a driver with discrete frame sizes has a reasonable number
3929e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // of them.
3939e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    do {
3949e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
3959e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                       static_cast<int32_t>(size_query.discrete.height)}}});
3969e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      ++size_query.index;
3979e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
3989e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    if (errno != EINVAL) {
3995d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen      HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
4005d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen               size_query.index,
4019e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen               strerror(errno));
4029e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      return -ENODEV;
4039e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    }
4049e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  } else {
4059e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Continuous/Step-wise: based on the stepwise struct returned by the query.
4069e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Fully listing all possible sizes, with large enough range/small enough
4079e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // step size, may produce far too many potential sizes. Instead, find the
408c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // closest to a set of standard sizes.
409abbf9cc0bd4160642c36f7bd47c0277a8bf17adfAri Hausman-Cohen    for (const auto size : kStandardSizes) {
4109e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      // Find the closest size, rounding up.
4119e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      uint32_t desired_width = size[0];
4129e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      uint32_t desired_height = size[1];
4139e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      if (desired_width < size_query.stepwise.min_width ||
4149e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen          desired_height < size_query.stepwise.min_height) {
4159e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen        HAL_LOGV("Standard size %u x %u is too small for format %d",
4165d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 desired_width,
4175d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 desired_height,
4185d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 v4l2_format);
4199e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen        continue;
420932d4dddd97ca2c690363a2245cfab46dab6496fJaesung Chung      } else if (desired_width > size_query.stepwise.max_width ||
4219e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                 desired_height > size_query.stepwise.max_height) {
4229e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen        HAL_LOGV("Standard size %u x %u is too big for format %d",
4235d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 desired_width,
4245d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 desired_height,
4255d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen                 v4l2_format);
4269e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen        continue;
4279e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      }
4289e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
4299e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      // Round up.
4309e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
4319e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                              size_query.stepwise.step_width - 1) /
4329e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                             size_query.stepwise.step_width;
4339e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
4349e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                               size_query.stepwise.step_height - 1) /
4359e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                              size_query.stepwise.step_height;
4369e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      sizes->insert(
4379e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen          {{{static_cast<int32_t>(size_query.stepwise.min_width +
4389e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                                  width_steps * size_query.stepwise.step_width),
4399e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen             static_cast<int32_t>(size_query.stepwise.min_height +
4409e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                                  height_steps *
4419e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen                                      size_query.stepwise.step_height)}}});
4429e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    }
4439e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
4449e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  return 0;
4459e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen}
4469e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
4479e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen// Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
4489e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Coheninline int64_t FractToNs(const v4l2_fract& fract) {
4499e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  return (1000000000LL * fract.numerator) / fract.denominator;
4509e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen}
4519e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
4529e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohenint V4L2Wrapper::GetFormatFrameDurationRange(
4535d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen    uint32_t v4l2_format,
4545d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen    const std::array<int32_t, 2>& size,
4559e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    std::array<int64_t, 2>* duration_range) {
4569e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  // Potentially called so many times logging entry is a bad idea.
4579e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
4589e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  v4l2_frmivalenum duration_query;
4599e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  memset(&duration_query, 0, sizeof(duration_query));
4609e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  duration_query.pixel_format = v4l2_format;
4619e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  duration_query.width = size[0];
4629e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  duration_query.height = size[1];
4639e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
4649e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
4659e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    return -ENODEV;
4669e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
4679e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
4689e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  int64_t min = std::numeric_limits<int64_t>::max();
4699e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  int64_t max = std::numeric_limits<int64_t>::min();
4709e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
4719e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
4729e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    do {
4739e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      min = std::min(min, FractToNs(duration_query.discrete));
4749e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      max = std::max(max, FractToNs(duration_query.discrete));
4759e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      ++duration_query.index;
4769e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
4779e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    if (errno != EINVAL) {
4789e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
4795d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen               duration_query.index,
4805d7532337a245450434203c5a6cf67005a001208Ari Hausman-Cohen               strerror(errno));
4819e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen      return -ENODEV;
4829e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    }
4839e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  } else {
4849e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    // Continuous/Step-wise: simply convert the given min and max.
4859e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    min = FractToNs(duration_query.stepwise.min);
4869e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    max = FractToNs(duration_query.stepwise.max);
4879e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  }
4889e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  (*duration_range)[0] = min;
4899e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  (*duration_range)[1] = max;
4909e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  return 0;
4919e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen}
4929e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen
493ef52310613342dd51a928af92e3287f6783ae8c7Ari Hausman-Cohenint V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
494660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen                           uint32_t* result_max_buffers) {
495c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  HAL_LOG_ENTER();
496c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
497660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  if (format_ && desired_format == *format_) {
498c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGV("Already in correct format, skipping format setting.");
499a5c9bfde31bd8b7ae541783094e6ed90f842cf32Ari Hausman-Cohen    *result_max_buffers = buffers_.size();
500c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return 0;
501c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
502c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
503c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  if (format_) {
504c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // If we had an old format, first request 0 buffers to inform the device
505c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // we're no longer using any previously "allocated" buffers from the old
506c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // format. This seems like it shouldn't be necessary for USERPTR memory,
507c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // and/or should happen from turning the stream off, but the driver
508c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    // complained. May be a driver issue, or may be intended behavior.
509c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    int res = RequestBuffers(0);
510c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    if (res) {
511c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      return res;
512c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    }
513c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  }
514c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen
51528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Select the matching format, or if not available, select a qualified format
51628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // we can convert from.
51728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  SupportedFormat format;
51828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (!StreamFormat::FindBestFitFormat(supported_formats_, qualified_formats_,
51928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan                                       desired_format.v4l2_pixel_format(),
52028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan                                       desired_format.width(),
52128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan                                       desired_format.height(), &format)) {
52228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    HAL_LOGE(
52328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan        "Unable to find supported resolution in list, "
52428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan        "width: %d, height: %d",
52528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan        desired_format.width(), desired_format.height());
52628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    return -EINVAL;
52728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
52828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
529c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  // Set the camera to the new format.
530c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  v4l2_format new_format;
53128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  const StreamFormat resolved_format(format);
53228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  resolved_format.FillFormatRequest(&new_format);
53328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
534c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // TODO(b/29334616): When async, this will need to check if the stream
535c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // is on, and if so, lock it off while setting format.
536c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
537c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("S_FMT failed: %s", strerror(errno));
538c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
539c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
540c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
541c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // Check that the driver actually set to the requested values.
54228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (resolved_format != new_format) {
543c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("Device doesn't support desired stream configuration.");
544c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -EINVAL;
545c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
546c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
547c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // Keep track of our new format.
548c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  format_.reset(new StreamFormat(new_format));
549c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
550c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  // Format changed, request new buffers.
551c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  int res = RequestBuffers(1);
552660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  if (res) {
553c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    HAL_LOGE("Requesting buffers for new format failed.");
554660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen    return res;
555660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  }
5560fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  *result_max_buffers = buffers_.size();
557c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
558c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
559c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
560c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohenint V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
561c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  v4l2_requestbuffers req_buffers;
562c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  memset(&req_buffers, 0, sizeof(req_buffers));
5634ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  req_buffers.type = format_->type();
564c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  req_buffers.memory = V4L2_MEMORY_USERPTR;
565c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  req_buffers.count = num_requested;
5664ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
5674ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
5684ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  // Calling REQBUFS releases all queued buffers back to the user.
5694ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  if (res < 0) {
570c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    HAL_LOGE("REQBUFS failed: %s", strerror(errno));
571c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen    return -ENODEV;
572c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  }
573c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
574c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  // V4L2 will set req_buffers.count to a number of buffers it can handle.
575c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  if (num_requested > 0 && req_buffers.count < 1) {
576660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen    HAL_LOGE("REQBUFS claims it can't handle any buffers.");
577660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen    return -ENODEV;
578660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  }
57928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  buffers_.resize(req_buffers.count);
580c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen  return 0;
581c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}
582c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen
58328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanint V4L2Wrapper::EnqueueRequest(
58428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    std::shared_ptr<default_camera_hal::CaptureRequest> request) {
585660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  if (!format_) {
586660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen    HAL_LOGE("Stream format must be set before enqueuing buffers.");
587660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen    return -ENODEV;
588660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  }
589660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen
5900fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  // Find a free buffer index. Could use some sort of persistent hinting
5910fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  // here to improve expected efficiency, but buffers_.size() is expected
5920fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  // to be low enough (<10 experimentally) that it's not worth it.
5930fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  int index = -1;
5940fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  {
5950fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    std::lock_guard<std::mutex> guard(buffer_queue_lock_);
59628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    for (size_t i = 0; i < buffers_.size(); ++i) {
59728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      if (!buffers_[i].active) {
5980fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen        index = i;
5990fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen        break;
6000fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen      }
6010fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    }
6020fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  }
6030fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  if (index < 0) {
6040fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    // Note: The HAL should be tracking the number of buffers in flight
6050fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    // for each stream, and should never overflow the device.
6060fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    HAL_LOGE("Cannot enqueue buffer: stream is already full.");
6070fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen    return -ENODEV;
6080fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  }
6090fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen
6104ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  // Set up a v4l2 buffer struct.
6114ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  v4l2_buffer device_buffer;
6124ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  memset(&device_buffer, 0, sizeof(device_buffer));
6134ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  device_buffer.type = format_->type();
6140fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  device_buffer.index = index;
6154ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
6169e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  // Use QUERYBUF to ensure our buffer/device is in good shape,
6179e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen  // and fill out remaining fields.
6184ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
6194ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen    HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
6201fc9b614b86534e5173b7861a2f1284d5eedd9deJaesung Chung    // Return buffer index.
6211fc9b614b86534e5173b7861a2f1284d5eedd9deJaesung Chung    std::lock_guard<std::mutex> guard(buffer_queue_lock_);
62228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    buffers_[index].active = false;
6234ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen    return -ENODEV;
6244ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  }
6254ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
62628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Setup our request context and fill in the user pointer field.
62728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  RequestContext* request_context;
62828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  void* data;
62928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  {
6301fc9b614b86534e5173b7861a2f1284d5eedd9deJaesung Chung    std::lock_guard<std::mutex> guard(buffer_queue_lock_);
63128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context = &buffers_[index];
63228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->camera_buffer->SetDataSize(device_buffer.length);
63328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->camera_buffer->Reset();
63428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->camera_buffer->SetFourcc(format_->v4l2_pixel_format());
63528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->camera_buffer->SetWidth(format_->width());
63628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->camera_buffer->SetHeight(format_->height());
63728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->request = request;
63828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    data = request_context->camera_buffer->GetData();
63928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
64028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  device_buffer.m.userptr = reinterpret_cast<unsigned long>(data);
64128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
64228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Pass the buffer to the camera.
6434ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
6449e6fd989450917be4d506114f1c1d6f1644b0f34Ari Hausman-Cohen    HAL_LOGE("QBUF fails: %s", strerror(errno));
6454ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen    return -ENODEV;
6464ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  }
6474ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
64828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Mark the buffer as in flight.
64928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::lock_guard<std::mutex> guard(buffer_queue_lock_);
65028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  request_context->active = true;
65128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
6524ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  return 0;
6534ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen}
6544ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
65528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanint V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request) {
656660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  if (!format_) {
657c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    HAL_LOGV(
658c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen        "Format not set, so stream can't be on, "
659c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen        "so no buffers available for dequeueing");
660c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    return -EAGAIN;
661660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen  }
662660f8b858d6523064f150fd54a163b9673d685e1Ari Hausman-Cohen
663c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  v4l2_buffer buffer;
664c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  memset(&buffer, 0, sizeof(buffer));
665c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  buffer.type = format_->type();
666c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  buffer.memory = V4L2_MEMORY_USERPTR;
667c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
668c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  if (res) {
669c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    if (errno == EAGAIN) {
670c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      // Expected failure.
671c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      return -EAGAIN;
672c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    } else {
673c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      // Unexpected failure.
674c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      HAL_LOGE("DQBUF fails: %s", strerror(errno));
675c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen      return -ENODEV;
676c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen    }
6774ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  }
6784ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
67928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::lock_guard<std::mutex> guard(buffer_queue_lock_);
68028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  RequestContext* request_context = &buffers_[buffer.index];
68128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
68228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Lock the camera stream buffer for painting.
68328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  const camera3_stream_buffer_t* stream_buffer =
68428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      &request_context->request->output_buffers[0];
68528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  uint32_t fourcc =
68628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      StreamFormat::HalToV4L2PixelFormat(stream_buffer->stream->format);
68728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
68828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (request) {
68928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    *request = request_context->request;
6900fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen  }
6910fbcaf53ca9802fd58f1a51ac94be70a50cbcd04Ari Hausman-Cohen
69228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Note that the device buffer length is passed to the output frame. If the
69328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // GrallocFrameBuffer does not have support for the transformation to
69428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // |fourcc|, it will assume that the amount of data to lock is based on
69528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // |buffer.length|, otherwise it will use the ImageProcessor::ConvertedSize.
69628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  arc::GrallocFrameBuffer output_frame(
69728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      *stream_buffer->buffer, stream_buffer->stream->width,
69828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      stream_buffer->stream->height, fourcc, buffer.length,
69928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      stream_buffer->stream->usage);
70028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  res = output_frame.Map();
7014ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  if (res) {
70228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    HAL_LOGE("Failed to map output frame.");
70328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    request_context->request.reset();
70428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    return -EINVAL;
7054ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  }
70628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  if (request_context->camera_buffer->GetFourcc() == fourcc &&
70728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      request_context->camera_buffer->GetWidth() ==
70828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan          stream_buffer->stream->width &&
70928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      request_context->camera_buffer->GetHeight() ==
71028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan          stream_buffer->stream->height) {
71128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    // If no format conversion needs to be applied, directly copy the data over.
71228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    memcpy(output_frame.GetData(), request_context->camera_buffer->GetData(),
71328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan           request_context->camera_buffer->GetDataSize());
71428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  } else {
71528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    // Perform the format conversion.
71628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    arc::CachedFrame cached_frame;
71728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    cached_frame.SetSource(request_context->camera_buffer.get(), 0);
71828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    cached_frame.Convert(request_context->request->settings, &output_frame);
719c5a485245169c1da02c4a5bfb80876cff68882ebAri Hausman-Cohen  }
72028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
72128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  request_context->request.reset();
72228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  // Mark the buffer as not in flight.
72328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  request_context->active = false;
7244ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen  return 0;
7254ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen}
7264ab49624207319ac99a75d7272d968c172064422Ari Hausman-Cohen
72728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathanint V4L2Wrapper::GetInFlightBufferCount() {
72828e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  int count = 0;
72928e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  std::lock_guard<std::mutex> guard(buffer_queue_lock_);
73028e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  for (auto& buffer : buffers_) {
73128e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    if (buffer.active) {
73228e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan      count++;
73328e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan    }
73428e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  }
73528e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan  return count;
73628e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan}
73728e0f76353e06b24b7dae54e636dbb5ddc64d1a5Prashanth Swaminathan
738c17fd09be838b093d3de3033c3a65a75b1813e19Ari Hausman-Cohen}  // namespace v4l2_camera_hal
739