blob: 085683d6e35b907159998d1e713ab63f8771b7cc [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
Sergii Piatakov2ad591f2018-08-03 11:41:06 +030017//#define LOG_NDEBUG 0
18#define LOG_TAG "V4L2Wrapper"
19
Ari Hausman-Cohen3841a7f2016-07-19 17:27:52 -070020#include "v4l2_wrapper.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070021
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070022#include <algorithm>
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -070023#include <array>
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070024#include <limits>
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -070025#include <mutex>
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070026#include <vector>
27
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070028#include <fcntl.h>
29#include <linux/videodev2.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -070033#include <android-base/unique_fd.h>
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070034
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070035#include "arc/cached_frame.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070036
37namespace v4l2_camera_hal {
38
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070039using arc::AllocatedFrameBuffer;
40using arc::SupportedFormat;
41using arc::SupportedFormats;
42using default_camera_hal::CaptureRequest;
43
Jaesung Chung932d4dd2017-12-15 15:27:21 +090044const int32_t kStandardSizes[][2] = {
45 {4096, 2160}, // 4KDCI (for USB camera)
46 {3840, 2160}, // 4KUHD (for USB camera)
47 {3280, 2464}, // 8MP
48 {2560, 1440}, // QHD
49 {1920, 1080}, // HD1080
50 {1640, 1232}, // 2MP
51 {1280, 720}, // HD
52 {1024, 768}, // XGA
53 { 640, 480}, // VGA
54 { 320, 240}, // QVGA
55 { 176, 144} // QCIF
56};
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070057
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070058V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070059 return new V4L2Wrapper(device_path);
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070060}
61
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070062V4L2Wrapper::V4L2Wrapper(const std::string device_path)
63 : device_path_(std::move(device_path)), connection_count_(0) {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070064
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -080065V4L2Wrapper::~V4L2Wrapper() {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070066
67int V4L2Wrapper::Connect() {
68 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070069 std::lock_guard<std::mutex> lock(connection_lock_);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070070
71 if (connected()) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070072 HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
73 ++connection_count_;
74 return 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070075 }
76
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -080077 // Open in nonblocking mode (DQBUF may return EAGAIN).
78 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070079 if (fd < 0) {
80 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070081 return -ENODEV;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070082 }
83 device_fd_.reset(fd);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070084 ++connection_count_;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070085
86 // Check if this connection has the extended control query capability.
87 v4l2_query_ext_ctrl query;
88 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070089 extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070090
91 // TODO(b/29185945): confirm this is a supported device.
92 // This is checked by the HAL, but the device at device_path_ may
93 // not be the same one that was there when the HAL was loaded.
94 // (Alternatively, better hotplugging support may make this unecessary
95 // by disabling cameras that get disconnected and checking newly connected
96 // cameras, so Connect() is never called on an unsupported camera)
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -070097
98 supported_formats_ = GetSupportedFormats();
99 qualified_formats_ = StreamFormat::GetQualifiedFormats(supported_formats_);
100
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700101 return 0;
102}
103
104void V4L2Wrapper::Disconnect() {
105 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700106 std::lock_guard<std::mutex> lock(connection_lock_);
107
108 if (connection_count_ == 0) {
109 // Not connected.
110 HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700111 device_path_.c_str());
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700112 return;
113 }
114
115 --connection_count_;
116 if (connection_count_ > 0) {
117 HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700118 device_path_.c_str(), connection_count_);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700119 return;
120 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700121
Ari Hausman-Cohen2d1ea3a2017-03-24 18:38:16 -0700122 device_fd_.reset(-1); // Includes close().
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700123 format_.reset();
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700124 {
125 std::lock_guard<std::mutex> buffer_lock(buffer_queue_lock_);
126 buffers_.clear();
127 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700128}
129
130// Helper function. Should be used instead of ioctl throughout this class.
131template <typename T>
132int V4L2Wrapper::IoctlLocked(int request, T data) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700133 // Potentially called so many times logging entry is a bad idea.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700134 std::lock_guard<std::mutex> lock(device_lock_);
135
136 if (!connected()) {
137 HAL_LOGE("Device %s not connected.", device_path_.c_str());
138 return -ENODEV;
139 }
140 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
141}
142
143int V4L2Wrapper::StreamOn() {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700144 if (!format_) {
145 HAL_LOGE("Stream format must be set before turning on stream.");
146 return -EINVAL;
147 }
148
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700149 int32_t type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700150 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700151 HAL_LOGE("STREAMON fails (%d): %s", errno, strerror(errno));
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700152 return -ENODEV;
153 }
154
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800155 HAL_LOGV("Stream turned on.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700156 return 0;
157}
158
159int V4L2Wrapper::StreamOff() {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700160 if (!format_) {
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800161 // Can't have turned on the stream without format being set,
Ari Hausman-Cohen71cb8742016-09-22 11:12:00 -0700162 // so nothing to turn off here.
163 return 0;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700164 }
165
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700166 int32_t type = format_->type();
167 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
168 // Calling STREAMOFF releases all queued buffers back to the user.
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800169 // No buffers in flight.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700170 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700171 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
172 return -ENODEV;
173 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700174 std::lock_guard<std::mutex> lock(buffer_queue_lock_);
175 for (auto& buffer : buffers_) {
176 buffer.active = false;
177 buffer.request.reset();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700178 }
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800179 HAL_LOGV("Stream turned off.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700180 return 0;
181}
182
183int V4L2Wrapper::QueryControl(uint32_t control_id,
184 v4l2_query_ext_ctrl* result) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700185 int res;
186
187 memset(result, 0, sizeof(*result));
188
189 if (extended_query_supported_) {
190 result->id = control_id;
191 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
192 // Assuming the operation was supported (not ENOTTY), no more to do.
193 if (errno != ENOTTY) {
194 if (res) {
195 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
196 return -ENODEV;
197 }
198 return 0;
199 }
200 }
201
202 // Extended control querying not supported, fall back to basic control query.
203 v4l2_queryctrl query;
204 query.id = control_id;
205 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
206 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
207 return -ENODEV;
208 }
209
210 // Convert the basic result to the extended result.
211 result->id = query.id;
212 result->type = query.type;
213 memcpy(result->name, query.name, sizeof(query.name));
214 result->minimum = query.minimum;
215 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
216 // According to the V4L2 documentation, when type is BITMASK,
217 // max and default should be interpreted as __u32. Practically,
218 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
219 result->maximum = static_cast<uint32_t>(query.maximum);
220 result->default_value = static_cast<uint32_t>(query.default_value);
221 } else {
222 result->maximum = query.maximum;
223 result->default_value = query.default_value;
224 }
225 result->step = static_cast<uint32_t>(query.step);
226 result->flags = query.flags;
227 result->elems = 1;
228 switch (result->type) {
229 case V4L2_CTRL_TYPE_INTEGER64:
230 result->elem_size = sizeof(int64_t);
231 break;
232 case V4L2_CTRL_TYPE_STRING:
233 result->elem_size = result->maximum + 1;
234 break;
235 default:
236 result->elem_size = sizeof(int32_t);
237 break;
238 }
239
240 return 0;
241}
242
243int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700244 // For extended controls (any control class other than "user"),
245 // G_EXT_CTRL must be used instead of G_CTRL.
246 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
247 v4l2_ext_control control;
248 v4l2_ext_controls controls;
249 memset(&control, 0, sizeof(control));
250 memset(&controls, 0, sizeof(controls));
251
252 control.id = control_id;
253 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
254 controls.count = 1;
255 controls.controls = &control;
256
257 if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
258 HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
259 return -ENODEV;
260 }
261 *value = control.value;
262 } else {
263 v4l2_control control{control_id, 0};
264 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
265 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
266 return -ENODEV;
267 }
268 *value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700269 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700270 return 0;
271}
272
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700273int V4L2Wrapper::SetControl(uint32_t control_id,
274 int32_t desired,
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700275 int32_t* result) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700276 int32_t result_value = 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700277
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700278 // TODO(b/29334616): When async, this may need to check if the stream
279 // is on, and if so, lock it off while setting format. Need to look
280 // into if V4L2 supports adjusting controls while the stream is on.
281
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700282 // For extended controls (any control class other than "user"),
283 // S_EXT_CTRL must be used instead of S_CTRL.
284 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
285 v4l2_ext_control control;
286 v4l2_ext_controls controls;
287 memset(&control, 0, sizeof(control));
288 memset(&controls, 0, sizeof(controls));
289
290 control.id = control_id;
291 control.value = desired;
292 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
293 controls.count = 1;
294 controls.controls = &control;
295
296 if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
297 HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
298 return -ENODEV;
299 }
300 result_value = control.value;
301 } else {
302 v4l2_control control{control_id, desired};
303 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
304 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
305 return -ENODEV;
306 }
307 result_value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700308 }
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700309
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700310 // If the caller wants to know the result, pass it back.
311 if (result != nullptr) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700312 *result = result_value;
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700313 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700314 return 0;
315}
316
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700317const SupportedFormats V4L2Wrapper::GetSupportedFormats() {
318 SupportedFormats formats;
319 std::set<uint32_t> pixel_formats;
320 int res = GetFormats(&pixel_formats);
321 if (res) {
322 HAL_LOGE("Failed to get device formats.");
323 return formats;
324 }
325
326 arc::SupportedFormat supported_format;
327 std::set<std::array<int32_t, 2>> frame_sizes;
328
329 for (auto pixel_format : pixel_formats) {
330 supported_format.fourcc = pixel_format;
331
332 frame_sizes.clear();
333 res = GetFormatFrameSizes(pixel_format, &frame_sizes);
334 if (res) {
335 HAL_LOGE("Failed to get frame sizes for format: 0x%x", pixel_format);
336 continue;
337 }
338 for (auto frame_size : frame_sizes) {
339 supported_format.width = frame_size[0];
340 supported_format.height = frame_size[1];
341 formats.push_back(supported_format);
342 }
343 }
344 return formats;
345}
346
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700347int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
348 HAL_LOG_ENTER();
349
350 v4l2_fmtdesc format_query;
351 memset(&format_query, 0, sizeof(format_query));
352 // TODO(b/30000211): multiplanar support.
353 format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
354 while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
355 v4l2_formats->insert(format_query.pixelformat);
356 ++format_query.index;
357 }
358
359 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700360 HAL_LOGE(
361 "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700362 return -ENODEV;
363 }
364 return 0;
365}
366
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700367int V4L2Wrapper::GetQualifiedFormats(std::vector<uint32_t>* v4l2_formats) {
368 HAL_LOG_ENTER();
369 if (!connected()) {
370 HAL_LOGE(
371 "Device is not connected, qualified formats may not have been set.");
372 return -EINVAL;
373 }
374 v4l2_formats->clear();
375 std::set<uint32_t> unique_fourccs;
376 for (auto& format : qualified_formats_) {
377 unique_fourccs.insert(format.fourcc);
378 }
379 v4l2_formats->assign(unique_fourccs.begin(), unique_fourccs.end());
380 return 0;
381}
382
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700383int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
384 std::set<std::array<int32_t, 2>>* sizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700385 v4l2_frmsizeenum size_query;
386 memset(&size_query, 0, sizeof(size_query));
387 size_query.pixel_format = v4l2_format;
388 if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
389 HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
390 return -ENODEV;
391 }
392 if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
393 // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
394 // Assuming that a driver with discrete frame sizes has a reasonable number
395 // of them.
396 do {
397 sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
398 static_cast<int32_t>(size_query.discrete.height)}}});
399 ++size_query.index;
400 } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
401 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700402 HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
403 size_query.index,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700404 strerror(errno));
405 return -ENODEV;
406 }
407 } else {
408 // Continuous/Step-wise: based on the stepwise struct returned by the query.
409 // Fully listing all possible sizes, with large enough range/small enough
410 // step size, may produce far too many potential sizes. Instead, find the
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800411 // closest to a set of standard sizes.
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700412 for (const auto size : kStandardSizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700413 // Find the closest size, rounding up.
414 uint32_t desired_width = size[0];
415 uint32_t desired_height = size[1];
416 if (desired_width < size_query.stepwise.min_width ||
417 desired_height < size_query.stepwise.min_height) {
418 HAL_LOGV("Standard size %u x %u is too small for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700419 desired_width,
420 desired_height,
421 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700422 continue;
Jaesung Chung932d4dd2017-12-15 15:27:21 +0900423 } else if (desired_width > size_query.stepwise.max_width ||
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700424 desired_height > size_query.stepwise.max_height) {
425 HAL_LOGV("Standard size %u x %u is too big for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700426 desired_width,
427 desired_height,
428 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700429 continue;
430 }
431
432 // Round up.
433 uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
434 size_query.stepwise.step_width - 1) /
435 size_query.stepwise.step_width;
436 uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
437 size_query.stepwise.step_height - 1) /
438 size_query.stepwise.step_height;
439 sizes->insert(
440 {{{static_cast<int32_t>(size_query.stepwise.min_width +
441 width_steps * size_query.stepwise.step_width),
442 static_cast<int32_t>(size_query.stepwise.min_height +
443 height_steps *
444 size_query.stepwise.step_height)}}});
445 }
446 }
447 return 0;
448}
449
450// Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
451inline int64_t FractToNs(const v4l2_fract& fract) {
452 return (1000000000LL * fract.numerator) / fract.denominator;
453}
454
455int V4L2Wrapper::GetFormatFrameDurationRange(
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700456 uint32_t v4l2_format,
457 const std::array<int32_t, 2>& size,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700458 std::array<int64_t, 2>* duration_range) {
459 // Potentially called so many times logging entry is a bad idea.
460
461 v4l2_frmivalenum duration_query;
462 memset(&duration_query, 0, sizeof(duration_query));
463 duration_query.pixel_format = v4l2_format;
464 duration_query.width = size[0];
465 duration_query.height = size[1];
466 if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
467 HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
468 return -ENODEV;
469 }
470
471 int64_t min = std::numeric_limits<int64_t>::max();
472 int64_t max = std::numeric_limits<int64_t>::min();
473 if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
474 // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
475 do {
476 min = std::min(min, FractToNs(duration_query.discrete));
477 max = std::max(max, FractToNs(duration_query.discrete));
478 ++duration_query.index;
479 } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
480 if (errno != EINVAL) {
481 HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700482 duration_query.index,
483 strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700484 return -ENODEV;
485 }
486 } else {
487 // Continuous/Step-wise: simply convert the given min and max.
488 min = FractToNs(duration_query.stepwise.min);
489 max = FractToNs(duration_query.stepwise.max);
490 }
491 (*duration_range)[0] = min;
492 (*duration_range)[1] = max;
493 return 0;
494}
495
Ari Hausman-Cohenef523102016-11-21 17:02:01 -0800496int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700497 uint32_t* result_max_buffers) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700498 HAL_LOG_ENTER();
499
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700500 if (format_ && desired_format == *format_) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700501 HAL_LOGV("Already in correct format, skipping format setting.");
Ari Hausman-Cohena5c9bfd2016-11-18 14:57:07 -0800502 *result_max_buffers = buffers_.size();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700503 return 0;
504 }
505
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800506 if (format_) {
507 // If we had an old format, first request 0 buffers to inform the device
508 // we're no longer using any previously "allocated" buffers from the old
509 // format. This seems like it shouldn't be necessary for USERPTR memory,
510 // and/or should happen from turning the stream off, but the driver
511 // complained. May be a driver issue, or may be intended behavior.
512 int res = RequestBuffers(0);
513 if (res) {
514 return res;
515 }
516 }
517
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700518 // Select the matching format, or if not available, select a qualified format
519 // we can convert from.
520 SupportedFormat format;
521 if (!StreamFormat::FindBestFitFormat(supported_formats_, qualified_formats_,
522 desired_format.v4l2_pixel_format(),
523 desired_format.width(),
524 desired_format.height(), &format)) {
525 HAL_LOGE(
526 "Unable to find supported resolution in list, "
527 "width: %d, height: %d",
528 desired_format.width(), desired_format.height());
529 return -EINVAL;
530 }
531
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800532 // Set the camera to the new format.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700533 v4l2_format new_format;
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700534 const StreamFormat resolved_format(format);
535 resolved_format.FillFormatRequest(&new_format);
536
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700537 // TODO(b/29334616): When async, this will need to check if the stream
538 // is on, and if so, lock it off while setting format.
539 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
540 HAL_LOGE("S_FMT failed: %s", strerror(errno));
541 return -ENODEV;
542 }
543
544 // Check that the driver actually set to the requested values.
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700545 if (resolved_format != new_format) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700546 HAL_LOGE("Device doesn't support desired stream configuration.");
547 return -EINVAL;
548 }
549
550 // Keep track of our new format.
551 format_.reset(new StreamFormat(new_format));
552
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800553 // Format changed, request new buffers.
554 int res = RequestBuffers(1);
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700555 if (res) {
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800556 HAL_LOGE("Requesting buffers for new format failed.");
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700557 return res;
558 }
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700559 *result_max_buffers = buffers_.size();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700560 return 0;
561}
562
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800563int V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700564 v4l2_requestbuffers req_buffers;
565 memset(&req_buffers, 0, sizeof(req_buffers));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700566 req_buffers.type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700567 req_buffers.memory = V4L2_MEMORY_USERPTR;
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800568 req_buffers.count = num_requested;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700569
570 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
571 // Calling REQBUFS releases all queued buffers back to the user.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700572 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700573 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
574 return -ENODEV;
575 }
576
577 // V4L2 will set req_buffers.count to a number of buffers it can handle.
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800578 if (num_requested > 0 && req_buffers.count < 1) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700579 HAL_LOGE("REQBUFS claims it can't handle any buffers.");
580 return -ENODEV;
581 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700582 buffers_.resize(req_buffers.count);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700583 return 0;
584}
585
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700586int V4L2Wrapper::EnqueueRequest(
587 std::shared_ptr<default_camera_hal::CaptureRequest> request) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700588 if (!format_) {
589 HAL_LOGE("Stream format must be set before enqueuing buffers.");
590 return -ENODEV;
591 }
592
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700593 // Find a free buffer index. Could use some sort of persistent hinting
594 // here to improve expected efficiency, but buffers_.size() is expected
595 // to be low enough (<10 experimentally) that it's not worth it.
596 int index = -1;
597 {
598 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700599 for (size_t i = 0; i < buffers_.size(); ++i) {
600 if (!buffers_[i].active) {
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700601 index = i;
602 break;
603 }
604 }
605 }
606 if (index < 0) {
607 // Note: The HAL should be tracking the number of buffers in flight
608 // for each stream, and should never overflow the device.
609 HAL_LOGE("Cannot enqueue buffer: stream is already full.");
610 return -ENODEV;
611 }
612
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700613 // Set up a v4l2 buffer struct.
614 v4l2_buffer device_buffer;
615 memset(&device_buffer, 0, sizeof(device_buffer));
616 device_buffer.type = format_->type();
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700617 device_buffer.index = index;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700618
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700619 // Use QUERYBUF to ensure our buffer/device is in good shape,
620 // and fill out remaining fields.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700621 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
622 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
Jaesung Chung1fc9b612017-11-10 18:09:38 +0900623 // Return buffer index.
624 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700625 buffers_[index].active = false;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700626 return -ENODEV;
627 }
628
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700629 // Setup our request context and fill in the user pointer field.
630 RequestContext* request_context;
631 void* data;
632 {
Jaesung Chung1fc9b612017-11-10 18:09:38 +0900633 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700634 request_context = &buffers_[index];
635 request_context->camera_buffer->SetDataSize(device_buffer.length);
636 request_context->camera_buffer->Reset();
637 request_context->camera_buffer->SetFourcc(format_->v4l2_pixel_format());
638 request_context->camera_buffer->SetWidth(format_->width());
639 request_context->camera_buffer->SetHeight(format_->height());
640 request_context->request = request;
641 data = request_context->camera_buffer->GetData();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700642 }
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700643 device_buffer.m.userptr = reinterpret_cast<unsigned long>(data);
644
645 // Pass the buffer to the camera.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700646 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700647 HAL_LOGE("QBUF fails: %s", strerror(errno));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700648 return -ENODEV;
649 }
650
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700651 // Mark the buffer as in flight.
652 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
653 request_context->active = true;
654
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700655 return 0;
656}
657
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700658int V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700659 if (!format_) {
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800660 HAL_LOGV(
661 "Format not set, so stream can't be on, "
662 "so no buffers available for dequeueing");
663 return -EAGAIN;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700664 }
665
Ari Hausman-Cohenc5a48522016-11-16 10:53:52 -0800666 v4l2_buffer buffer;
667 memset(&buffer, 0, sizeof(buffer));
668 buffer.type = format_->type();
669 buffer.memory = V4L2_MEMORY_USERPTR;
670 int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
671 if (res) {
672 if (errno == EAGAIN) {
673 // Expected failure.
674 return -EAGAIN;
675 } else {
676 // Unexpected failure.
677 HAL_LOGE("DQBUF fails: %s", strerror(errno));
678 return -ENODEV;
679 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700680 }
681
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700682 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
683 RequestContext* request_context = &buffers_[buffer.index];
684
685 // Lock the camera stream buffer for painting.
686 const camera3_stream_buffer_t* stream_buffer =
687 &request_context->request->output_buffers[0];
688 uint32_t fourcc =
689 StreamFormat::HalToV4L2PixelFormat(stream_buffer->stream->format);
690
691 if (request) {
692 *request = request_context->request;
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700693 }
694
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700695 // Note that the device buffer length is passed to the output frame. If the
696 // GrallocFrameBuffer does not have support for the transformation to
697 // |fourcc|, it will assume that the amount of data to lock is based on
698 // |buffer.length|, otherwise it will use the ImageProcessor::ConvertedSize.
699 arc::GrallocFrameBuffer output_frame(
700 *stream_buffer->buffer, stream_buffer->stream->width,
701 stream_buffer->stream->height, fourcc, buffer.length,
702 stream_buffer->stream->usage);
703 res = output_frame.Map();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700704 if (res) {
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700705 HAL_LOGE("Failed to map output frame.");
706 request_context->request.reset();
707 return -EINVAL;
708 }
709 if (request_context->camera_buffer->GetFourcc() == fourcc &&
710 request_context->camera_buffer->GetWidth() ==
711 stream_buffer->stream->width &&
712 request_context->camera_buffer->GetHeight() ==
713 stream_buffer->stream->height) {
714 // If no format conversion needs to be applied, directly copy the data over.
715 memcpy(output_frame.GetData(), request_context->camera_buffer->GetData(),
716 request_context->camera_buffer->GetDataSize());
717 } else {
718 // Perform the format conversion.
719 arc::CachedFrame cached_frame;
720 cached_frame.SetSource(request_context->camera_buffer.get(), 0);
721 cached_frame.Convert(request_context->request->settings, &output_frame);
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700722 }
723
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700724 request_context->request.reset();
725 // Mark the buffer as not in flight.
726 request_context->active = false;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700727 return 0;
728}
729
Prashanth Swaminathan28e0f762017-04-27 11:32:11 -0700730int V4L2Wrapper::GetInFlightBufferCount() {
731 int count = 0;
732 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
733 for (auto& buffer : buffers_) {
734 if (buffer.active) {
735 count++;
736 }
737 }
738 return count;
739}
740
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700741} // namespace v4l2_camera_hal