1 /*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "V4L2Wrapper"
19
20 #include "v4l2_wrapper.h"
21
22 #include <algorithm>
23 #include <fcntl.h>
24 #include <limits>
25
26 #include <android-base/unique_fd.h>
27 #include <linux/videodev2.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include "arc/cached_frame.h"
31
32 namespace v4l2_camera_hal {
33
34 using arc::AllocatedFrameBuffer;
35 using arc::SupportedFormat;
36 using arc::SupportedFormats;
37 using default_camera_hal::CaptureRequest;
38
39 const int32_t kStandardSizes[][2] = {
40 {4096, 2160}, // 4KDCI (for USB camera)
41 {3840, 2160}, // 4KUHD (for USB camera)
42 {3280, 2464}, // 8MP
43 {2560, 1440}, // QHD
44 {1920, 1080}, // HD1080
45 {1640, 1232}, // 2MP
46 {1280, 720}, // HD
47 {1024, 768}, // XGA
48 { 640, 480}, // VGA
49 { 320, 240}, // QVGA
50 { 176, 144} // QCIF
51 };
52
NewV4L2Wrapper(const std::string device_path)53 V4L2Wrapper* V4L2Wrapper::NewV4L2Wrapper(const std::string device_path) {
54 return new V4L2Wrapper(device_path);
55 }
56
V4L2Wrapper(const std::string device_path)57 V4L2Wrapper::V4L2Wrapper(const std::string device_path)
58 : device_path_(std::move(device_path)), connection_count_(0) {}
59
~V4L2Wrapper()60 V4L2Wrapper::~V4L2Wrapper() {}
61
Connect()62 int V4L2Wrapper::Connect() {
63 HAL_LOG_ENTER();
64 std::lock_guard<std::mutex> lock(connection_lock_);
65
66 if (connected()) {
67 HAL_LOGV("Camera device %s is already connected.", device_path_.c_str());
68 ++connection_count_;
69 return 0;
70 }
71
72 // Open in nonblocking mode (DQBUF may return EAGAIN).
73 int fd = TEMP_FAILURE_RETRY(open(device_path_.c_str(), O_RDWR | O_NONBLOCK));
74 if (fd < 0) {
75 HAL_LOGE("failed to open %s (%s)", device_path_.c_str(), strerror(errno));
76 return -ENODEV;
77 }
78 device_fd_.reset(fd);
79 ++connection_count_;
80
81 // Check if this connection has the extended control query capability.
82 v4l2_query_ext_ctrl query;
83 query.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
84 extended_query_supported_ = (IoctlLocked(VIDIOC_QUERY_EXT_CTRL, &query) == 0);
85
86 // TODO(b/29185945): confirm this is a supported device.
87 // This is checked by the HAL, but the device at device_path_ may
88 // not be the same one that was there when the HAL was loaded.
89 // (Alternatively, better hotplugging support may make this unecessary
90 // by disabling cameras that get disconnected and checking newly connected
91 // cameras, so Connect() is never called on an unsupported camera)
92
93 supported_formats_ = GetSupportedFormats();
94 qualified_formats_ = StreamFormat::GetQualifiedFormats(supported_formats_);
95
96 return 0;
97 }
98
Disconnect()99 void V4L2Wrapper::Disconnect() {
100 HAL_LOG_ENTER();
101 std::lock_guard<std::mutex> lock(connection_lock_);
102
103 if (connection_count_ == 0) {
104 // Not connected.
105 HAL_LOGE("Camera device %s is not connected, cannot disconnect.",
106 device_path_.c_str());
107 return;
108 }
109
110 --connection_count_;
111 if (connection_count_ > 0) {
112 HAL_LOGV("Disconnected from camera device %s. %d connections remain.",
113 device_path_.c_str(), connection_count_);
114 return;
115 }
116
117 device_fd_.reset(-1); // Includes close().
118 format_.reset();
119 {
120 std::lock_guard<std::mutex> buffer_lock(buffer_queue_lock_);
121 buffers_.clear();
122 }
123 }
124
125 // Helper function. Should be used instead of ioctl throughout this class.
126 template <typename T>
IoctlLocked(unsigned long request,T data)127 int V4L2Wrapper::IoctlLocked(unsigned long request, T data) {
128 // Potentially called so many times logging entry is a bad idea.
129 std::lock_guard<std::mutex> lock(device_lock_);
130
131 if (!connected()) {
132 HAL_LOGE("Device %s not connected.", device_path_.c_str());
133 return -ENODEV;
134 }
135 return TEMP_FAILURE_RETRY(ioctl(device_fd_.get(), request, data));
136 }
137
StreamOn()138 int V4L2Wrapper::StreamOn() {
139 if (!format_) {
140 HAL_LOGE("Stream format must be set before turning on stream.");
141 return -EINVAL;
142 }
143
144 int32_t type = format_->type();
145 if (IoctlLocked(VIDIOC_STREAMON, &type) < 0) {
146 HAL_LOGE("STREAMON fails (%d): %s", errno, strerror(errno));
147 return -ENODEV;
148 }
149
150 HAL_LOGV("Stream turned on.");
151 return 0;
152 }
153
StreamOff()154 int V4L2Wrapper::StreamOff() {
155 if (!format_) {
156 // Can't have turned on the stream without format being set,
157 // so nothing to turn off here.
158 return 0;
159 }
160
161 int32_t type = format_->type();
162 int res = IoctlLocked(VIDIOC_STREAMOFF, &type);
163 // Calling STREAMOFF releases all queued buffers back to the user.
164 // No buffers in flight.
165 if (res < 0) {
166 HAL_LOGE("STREAMOFF fails: %s", strerror(errno));
167 return -ENODEV;
168 }
169 std::lock_guard<std::mutex> lock(buffer_queue_lock_);
170 for (auto& buffer : buffers_) {
171 buffer.active = false;
172 buffer.request.reset();
173 }
174 HAL_LOGV("Stream turned off.");
175 return 0;
176 }
177
QueryControl(uint32_t control_id,v4l2_query_ext_ctrl * result)178 int V4L2Wrapper::QueryControl(uint32_t control_id,
179 v4l2_query_ext_ctrl* result) {
180 int res;
181
182 memset(result, 0, sizeof(*result));
183
184 if (extended_query_supported_) {
185 result->id = control_id;
186 res = IoctlLocked(VIDIOC_QUERY_EXT_CTRL, result);
187 // Assuming the operation was supported (not ENOTTY), no more to do.
188 if (errno != ENOTTY) {
189 if (res) {
190 HAL_LOGE("QUERY_EXT_CTRL fails: %s", strerror(errno));
191 return -ENODEV;
192 }
193 return 0;
194 }
195 }
196
197 // Extended control querying not supported, fall back to basic control query.
198 v4l2_queryctrl query;
199 query.id = control_id;
200 if (IoctlLocked(VIDIOC_QUERYCTRL, &query)) {
201 HAL_LOGE("QUERYCTRL fails: %s", strerror(errno));
202 return -ENODEV;
203 }
204
205 // Convert the basic result to the extended result.
206 result->id = query.id;
207 result->type = query.type;
208 memcpy(result->name, query.name, sizeof(query.name));
209 result->minimum = query.minimum;
210 if (query.type == V4L2_CTRL_TYPE_BITMASK) {
211 // According to the V4L2 documentation, when type is BITMASK,
212 // max and default should be interpreted as __u32. Practically,
213 // this means the conversion from 32 bit to 64 will pad with 0s not 1s.
214 result->maximum = static_cast<uint32_t>(query.maximum);
215 result->default_value = static_cast<uint32_t>(query.default_value);
216 } else {
217 result->maximum = query.maximum;
218 result->default_value = query.default_value;
219 }
220 result->step = static_cast<uint32_t>(query.step);
221 result->flags = query.flags;
222 result->elems = 1;
223 switch (result->type) {
224 case V4L2_CTRL_TYPE_INTEGER64:
225 result->elem_size = sizeof(int64_t);
226 break;
227 case V4L2_CTRL_TYPE_STRING:
228 result->elem_size = result->maximum + 1;
229 break;
230 default:
231 result->elem_size = sizeof(int32_t);
232 break;
233 }
234
235 return 0;
236 }
237
GetControl(uint32_t control_id,int32_t * value)238 int V4L2Wrapper::GetControl(uint32_t control_id, int32_t* value) {
239 // For extended controls (any control class other than "user"),
240 // G_EXT_CTRL must be used instead of G_CTRL.
241 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
242 v4l2_ext_control control;
243 v4l2_ext_controls controls;
244 memset(&control, 0, sizeof(control));
245 memset(&controls, 0, sizeof(controls));
246
247 control.id = control_id;
248 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
249 controls.count = 1;
250 controls.controls = &control;
251
252 if (IoctlLocked(VIDIOC_G_EXT_CTRLS, &controls) < 0) {
253 HAL_LOGE("G_EXT_CTRLS fails: %s", strerror(errno));
254 return -ENODEV;
255 }
256 *value = control.value;
257 } else {
258 v4l2_control control{control_id, 0};
259 if (IoctlLocked(VIDIOC_G_CTRL, &control) < 0) {
260 HAL_LOGE("G_CTRL fails: %s", strerror(errno));
261 return -ENODEV;
262 }
263 *value = control.value;
264 }
265 return 0;
266 }
267
SetControl(uint32_t control_id,int32_t desired,int32_t * result)268 int V4L2Wrapper::SetControl(uint32_t control_id,
269 int32_t desired,
270 int32_t* result) {
271 int32_t result_value = 0;
272
273 // TODO(b/29334616): When async, this may need to check if the stream
274 // is on, and if so, lock it off while setting format. Need to look
275 // into if V4L2 supports adjusting controls while the stream is on.
276
277 // For extended controls (any control class other than "user"),
278 // S_EXT_CTRL must be used instead of S_CTRL.
279 if (V4L2_CTRL_ID2CLASS(control_id) != V4L2_CTRL_CLASS_USER) {
280 v4l2_ext_control control;
281 v4l2_ext_controls controls;
282 memset(&control, 0, sizeof(control));
283 memset(&controls, 0, sizeof(controls));
284
285 control.id = control_id;
286 control.value = desired;
287 controls.ctrl_class = V4L2_CTRL_ID2CLASS(control_id);
288 controls.count = 1;
289 controls.controls = &control;
290
291 if (IoctlLocked(VIDIOC_S_EXT_CTRLS, &controls) < 0) {
292 HAL_LOGE("S_EXT_CTRLS fails: %s", strerror(errno));
293 return -ENODEV;
294 }
295 result_value = control.value;
296 } else {
297 v4l2_control control{control_id, desired};
298 if (IoctlLocked(VIDIOC_S_CTRL, &control) < 0) {
299 HAL_LOGE("S_CTRL fails: %s", strerror(errno));
300 return -ENODEV;
301 }
302 result_value = control.value;
303 }
304
305 // If the caller wants to know the result, pass it back.
306 if (result != nullptr) {
307 *result = result_value;
308 }
309 return 0;
310 }
311
GetSupportedFormats()312 const SupportedFormats V4L2Wrapper::GetSupportedFormats() {
313 SupportedFormats formats;
314 std::set<uint32_t> pixel_formats;
315 int res = GetFormats(&pixel_formats);
316 if (res) {
317 HAL_LOGE("Failed to get device formats.");
318 return formats;
319 }
320
321 arc::SupportedFormat supported_format;
322 std::set<std::array<int32_t, 2>> frame_sizes;
323
324 for (auto pixel_format : pixel_formats) {
325 supported_format.fourcc = pixel_format;
326
327 frame_sizes.clear();
328 res = GetFormatFrameSizes(pixel_format, &frame_sizes);
329 if (res) {
330 HAL_LOGE("Failed to get frame sizes for format: 0x%x", pixel_format);
331 continue;
332 }
333 for (auto frame_size : frame_sizes) {
334 supported_format.width = frame_size[0];
335 supported_format.height = frame_size[1];
336 formats.push_back(supported_format);
337 }
338 }
339 return formats;
340 }
341
GetFormats(std::set<uint32_t> * v4l2_formats)342 int V4L2Wrapper::GetFormats(std::set<uint32_t>* v4l2_formats) {
343 HAL_LOG_ENTER();
344
345 v4l2_fmtdesc format_query;
346 memset(&format_query, 0, sizeof(format_query));
347 // TODO(b/30000211): multiplanar support.
348 format_query.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
349 while (IoctlLocked(VIDIOC_ENUM_FMT, &format_query) >= 0) {
350 v4l2_formats->insert(format_query.pixelformat);
351 ++format_query.index;
352 }
353
354 if (errno != EINVAL) {
355 HAL_LOGE(
356 "ENUM_FMT fails at index %d: %s", format_query.index, strerror(errno));
357 return -ENODEV;
358 }
359 return 0;
360 }
361
GetQualifiedFormats(std::vector<uint32_t> * v4l2_formats)362 int V4L2Wrapper::GetQualifiedFormats(std::vector<uint32_t>* v4l2_formats) {
363 HAL_LOG_ENTER();
364 if (!connected()) {
365 HAL_LOGE(
366 "Device is not connected, qualified formats may not have been set.");
367 return -EINVAL;
368 }
369 v4l2_formats->clear();
370 std::set<uint32_t> unique_fourccs;
371 for (auto& format : qualified_formats_) {
372 unique_fourccs.insert(format.fourcc);
373 }
374 v4l2_formats->assign(unique_fourccs.begin(), unique_fourccs.end());
375 return 0;
376 }
377
GetFormatFrameSizes(uint32_t v4l2_format,std::set<std::array<int32_t,2>> * sizes)378 int V4L2Wrapper::GetFormatFrameSizes(uint32_t v4l2_format,
379 std::set<std::array<int32_t, 2>>* sizes) {
380 v4l2_frmsizeenum size_query;
381 memset(&size_query, 0, sizeof(size_query));
382 size_query.pixel_format = v4l2_format;
383 if (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) < 0) {
384 HAL_LOGE("ENUM_FRAMESIZES failed: %s", strerror(errno));
385 return -ENODEV;
386 }
387 if (size_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
388 // Discrete: enumerate all sizes using VIDIOC_ENUM_FRAMESIZES.
389 // Assuming that a driver with discrete frame sizes has a reasonable number
390 // of them.
391 do {
392 sizes->insert({{{static_cast<int32_t>(size_query.discrete.width),
393 static_cast<int32_t>(size_query.discrete.height)}}});
394 ++size_query.index;
395 } while (IoctlLocked(VIDIOC_ENUM_FRAMESIZES, &size_query) >= 0);
396 if (errno != EINVAL) {
397 HAL_LOGE("ENUM_FRAMESIZES fails at index %d: %s",
398 size_query.index,
399 strerror(errno));
400 return -ENODEV;
401 }
402 } else {
403 // Continuous/Step-wise: based on the stepwise struct returned by the query.
404 // Fully listing all possible sizes, with large enough range/small enough
405 // step size, may produce far too many potential sizes. Instead, find the
406 // closest to a set of standard sizes.
407 for (const auto size : kStandardSizes) {
408 // Find the closest size, rounding up.
409 uint32_t desired_width = size[0];
410 uint32_t desired_height = size[1];
411 if (desired_width < size_query.stepwise.min_width ||
412 desired_height < size_query.stepwise.min_height) {
413 HAL_LOGV("Standard size %u x %u is too small for format %d",
414 desired_width,
415 desired_height,
416 v4l2_format);
417 continue;
418 } else if (desired_width > size_query.stepwise.max_width ||
419 desired_height > size_query.stepwise.max_height) {
420 HAL_LOGV("Standard size %u x %u is too big for format %d",
421 desired_width,
422 desired_height,
423 v4l2_format);
424 continue;
425 }
426
427 // Round up.
428 uint32_t width_steps = (desired_width - size_query.stepwise.min_width +
429 size_query.stepwise.step_width - 1) /
430 size_query.stepwise.step_width;
431 uint32_t height_steps = (desired_height - size_query.stepwise.min_height +
432 size_query.stepwise.step_height - 1) /
433 size_query.stepwise.step_height;
434 sizes->insert(
435 {{{static_cast<int32_t>(size_query.stepwise.min_width +
436 width_steps * size_query.stepwise.step_width),
437 static_cast<int32_t>(size_query.stepwise.min_height +
438 height_steps *
439 size_query.stepwise.step_height)}}});
440 }
441 }
442 return 0;
443 }
444
445 // Converts a v4l2_fract with units of seconds to an int64_t with units of ns.
FractToNs(const v4l2_fract & fract)446 inline int64_t FractToNs(const v4l2_fract& fract) {
447 return (1000000000LL * fract.numerator) / fract.denominator;
448 }
449
GetFormatFrameDurationRange(uint32_t v4l2_format,const std::array<int32_t,2> & size,std::array<int64_t,2> * duration_range)450 int V4L2Wrapper::GetFormatFrameDurationRange(
451 uint32_t v4l2_format,
452 const std::array<int32_t, 2>& size,
453 std::array<int64_t, 2>* duration_range) {
454 // Potentially called so many times logging entry is a bad idea.
455
456 v4l2_frmivalenum duration_query;
457 memset(&duration_query, 0, sizeof(duration_query));
458 duration_query.pixel_format = v4l2_format;
459 duration_query.width = size[0];
460 duration_query.height = size[1];
461 if (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) < 0) {
462 HAL_LOGE("ENUM_FRAMEINTERVALS failed: %s", strerror(errno));
463 return -ENODEV;
464 }
465
466 int64_t min = std::numeric_limits<int64_t>::max();
467 int64_t max = std::numeric_limits<int64_t>::min();
468 if (duration_query.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
469 // Discrete: enumerate all durations using VIDIOC_ENUM_FRAMEINTERVALS.
470 do {
471 min = std::min(min, FractToNs(duration_query.discrete));
472 max = std::max(max, FractToNs(duration_query.discrete));
473 ++duration_query.index;
474 } while (IoctlLocked(VIDIOC_ENUM_FRAMEINTERVALS, &duration_query) >= 0);
475 if (errno != EINVAL) {
476 HAL_LOGE("ENUM_FRAMEINTERVALS fails at index %d: %s",
477 duration_query.index,
478 strerror(errno));
479 return -ENODEV;
480 }
481 } else {
482 // Continuous/Step-wise: simply convert the given min and max.
483 min = FractToNs(duration_query.stepwise.min);
484 max = FractToNs(duration_query.stepwise.max);
485 }
486 (*duration_range)[0] = min;
487 (*duration_range)[1] = max;
488 return 0;
489 }
490
SetFormat(const StreamFormat & desired_format,uint32_t * result_max_buffers)491 int V4L2Wrapper::SetFormat(const StreamFormat& desired_format,
492 uint32_t* result_max_buffers) {
493 HAL_LOG_ENTER();
494
495 if (format_ && desired_format == *format_) {
496 HAL_LOGV("Already in correct format, skipping format setting.");
497 *result_max_buffers = buffers_.size();
498 return 0;
499 }
500
501 if (format_) {
502 // If we had an old format, first request 0 buffers to inform the device
503 // we're no longer using any previously "allocated" buffers from the old
504 // format. This seems like it shouldn't be necessary for USERPTR memory,
505 // and/or should happen from turning the stream off, but the driver
506 // complained. May be a driver issue, or may be intended behavior.
507 int res = RequestBuffers(0);
508 if (res) {
509 return res;
510 }
511 }
512
513 // Select the matching format, or if not available, select a qualified format
514 // we can convert from.
515 SupportedFormat format;
516 if (!StreamFormat::FindBestFitFormat(supported_formats_, qualified_formats_,
517 desired_format.v4l2_pixel_format(),
518 desired_format.width(),
519 desired_format.height(), &format)) {
520 HAL_LOGE(
521 "Unable to find supported resolution in list, "
522 "width: %d, height: %d",
523 desired_format.width(), desired_format.height());
524 return -EINVAL;
525 }
526
527 // Set the camera to the new format.
528 v4l2_format new_format;
529 const StreamFormat resolved_format(format);
530 resolved_format.FillFormatRequest(&new_format);
531
532 // TODO(b/29334616): When async, this will need to check if the stream
533 // is on, and if so, lock it off while setting format.
534 if (IoctlLocked(VIDIOC_S_FMT, &new_format) < 0) {
535 HAL_LOGE("S_FMT failed: %s", strerror(errno));
536 return -ENODEV;
537 }
538
539 // Check that the driver actually set to the requested values.
540 if (resolved_format != new_format) {
541 HAL_LOGE("Device doesn't support desired stream configuration.");
542 return -EINVAL;
543 }
544
545 // Keep track of our new format.
546 format_.reset(new StreamFormat(new_format));
547
548 // Format changed, request new buffers.
549 int res = RequestBuffers(1);
550 if (res) {
551 HAL_LOGE("Requesting buffers for new format failed.");
552 return res;
553 }
554 *result_max_buffers = buffers_.size();
555 return 0;
556 }
557
RequestBuffers(uint32_t num_requested)558 int V4L2Wrapper::RequestBuffers(uint32_t num_requested) {
559 v4l2_requestbuffers req_buffers;
560 memset(&req_buffers, 0, sizeof(req_buffers));
561 req_buffers.type = format_->type();
562 req_buffers.memory = V4L2_MEMORY_USERPTR;
563 req_buffers.count = num_requested;
564
565 int res = IoctlLocked(VIDIOC_REQBUFS, &req_buffers);
566 // Calling REQBUFS releases all queued buffers back to the user.
567 if (res < 0) {
568 HAL_LOGE("REQBUFS failed: %s", strerror(errno));
569 return -ENODEV;
570 }
571
572 // V4L2 will set req_buffers.count to a number of buffers it can handle.
573 if (num_requested > 0 && req_buffers.count < 1) {
574 HAL_LOGE("REQBUFS claims it can't handle any buffers.");
575 return -ENODEV;
576 }
577 buffers_.resize(req_buffers.count);
578 return 0;
579 }
580
EnqueueRequest(std::shared_ptr<default_camera_hal::CaptureRequest> request)581 int V4L2Wrapper::EnqueueRequest(
582 std::shared_ptr<default_camera_hal::CaptureRequest> request) {
583 if (!format_) {
584 HAL_LOGE("Stream format must be set before enqueuing buffers.");
585 return -ENODEV;
586 }
587
588 // Find a free buffer index. Could use some sort of persistent hinting
589 // here to improve expected efficiency, but buffers_.size() is expected
590 // to be low enough (<10 experimentally) that it's not worth it.
591 int index = -1;
592 {
593 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
594 for (size_t i = 0; i < buffers_.size(); ++i) {
595 if (!buffers_[i].active) {
596 index = i;
597 break;
598 }
599 }
600 }
601 if (index < 0) {
602 // Note: The HAL should be tracking the number of buffers in flight
603 // for each stream, and should never overflow the device.
604 HAL_LOGE("Cannot enqueue buffer: stream is already full.");
605 return -ENODEV;
606 }
607
608 // Set up a v4l2 buffer struct.
609 v4l2_buffer device_buffer;
610 memset(&device_buffer, 0, sizeof(device_buffer));
611 device_buffer.type = format_->type();
612 device_buffer.index = index;
613
614 // Use QUERYBUF to ensure our buffer/device is in good shape,
615 // and fill out remaining fields.
616 if (IoctlLocked(VIDIOC_QUERYBUF, &device_buffer) < 0) {
617 HAL_LOGE("QUERYBUF fails: %s", strerror(errno));
618 // Return buffer index.
619 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
620 buffers_[index].active = false;
621 return -ENODEV;
622 }
623
624 // Setup our request context and fill in the user pointer field.
625 RequestContext* request_context;
626 void* data;
627 {
628 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
629 request_context = &buffers_[index];
630 request_context->camera_buffer->SetDataSize(device_buffer.length);
631 request_context->camera_buffer->Reset();
632 request_context->camera_buffer->SetFourcc(format_->v4l2_pixel_format());
633 request_context->camera_buffer->SetWidth(format_->width());
634 request_context->camera_buffer->SetHeight(format_->height());
635 request_context->request = request;
636 data = request_context->camera_buffer->GetData();
637 }
638 device_buffer.m.userptr = reinterpret_cast<unsigned long>(data);
639
640 // Pass the buffer to the camera.
641 if (IoctlLocked(VIDIOC_QBUF, &device_buffer) < 0) {
642 HAL_LOGE("QBUF fails: %s", strerror(errno));
643 return -ENODEV;
644 }
645
646 // Mark the buffer as in flight.
647 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
648 request_context->active = true;
649
650 return 0;
651 }
652
DequeueRequest(std::shared_ptr<CaptureRequest> * request)653 int V4L2Wrapper::DequeueRequest(std::shared_ptr<CaptureRequest>* request) {
654 if (!format_) {
655 HAL_LOGV(
656 "Format not set, so stream can't be on, "
657 "so no buffers available for dequeueing");
658 return -EAGAIN;
659 }
660
661 v4l2_buffer buffer;
662 memset(&buffer, 0, sizeof(buffer));
663 buffer.type = format_->type();
664 buffer.memory = V4L2_MEMORY_USERPTR;
665 int res = IoctlLocked(VIDIOC_DQBUF, &buffer);
666 if (res) {
667 if (errno == EAGAIN) {
668 // Expected failure.
669 return -EAGAIN;
670 } else {
671 // Unexpected failure.
672 HAL_LOGE("DQBUF fails: %s", strerror(errno));
673 return -ENODEV;
674 }
675 }
676
677 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
678 RequestContext* request_context = &buffers_[buffer.index];
679
680 // Lock the camera stream buffer for painting.
681 const camera3_stream_buffer_t* stream_buffer =
682 &request_context->request->output_buffers[0];
683 uint32_t fourcc =
684 StreamFormat::HalToV4L2PixelFormat(stream_buffer->stream->format);
685
686 if (request) {
687 *request = request_context->request;
688 }
689
690 // Note that the device buffer length is passed to the output frame. If the
691 // GrallocFrameBuffer does not have support for the transformation to
692 // |fourcc|, it will assume that the amount of data to lock is based on
693 // |buffer.length|, otherwise it will use the ImageProcessor::ConvertedSize.
694 arc::GrallocFrameBuffer output_frame(
695 *stream_buffer->buffer, stream_buffer->stream->width,
696 stream_buffer->stream->height, fourcc, buffer.length,
697 stream_buffer->stream->usage);
698 res = output_frame.Map();
699 if (res) {
700 HAL_LOGE("Failed to map output frame.");
701 request_context->request.reset();
702 return -EINVAL;
703 }
704 if (request_context->camera_buffer->GetFourcc() == fourcc &&
705 request_context->camera_buffer->GetWidth() ==
706 stream_buffer->stream->width &&
707 request_context->camera_buffer->GetHeight() ==
708 stream_buffer->stream->height) {
709 // If no format conversion needs to be applied, directly copy the data over.
710 memcpy(output_frame.GetData(), request_context->camera_buffer->GetData(),
711 request_context->camera_buffer->GetDataSize());
712 } else {
713 // Perform the format conversion.
714 arc::CachedFrame cached_frame;
715 cached_frame.SetSource(request_context->camera_buffer.get(), 0);
716 cached_frame.Convert(request_context->request->settings, &output_frame);
717 }
718
719 request_context->request.reset();
720 // Mark the buffer as not in flight.
721 request_context->active = false;
722 return 0;
723 }
724
GetInFlightBufferCount()725 int V4L2Wrapper::GetInFlightBufferCount() {
726 int count = 0;
727 std::lock_guard<std::mutex> guard(buffer_queue_lock_);
728 for (auto& buffer : buffers_) {
729 if (buffer.active) {
730 count++;
731 }
732 }
733 return count;
734 }
735
736 } // namespace v4l2_camera_hal
737