blob: 2f21c9424dbd881a5afa1579602acad605e76a07 [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>
22#include <vector>
23
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070024#include <fcntl.h>
25#include <linux/videodev2.h>
26#include <sys/stat.h>
27#include <sys/types.h>
28
29#include <mutex>
30
31#include <nativehelper/ScopedFd.h>
32
Ari Hausman-Cohen3841a7f2016-07-19 17:27:52 -070033#include "common.h"
34#include "stream.h"
35#include "stream_format.h"
36#include "v4l2_gralloc.h"
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070037
38namespace v4l2_camera_hal {
39
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -070040const int32_t kStandardSizes[][2] = {
41 {1920, 1080}, {1280, 720}, {640, 480}, {320, 240}};
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070042
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070043V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -070044 std::unique_ptr<V4L2Gralloc> gralloc(V4L2Gralloc::NewV4L2Gralloc());
45 if (!gralloc) {
46 HAL_LOGE("Failed to initialize gralloc helper.");
47 return nullptr;
48 }
49
50 return new V4L2Wrapper(device_path, std::move(gralloc));
51}
52
53V4L2Wrapper::V4L2Wrapper(const std::string device_path,
54 std::unique_ptr<V4L2Gralloc> gralloc)
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -070055 : device_path_(std::move(device_path)),
56 gralloc_(std::move(gralloc)),
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -080057 connection_count_(0) {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070058
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -080059V4L2Wrapper::~V4L2Wrapper() {}
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070060
61int V4L2Wrapper::Connect() {
62 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070063 std::lock_guard<std::mutex> lock(connection_lock_);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070064
65 if (connected()) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070066 HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
67 ++connection_count_;
68 return 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070069 }
70
71 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR));
72 if (fd < 0) {
73 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070074 return -ENODEV;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070075 }
76 device_fd_.reset(fd);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070077 ++connection_count_;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070078
79 // Check if this connection has the extended control query capability.
80 v4l2_query_ext_ctrl query;
81 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070082 extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -070083
84 // TODO(b/29185945): confirm this is a supported device.
85 // This is checked by the HAL, but the device at device_path_ may
86 // not be the same one that was there when the HAL was loaded.
87 // (Alternatively, better hotplugging support may make this unecessary
88 // by disabling cameras that get disconnected and checking newly connected
89 // cameras, so Connect() is never called on an unsupported camera)
90 return 0;
91}
92
93void V4L2Wrapper::Disconnect() {
94 HAL_LOG_ENTER();
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -070095 std::lock_guard<std::mutex> lock(connection_lock_);
96
97 if (connection_count_ == 0) {
98 // Not connected.
99 HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700100 device_path_.c_str());
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700101 return;
102 }
103
104 --connection_count_;
105 if (connection_count_ > 0) {
106 HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700107 device_path_.c_str());
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700108 return;
109 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700110
111 device_fd_.reset(); // Includes close().
112 format_.reset();
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700113 buffers_.clear();
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700114 // Closing the device releases all queued buffers back to the user.
115 gralloc_->unlockAllBuffers();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700116}
117
118// Helper function. Should be used instead of ioctl throughout this class.
119template <typename T>
120int V4L2Wrapper::IoctlLocked(int request, T data) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700121 // Potentially called so many times logging entry is a bad idea.
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700122 std::lock_guard<std::mutex> lock(device_lock_);
123
124 if (!connected()) {
125 HAL_LOGE("Device %s not connected.", device_path_.c_str());
126 return -ENODEV;
127 }
128 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
129}
130
131int V4L2Wrapper::StreamOn() {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700132 if (!format_) {
133 HAL_LOGE("Stream format must be set before turning on stream.");
134 return -EINVAL;
135 }
136
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700137 int32_t type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700138 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
139 HAL_LOGE("STREAMON fails: %s", strerror(errno));
140 return -ENODEV;
141 }
142
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800143 HAL_LOGV("Stream turned on.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700144 return 0;
145}
146
147int V4L2Wrapper::StreamOff() {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700148 if (!format_) {
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800149 // Can't have turned on the stream without format being set,
Ari Hausman-Cohen71cb8742016-09-22 11:12:00 -0700150 // so nothing to turn off here.
151 return 0;
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700152 }
153
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700154 int32_t type = format_->type();
155 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
156 // Calling STREAMOFF releases all queued buffers back to the user.
157 int gralloc_res = gralloc_->unlockAllBuffers();
158 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700159 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
160 return -ENODEV;
161 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700162 if (gralloc_res < 0) {
163 HAL_LOGE("Failed to unlock all buffers after turning stream off.");
164 return gralloc_res;
165 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700166
Ari Hausman-Cohenad6fe2b2016-11-16 10:48:07 -0800167 HAL_LOGV("Stream turned off.");
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700168 return 0;
169}
170
171int V4L2Wrapper::QueryControl(uint32_t control_id,
172 v4l2_query_ext_ctrl* result) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700173 int res;
174
175 memset(result, 0, sizeof(*result));
176
177 if (extended_query_supported_) {
178 result->id = control_id;
179 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
180 // Assuming the operation was supported (not ENOTTY), no more to do.
181 if (errno != ENOTTY) {
182 if (res) {
183 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
184 return -ENODEV;
185 }
186 return 0;
187 }
188 }
189
190 // Extended control querying not supported, fall back to basic control query.
191 v4l2_queryctrl query;
192 query.id = control_id;
193 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
194 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
195 return -ENODEV;
196 }
197
198 // Convert the basic result to the extended result.
199 result->id = query.id;
200 result->type = query.type;
201 memcpy(result->name, query.name, sizeof(query.name));
202 result->minimum = query.minimum;
203 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
204 // According to the V4L2 documentation, when type is BITMASK,
205 // max and default should be interpreted as __u32. Practically,
206 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
207 result->maximum = static_cast<uint32_t>(query.maximum);
208 result->default_value = static_cast<uint32_t>(query.default_value);
209 } else {
210 result->maximum = query.maximum;
211 result->default_value = query.default_value;
212 }
213 result->step = static_cast<uint32_t>(query.step);
214 result->flags = query.flags;
215 result->elems = 1;
216 switch (result->type) {
217 case V4L2_CTRL_TYPE_INTEGER64:
218 result->elem_size = sizeof(int64_t);
219 break;
220 case V4L2_CTRL_TYPE_STRING:
221 result->elem_size = result->maximum + 1;
222 break;
223 default:
224 result->elem_size = sizeof(int32_t);
225 break;
226 }
227
228 return 0;
229}
230
231int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700232 // For extended controls (any control class other than "user"),
233 // G_EXT_CTRL must be used instead of G_CTRL.
234 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
235 v4l2_ext_control control;
236 v4l2_ext_controls controls;
237 memset(&control, 0, sizeof(control));
238 memset(&controls, 0, sizeof(controls));
239
240 control.id = control_id;
241 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
242 controls.count = 1;
243 controls.controls = &control;
244
245 if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
246 HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
247 return -ENODEV;
248 }
249 *value = control.value;
250 } else {
251 v4l2_control control{control_id, 0};
252 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
253 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
254 return -ENODEV;
255 }
256 *value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700257 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700258 return 0;
259}
260
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700261int V4L2Wrapper::SetControl(uint32_t control_id,
262 int32_t desired,
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700263 int32_t* result) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700264 int32_t result_value = 0;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700265
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700266 // TODO(b/29334616): When async, this may need to check if the stream
267 // is on, and if so, lock it off while setting format. Need to look
268 // into if V4L2 supports adjusting controls while the stream is on.
269
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700270 // For extended controls (any control class other than "user"),
271 // S_EXT_CTRL must be used instead of S_CTRL.
272 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
273 v4l2_ext_control control;
274 v4l2_ext_controls controls;
275 memset(&control, 0, sizeof(control));
276 memset(&controls, 0, sizeof(controls));
277
278 control.id = control_id;
279 control.value = desired;
280 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
281 controls.count = 1;
282 controls.controls = &control;
283
284 if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
285 HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
286 return -ENODEV;
287 }
288 result_value = control.value;
289 } else {
290 v4l2_control control{control_id, desired};
291 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
292 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
293 return -ENODEV;
294 }
295 result_value = control.value;
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700296 }
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700297
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700298 // If the caller wants to know the result, pass it back.
299 if (result != nullptr) {
Ari Hausman-Cohen7a1fba62016-08-10 11:31:04 -0700300 *result = result_value;
Ari Hausman-Cohen99f3ea02016-08-02 10:47:07 -0700301 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700302 return 0;
303}
304
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700305int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
306 HAL_LOG_ENTER();
307
308 v4l2_fmtdesc format_query;
309 memset(&format_query, 0, sizeof(format_query));
310 // TODO(b/30000211): multiplanar support.
311 format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
312 while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
313 v4l2_formats->insert(format_query.pixelformat);
314 ++format_query.index;
315 }
316
317 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700318 HAL_LOGE(
319 "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700320 return -ENODEV;
321 }
322 return 0;
323}
324
325int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
326 std::set<std::array<int32_t, 2>>* sizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700327 v4l2_frmsizeenum size_query;
328 memset(&size_query, 0, sizeof(size_query));
329 size_query.pixel_format = v4l2_format;
330 if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
331 HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
332 return -ENODEV;
333 }
334 if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
335 // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
336 // Assuming that a driver with discrete frame sizes has a reasonable number
337 // of them.
338 do {
339 sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
340 static_cast<int32_t>(size_query.discrete.height)}}});
341 ++size_query.index;
342 } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
343 if (errno != EINVAL) {
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700344 HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
345 size_query.index,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700346 strerror(errno));
347 return -ENODEV;
348 }
349 } else {
350 // Continuous/Step-wise: based on the stepwise struct returned by the query.
351 // Fully listing all possible sizes, with large enough range/small enough
352 // step size, may produce far too many potential sizes. Instead, find the
353 // closest to a set of standard sizes plus largest possible.
354 sizes->insert({{{static_cast<int32_t>(size_query.stepwise.max_width),
355 static_cast<int32_t>(size_query.stepwise.max_height)}}});
Ari Hausman-Cohenabbf9cc2016-08-23 11:59:59 -0700356 for (const auto size : kStandardSizes) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700357 // Find the closest size, rounding up.
358 uint32_t desired_width = size[0];
359 uint32_t desired_height = size[1];
360 if (desired_width < size_query.stepwise.min_width ||
361 desired_height < size_query.stepwise.min_height) {
362 HAL_LOGV("Standard size %u x %u is too small for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700363 desired_width,
364 desired_height,
365 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700366 continue;
367 } else if (desired_width > size_query.stepwise.max_width &&
368 desired_height > size_query.stepwise.max_height) {
369 HAL_LOGV("Standard size %u x %u is too big for format %d",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700370 desired_width,
371 desired_height,
372 v4l2_format);
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700373 continue;
374 }
375
376 // Round up.
377 uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
378 size_query.stepwise.step_width - 1) /
379 size_query.stepwise.step_width;
380 uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
381 size_query.stepwise.step_height - 1) /
382 size_query.stepwise.step_height;
383 sizes->insert(
384 {{{static_cast<int32_t>(size_query.stepwise.min_width +
385 width_steps * size_query.stepwise.step_width),
386 static_cast<int32_t>(size_query.stepwise.min_height +
387 height_steps *
388 size_query.stepwise.step_height)}}});
389 }
390 }
391 return 0;
392}
393
394// Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
395inline int64_t FractToNs(const v4l2_fract& fract) {
396 return (1000000000LL * fract.numerator) / fract.denominator;
397}
398
399int V4L2Wrapper::GetFormatFrameDurationRange(
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700400 uint32_t v4l2_format,
401 const std::array<int32_t, 2>& size,
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700402 std::array<int64_t, 2>* duration_range) {
403 // Potentially called so many times logging entry is a bad idea.
404
405 v4l2_frmivalenum duration_query;
406 memset(&duration_query, 0, sizeof(duration_query));
407 duration_query.pixel_format = v4l2_format;
408 duration_query.width = size[0];
409 duration_query.height = size[1];
410 if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
411 HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
412 return -ENODEV;
413 }
414
415 int64_t min = std::numeric_limits<int64_t>::max();
416 int64_t max = std::numeric_limits<int64_t>::min();
417 if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
418 // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
419 do {
420 min = std::min(min, FractToNs(duration_query.discrete));
421 max = std::max(max, FractToNs(duration_query.discrete));
422 ++duration_query.index;
423 } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
424 if (errno != EINVAL) {
425 HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
Ari Hausman-Cohen5d753232016-08-10 14:27:36 -0700426 duration_query.index,
427 strerror(errno));
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700428 return -ENODEV;
429 }
430 } else {
431 // Continuous/Step-wise: simply convert the given min and max.
432 min = FractToNs(duration_query.stepwise.min);
433 max = FractToNs(duration_query.stepwise.max);
434 }
435 (*duration_range)[0] = min;
436 (*duration_range)[1] = max;
437 return 0;
438}
439
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700440int V4L2Wrapper::SetFormat(const default_camera_hal::Stream& stream,
441 uint32_t* result_max_buffers) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700442 HAL_LOG_ENTER();
443
444 // Should be checked earlier; sanity check.
445 if (stream.isInputType()) {
446 HAL_LOGE("Input streams not supported.");
447 return -EINVAL;
448 }
449
450 StreamFormat desired_format(stream);
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700451 if (format_ && desired_format == *format_) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700452 HAL_LOGV("Already in correct format, skipping format setting.");
453 return 0;
454 }
455
456 // Not in the correct format, set our format.
457 v4l2_format new_format;
458 desired_format.FillFormatRequest(&new_format);
459 // TODO(b/29334616): When async, this will need to check if the stream
460 // is on, and if so, lock it off while setting format.
461 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
462 HAL_LOGE("S_FMT failed: %s", strerror(errno));
463 return -ENODEV;
464 }
465
466 // Check that the driver actually set to the requested values.
467 if (desired_format != new_format) {
468 HAL_LOGE("Device doesn't support desired stream configuration.");
469 return -EINVAL;
470 }
471
472 // Keep track of our new format.
473 format_.reset(new StreamFormat(new_format));
474
475 // Format changed, setup new buffers.
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700476 int res = SetupBuffers();
477 if (res) {
478 HAL_LOGE("Failed to set up buffers for new format.");
479 return res;
480 }
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700481 *result_max_buffers = buffers_.size();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700482 return 0;
483}
484
485int V4L2Wrapper::SetupBuffers() {
486 HAL_LOG_ENTER();
487
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700488 if (!format_) {
489 HAL_LOGE("Stream format must be set before setting up buffers.");
490 return -ENODEV;
491 }
492
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700493 // "Request" a buffer (since we're using a userspace buffer, this just
494 // tells V4L2 to switch into userspace buffer mode).
495 v4l2_requestbuffers req_buffers;
496 memset(&req_buffers, 0, sizeof(req_buffers));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700497 req_buffers.type = format_->type();
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700498 req_buffers.memory = V4L2_MEMORY_USERPTR;
499 req_buffers.count = 1;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700500
501 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
502 // Calling REQBUFS releases all queued buffers back to the user.
503 int gralloc_res = gralloc_->unlockAllBuffers();
504 if (res < 0) {
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700505 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
506 return -ENODEV;
507 }
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700508 if (gralloc_res < 0) {
509 HAL_LOGE("Failed to unlock all buffers when setting up new buffers.");
510 return gralloc_res;
511 }
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700512
513 // V4L2 will set req_buffers.count to a number of buffers it can handle.
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700514 if (req_buffers.count < 1) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700515 HAL_LOGE("REQBUFS claims it can't handle any buffers.");
516 return -ENODEV;
517 }
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700518 buffers_.resize(req_buffers.count, false);
519
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700520 return 0;
521}
522
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700523int V4L2Wrapper::EnqueueBuffer(const camera3_stream_buffer_t* camera_buffer) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700524 if (!format_) {
525 HAL_LOGE("Stream format must be set before enqueuing buffers.");
526 return -ENODEV;
527 }
528
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700529 // Find a free buffer index. Could use some sort of persistent hinting
530 // here to improve expected efficiency, but buffers_.size() is expected
531 // to be low enough (<10 experimentally) that it's not worth it.
532 int index = -1;
533 {
534 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
535 for (int i = 0; i < buffers_.size(); ++i) {
536 if (!buffers_[i]) {
537 index = i;
538 break;
539 }
540 }
541 }
542 if (index < 0) {
543 // Note: The HAL should be tracking the number of buffers in flight
544 // for each stream, and should never overflow the device.
545 HAL_LOGE("Cannot enqueue buffer: stream is already full.");
546 return -ENODEV;
547 }
548
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700549 // Set up a v4l2 buffer struct.
550 v4l2_buffer device_buffer;
551 memset(&device_buffer, 0, sizeof(device_buffer));
552 device_buffer.type = format_->type();
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700553 device_buffer.index = index;
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700554
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700555 // Use QUERYBUF to ensure our buffer/device is in good shape,
556 // and fill out remaining fields.
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700557 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
558 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
559 return -ENODEV;
560 }
561
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700562 // Lock the buffer for writing (fills in the user pointer field).
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700563 int res =
564 gralloc_->lock(camera_buffer, format_->bytes_per_line(), &device_buffer);
565 if (res) {
566 HAL_LOGE("Gralloc failed to lock buffer.");
567 return res;
568 }
569 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
Ari Hausman-Cohen9e6fd982016-08-02 16:29:53 -0700570 HAL_LOGE("QBUF fails: %s", strerror(errno));
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700571 gralloc_->unlock(&device_buffer);
572 return -ENODEV;
573 }
574
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700575 // Mark the buffer as in flight.
576 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
577 buffers_[index] = true;
578
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700579 return 0;
580}
581
582int V4L2Wrapper::DequeueBuffer(v4l2_buffer* buffer) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700583 if (!format_) {
584 HAL_LOGE("Stream format must be set before dequeueing buffers.");
585 return -ENODEV;
586 }
587
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700588 memset(buffer, 0, sizeof(*buffer));
589 buffer->type = format_->type();
590 buffer->memory = V4L2_MEMORY_USERPTR;
591 if (IoctlLocked(VIDIOC_DQBUF, buffer) < 0) {
592 HAL_LOGE("DQBUF fails: %s", strerror(errno));
593 return -ENODEV;
594 }
595
Ari Hausman-Cohen0fbcaf52016-09-28 13:21:31 -0700596 // Mark the buffer as no longer in flight.
597 {
598 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
599 buffers_[buffer->index] = false;
600 }
601
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700602 // Now that we're done painting the buffer, we can unlock it.
603 int res = gralloc_->unlock(buffer);
604 if (res) {
Ari Hausman-Cohen660f8b82016-07-19 17:27:52 -0700605 HAL_LOGE("Gralloc failed to unlock buffer after dequeueing.");
Ari Hausman-Cohen4ab49622016-07-21 14:33:54 -0700606 return res;
607 }
608
609 return 0;
610}
611
Ari Hausman-Cohenc17fd092016-07-18 10:13:26 -0700612} // namespace v4l2_camera_hal