blob: 3f047517ddb1bd07a48823931fbdf86f75874e14 [file] [log] [blame]
Yin-Chia Yeh19030592017-10-19 17:30:11 -07001/*
2 * Copyright (C) 2018 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_TAG "ExtCamDev@3.4"
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -080018//#define LOG_NDEBUG 0
Yin-Chia Yeh19030592017-10-19 17:30:11 -070019#include <log/log.h>
20
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -080021#include <algorithm>
Yin-Chia Yeh19030592017-10-19 17:30:11 -070022#include <array>
23#include <linux/videodev2.h>
24#include "android-base/macros.h"
25#include "CameraMetadata.h"
26#include "../../3.2/default/include/convert.h"
27#include "ExternalCameraDevice_3_4.h"
28
Yin-Chia Yeh19030592017-10-19 17:30:11 -070029namespace android {
30namespace hardware {
31namespace camera {
32namespace device {
33namespace V3_4 {
34namespace implementation {
35
36namespace {
37// Only support MJPEG for now as it seems to be the one supports higher fps
38// Other formats to consider in the future:
39// * V4L2_PIX_FMT_YVU420 (== YV12)
40// * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
Emil Jahshaneed00402018-12-11 15:15:17 +020041const std::array<uint32_t, /*size*/ 2> kSupportedFourCCs{
42 {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_Z16}}; // double braces required in C++11
Yin-Chia Yeh19030592017-10-19 17:30:11 -070043
Yin-Chia Yeh2d61bfd2018-03-14 13:50:23 -070044constexpr int MAX_RETRY = 5; // Allow retry v4l2 open failures a few times.
45constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds
46
Yin-Chia Yeh19030592017-10-19 17:30:11 -070047} // anonymous namespace
48
Yin-Chia Yeh17982492018-02-05 17:41:01 -080049ExternalCameraDevice::ExternalCameraDevice(
Yin-Chia Yehee238402018-11-04 16:30:11 -080050 const std::string& cameraId, const ExternalCameraConfig& cfg) :
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -080051 mCameraId(cameraId),
Yin-Chia Yehee238402018-11-04 16:30:11 -080052 mCfg(cfg) {}
Yin-Chia Yeh19030592017-10-19 17:30:11 -070053
54ExternalCameraDevice::~ExternalCameraDevice() {}
55
56bool ExternalCameraDevice::isInitFailed() {
Yin-Chia Yehee238402018-11-04 16:30:11 -080057 Mutex::Autolock _l(mLock);
58 return isInitFailedLocked();
59}
60
61bool ExternalCameraDevice::isInitFailedLocked() {
62 if (!mInitialized) {
63 status_t ret = initCameraCharacteristics();
64 if (ret != OK) {
65 ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
66 mInitFailed = true;
67 }
68 mInitialized = true;
69 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -070070 return mInitFailed;
71}
72
Yin-Chia Yehee238402018-11-04 16:30:11 -080073Return<void> ExternalCameraDevice::getResourceCost(
74 ICameraDevice::getResourceCost_cb _hidl_cb) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -070075 CameraResourceCost resCost;
76 resCost.resourceCost = 100;
77 _hidl_cb(Status::OK, resCost);
78 return Void();
79}
80
81Return<void> ExternalCameraDevice::getCameraCharacteristics(
Yin-Chia Yehee238402018-11-04 16:30:11 -080082 ICameraDevice::getCameraCharacteristics_cb _hidl_cb) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -070083 Mutex::Autolock _l(mLock);
84 V3_2::CameraMetadata hidlChars;
85
Yin-Chia Yehee238402018-11-04 16:30:11 -080086 if (isInitFailedLocked()) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -070087 _hidl_cb(Status::INTERNAL_ERROR, hidlChars);
88 return Void();
89 }
90
91 const camera_metadata_t* rawMetadata = mCameraCharacteristics.getAndLock();
92 V3_2::implementation::convertToHidl(rawMetadata, &hidlChars);
93 _hidl_cb(Status::OK, hidlChars);
94 mCameraCharacteristics.unlock(rawMetadata);
95 return Void();
96}
97
98Return<Status> ExternalCameraDevice::setTorchMode(TorchMode) {
Yin-Chia Yehbbc046e2018-08-28 10:52:43 -070099 return Status::OPERATION_NOT_SUPPORTED;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700100}
101
102Return<void> ExternalCameraDevice::open(
Yin-Chia Yehee238402018-11-04 16:30:11 -0800103 const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700104 Status status = Status::OK;
105 sp<ExternalCameraDeviceSession> session = nullptr;
106
107 if (callback == nullptr) {
108 ALOGE("%s: cannot open camera %s. callback is null!",
109 __FUNCTION__, mCameraId.c_str());
110 _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
111 return Void();
112 }
113
114 if (isInitFailed()) {
115 ALOGE("%s: cannot open camera %s. camera init failed!",
116 __FUNCTION__, mCameraId.c_str());
117 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
118 return Void();
119 }
120
121 mLock.lock();
122
123 ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
124 session = mSession.promote();
125 if (session != nullptr && !session->isClosed()) {
126 ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
127 mLock.unlock();
128 _hidl_cb(Status::CAMERA_IN_USE, nullptr);
129 return Void();
130 }
131
132 unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
133 if (fd.get() < 0) {
Yin-Chia Yeh2d61bfd2018-03-14 13:50:23 -0700134 int numAttempt = 0;
135 do {
136 ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
137 __FUNCTION__, mCameraId.c_str());
138 usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
139 fd.reset(::open(mCameraId.c_str(), O_RDWR));
140 numAttempt++;
141 } while (fd.get() < 0 && numAttempt <= MAX_RETRY);
142
143 if (fd.get() < 0) {
144 ALOGE("%s: v4l2 device open %s failed: %s",
145 __FUNCTION__, mCameraId.c_str(), strerror(errno));
146 mLock.unlock();
147 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
148 return Void();
149 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700150 }
151
Yin-Chia Yehee238402018-11-04 16:30:11 -0800152 session = createSession(
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800153 callback, mCfg, mSupportedFormats, mCroppingType,
Yin-Chia Yeh4a3393c2018-02-14 12:47:16 -0800154 mCameraCharacteristics, mCameraId, std::move(fd));
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700155 if (session == nullptr) {
156 ALOGE("%s: camera device session allocation failed", __FUNCTION__);
157 mLock.unlock();
158 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
159 return Void();
160 }
161 if (session->isInitFailed()) {
162 ALOGE("%s: camera device session init failed", __FUNCTION__);
163 session = nullptr;
164 mLock.unlock();
165 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
166 return Void();
167 }
168 mSession = session;
169
170 mLock.unlock();
171
172 _hidl_cb(status, session->getInterface());
173 return Void();
174}
175
176Return<void> ExternalCameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) {
177 Mutex::Autolock _l(mLock);
178 if (handle.getNativeHandle() == nullptr) {
179 ALOGE("%s: handle must not be null", __FUNCTION__);
180 return Void();
181 }
182 if (handle->numFds != 1 || handle->numInts != 0) {
183 ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
184 __FUNCTION__, handle->numFds, handle->numInts);
185 return Void();
186 }
187 int fd = handle->data[0];
188 if (mSession == nullptr) {
189 dprintf(fd, "No active camera device session instance\n");
190 return Void();
191 }
192 auto session = mSession.promote();
193 if (session == nullptr) {
194 dprintf(fd, "No active camera device session instance\n");
195 return Void();
196 }
197 // Call into active session to dump states
198 session->dumpState(handle);
199 return Void();
200}
201
202
203status_t ExternalCameraDevice::initCameraCharacteristics() {
204 if (mCameraCharacteristics.isEmpty()) {
205 // init camera characteristics
206 unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
207 if (fd.get() < 0) {
208 ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
209 return DEAD_OBJECT;
210 }
211
212 status_t ret;
213 ret = initDefaultCharsKeys(&mCameraCharacteristics);
214 if (ret != OK) {
215 ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
216 mCameraCharacteristics.clear();
217 return ret;
218 }
219
220 ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
221 if (ret != OK) {
222 ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
223 mCameraCharacteristics.clear();
224 return ret;
225 }
226
227 ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
228 if (ret != OK) {
229 ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
230 mCameraCharacteristics.clear();
231 return ret;
232 }
Emil Jahshaneed00402018-12-11 15:15:17 +0200233
234 ret = initAvailableCapabilities(&mCameraCharacteristics);
235 if (ret != OK) {
236 ALOGE("%s: init available capabilities key failed: errorno %d", __FUNCTION__, ret);
237 mCameraCharacteristics.clear();
238 return ret;
239 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700240 }
241 return OK;
242}
243
244#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
245#define UPDATE(tag, data, size) \
246do { \
247 if (metadata->update((tag), (data), (size))) { \
248 ALOGE("Update " #tag " failed!"); \
249 return -EINVAL; \
250 } \
251} while (0)
252
Emil Jahshaneed00402018-12-11 15:15:17 +0200253status_t ExternalCameraDevice::initAvailableCapabilities(
254 ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
255
256 if (mSupportedFormats.empty()) {
257 ALOGE("%s: Supported formats list is empty", __FUNCTION__);
258 return UNKNOWN_ERROR;
259 }
260
261 bool hasDepth = false;
262 bool hasColor = false;
263 for (const auto& fmt : mSupportedFormats) {
264 switch (fmt.fourcc) {
265 case V4L2_PIX_FMT_Z16: hasDepth = true; break;
266 case V4L2_PIX_FMT_MJPEG: hasColor = true; break;
267 default: ALOGW("%s: Unsupported format found", __FUNCTION__);
268 }
269 }
270
271 std::vector<uint8_t> availableCapabilities;
272 if (hasDepth) {
273 availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
274 }
275 if (hasColor) {
276 availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
277 }
278 if(!availableCapabilities.empty()) {
279 UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities.data(),
280 availableCapabilities.size());
281 }
282
283 return OK;
284}
285
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700286status_t ExternalCameraDevice::initDefaultCharsKeys(
287 ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
Yin-Chia Yeh4acd76e2018-01-23 15:29:14 -0800288 const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700289 UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
290
291 // android.colorCorrection
292 const uint8_t availableAberrationModes[] = {
293 ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF};
294 UPDATE(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
295 availableAberrationModes, ARRAY_SIZE(availableAberrationModes));
296
297 // android.control
298 const uint8_t antibandingMode =
299 ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
300 UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
301 &antibandingMode, 1);
302
303 const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
304 UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions,
305 ARRAY_SIZE(controlMaxRegions));
306
307 const uint8_t videoStabilizationMode =
308 ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
309 UPDATE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
310 &videoStabilizationMode, 1);
311
312 const uint8_t awbAvailableMode = ANDROID_CONTROL_AWB_MODE_AUTO;
313 UPDATE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &awbAvailableMode, 1);
314
315 const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
316 UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
317
318 const uint8_t availableFffect = ANDROID_CONTROL_EFFECT_MODE_OFF;
319 UPDATE(ANDROID_CONTROL_AVAILABLE_EFFECTS, &availableFffect, 1);
320
321 const uint8_t controlAvailableModes[] = {ANDROID_CONTROL_MODE_OFF,
322 ANDROID_CONTROL_MODE_AUTO};
323 UPDATE(ANDROID_CONTROL_AVAILABLE_MODES, controlAvailableModes,
324 ARRAY_SIZE(controlAvailableModes));
325
326 // android.edge
327 const uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
328 UPDATE(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &edgeMode, 1);
329
330 // android.flash
331 const uint8_t flashInfo = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
332 UPDATE(ANDROID_FLASH_INFO_AVAILABLE, &flashInfo, 1);
333
334 // android.hotPixel
335 const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
336 UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
337
338 // android.jpeg
chenhg564cdae2018-06-20 14:21:20 -0700339 const int32_t jpegAvailableThumbnailSizes[] = {0, 0,
340 176, 144,
341 240, 144,
342 256, 144,
343 240, 160,
344 256, 154,
345 240, 240,
346 320, 240};
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700347 UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
348 ARRAY_SIZE(jpegAvailableThumbnailSizes));
349
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800350 const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700351 UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
352
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700353 // android.lens
354 const uint8_t focusDistanceCalibration =
355 ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
356 UPDATE(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &focusDistanceCalibration, 1);
357
358 const uint8_t opticalStabilizationMode =
359 ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
360 UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
361 &opticalStabilizationMode, 1);
362
363 const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;
364 UPDATE(ANDROID_LENS_FACING, &facing, 1);
365
366 // android.noiseReduction
367 const uint8_t noiseReductionMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
368 UPDATE(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
369 &noiseReductionMode, 1);
370 UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
371
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700372 const int32_t partialResultCount = 1;
373 UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
374
375 // This means pipeline latency of X frame intervals. The maximum number is 4.
376 const uint8_t requestPipelineMaxDepth = 4;
377 UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700378
379 // Three numbers represent the maximum numbers of different types of output
380 // streams simultaneously. The types are raw sensor, processed (but not
381 // stalling), and processed (but stalling). For usb limited mode, raw sensor
382 // is not supported. Stalling stream is JPEG. Non-stalling streams are
383 // YUV_420_888 or YV12.
384 const int32_t requestMaxNumOutputStreams[] = {
385 /*RAW*/0,
386 /*Processed*/ExternalCameraDeviceSession::kMaxProcessedStream,
387 /*Stall*/ExternalCameraDeviceSession::kMaxStallStream};
388 UPDATE(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, requestMaxNumOutputStreams,
389 ARRAY_SIZE(requestMaxNumOutputStreams));
390
391 // Limited mode doesn't support reprocessing.
392 const int32_t requestMaxNumInputStreams = 0;
393 UPDATE(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &requestMaxNumInputStreams,
394 1);
395
396 // android.scaler
397 // TODO: b/72263447 V4L2_CID_ZOOM_*
398 const float scalerAvailableMaxDigitalZoom[] = {1};
399 UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
400 scalerAvailableMaxDigitalZoom,
401 ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
402
403 const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
404 UPDATE(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
405
406 const int32_t testPatternModes[] = {
407 ANDROID_SENSOR_TEST_PATTERN_MODE_OFF};
408 UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
409 ARRAY_SIZE(testPatternModes));
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700410
411 const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
412 UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1);
413
Yin-Chia Yeh1c30a5e2018-11-28 16:00:16 -0800414 // Orientation is a bit odd for external camera, but consider it as the orientation
415 // between the external camera sensor (which is usually landscape) and the device's
416 // natural display orientation. For devices with natural landscape display (ex: tablet/TV), the
417 // orientation should be 0. For devices with natural portrait display (phone), the orientation
418 // should be 270.
419 const int32_t orientation = mCfg.orientation;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700420 UPDATE(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
421
422 // android.shading
423 const uint8_t availabeMode = ANDROID_SHADING_MODE_OFF;
424 UPDATE(ANDROID_SHADING_AVAILABLE_MODES, &availabeMode, 1);
425
426 // android.statistics
427 const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
428 UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode,
429 1);
430
431 const int32_t maxFaceCount = 0;
432 UPDATE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
433
434 const uint8_t availableHotpixelMode =
435 ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
436 UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
437 &availableHotpixelMode, 1);
438
439 const uint8_t lensShadingMapMode =
440 ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
441 UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
442 &lensShadingMapMode, 1);
443
444 // android.sync
445 const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
446 UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
447
448 /* Other sensor/RAW realted keys:
449 * android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
450 * android.sensor.info.physicalSize -> not available
451 * android.sensor.info.whiteLevel -> not available/not needed
452 * android.sensor.info.lensShadingApplied -> not needed
453 * android.sensor.info.preCorrectionActiveArraySize -> not available/not needed
454 * android.sensor.blackLevelPattern -> not available/not needed
455 */
456
457 const int32_t availableRequestKeys[] = {
458 ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
459 ANDROID_CONTROL_AE_ANTIBANDING_MODE,
460 ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
461 ANDROID_CONTROL_AE_LOCK,
462 ANDROID_CONTROL_AE_MODE,
463 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
464 ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
465 ANDROID_CONTROL_AF_MODE,
466 ANDROID_CONTROL_AF_TRIGGER,
467 ANDROID_CONTROL_AWB_LOCK,
468 ANDROID_CONTROL_AWB_MODE,
469 ANDROID_CONTROL_CAPTURE_INTENT,
470 ANDROID_CONTROL_EFFECT_MODE,
471 ANDROID_CONTROL_MODE,
472 ANDROID_CONTROL_SCENE_MODE,
473 ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
474 ANDROID_FLASH_MODE,
475 ANDROID_JPEG_ORIENTATION,
476 ANDROID_JPEG_QUALITY,
477 ANDROID_JPEG_THUMBNAIL_QUALITY,
478 ANDROID_JPEG_THUMBNAIL_SIZE,
479 ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
480 ANDROID_NOISE_REDUCTION_MODE,
481 ANDROID_SCALER_CROP_REGION,
482 ANDROID_SENSOR_TEST_PATTERN_MODE,
483 ANDROID_STATISTICS_FACE_DETECT_MODE,
484 ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE};
485 UPDATE(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys,
486 ARRAY_SIZE(availableRequestKeys));
487
488 const int32_t availableResultKeys[] = {
489 ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
490 ANDROID_CONTROL_AE_ANTIBANDING_MODE,
491 ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
492 ANDROID_CONTROL_AE_LOCK,
493 ANDROID_CONTROL_AE_MODE,
494 ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
495 ANDROID_CONTROL_AE_STATE,
496 ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
497 ANDROID_CONTROL_AF_MODE,
498 ANDROID_CONTROL_AF_STATE,
499 ANDROID_CONTROL_AF_TRIGGER,
500 ANDROID_CONTROL_AWB_LOCK,
501 ANDROID_CONTROL_AWB_MODE,
502 ANDROID_CONTROL_AWB_STATE,
503 ANDROID_CONTROL_CAPTURE_INTENT,
504 ANDROID_CONTROL_EFFECT_MODE,
505 ANDROID_CONTROL_MODE,
506 ANDROID_CONTROL_SCENE_MODE,
507 ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
508 ANDROID_FLASH_MODE,
509 ANDROID_FLASH_STATE,
510 ANDROID_JPEG_ORIENTATION,
511 ANDROID_JPEG_QUALITY,
512 ANDROID_JPEG_THUMBNAIL_QUALITY,
513 ANDROID_JPEG_THUMBNAIL_SIZE,
514 ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
515 ANDROID_NOISE_REDUCTION_MODE,
516 ANDROID_REQUEST_PIPELINE_DEPTH,
517 ANDROID_SCALER_CROP_REGION,
518 ANDROID_SENSOR_TIMESTAMP,
519 ANDROID_STATISTICS_FACE_DETECT_MODE,
520 ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
521 ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
522 ANDROID_STATISTICS_SCENE_FLICKER};
523 UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
524 ARRAY_SIZE(availableResultKeys));
525
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700526 UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
Yin-Chia Yehee238402018-11-04 16:30:11 -0800527 AVAILABLE_CHARACTERISTICS_KEYS_3_4.data(),
528 AVAILABLE_CHARACTERISTICS_KEYS_3_4.size());
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700529
530 return OK;
531}
532
533status_t ExternalCameraDevice::initCameraControlsCharsKeys(int,
534 ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
535 /**
536 * android.sensor.info.sensitivityRange -> V4L2_CID_ISO_SENSITIVITY
537 * android.sensor.info.exposureTimeRange -> V4L2_CID_EXPOSURE_ABSOLUTE
538 * android.sensor.info.maxFrameDuration -> TBD
539 * android.lens.info.minimumFocusDistance -> V4L2_CID_FOCUS_ABSOLUTE
540 * android.lens.info.hyperfocalDistance
541 * android.lens.info.availableFocalLengths -> not available?
542 */
543
544 // android.control
545 // No AE compensation support for now.
546 // TODO: V4L2_CID_EXPOSURE_BIAS
547 const int32_t controlAeCompensationRange[] = {0, 0};
548 UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
549 ARRAY_SIZE(controlAeCompensationRange));
550 const camera_metadata_rational_t controlAeCompensationStep[] = {{0, 1}};
551 UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
552 ARRAY_SIZE(controlAeCompensationStep));
553
554
555 // TODO: Check V4L2_CID_AUTO_FOCUS_*.
556 const uint8_t afAvailableModes[] = {ANDROID_CONTROL_AF_MODE_AUTO,
557 ANDROID_CONTROL_AF_MODE_OFF};
558 UPDATE(ANDROID_CONTROL_AF_AVAILABLE_MODES, afAvailableModes,
559 ARRAY_SIZE(afAvailableModes));
560
561 // TODO: V4L2_CID_SCENE_MODE
562 const uint8_t availableSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
563 UPDATE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &availableSceneMode, 1);
564
565 // TODO: V4L2_CID_3A_LOCK
566 const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
567 UPDATE(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
568 const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
569 UPDATE(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
570
571 // TODO: V4L2_CID_ZOOM_*
572 const float scalerAvailableMaxDigitalZoom[] = {1};
573 UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
574 scalerAvailableMaxDigitalZoom,
575 ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
576
577 return OK;
578}
579
Emil Jahshaneed00402018-12-11 15:15:17 +0200580template <size_t SIZE>
581status_t ExternalCameraDevice::initOutputCharskeysByFormat(
582 ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
583 uint32_t fourcc, const std::array<int, SIZE>& halFormats,
584 int streamConfigTag, int streamConfiguration, int minFrameDuration, int stallDuration) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700585 if (mSupportedFormats.empty()) {
586 ALOGE("%s: Init supported format list failed", __FUNCTION__);
587 return UNKNOWN_ERROR;
588 }
589
590 std::vector<int32_t> streamConfigurations;
591 std::vector<int64_t> minFrameDurations;
592 std::vector<int64_t> stallDurations;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700593
594 for (const auto& supportedFormat : mSupportedFormats) {
Emil Jahshaneed00402018-12-11 15:15:17 +0200595 if (supportedFormat.fourcc != fourcc) {
596 // Skip 4CCs not meant for the halFormats
597 continue;
598 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700599 for (const auto& format : halFormats) {
600 streamConfigurations.push_back(format);
601 streamConfigurations.push_back(supportedFormat.width);
602 streamConfigurations.push_back(supportedFormat.height);
Emil Jahshaneed00402018-12-11 15:15:17 +0200603 streamConfigurations.push_back(streamConfigTag);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700604 }
605
Yin-Chia Yeh134093a2018-02-12 14:05:48 -0800606 int64_t minFrameDuration = std::numeric_limits<int64_t>::max();
607 for (const auto& fr : supportedFormat.frameRates) {
608 // 1000000000LL < (2^32 - 1) and
609 // fr.durationNumerator is uint32_t, so no overflow here
610 int64_t frameDuration = 1000000000LL * fr.durationNumerator /
611 fr.durationDenominator;
612 if (frameDuration < minFrameDuration) {
613 minFrameDuration = frameDuration;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700614 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700615 }
616
617 for (const auto& format : halFormats) {
618 minFrameDurations.push_back(format);
619 minFrameDurations.push_back(supportedFormat.width);
620 minFrameDurations.push_back(supportedFormat.height);
Yin-Chia Yeh134093a2018-02-12 14:05:48 -0800621 minFrameDurations.push_back(minFrameDuration);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700622 }
623
624 // The stall duration is 0 for non-jpeg formats. For JPEG format, stall
625 // duration can be 0 if JPEG is small. Here we choose 1 sec for JPEG.
626 // TODO: b/72261675. Maybe set this dynamically
627 for (const auto& format : halFormats) {
628 const int64_t NS_TO_SECOND = 1000000000;
629 int64_t stall_duration =
630 (format == HAL_PIXEL_FORMAT_BLOB) ? NS_TO_SECOND : 0;
631 stallDurations.push_back(format);
632 stallDurations.push_back(supportedFormat.width);
633 stallDurations.push_back(supportedFormat.height);
634 stallDurations.push_back(stall_duration);
635 }
636 }
637
Emil Jahshaneed00402018-12-11 15:15:17 +0200638 UPDATE(streamConfiguration, streamConfigurations.data(), streamConfigurations.size());
639
640 UPDATE(minFrameDuration, minFrameDurations.data(), minFrameDurations.size());
641
642 UPDATE(stallDuration, stallDurations.data(), stallDurations.size());
643
644 return true;
645}
646
647bool ExternalCameraDevice::calculateMinFps(
648 ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
649 std::set<int32_t> framerates;
650 int32_t minFps = std::numeric_limits<int32_t>::max();
651
652 for (const auto& supportedFormat : mSupportedFormats) {
653 for (const auto& fr : supportedFormat.frameRates) {
654 int32_t frameRateInt = static_cast<int32_t>(fr.getDouble());
655 if (minFps > frameRateInt) {
656 minFps = frameRateInt;
657 }
658 framerates.insert(frameRateInt);
659 }
660 }
661
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700662 std::vector<int32_t> fpsRanges;
Yin-Chia Yeh8b699aa2018-02-28 15:58:54 -0800663 // FPS ranges
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700664 for (const auto& framerate : framerates) {
Yin-Chia Yeh8b699aa2018-02-28 15:58:54 -0800665 // Empirical: webcams often have close to 2x fps error and cannot support fixed fps range
666 fpsRanges.push_back(framerate / 2);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700667 fpsRanges.push_back(framerate);
668 }
Yin-Chia Yehc15a1ca2018-03-02 14:16:52 -0800669 minFps /= 2;
670 int64_t maxFrameDuration = 1000000000LL / minFps;
Yin-Chia Yeh8b699aa2018-02-28 15:58:54 -0800671
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700672 UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(),
673 fpsRanges.size());
674
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700675 UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
676
Emil Jahshaneed00402018-12-11 15:15:17 +0200677 return true;
678}
679
680status_t ExternalCameraDevice::initOutputCharsKeys(
681 int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
682 initSupportedFormatsLocked(fd);
683 if (mSupportedFormats.empty()) {
684 ALOGE("%s: Init supported format list failed", __FUNCTION__);
685 return UNKNOWN_ERROR;
686 }
687
688 bool hasDepth = false;
689 bool hasColor = false;
690
691 // For V4L2_PIX_FMT_Z16
692 std::array<int, /*size*/ 1> halDepthFormats{{HAL_PIXEL_FORMAT_Y16}};
693 // For V4L2_PIX_FMT_MJPEG
694 std::array<int, /*size*/ 3> halFormats{{HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_YCbCr_420_888,
695 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
696
697 for (const auto& supportedFormat : mSupportedFormats) {
698 switch (supportedFormat.fourcc) {
699 case V4L2_PIX_FMT_Z16:
700 hasDepth = true;
701 break;
702 case V4L2_PIX_FMT_MJPEG:
703 hasColor = true;
704 break;
705 default:
706 ALOGW("%s: format %c%c%c%c is not supported!", __FUNCTION__,
707 supportedFormat.fourcc & 0xFF, (supportedFormat.fourcc >> 8) & 0xFF,
708 (supportedFormat.fourcc >> 16) & 0xFF, (supportedFormat.fourcc >> 24) & 0xFF);
709 }
710 }
711
712 if (hasDepth) {
713 initOutputCharskeysByFormat(metadata, V4L2_PIX_FMT_Z16, halDepthFormats,
714 ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
715 ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
716 ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
717 ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
718 }
719 if (hasColor) {
720 initOutputCharskeysByFormat(metadata, V4L2_PIX_FMT_MJPEG, halFormats,
721 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
722 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
723 ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
724 ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
725 }
726
727 calculateMinFps(metadata);
728
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700729 SupportedV4L2Format maximumFormat {.width = 0, .height = 0};
730 for (const auto& supportedFormat : mSupportedFormats) {
731 if (supportedFormat.width >= maximumFormat.width &&
732 supportedFormat.height >= maximumFormat.height) {
733 maximumFormat = supportedFormat;
734 }
735 }
736 int32_t activeArraySize[] = {0, 0,
737 static_cast<int32_t>(maximumFormat.width),
738 static_cast<int32_t>(maximumFormat.height)};
739 UPDATE(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
740 activeArraySize, ARRAY_SIZE(activeArraySize));
741 UPDATE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArraySize,
742 ARRAY_SIZE(activeArraySize));
743
744 int32_t pixelArraySize[] = {static_cast<int32_t>(maximumFormat.width),
745 static_cast<int32_t>(maximumFormat.height)};
746 UPDATE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize,
747 ARRAY_SIZE(pixelArraySize));
748 return OK;
749}
750
751#undef ARRAY_SIZE
752#undef UPDATE
753
754void ExternalCameraDevice::getFrameRateList(
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800755 int fd, double fpsUpperBound, SupportedV4L2Format* format) {
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700756 format->frameRates.clear();
757
758 v4l2_frmivalenum frameInterval {
759 .pixel_format = format->fourcc,
760 .width = format->width,
761 .height = format->height,
762 .index = 0
763 };
764
765 for (frameInterval.index = 0;
766 TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) == 0;
767 ++frameInterval.index) {
768 if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
769 if (frameInterval.discrete.numerator != 0) {
Yin-Chia Yeh134093a2018-02-12 14:05:48 -0800770 SupportedV4L2Format::FrameRate fr = {
771 frameInterval.discrete.numerator,
772 frameInterval.discrete.denominator};
773 double framerate = fr.getDouble();
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800774 if (framerate > fpsUpperBound) {
775 continue;
776 }
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800777 ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700778 frameInterval.index,
779 frameInterval.pixel_format & 0xFF,
780 (frameInterval.pixel_format >> 8) & 0xFF,
781 (frameInterval.pixel_format >> 16) & 0xFF,
782 (frameInterval.pixel_format >> 24) & 0xFF,
783 frameInterval.width, frameInterval.height, framerate);
Yin-Chia Yeh134093a2018-02-12 14:05:48 -0800784 format->frameRates.push_back(fr);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700785 }
786 }
787 }
788
789 if (format->frameRates.empty()) {
790 ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d",
791 __FUNCTION__,
792 frameInterval.pixel_format & 0xFF,
793 (frameInterval.pixel_format >> 8) & 0xFF,
794 (frameInterval.pixel_format >> 16) & 0xFF,
795 (frameInterval.pixel_format >> 24) & 0xFF,
796 frameInterval.width, frameInterval.height);
797 }
798}
799
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800800void ExternalCameraDevice::trimSupportedFormats(
801 CroppingType cropType,
802 /*inout*/std::vector<SupportedV4L2Format>* pFmts) {
803 std::vector<SupportedV4L2Format>& sortedFmts = *pFmts;
804 if (cropType == VERTICAL) {
805 std::sort(sortedFmts.begin(), sortedFmts.end(),
806 [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
807 if (a.width == b.width) {
808 return a.height < b.height;
809 }
810 return a.width < b.width;
811 });
812 } else {
813 std::sort(sortedFmts.begin(), sortedFmts.end(),
814 [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
815 if (a.height == b.height) {
816 return a.width < b.width;
817 }
818 return a.height < b.height;
819 });
820 }
821
822 if (sortedFmts.size() == 0) {
823 ALOGE("%s: input format list is empty!", __FUNCTION__);
824 return;
825 }
826
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800827 const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
828 float maxSizeAr = ASPECT_RATIO(maxSize);
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800829
830 // Remove formats that has aspect ratio not croppable from largest size
831 std::vector<SupportedV4L2Format> out;
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800832 for (const auto& fmt : sortedFmts) {
833 float ar = ASPECT_RATIO(fmt);
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800834 if (isAspectRatioClose(ar, maxSizeAr)) {
835 out.push_back(fmt);
836 } else if (cropType == HORIZONTAL && ar < maxSizeAr) {
837 out.push_back(fmt);
838 } else if (cropType == VERTICAL && ar > maxSizeAr) {
839 out.push_back(fmt);
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800840 } else {
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800841 ALOGV("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)",
842 __FUNCTION__, fmt.width, fmt.height,
843 cropType == VERTICAL ? "vertically" : "horizontally",
844 maxSize.width, maxSize.height);
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800845 }
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800846 }
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800847 sortedFmts = out;
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800848}
849
Emil Jahshaneed00402018-12-11 15:15:17 +0200850std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormatsLocked(
851 int fd, CroppingType cropType,
852 const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
853 const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
854 const Size& minStreamSize,
855 bool depthEnabled) {
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800856 std::vector<SupportedV4L2Format> outFmts;
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700857 struct v4l2_fmtdesc fmtdesc {
858 .index = 0,
859 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
860 int ret = 0;
861 while (ret == 0) {
862 ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800863 ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700864 fmtdesc.pixelformat & 0xFF,
865 (fmtdesc.pixelformat >> 8) & 0xFF,
866 (fmtdesc.pixelformat >> 16) & 0xFF,
867 (fmtdesc.pixelformat >> 24) & 0xFF);
868 if (ret == 0 && !(fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
869 auto it = std::find (
870 kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
871 if (it != kSupportedFourCCs.end()) {
872 // Found supported format
873 v4l2_frmsizeenum frameSize {
874 .index = 0,
875 .pixel_format = fmtdesc.pixelformat};
876 for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
877 ++frameSize.index) {
878 if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800879 ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700880 fmtdesc.pixelformat & 0xFF,
881 (fmtdesc.pixelformat >> 8) & 0xFF,
882 (fmtdesc.pixelformat >> 16) & 0xFF,
883 (fmtdesc.pixelformat >> 24) & 0xFF,
884 frameSize.discrete.width, frameSize.discrete.height);
885 // Disregard h > w formats so all aspect ratio (h/w) <= 1.0
886 // This will simplify the crop/scaling logic down the road
887 if (frameSize.discrete.height > frameSize.discrete.width) {
888 continue;
889 }
chenhgf2a6c472018-06-22 13:27:50 -0700890 // Discard all formats which is smaller than minStreamSize
891 if (frameSize.discrete.width < minStreamSize.width
892 || frameSize.discrete.height < minStreamSize.height) {
893 continue;
894 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700895 SupportedV4L2Format format {
896 .width = frameSize.discrete.width,
897 .height = frameSize.discrete.height,
898 .fourcc = fmtdesc.pixelformat
899 };
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800900
Emil Jahshaneed00402018-12-11 15:15:17 +0200901 if (format.fourcc == V4L2_PIX_FMT_Z16 && depthEnabled) {
902 updateFpsBounds(fd, cropType, depthFpsLimits, format, outFmts);
903 } else {
904 updateFpsBounds(fd, cropType, fpsLimits, format, outFmts);
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700905 }
906 }
907 }
908 }
909 }
910 fmtdesc.index++;
911 }
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800912 trimSupportedFormats(cropType, &outFmts);
913 return outFmts;
914}
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800915
Emil Jahshaneed00402018-12-11 15:15:17 +0200916void ExternalCameraDevice::updateFpsBounds(
917 int fd, CroppingType cropType,
918 const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits, SupportedV4L2Format format,
919 std::vector<SupportedV4L2Format>& outFmts) {
920 double fpsUpperBound = -1.0;
921 for (const auto& limit : fpsLimits) {
922 if (cropType == VERTICAL) {
923 if (format.width <= limit.size.width) {
924 fpsUpperBound = limit.fpsUpperBound;
925 break;
926 }
927 } else { // HORIZONTAL
928 if (format.height <= limit.size.height) {
929 fpsUpperBound = limit.fpsUpperBound;
930 break;
931 }
932 }
933 }
934 if (fpsUpperBound < 0.f) {
935 return;
936 }
Yin-Chia Yeh53f4cb12018-01-29 10:31:45 -0800937
Emil Jahshaneed00402018-12-11 15:15:17 +0200938 getFrameRateList(fd, fpsUpperBound, &format);
939 if (!format.frameRates.empty()) {
940 outFmts.push_back(format);
941 }
942}
943
944void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
945 std::vector<SupportedV4L2Format> horizontalFmts = getCandidateSupportedFormatsLocked(
946 fd, HORIZONTAL, mCfg.fpsLimits, mCfg.depthFpsLimits, mCfg.minStreamSize, mCfg.depthEnabled);
947 std::vector<SupportedV4L2Format> verticalFmts = getCandidateSupportedFormatsLocked(
948 fd, VERTICAL, mCfg.fpsLimits, mCfg.depthFpsLimits, mCfg.minStreamSize, mCfg.depthEnabled);
Yin-Chia Yeh3aa9ae92018-02-23 17:21:51 -0800949
950 size_t horiSize = horizontalFmts.size();
951 size_t vertSize = verticalFmts.size();
952
953 if (horiSize == 0 && vertSize == 0) {
954 ALOGE("%s: cannot find suitable cropping type!", __FUNCTION__);
955 return;
956 }
957
958 if (horiSize == 0) {
959 mSupportedFormats = verticalFmts;
960 mCroppingType = VERTICAL;
961 return;
962 } else if (vertSize == 0) {
963 mSupportedFormats = horizontalFmts;
964 mCroppingType = HORIZONTAL;
965 return;
966 }
967
968 const auto& maxHoriSize = horizontalFmts[horizontalFmts.size() - 1];
969 const auto& maxVertSize = verticalFmts[verticalFmts.size() - 1];
970
971 // Try to keep largest possible output size
972 // When they are the same or ambiguous, pick the one support more sizes
973 if (maxHoriSize.width == maxVertSize.width &&
974 maxHoriSize.height == maxVertSize.height) {
975 if (horiSize > vertSize) {
976 mSupportedFormats = horizontalFmts;
977 mCroppingType = HORIZONTAL;
978 } else {
979 mSupportedFormats = verticalFmts;
980 mCroppingType = VERTICAL;
981 }
982 } else if (maxHoriSize.width >= maxVertSize.width &&
983 maxHoriSize.height >= maxVertSize.height) {
984 mSupportedFormats = horizontalFmts;
985 mCroppingType = HORIZONTAL;
986 } else if (maxHoriSize.width <= maxVertSize.width &&
987 maxHoriSize.height <= maxVertSize.height) {
988 mSupportedFormats = verticalFmts;
989 mCroppingType = VERTICAL;
990 } else {
991 if (horiSize > vertSize) {
992 mSupportedFormats = horizontalFmts;
993 mCroppingType = HORIZONTAL;
994 } else {
995 mSupportedFormats = verticalFmts;
996 mCroppingType = VERTICAL;
997 }
998 }
Yin-Chia Yeh19030592017-10-19 17:30:11 -0700999}
1000
Yin-Chia Yehee238402018-11-04 16:30:11 -08001001sp<ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
1002 const sp<ICameraDeviceCallback>& cb,
1003 const ExternalCameraConfig& cfg,
1004 const std::vector<SupportedV4L2Format>& sortedFormats,
1005 const CroppingType& croppingType,
1006 const common::V1_0::helper::CameraMetadata& chars,
1007 const std::string& cameraId,
1008 unique_fd v4l2Fd) {
1009 return new ExternalCameraDeviceSession(
1010 cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
1011}
1012
Yin-Chia Yeh19030592017-10-19 17:30:11 -07001013} // namespace implementation
1014} // namespace V3_4
1015} // namespace device
1016} // namespace camera
1017} // namespace hardware
1018} // namespace android
1019