blob: d715e7ec1c172c21629ca93668304a401b7f7618 [file] [log] [blame]
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -07001/*
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
Ari Hausman-Cohen3841a7f2016-07-19 17:27:52 -070017#include "v4l2_wrapper.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070018
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070019#include <algorithm>
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -070020#include <array>
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070021#include <limits>
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -070022#include <mutex>
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070023#include <vector>
24
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070025#include <fcntl.h>
26#include <linux/videodev2.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -070030#include <android-base/unique_fd.h>
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070031
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070032#include "arc/cached_frame.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070033
34namespace v4l2_camera_hal {
35
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070036using arc::AllocatedFrameBuffer;
37using arc::SupportedFormat;
38using arc::SupportedFormats;
39using default_camera_hal::CaptureRequest;
40
Jaesung Chung932d4dd2017-12-15 15:27:21 +090041const int32_t kStandardSizes[][2] = {
42 {4096, 2160}, // 4KDCI (for USB camera)
43 {3840, 2160}, // 4KUHD (for USB camera)
44 {3280, 2464}, // 8MP
45 {2560, 1440}, // QHD
46 {1920, 1080}, // HD1080
47 {1640, 1232}, // 2MP
48 {1280, 720}, // HD
49 {1024, 768}, // XGA
50 { 640, 480}, // VGA
51 { 320, 240}, // QVGA
52 { 176, 144} // QCIF
53};
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070054
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070055V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070056 return new V4L2Wrapper(device_path);
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070057}
58
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070059V4L2Wrapper::V4L2Wrapper(const std::string device_path)
60 : device_path_(std::move(device_path)), connection_count_(0) {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070061
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -080062V4L2Wrapper::~V4L2Wrapper() {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070063
64int V4L2Wrapper::Connect() {
65 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070066 std::lock_guard<std::mutex> lock(connection_lock_);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070067
68 if (connected()) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070069 HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
70 ++connection_count_;
71 return 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070072 }
73
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -080074 // Open in nonblocking mode (DQBUF may return EAGAIN).
75 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070076 if (fd < 0) {
77 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070078 return -ENODEV;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070079 }
80 device_fd_.reset(fd);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070081 ++connection_count_;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070082
83 // Check if this connection has the extended control query capability.
84 v4l2_query_ext_ctrl query;
85 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070086 extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070087
88 // TODO(b/29185945): confirm this is a supported device.
89 // This is checked by the HAL, but the device at device_path_ may
90 // not be the same one that was there when the HAL was loaded.
91 // (Alternatively, better hotplugging support may make this unecessary
92 // by disabling cameras that get disconnected and checking newly connected
93 // cameras, so Connect() is never called on an unsupported camera)
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070094
95 supported_formats_ = GetSupportedFormats();
96 qualified_formats_ = StreamFormat::GetQualifiedFormats(supported_formats_);
97
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070098 return 0;
99}
100
101void V4L2Wrapper::Disconnect() {
102 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700103 std::lock_guard<std::mutex> lock(connection_lock_);
104
105 if (connection_count_ == 0) {
106 // Not connected.
107 HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700108 device_path_.c_str());
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700109 return;
110 }
111
112 --connection_count_;
113 if (connection_count_ > 0) {
114 HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700115 device_path_.c_str(), connection_count_);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700116 return;
117 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700118
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -0700119 device_fd_.reset(-1); // Includes close().
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700120 format_.reset();
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700121 {
122 std::lock_guard<std::mutex> buffer_lock(buffer_queue_lock_);
123 buffers_.clear();
124 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700125}
126
127// Helper function. Should be used instead of ioctl throughout this class.
128template <typename T>
129int V4L2Wrapper::IoctlLocked(int request, T data) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700130 // Potentially called so many times logging entry is a bad idea.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700131 std::lock_guard<std::mutex> lock(device_lock_);
132
133 if (!connected()) {
134 HAL_LOGE("Device %s not connected.", device_path_.c_str());
135 return -ENODEV;
136 }
137 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
138}
139
140int V4L2Wrapper::StreamOn() {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700141 if (!format_) {
142 HAL_LOGE("Stream format must be set before turning on stream.");
143 return -EINVAL;
144 }
145
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700146 int32_t type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700147 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700148 HAL_LOGE("STREAMON fails (%d): %s", errno, strerror(errno));
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700149 return -ENODEV;
150 }
151
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800152 HAL_LOGV("Stream turned on.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700153 return 0;
154}
155
156int V4L2Wrapper::StreamOff() {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700157 if (!format_) {
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800158 // Can't have turned on the stream without format being set,
Ari Hausman-Cohen71cb8742016-09-22 11:12:00 -0700159 // so nothing to turn off here.
160 return 0;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700161 }
162
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700163 int32_t type = format_->type();
164 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
165 // Calling STREAMOFF releases all queued buffers back to the user.
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800166 // No buffers in flight.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700167 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700168 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
169 return -ENODEV;
170 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700171 std::lock_guard<std::mutex> lock(buffer_queue_lock_);
172 for (auto& buffer : buffers_) {
173 buffer.active = false;
174 buffer.request.reset();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700175 }
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800176 HAL_LOGV("Stream turned off.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700177 return 0;
178}
179
180int V4L2Wrapper::QueryControl(uint32_t control_id,
181 v4l2_query_ext_ctrl* result) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700182 int res;
183
184 memset(result, 0, sizeof(*result));
185
186 if (extended_query_supported_) {
187 result->id = control_id;
188 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
189 // Assuming the operation was supported (not ENOTTY), no more to do.
190 if (errno != ENOTTY) {
191 if (res) {
192 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
193 return -ENODEV;
194 }
195 return 0;
196 }
197 }
198
199 // Extended control querying not supported, fall back to basic control query.
200 v4l2_queryctrl query;
201 query.id = control_id;
202 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
203 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
204 return -ENODEV;
205 }
206
207 // Convert the basic result to the extended result.
208 result->id = query.id;
209 result->type = query.type;
210 memcpy(result->name, query.name, sizeof(query.name));
211 result->minimum = query.minimum;
212 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
213 // According to the V4L2 documentation, when type is BITMASK,
214 // max and default should be interpreted as __u32. Practically,
215 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
216 result->maximum = static_cast<uint32_t>(query.maximum);
217 result->default_value = static_cast<uint32_t>(query.default_value);
218 } else {
219 result->maximum = query.maximum;
220 result->default_value = query.default_value;
221 }
222 result->step = static_cast<uint32_t>(query.step);
223 result->flags = query.flags;
224 result->elems = 1;
225 switch (result->type) {
226 case V4L2_CTRL_TYPE_INTEGER64:
227 result->elem_size = sizeof(int64_t);
228 break;
229 case V4L2_CTRL_TYPE_STRING:
230 result->elem_size = result->maximum + 1;
231 break;
232 default:
233 result->elem_size = sizeof(int32_t);
234 break;
235 }
236
237 return 0;
238}
239
240int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700241 // For extended controls (any control class other than "user"),
242 // G_EXT_CTRL must be used instead of G_CTRL.
243 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
244 v4l2_ext_control control;
245 v4l2_ext_controls controls;
246 memset(&control, 0, sizeof(control));
247 memset(&controls, 0, sizeof(controls));
248
249 control.id = control_id;
250 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
251 controls.count = 1;
252 controls.controls = &control;
253
254 if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
255 HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
256 return -ENODEV;
257 }
258 *value = control.value;
259 } else {
260 v4l2_control control{control_id, 0};
261 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
262 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
263 return -ENODEV;
264 }
265 *value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700266 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700267 return 0;
268}
269
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700270int V4L2Wrapper::SetControl(uint32_t control_id,
271 int32_t desired,
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700272 int32_t* result) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700273 int32_t result_value = 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700274
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700275 // TODO(b/29334616): When async, this may need to check if the stream
276 // is on, and if so, lock it off while setting format. Need to look
277 // into if V4L2 supports adjusting controls while the stream is on.
278
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700279 // For extended controls (any control class other than "user"),
280 // S_EXT_CTRL must be used instead of S_CTRL.
281 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
282 v4l2_ext_control control;
283 v4l2_ext_controls controls;
284 memset(&control, 0, sizeof(control));
285 memset(&controls, 0, sizeof(controls));
286
287 control.id = control_id;
288 control.value = desired;
289 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
290 controls.count = 1;
291 controls.controls = &control;
292
293 if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
294 HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
295 return -ENODEV;
296 }
297 result_value = control.value;
298 } else {
299 v4l2_control control{control_id, desired};
300 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
301 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
302 return -ENODEV;
303 }
304 result_value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700305 }
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700306
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700307 // If the caller wants to know the result, pass it back.
308 if (result != nullptr) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700309 *result = result_value;
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700310 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700311 return 0;
312}
313
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700314const SupportedFormats V4L2Wrapper::GetSupportedFormats() {
315 SupportedFormats formats;
316 std::set<uint32_t> pixel_formats;
317 int res = GetFormats(&pixel_formats);
318 if (res) {
319 HAL_LOGE("Failed to get device formats.");
320 return formats;
321 }
322
323 arc::SupportedFormat supported_format;
324 std::set<std::array<int32_t, 2>> frame_sizes;
325
326 for (auto pixel_format : pixel_formats) {
327 supported_format.fourcc = pixel_format;
328
329 frame_sizes.clear();
330 res = GetFormatFrameSizes(pixel_format, &frame_sizes);
331 if (res) {
332 HAL_LOGE("Failed to get frame sizes for format: 0x%x", pixel_format);
333 continue;
334 }
335 for (auto frame_size : frame_sizes) {
336 supported_format.width = frame_size[0];
337 supported_format.height = frame_size[1];
338 formats.push_back(supported_format);
339 }
340 }
341 return formats;
342}
343
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700344int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
345 HAL_LOG_ENTER();
346
347 v4l2_fmtdesc format_query;
348 memset(&format_query, 0, sizeof(format_query));
349 // TODO(b/30000211): multiplanar support.
350 format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
351 while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
352 v4l2_formats->insert(format_query.pixelformat);
353 ++format_query.index;
354 }
355
356 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700357 HAL_LOGE(
358 "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700359 return -ENODEV;
360 }
361 return 0;
362}
363
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700364int V4L2Wrapper::GetQualifiedFormats(std::vector<uint32_t>* v4l2_formats) {
365 HAL_LOG_ENTER();
366 if (!connected()) {
367 HAL_LOGE(
368 "Device is not connected, qualified formats may not have been set.");
369 return -EINVAL;
370 }
371 v4l2_formats->clear();
372 std::set<uint32_t> unique_fourccs;
373 for (auto& format : qualified_formats_) {
374 unique_fourccs.insert(format.fourcc);
375 }
376 v4l2_formats->assign(unique_fourccs.begin(), unique_fourccs.end());
377 return 0;
378}
379
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700380int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
381 std::set<std::array<int32_t, 2>>* sizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700382 v4l2_frmsizeenum size_query;
383 memset(&size_query, 0, sizeof(size_query));
384 size_query.pixel_format = v4l2_format;
385 if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
386 HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
387 return -ENODEV;
388 }
389 if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
390 // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
391 // Assuming that a driver with discrete frame sizes has a reasonable number
392 // of them.
393 do {
394 sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
395 static_cast<int32_t>(size_query.discrete.height)}}});
396 ++size_query.index;
397 } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
398 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700399 HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
400 size_query.index,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700401 strerror(errno));
402 return -ENODEV;
403 }
404 } else {
405 // Continuous/Step-wise: based on the stepwise struct returned by the query.
406 // Fully listing all possible sizes, with large enough range/small enough
407 // step size, may produce far too many potential sizes. Instead, find the
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800408 // closest to a set of standard sizes.
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700409 for (const auto size : kStandardSizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700410 // Find the closest size, rounding up.
411 uint32_t desired_width = size[0];
412 uint32_t desired_height = size[1];
413 if (desired_width < size_query.stepwise.min_width ||
414 desired_height < size_query.stepwise.min_height) {
415 HAL_LOGV("Standard size %u x %u is too small for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700416 desired_width,
417 desired_height,
418 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700419 continue;
Jaesung Chung932d4dd2017-12-15 15:27:21 +0900420 } else if (desired_width > size_query.stepwise.max_width ||
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700421 desired_height > size_query.stepwise.max_height) {
422 HAL_LOGV("Standard size %u x %u is too big for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700423 desired_width,
424 desired_height,
425 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700426 continue;
427 }
428
429 // Round up.
430 uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
431 size_query.stepwise.step_width - 1) /
432 size_query.stepwise.step_width;
433 uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
434 size_query.stepwise.step_height - 1) /
435 size_query.stepwise.step_height;
436 sizes->insert(
437 {{{static_cast<int32_t>(size_query.stepwise.min_width +
438 width_steps * size_query.stepwise.step_width),
439 static_cast<int32_t>(size_query.stepwise.min_height +
440 height_steps *
441 size_query.stepwise.step_height)}}});
442 }
443 }
444 return 0;
445}
446
447// Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
448inline int64_t FractToNs(const v4l2_fract& fract) {
449 return (1000000000LL * fract.numerator) / fract.denominator;
450}
451
452int V4L2Wrapper::GetFormatFrameDurationRange(
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700453 uint32_t v4l2_format,
454 const std::array<int32_t, 2>& size,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700455 std::array<int64_t, 2>* duration_range) {
456 // Potentially called so many times logging entry is a bad idea.
457
458 v4l2_frmivalenum duration_query;
459 memset(&duration_query, 0, sizeof(duration_query));
460 duration_query.pixel_format = v4l2_format;
461 duration_query.width = size[0];
462 duration_query.height = size[1];
463 if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
464 HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
465 return -ENODEV;
466 }
467
468 int64_t min = std::numeric_limits<int64_t>::max();
469 int64_t max = std::numeric_limits<int64_t>::min();
470 if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
471 // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
472 do {
473 min = std::min(min, FractToNs(duration_query.discrete));
474 max = std::max(max, FractToNs(duration_query.discrete));
475 ++duration_query.index;
476 } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
477 if (errno != EINVAL) {
478 HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700479 duration_query.index,
480 strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700481 return -ENODEV;
482 }
483 } else {
484 // Continuous/Step-wise: simply convert the given min and max.
485 min = FractToNs(duration_query.stepwise.min);
486 max = FractToNs(duration_query.stepwise.max);
487 }
488 (*duration_range)[0] = min;
489 (*duration_range)[1] = max;
490 return 0;
491}
492
Ari Hausman-Cohenef523102016-11-21 17:02:01 -0800493int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700494 uint32_t* result_max_buffers) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700495 HAL_LOG_ENTER();
496
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700497 if (format_ && desired_format == *format_) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700498 HAL_LOGV("Already in correct format, skipping format setting.");
Ari Hausman-Cohena5c9bfd2016-11-18 14:57:07 -0800499 *result_max_buffers = buffers_.size();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700500 return 0;
501 }
502
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800503 if (format_) {
504 // If we had an old format, first request 0 buffers to inform the device
505 // we're no longer using any previously "allocated" buffers from the old
506 // format. This seems like it shouldn't be necessary for USERPTR memory,
507 // and/or should happen from turning the stream off, but the driver
508 // complained. May be a driver issue, or may be intended behavior.
509 int res = RequestBuffers(0);
510 if (res) {
511 return res;
512 }
513 }
514
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700515 // Select the matching format, or if not available, select a qualified format
516 // we can convert from.
517 SupportedFormat format;
518 if (!StreamFormat::FindBestFitFormat(supported_formats_, qualified_formats_,
519 desired_format.v4l2_pixel_format(),
520 desired_format.width(),
521 desired_format.height(), &format)) {
522 HAL_LOGE(
523 "Unable to find supported resolution in list, "
524 "width: %d, height: %d",
525 desired_format.width(), desired_format.height());
526 return -EINVAL;
527 }
528
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800529 // Set the camera to the new format.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700530 v4l2_format new_format;
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700531 const StreamFormat resolved_format(format);
532 resolved_format.FillFormatRequest(&new_format);
533
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700534 // TODO(b/29334616): When async, this will need to check if the stream
535 // is on, and if so, lock it off while setting format.
536 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
537 HAL_LOGE("S_FMT failed: %s", strerror(errno));
538 return -ENODEV;
539 }
540
541 // Check that the driver actually set to the requested values.
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700542 if (resolved_format != new_format) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700543 HAL_LOGE("Device doesn't support desired stream configuration.");
544 return -EINVAL;
545 }
546
547 // Keep track of our new format.
548 format_.reset(new StreamFormat(new_format));
549
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800550 // Format changed, request new buffers.
551 int res = RequestBuffers(1);
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700552 if (res) {
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800553 HAL_LOGE("Requesting buffers for new format failed.");
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700554 return res;
555 }
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700556 *result_max_buffers = buffers_.size();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700557 return 0;
558}
559
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800560int V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700561 v4l2_requestbuffers req_buffers;
562 memset(&req_buffers, 0, sizeof(req_buffers));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700563 req_buffers.type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700564 req_buffers.memory = V4L2_MEMORY_USERPTR;
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800565 req_buffers.count = num_requested;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700566
567 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
568 // Calling REQBUFS releases all queued buffers back to the user.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700569 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700570 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
571 return -ENODEV;
572 }
573
574 // V4L2 will set req_buffers.count to a number of buffers it can handle.
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800575 if (num_requested > 0 && req_buffers.count < 1) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700576 HAL_LOGE("REQBUFS claims it can't handle any buffers.");
577 return -ENODEV;
578 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700579 buffers_.resize(req_buffers.count);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700580 return 0;
581}
582
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700583int V4L2Wrapper::EnqueueRequest(
584 std::shared_ptr<default_camera_hal::CaptureRequest> request) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700585 if (!format_) {
586 HAL_LOGE("Stream format must be set before enqueuing buffers.");
587 return -ENODEV;
588 }
589
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700590 // Find a free buffer index. Could use some sort of persistent hinting
591 // here to improve expected efficiency, but buffers_.size() is expected
592 // to be low enough (<10 experimentally) that it's not worth it.
593 int index = -1;
594 {
595 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700596 for (size_t i = 0; i < buffers_.size(); ++i) {
597 if (!buffers_[i].active) {
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700598 index = i;
599 break;
600 }
601 }
602 }
603 if (index < 0) {
604 // Note: The HAL should be tracking the number of buffers in flight
605 // for each stream, and should never overflow the device.
606 HAL_LOGE("Cannot enqueue buffer: stream is already full.");
607 return -ENODEV;
608 }
609
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700610 // Set up a v4l2 buffer struct.
611 v4l2_buffer device_buffer;
612 memset(&device_buffer, 0, sizeof(device_buffer));
613 device_buffer.type = format_->type();
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700614 device_buffer.index = index;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700615
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700616 // Use QUERYBUF to ensure our buffer/device is in good shape,
617 // and fill out remaining fields.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700618 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
619 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
Jaesung Chung1fc9b612017-11-10 18:09:38 +0900620 // Return buffer index.
621 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700622 buffers_[index].active = false;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700623 return -ENODEV;
624 }
625
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700626 // Setup our request context and fill in the user pointer field.
627 RequestContext* request_context;
628 void* data;
629 {
Jaesung Chung1fc9b612017-11-10 18:09:38 +0900630 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700631 request_context = &buffers_[index];
632 request_context->camera_buffer->SetDataSize(device_buffer.length);
633 request_context->camera_buffer->Reset();
634 request_context->camera_buffer->SetFourcc(format_->v4l2_pixel_format());
635 request_context->camera_buffer->SetWidth(format_->width());
636 request_context->camera_buffer->SetHeight(format_->height());
637 request_context->request = request;
638 data = request_context->camera_buffer->GetData();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700639 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700640 device_buffer.m.userptr = reinterpret_cast<unsigned long>(data);
641
642 // Pass the buffer to the camera.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700643 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700644 HAL_LOGE("QBUF fails: %s", strerror(errno));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700645 return -ENODEV;
646 }
647
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700648 // Mark the buffer as in flight.
649 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
650 request_context->active = true;
651
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700652 return 0;
653}
654
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700655int V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700656 if (!format_) {
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800657 HAL_LOGV(
658 "Format not set, so stream can't be on, "
659 "so no buffers available for dequeueing");
660 return -EAGAIN;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700661 }
662
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800663 v4l2_buffer buffer;
664 memset(&buffer, 0, sizeof(buffer));
665 buffer.type = format_->type();
666 buffer.memory = V4L2_MEMORY_USERPTR;
667 int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
668 if (res) {
669 if (errno == EAGAIN) {
670 // Expected failure.
671 return -EAGAIN;
672 } else {
673 // Unexpected failure.
674 HAL_LOGE("DQBUF fails: %s", strerror(errno));
675 return -ENODEV;
676 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700677 }
678
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700679 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
680 RequestContext* request_context = &buffers_[buffer.index];
681
682 // Lock the camera stream buffer for painting.
683 const camera3_stream_buffer_t* stream_buffer =
684 &request_context->request->output_buffers[0];
685 uint32_t fourcc =
686 StreamFormat::HalToV4L2PixelFormat(stream_buffer->stream->format);
687
688 if (request) {
689 *request = request_context->request;
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700690 }
691
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700692 // Note that the device buffer length is passed to the output frame. If the
693 // GrallocFrameBuffer does not have support for the transformation to
694 // |fourcc|, it will assume that the amount of data to lock is based on
695 // |buffer.length|, otherwise it will use the ImageProcessor::ConvertedSize.
696 arc::GrallocFrameBuffer output_frame(
697 *stream_buffer->buffer, stream_buffer->stream->width,
698 stream_buffer->stream->height, fourcc, buffer.length,
699 stream_buffer->stream->usage);
700 res = output_frame.Map();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700701 if (res) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700702 HAL_LOGE("Failed to map output frame.");
703 request_context->request.reset();
704 return -EINVAL;
705 }
706 if (request_context->camera_buffer->GetFourcc() == fourcc &&
707 request_context->camera_buffer->GetWidth() ==
708 stream_buffer->stream->width &&
709 request_context->camera_buffer->GetHeight() ==
710 stream_buffer->stream->height) {
711 // If no format conversion needs to be applied, directly copy the data over.
712 memcpy(output_frame.GetData(), request_context->camera_buffer->GetData(),
713 request_context->camera_buffer->GetDataSize());
714 } else {
715 // Perform the format conversion.
716 arc::CachedFrame cached_frame;
717 cached_frame.SetSource(request_context->camera_buffer.get(), 0);
718 cached_frame.Convert(request_context->request->settings, &output_frame);
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700719 }
720
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700721 request_context->request.reset();
722 // Mark the buffer as not in flight.
723 request_context->active = false;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700724 return 0;
725}
726
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700727int V4L2Wrapper::GetInFlightBufferCount() {
728 int count = 0;
729 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
730 for (auto& buffer : buffers_) {
731 if (buffer.active) {
732 count++;
733 }
734 }
735 return count;
736}
737
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700738} // namespace v4l2_camera_hal