summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice/api1/client2/Parameters.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/camera/libcameraservice/api1/client2/Parameters.cpp')
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp2752
1 files changed, 2752 insertions, 0 deletions
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
new file mode 100644
index 0000000..8a4e75c
--- /dev/null
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -0,0 +1,2752 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2-Parameters"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+#include <math.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+
+#include "Parameters.h"
+#include "system/camera.h"
+
+namespace android {
+namespace camera2 {
+
+Parameters::Parameters(int cameraId,
+ int cameraFacing) :
+ cameraId(cameraId),
+ cameraFacing(cameraFacing),
+ info(NULL) {
+}
+
+Parameters::~Parameters() {
+}
+
+status_t Parameters::initialize(const CameraMetadata *info) {
+ status_t res;
+
+ if (info->entryCount() == 0) {
+ ALOGE("%s: No static information provided!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ Parameters::info = info;
+
+ res = buildFastInfo();
+ if (res != OK) return res;
+
+ res = buildQuirks();
+ if (res != OK) return res;
+
+ const Size MAX_PREVIEW_SIZE = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
+ res = getFilteredPreviewSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);
+ if (res != OK) return res;
+
+ // TODO: Pick more intelligently
+ previewWidth = availablePreviewSizes[0].width;
+ previewHeight = availablePreviewSizes[0].height;
+ videoWidth = previewWidth;
+ videoHeight = previewHeight;
+
+ params.setPreviewSize(previewWidth, previewHeight);
+ params.setVideoSize(videoWidth, videoHeight);
+ params.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
+ String8::format("%dx%d",
+ previewWidth, previewHeight));
+ {
+ String8 supportedPreviewSizes;
+ for (size_t i = 0; i < availablePreviewSizes.size(); i++) {
+ if (i != 0) supportedPreviewSizes += ",";
+ supportedPreviewSizes += String8::format("%dx%d",
+ availablePreviewSizes[i].width,
+ availablePreviewSizes[i].height);
+ }
+ ALOGV("Supported preview sizes are: %s", supportedPreviewSizes.string());
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
+ supportedPreviewSizes);
+ params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
+ supportedPreviewSizes);
+ }
+
+ camera_metadata_ro_entry_t availableFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ if (!availableFpsRanges.count) return NO_INIT;
+
+ previewFpsRange[0] = availableFpsRanges.data.i32[0];
+ previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
+ params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ String8::format("%d,%d",
+ previewFpsRange[0] * kFpsToApiScale,
+ previewFpsRange[1] * kFpsToApiScale));
+
+ {
+ String8 supportedPreviewFpsRange;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ if (i != 0) supportedPreviewFpsRange += ",";
+ supportedPreviewFpsRange += String8::format("(%d,%d)",
+ availableFpsRanges.data.i32[i] * kFpsToApiScale,
+ availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+ supportedPreviewFpsRange);
+ }
+
+ previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ params.set(CameraParameters::KEY_PREVIEW_FORMAT,
+ formatEnumToString(previewFormat)); // NV21
+
+ previewTransform = degToTransform(0,
+ cameraFacing == CAMERA_FACING_FRONT);
+
+ camera_metadata_ro_entry_t availableFormats =
+ staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+
+ {
+ String8 supportedPreviewFormats;
+ bool addComma = false;
+ for (size_t i=0; i < availableFormats.count; i++) {
+ if (addComma) supportedPreviewFormats += ",";
+ addComma = true;
+ switch (availableFormats.data.i32[i]) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV422SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV422I;
+ break;
+ case HAL_PIXEL_FORMAT_YV12:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420P;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_RGB565;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_RGBA8888;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ // Flexible YUV allows both YV12 and NV21
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420P;
+ supportedPreviewFormats += ",";
+ supportedPreviewFormats +=
+ CameraParameters::PIXEL_FORMAT_YUV420SP;
+ break;
+ // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ case HAL_PIXEL_FORMAT_BLOB:
+ addComma = false;
+ break;
+
+ default:
+ ALOGW("%s: Camera %d: Unknown preview format: %x",
+ __FUNCTION__, cameraId, availableFormats.data.i32[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS,
+ supportedPreviewFormats);
+ }
+
+ // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
+ // still have to do something sane for them
+
+ // NOTE: Not scaled like FPS range values are.
+ previewFps = fpsFromRange(previewFpsRange[0], previewFpsRange[1]);
+ lastSetPreviewFps = previewFps;
+ params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
+ previewFps);
+
+ {
+ SortedVector<int32_t> sortedPreviewFrameRates;
+
+ String8 supportedPreviewFrameRates;
+ for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+ // from the [min, max] fps range use the max value
+ int fps = fpsFromRange(availableFpsRanges.data.i32[i],
+ availableFpsRanges.data.i32[i+1]);
+
+ // de-dupe frame rates
+ if (sortedPreviewFrameRates.indexOf(fps) == NAME_NOT_FOUND) {
+ sortedPreviewFrameRates.add(fps);
+ }
+ else {
+ continue;
+ }
+
+ if (sortedPreviewFrameRates.size() > 1) {
+ supportedPreviewFrameRates += ",";
+ }
+
+ supportedPreviewFrameRates += String8::format("%d",
+ fps);
+
+ ALOGV("%s: Supported preview frame rates: %s",
+ __FUNCTION__, supportedPreviewFrameRates.string());
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES,
+ supportedPreviewFrameRates);
+ }
+
+ camera_metadata_ro_entry_t availableJpegSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
+ if (!availableJpegSizes.count) return NO_INIT;
+
+ // TODO: Pick maximum
+ pictureWidth = availableJpegSizes.data.i32[0];
+ pictureHeight = availableJpegSizes.data.i32[1];
+
+ params.setPictureSize(pictureWidth,
+ pictureHeight);
+
+ {
+ String8 supportedPictureSizes;
+ for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+ if (i != 0) supportedPictureSizes += ",";
+ supportedPictureSizes += String8::format("%dx%d",
+ availableJpegSizes.data.i32[i],
+ availableJpegSizes.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
+ supportedPictureSizes);
+ }
+
+ params.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
+ params.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
+ CameraParameters::PIXEL_FORMAT_JPEG);
+
+ camera_metadata_ro_entry_t availableJpegThumbnailSizes =
+ staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 4);
+ if (!availableJpegThumbnailSizes.count) return NO_INIT;
+
+ // Pick the largest thumbnail size that matches still image aspect ratio.
+ ALOG_ASSERT(pictureWidth > 0 && pictureHeight > 0,
+ "Invalid picture size, %d x %d", pictureWidth, pictureHeight);
+ float picAspectRatio = static_cast<float>(pictureWidth) / pictureHeight;
+ Size thumbnailSize =
+ getMaxSizeForRatio(
+ picAspectRatio,
+ &availableJpegThumbnailSizes.data.i32[0],
+ availableJpegThumbnailSizes.count);
+ jpegThumbSize[0] = thumbnailSize.width;
+ jpegThumbSize[1] = thumbnailSize.height;
+
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
+ jpegThumbSize[0]);
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
+ jpegThumbSize[1]);
+
+ {
+ String8 supportedJpegThumbSizes;
+ for (size_t i=0; i < availableJpegThumbnailSizes.count; i += 2) {
+ if (i != 0) supportedJpegThumbSizes += ",";
+ supportedJpegThumbSizes += String8::format("%dx%d",
+ availableJpegThumbnailSizes.data.i32[i],
+ availableJpegThumbnailSizes.data.i32[i+1]);
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES,
+ supportedJpegThumbSizes);
+ }
+
+ jpegThumbQuality = 90;
+ params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
+ jpegThumbQuality);
+ jpegQuality = 90;
+ params.set(CameraParameters::KEY_JPEG_QUALITY,
+ jpegQuality);
+ jpegRotation = 0;
+ params.set(CameraParameters::KEY_ROTATION,
+ jpegRotation);
+
+ gpsEnabled = false;
+ gpsCoordinates[0] = 0.0;
+ gpsCoordinates[1] = 0.0;
+ gpsCoordinates[2] = 0.0;
+ gpsTimestamp = 0;
+ gpsProcessingMethod = "unknown";
+ // GPS fields in CameraParameters are not set by implementation
+
+ wbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+ params.set(CameraParameters::KEY_WHITE_BALANCE,
+ CameraParameters::WHITE_BALANCE_AUTO);
+
+ camera_metadata_ro_entry_t availableWhiteBalanceModes =
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES, 0, 0, false);
+ if (!availableWhiteBalanceModes.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+ CameraParameters::WHITE_BALANCE_AUTO);
+ } else {
+ String8 supportedWhiteBalance;
+ bool addComma = false;
+ for (size_t i=0; i < availableWhiteBalanceModes.count; i++) {
+ if (addComma) supportedWhiteBalance += ",";
+ addComma = true;
+ switch (availableWhiteBalanceModes.data.u8[i]) {
+ case ANDROID_CONTROL_AWB_MODE_AUTO:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_AUTO;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_INCANDESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_INCANDESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_FLUORESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_FLUORESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_DAYLIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_DAYLIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_TWILIGHT:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_TWILIGHT;
+ break;
+ case ANDROID_CONTROL_AWB_MODE_SHADE:
+ supportedWhiteBalance +=
+ CameraParameters::WHITE_BALANCE_SHADE;
+ break;
+ // Skipping values not mappable to v1 API
+ case ANDROID_CONTROL_AWB_MODE_OFF:
+ addComma = false;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown white balance value: %d",
+ __FUNCTION__, cameraId,
+ availableWhiteBalanceModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+ supportedWhiteBalance);
+ }
+
+ effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+ params.set(CameraParameters::KEY_EFFECT,
+ CameraParameters::EFFECT_NONE);
+
+ camera_metadata_ro_entry_t availableEffects =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS, 0, 0, false);
+ if (!availableEffects.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_EFFECTS,
+ CameraParameters::EFFECT_NONE);
+ } else {
+ String8 supportedEffects;
+ bool addComma = false;
+ for (size_t i=0; i < availableEffects.count; i++) {
+ if (addComma) supportedEffects += ",";
+ addComma = true;
+ switch (availableEffects.data.u8[i]) {
+ case ANDROID_CONTROL_EFFECT_MODE_OFF:
+ supportedEffects +=
+ CameraParameters::EFFECT_NONE;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_MONO:
+ supportedEffects +=
+ CameraParameters::EFFECT_MONO;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_NEGATIVE:
+ supportedEffects +=
+ CameraParameters::EFFECT_NEGATIVE;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_SOLARIZE:
+ supportedEffects +=
+ CameraParameters::EFFECT_SOLARIZE;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_SEPIA:
+ supportedEffects +=
+ CameraParameters::EFFECT_SEPIA;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_POSTERIZE:
+ supportedEffects +=
+ CameraParameters::EFFECT_POSTERIZE;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD:
+ supportedEffects +=
+ CameraParameters::EFFECT_WHITEBOARD;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD:
+ supportedEffects +=
+ CameraParameters::EFFECT_BLACKBOARD;
+ break;
+ case ANDROID_CONTROL_EFFECT_MODE_AQUA:
+ supportedEffects +=
+ CameraParameters::EFFECT_AQUA;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown effect value: %d",
+ __FUNCTION__, cameraId, availableEffects.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
+ }
+
+ antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+ params.set(CameraParameters::KEY_ANTIBANDING,
+ CameraParameters::ANTIBANDING_AUTO);
+
+ camera_metadata_ro_entry_t availableAntibandingModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, 0, 0, false);
+ if (!availableAntibandingModes.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+ CameraParameters::ANTIBANDING_OFF);
+ } else {
+ String8 supportedAntibanding;
+ bool addComma = false;
+ for (size_t i=0; i < availableAntibandingModes.count; i++) {
+ if (addComma) supportedAntibanding += ",";
+ addComma = true;
+ switch (availableAntibandingModes.data.u8[i]) {
+ case ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_OFF;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_50HZ;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_60HZ;
+ break;
+ case ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO:
+ supportedAntibanding +=
+ CameraParameters::ANTIBANDING_AUTO;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown antibanding value: %d",
+ __FUNCTION__, cameraId,
+ availableAntibandingModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+ supportedAntibanding);
+ }
+
+ sceneMode = ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ params.set(CameraParameters::KEY_SCENE_MODE,
+ CameraParameters::SCENE_MODE_AUTO);
+
+ camera_metadata_ro_entry_t availableSceneModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, 0, 0, false);
+ if (!availableSceneModes.count) {
+ params.remove(CameraParameters::KEY_SCENE_MODE);
+ } else {
+ String8 supportedSceneModes(CameraParameters::SCENE_MODE_AUTO);
+ bool addComma = true;
+ bool noSceneModes = false;
+ for (size_t i=0; i < availableSceneModes.count; i++) {
+ if (addComma) supportedSceneModes += ",";
+ addComma = true;
+ switch (availableSceneModes.data.u8[i]) {
+ case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+ noSceneModes = true;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
+ // Not in old API
+ addComma = false;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_ACTION:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_ACTION;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_PORTRAIT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_PORTRAIT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_LANDSCAPE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_LANDSCAPE;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_NIGHT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_NIGHT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_NIGHT_PORTRAIT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_THEATRE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_THEATRE;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_BEACH:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_BEACH;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SNOW:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SNOW;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SUNSET:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SUNSET;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_STEADYPHOTO;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_FIREWORKS:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_FIREWORKS;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_SPORTS:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_SPORTS;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_PARTY:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_PARTY;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_CANDLELIGHT;
+ break;
+ case ANDROID_CONTROL_SCENE_MODE_BARCODE:
+ supportedSceneModes +=
+ CameraParameters::SCENE_MODE_BARCODE;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown scene mode value: %d",
+ __FUNCTION__, cameraId,
+ availableSceneModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ if (!noSceneModes) {
+ params.set(CameraParameters::KEY_SUPPORTED_SCENE_MODES,
+ supportedSceneModes);
+ } else {
+ params.remove(CameraParameters::KEY_SCENE_MODE);
+ }
+ }
+
+ bool isFlashAvailable = false;
+ camera_metadata_ro_entry_t flashAvailable =
+ staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 0, 1, false);
+ if (flashAvailable.count) {
+ isFlashAvailable = flashAvailable.data.u8[0];
+ }
+
+ camera_metadata_ro_entry_t availableAeModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES, 0, 0, false);
+
+ if (isFlashAvailable) {
+ flashMode = Parameters::FLASH_MODE_OFF;
+ params.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_OFF);
+
+ String8 supportedFlashModes(CameraParameters::FLASH_MODE_OFF);
+ supportedFlashModes = supportedFlashModes +
+ "," + CameraParameters::FLASH_MODE_AUTO +
+ "," + CameraParameters::FLASH_MODE_ON +
+ "," + CameraParameters::FLASH_MODE_TORCH;
+ for (size_t i=0; i < availableAeModes.count; i++) {
+ if (availableAeModes.data.u8[i] ==
+ ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
+ supportedFlashModes = supportedFlashModes + "," +
+ CameraParameters::FLASH_MODE_RED_EYE;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+ supportedFlashModes);
+ } else {
+ flashMode = Parameters::FLASH_MODE_OFF;
+ params.set(CameraParameters::KEY_FLASH_MODE,
+ CameraParameters::FLASH_MODE_OFF);
+ params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
+ CameraParameters::FLASH_MODE_OFF);
+ }
+
+ camera_metadata_ro_entry_t minFocusDistance =
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 1, false);
+
+ camera_metadata_ro_entry_t availableAfModes =
+ staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES, 0, 0, false);
+
+ if (!minFocusDistance.count || minFocusDistance.data.f[0] == 0) {
+ // Fixed-focus lens
+ focusMode = Parameters::FOCUS_MODE_FIXED;
+ params.set(CameraParameters::KEY_FOCUS_MODE,
+ CameraParameters::FOCUS_MODE_FIXED);
+ params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+ CameraParameters::FOCUS_MODE_FIXED);
+ } else {
+ focusMode = Parameters::FOCUS_MODE_AUTO;
+ params.set(CameraParameters::KEY_FOCUS_MODE,
+ CameraParameters::FOCUS_MODE_AUTO);
+ String8 supportedFocusModes(CameraParameters::FOCUS_MODE_INFINITY);
+ bool addComma = true;
+
+ for (size_t i=0; i < availableAfModes.count; i++) {
+ if (addComma) supportedFocusModes += ",";
+ addComma = true;
+ switch (availableAfModes.data.u8[i]) {
+ case ANDROID_CONTROL_AF_MODE_AUTO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_AUTO;
+ break;
+ case ANDROID_CONTROL_AF_MODE_MACRO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_MACRO;
+ break;
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+ break;
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+ break;
+ case ANDROID_CONTROL_AF_MODE_EDOF:
+ supportedFocusModes +=
+ CameraParameters::FOCUS_MODE_EDOF;
+ break;
+ // Not supported in old API
+ case ANDROID_CONTROL_AF_MODE_OFF:
+ addComma = false;
+ break;
+ default:
+ ALOGW("%s: Camera %d: Unknown AF mode value: %d",
+ __FUNCTION__, cameraId, availableAfModes.data.u8[i]);
+ addComma = false;
+ break;
+ }
+ }
+ params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
+ supportedFocusModes);
+ }
+ focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ shadowFocusMode = FOCUS_MODE_INVALID;
+
+ camera_metadata_ro_entry_t max3aRegions =
+ staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
+ if (!max3aRegions.count) return NO_INIT;
+
+ int32_t maxNumFocusAreas = 0;
+ if (focusMode != Parameters::FOCUS_MODE_FIXED) {
+ maxNumFocusAreas = max3aRegions.data.i32[0];
+ }
+ params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, maxNumFocusAreas);
+ params.set(CameraParameters::KEY_FOCUS_AREAS,
+ "(0,0,0,0,0)");
+ focusingAreas.clear();
+ focusingAreas.add(Parameters::Area(0,0,0,0,0));
+
+ camera_metadata_ro_entry_t availableFocalLengths =
+ staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
+ if (!availableFocalLengths.count) return NO_INIT;
+
+ float minFocalLength = availableFocalLengths.data.f[0];
+ params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+
+ float horizFov, vertFov;
+ res = calculatePictureFovs(&horizFov, &vertFov);
+ if (res != OK) {
+ ALOGE("%s: Can't calculate field of views!", __FUNCTION__);
+ return res;
+ }
+
+ params.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
+ params.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
+
+ exposureCompensation = 0;
+ params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION,
+ exposureCompensation);
+
+ camera_metadata_ro_entry_t exposureCompensationRange =
+ staticInfo(ANDROID_CONTROL_AE_COMPENSATION_RANGE, 2, 2);
+ if (!exposureCompensationRange.count) return NO_INIT;
+
+ params.set(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION,
+ exposureCompensationRange.data.i32[1]);
+ params.set(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION,
+ exposureCompensationRange.data.i32[0]);
+
+ camera_metadata_ro_entry_t exposureCompensationStep =
+ staticInfo(ANDROID_CONTROL_AE_COMPENSATION_STEP, 1, 1);
+ if (!exposureCompensationStep.count) return NO_INIT;
+
+ params.setFloat(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP,
+ (float)exposureCompensationStep.data.r[0].numerator /
+ exposureCompensationStep.data.r[0].denominator);
+
+ autoExposureLock = false;
+ params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK,
+ CameraParameters::FALSE);
+ params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED,
+ CameraParameters::TRUE);
+
+ autoWhiteBalanceLock = false;
+ params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK,
+ CameraParameters::FALSE);
+ params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED,
+ CameraParameters::TRUE);
+
+ meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
+ params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
+ max3aRegions.data.i32[0]);
+ params.set(CameraParameters::KEY_METERING_AREAS,
+ "(0,0,0,0,0)");
+
+ zoom = 0;
+ params.set(CameraParameters::KEY_ZOOM, zoom);
+ params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
+
+ camera_metadata_ro_entry_t maxDigitalZoom =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, /*minCount*/1, /*maxCount*/1);
+ if (!maxDigitalZoom.count) return NO_INIT;
+
+ {
+ String8 zoomRatios;
+ float zoom = 1.f;
+ float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
+ (NUM_ZOOM_STEPS-1);
+ bool addComma = false;
+ for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
+ if (addComma) zoomRatios += ",";
+ addComma = true;
+ zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
+ zoom += zoomIncrement;
+ }
+ params.set(CameraParameters::KEY_ZOOM_RATIOS, zoomRatios);
+ }
+
+ params.set(CameraParameters::KEY_ZOOM_SUPPORTED,
+ CameraParameters::TRUE);
+ params.set(CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED,
+ CameraParameters::FALSE);
+
+ params.set(CameraParameters::KEY_FOCUS_DISTANCES,
+ "Infinity,Infinity,Infinity");
+
+ params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW,
+ fastInfo.maxFaces);
+ params.set(CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW,
+ 0);
+
+ params.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT,
+ CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE);
+
+ recordingHint = false;
+ params.set(CameraParameters::KEY_RECORDING_HINT,
+ CameraParameters::FALSE);
+
+ params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED,
+ CameraParameters::TRUE);
+
+ videoStabilization = false;
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION,
+ CameraParameters::FALSE);
+
+ camera_metadata_ro_entry_t availableVideoStabilizationModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, 0, 0,
+ false);
+
+ if (availableVideoStabilizationModes.count > 1) {
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+ CameraParameters::TRUE);
+ } else {
+ params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
+ CameraParameters::FALSE);
+ }
+
+ // Set up initial state for non-Camera.Parameters state variables
+
+ storeMetadataInBuffers = true;
+ playShutterSound = true;
+ enableFaceDetect = false;
+
+ enableFocusMoveMessages = false;
+ afTriggerCounter = 1;
+ afStateCounter = 0;
+ currentAfTriggerId = -1;
+ afInMotion = false;
+
+ precaptureTriggerCounter = 1;
+
+ takePictureCounter = 0;
+
+ previewCallbackFlags = 0;
+ previewCallbackOneShot = false;
+ previewCallbackSurface = false;
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("camera.disable_zsl_mode", value, "0");
+ if (!strcmp(value,"1")) {
+ ALOGI("Camera %d: Disabling ZSL mode", cameraId);
+ zslMode = false;
+ } else {
+ zslMode = true;
+ }
+
+ lightFx = LIGHTFX_NONE;
+
+ state = STOPPED;
+
+ paramsFlattened = params.flatten();
+
+ return OK;
+}
+
+String8 Parameters::get() const {
+ return paramsFlattened;
+}
+
+status_t Parameters::buildFastInfo() {
+
+ camera_metadata_ro_entry_t activeArraySize =
+ staticInfo(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, 2, 4);
+ if (!activeArraySize.count) return NO_INIT;
+ int32_t arrayWidth;
+ int32_t arrayHeight;
+ if (activeArraySize.count == 2) {
+ ALOGW("%s: Camera %d: activeArraySize is missing xmin/ymin!",
+ __FUNCTION__, cameraId);
+ arrayWidth = activeArraySize.data.i32[0];
+ arrayHeight = activeArraySize.data.i32[1];
+ } else if (activeArraySize.count == 4) {
+ arrayWidth = activeArraySize.data.i32[2];
+ arrayHeight = activeArraySize.data.i32[3];
+ } else return NO_INIT;
+
+ // We'll set the target FPS range for still captures to be as wide
+ // as possible to give the HAL maximum latitude for exposure selection
+ camera_metadata_ro_entry_t availableFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ if (availableFpsRanges.count < 2 || availableFpsRanges.count % 2 != 0) {
+ return NO_INIT;
+ }
+
+ int32_t bestStillCaptureFpsRange[2] = {
+ availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
+ };
+ int32_t curRange =
+ bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
+ for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
+ int32_t nextRange =
+ availableFpsRanges.data.i32[i + 1] -
+ availableFpsRanges.data.i32[i];
+ if ( (nextRange > curRange) || // Maximize size of FPS range first
+ (nextRange == curRange && // Then minimize low-end FPS
+ bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
+
+ bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
+ bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
+ curRange = nextRange;
+ }
+ }
+
+ camera_metadata_ro_entry_t availableFaceDetectModes =
+ staticInfo(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, 0, 0,
+ false);
+
+ uint8_t bestFaceDetectMode =
+ ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+ for (size_t i = 0 ; i < availableFaceDetectModes.count; i++) {
+ switch (availableFaceDetectModes.data.u8[i]) {
+ case ANDROID_STATISTICS_FACE_DETECT_MODE_OFF:
+ break;
+ case ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE:
+ if (bestFaceDetectMode !=
+ ANDROID_STATISTICS_FACE_DETECT_MODE_FULL) {
+ bestFaceDetectMode =
+ ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE;
+ }
+ break;
+ case ANDROID_STATISTICS_FACE_DETECT_MODE_FULL:
+ bestFaceDetectMode =
+ ANDROID_STATISTICS_FACE_DETECT_MODE_FULL;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown face detect mode %d:",
+ __FUNCTION__, cameraId,
+ availableFaceDetectModes.data.u8[i]);
+ return NO_INIT;
+ }
+ }
+
+ int32_t maxFaces = 0;
+ camera_metadata_ro_entry_t maxFacesDetected =
+ staticInfo(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, 0, 1, false);
+ if (maxFacesDetected.count) {
+ maxFaces = maxFacesDetected.data.i32[0];
+ }
+
+ camera_metadata_ro_entry_t availableSceneModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, 0, 0, false);
+ camera_metadata_ro_entry_t sceneModeOverrides =
+ staticInfo(ANDROID_CONTROL_SCENE_MODE_OVERRIDES, 0, 0, false);
+ camera_metadata_ro_entry_t minFocusDistance =
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 0, false);
+ bool fixedLens = minFocusDistance.count == 0 ||
+ minFocusDistance.data.f[0] == 0;
+
+ camera_metadata_ro_entry_t availableFocalLengths =
+ staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
+ if (!availableFocalLengths.count) return NO_INIT;
+
+ camera_metadata_ro_entry_t availableFormats =
+ staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+ if (!availableFormats.count) return NO_INIT;
+
+
+ if (sceneModeOverrides.count > 0) {
+ // sceneModeOverrides is defined to have 3 entries for each scene mode,
+ // which are AE, AWB, and AF override modes the HAL wants for that scene
+ // mode.
+ const size_t kModesPerSceneMode = 3;
+ if (sceneModeOverrides.count !=
+ availableSceneModes.count * kModesPerSceneMode) {
+ ALOGE("%s: Camera %d: Scene mode override list is an "
+ "unexpected size: %d (expected %d)", __FUNCTION__,
+ cameraId, sceneModeOverrides.count,
+ availableSceneModes.count);
+ return NO_INIT;
+ }
+ for (size_t i = 0; i < availableSceneModes.count; i++) {
+ DeviceInfo::OverrideModes modes;
+ uint8_t aeMode =
+ sceneModeOverrides.data.u8[i * kModesPerSceneMode + 0];
+ switch(aeMode) {
+ case ANDROID_CONTROL_AE_MODE_ON:
+ modes.flashMode = FLASH_MODE_OFF;
+ break;
+ case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH:
+ modes.flashMode = FLASH_MODE_AUTO;
+ break;
+ case ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH:
+ modes.flashMode = FLASH_MODE_ON;
+ break;
+ case ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE:
+ modes.flashMode = FLASH_MODE_RED_EYE;
+ break;
+ default:
+ ALOGE("%s: Unknown override AE mode: %d", __FUNCTION__,
+ aeMode);
+ modes.flashMode = FLASH_MODE_INVALID;
+ break;
+ }
+ modes.wbMode =
+ sceneModeOverrides.data.u8[i * kModesPerSceneMode + 1];
+ uint8_t afMode =
+ sceneModeOverrides.data.u8[i * kModesPerSceneMode + 2];
+ switch(afMode) {
+ case ANDROID_CONTROL_AF_MODE_OFF:
+ modes.focusMode = fixedLens ?
+ FOCUS_MODE_FIXED : FOCUS_MODE_INFINITY;
+ break;
+ case ANDROID_CONTROL_AF_MODE_AUTO:
+ case ANDROID_CONTROL_AF_MODE_MACRO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ case ANDROID_CONTROL_AF_MODE_EDOF:
+ modes.focusMode = static_cast<focusMode_t>(afMode);
+ break;
+ default:
+ ALOGE("%s: Unknown override AF mode: %d", __FUNCTION__,
+ afMode);
+ modes.focusMode = FOCUS_MODE_INVALID;
+ break;
+ }
+ fastInfo.sceneModeOverrides.add(availableSceneModes.data.u8[i],
+ modes);
+ }
+ }
+
+ fastInfo.arrayWidth = arrayWidth;
+ fastInfo.arrayHeight = arrayHeight;
+ fastInfo.bestStillCaptureFpsRange[0] = bestStillCaptureFpsRange[0];
+ fastInfo.bestStillCaptureFpsRange[1] = bestStillCaptureFpsRange[1];
+ fastInfo.bestFaceDetectMode = bestFaceDetectMode;
+ fastInfo.maxFaces = maxFaces;
+
+ // Find smallest (widest-angle) focal length to use as basis of still
+ // picture FOV reporting.
+ fastInfo.minFocalLength = availableFocalLengths.data.f[0];
+ for (size_t i = 1; i < availableFocalLengths.count; i++) {
+ if (fastInfo.minFocalLength > availableFocalLengths.data.f[i]) {
+ fastInfo.minFocalLength = availableFocalLengths.data.f[i];
+ }
+ }
+
+ // Check if the HAL supports HAL_PIXEL_FORMAT_YCbCr_420_888
+ fastInfo.useFlexibleYuv = false;
+ for (size_t i = 0; i < availableFormats.count; i++) {
+ if (availableFormats.data.i32[i] == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ fastInfo.useFlexibleYuv = true;
+ break;
+ }
+ }
+ ALOGV("Camera %d: Flexible YUV %s supported",
+ cameraId, fastInfo.useFlexibleYuv ? "is" : "is not");
+
+ return OK;
+}
+
+status_t Parameters::buildQuirks() {
+ camera_metadata_ro_entry_t entry;
+ entry = info->find(ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO);
+ quirks.triggerAfWithAuto = (entry.count != 0 && entry.data.u8[0] == 1);
+ ALOGV_IF(quirks.triggerAfWithAuto, "Camera %d: Quirk triggerAfWithAuto enabled",
+ cameraId);
+
+ entry = info->find(ANDROID_QUIRKS_USE_ZSL_FORMAT);
+ quirks.useZslFormat = (entry.count != 0 && entry.data.u8[0] == 1);
+ ALOGV_IF(quirks.useZslFormat, "Camera %d: Quirk useZslFormat enabled",
+ cameraId);
+
+ entry = info->find(ANDROID_QUIRKS_METERING_CROP_REGION);
+ quirks.meteringCropRegion = (entry.count != 0 && entry.data.u8[0] == 1);
+ ALOGV_IF(quirks.meteringCropRegion, "Camera %d: Quirk meteringCropRegion"
+ " enabled", cameraId);
+
+ return OK;
+}
+
+camera_metadata_ro_entry_t Parameters::staticInfo(uint32_t tag,
+ size_t minCount, size_t maxCount, bool required) const {
+ camera_metadata_ro_entry_t entry = info->find(tag);
+
+ if (CC_UNLIKELY( entry.count == 0 ) && required) {
+ const char* tagSection = get_camera_metadata_section_name(tag);
+ if (tagSection == NULL) tagSection = "<unknown>";
+ const char* tagName = get_camera_metadata_tag_name(tag);
+ if (tagName == NULL) tagName = "<unknown>";
+
+ ALOGE("Error finding static metadata entry '%s.%s' (%x)",
+ tagSection, tagName, tag);
+ } else if (CC_UNLIKELY(
+ (minCount != 0 && entry.count < minCount) ||
+ (maxCount != 0 && entry.count > maxCount) ) ) {
+ const char* tagSection = get_camera_metadata_section_name(tag);
+ if (tagSection == NULL) tagSection = "<unknown>";
+ const char* tagName = get_camera_metadata_tag_name(tag);
+ if (tagName == NULL) tagName = "<unknown>";
+ ALOGE("Malformed static metadata entry '%s.%s' (%x):"
+ "Expected between %d and %d values, but got %d values",
+ tagSection, tagName, tag, minCount, maxCount, entry.count);
+ }
+
+ return entry;
+}
+
+status_t Parameters::set(const String8& paramString) {
+ status_t res;
+
+ CameraParameters newParams(paramString);
+
+ // TODO: Currently ignoring any changes to supposedly read-only parameters
+ // such as supported preview sizes, etc. Should probably produce an error if
+ // they're changed.
+
+ /** Extract and verify new parameters */
+
+ size_t i;
+
+ Parameters validatedParams(*this);
+
+ // PREVIEW_SIZE
+ newParams.getPreviewSize(&validatedParams.previewWidth,
+ &validatedParams.previewHeight);
+
+ if (validatedParams.previewWidth != previewWidth ||
+ validatedParams.previewHeight != previewHeight) {
+ if (state >= PREVIEW) {
+ ALOGE("%s: Preview size cannot be updated when preview "
+ "is active! (Currently %d x %d, requested %d x %d",
+ __FUNCTION__,
+ previewWidth, previewHeight,
+ validatedParams.previewWidth, validatedParams.previewHeight);
+ return BAD_VALUE;
+ }
+ for (i = 0; i < availablePreviewSizes.size(); i++) {
+ if ((availablePreviewSizes[i].width ==
+ validatedParams.previewWidth) &&
+ (availablePreviewSizes[i].height ==
+ validatedParams.previewHeight)) break;
+ }
+ if (i == availablePreviewSizes.size()) {
+ ALOGE("%s: Requested preview size %d x %d is not supported",
+ __FUNCTION__, validatedParams.previewWidth,
+ validatedParams.previewHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // RECORDING_HINT (always supported)
+ validatedParams.recordingHint = boolFromString(
+ newParams.get(CameraParameters::KEY_RECORDING_HINT) );
+ bool recordingHintChanged = validatedParams.recordingHint != recordingHint;
+ ALOGV_IF(recordingHintChanged, "%s: Recording hint changed to %d",
+ __FUNCTION__, recordingHintChanged);
+
+ // PREVIEW_FPS_RANGE
+ bool fpsRangeChanged = false;
+ newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0],
+ &validatedParams.previewFpsRange[1]);
+ validatedParams.previewFpsRange[0] /= kFpsToApiScale;
+ validatedParams.previewFpsRange[1] /= kFpsToApiScale;
+
+ if (validatedParams.previewFpsRange[0] != previewFpsRange[0] ||
+ validatedParams.previewFpsRange[1] != previewFpsRange[1]) {
+ fpsRangeChanged = true;
+ camera_metadata_ro_entry_t availablePreviewFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
+ if ((availablePreviewFpsRanges.data.i32[i] ==
+ validatedParams.previewFpsRange[0]) &&
+ (availablePreviewFpsRanges.data.i32[i+1] ==
+ validatedParams.previewFpsRange[1]) ) {
+ break;
+ }
+ }
+ if (i == availablePreviewFpsRanges.count) {
+ ALOGE("%s: Requested preview FPS range %d - %d is not supported",
+ __FUNCTION__, validatedParams.previewFpsRange[0],
+ validatedParams.previewFpsRange[1]);
+ return BAD_VALUE;
+ }
+ validatedParams.previewFps =
+ fpsFromRange(validatedParams.previewFpsRange[0],
+ validatedParams.previewFpsRange[1]);
+
+ // Update our last-seen single preview FPS, needed for disambiguating
+ // when the application is intending to use the deprecated single-FPS
+ // setting vs. the range FPS setting
+ validatedParams.lastSetPreviewFps = newParams.getPreviewFrameRate();
+
+ newParams.setPreviewFrameRate(validatedParams.previewFps);
+ }
+
+ // PREVIEW_FORMAT
+ validatedParams.previewFormat =
+ formatStringToEnum(newParams.getPreviewFormat());
+ if (validatedParams.previewFormat != previewFormat) {
+ if (state >= PREVIEW) {
+ ALOGE("%s: Preview format cannot be updated when preview "
+ "is active!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ camera_metadata_ro_entry_t availableFormats =
+ staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+ // If using flexible YUV, always support NV21/YV12. Otherwise, check
+ // HAL's list.
+ if (! (fastInfo.useFlexibleYuv &&
+ (validatedParams.previewFormat ==
+ HAL_PIXEL_FORMAT_YCrCb_420_SP ||
+ validatedParams.previewFormat ==
+ HAL_PIXEL_FORMAT_YV12) ) ) {
+ // Not using flexible YUV format, so check explicitly
+ for (i = 0; i < availableFormats.count; i++) {
+ if (availableFormats.data.i32[i] ==
+ validatedParams.previewFormat) break;
+ }
+ if (i == availableFormats.count) {
+ ALOGE("%s: Requested preview format %s (0x%x) is not supported",
+ __FUNCTION__, newParams.getPreviewFormat(),
+ validatedParams.previewFormat);
+ return BAD_VALUE;
+ }
+ }
+ }
+
+ // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is
+ // unchanged this time. The single-value FPS is the same as the minimum of
+ // the range. To detect whether the application has changed the value of
+ // previewFps, compare against their last-set preview FPS instead of the
+ // single FPS we may have synthesized from a range FPS set.
+ if (!fpsRangeChanged) {
+ validatedParams.previewFps = newParams.getPreviewFrameRate();
+ if (validatedParams.previewFps != lastSetPreviewFps ||
+ recordingHintChanged) {
+ camera_metadata_ro_entry_t availableFrameRates =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
+ /**
+ * If recording hint is set, find the range that encompasses
+ * previewFps with the largest min index.
+ *
+ * If recording hint is not set, find the range with previewFps
+ * with the smallest min index.
+ *
+ * Either way, in case of multiple ranges, break the tie by
+ * selecting the smaller range.
+ */
+ int targetFps = validatedParams.previewFps;
+ // all ranges which have targetFps
+ Vector<Range> candidateRanges;
+ for (i = 0; i < availableFrameRates.count; i+=2) {
+ Range r = {
+ availableFrameRates.data.i32[i],
+ availableFrameRates.data.i32[i+1]
+ };
+
+ if (r.min <= targetFps && targetFps <= r.max) {
+ candidateRanges.push(r);
+ }
+ }
+ if (candidateRanges.isEmpty()) {
+ ALOGE("%s: Requested preview frame rate %d is not supported",
+ __FUNCTION__, validatedParams.previewFps);
+ return BAD_VALUE;
+ }
+ // most applicable range with targetFps
+ Range bestRange = candidateRanges[0];
+ for (i = 1; i < candidateRanges.size(); ++i) {
+ Range r = candidateRanges[i];
+
+ // Find by largest minIndex in recording mode
+ if (validatedParams.recordingHint) {
+ if (r.min > bestRange.min) {
+ bestRange = r;
+ }
+ else if (r.min == bestRange.min && r.max < bestRange.max) {
+ bestRange = r;
+ }
+ }
+ // Find by smallest minIndex in preview mode
+ else {
+ if (r.min < bestRange.min) {
+ bestRange = r;
+ }
+ else if (r.min == bestRange.min && r.max < bestRange.max) {
+ bestRange = r;
+ }
+ }
+ }
+
+ validatedParams.previewFpsRange[0] =
+ bestRange.min;
+ validatedParams.previewFpsRange[1] =
+ bestRange.max;
+
+ ALOGV("%s: New preview FPS range: %d, %d, recordingHint = %d",
+ __FUNCTION__,
+ validatedParams.previewFpsRange[0],
+ validatedParams.previewFpsRange[1],
+ validatedParams.recordingHint);
+ }
+ newParams.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+ String8::format("%d,%d",
+ validatedParams.previewFpsRange[0] * kFpsToApiScale,
+ validatedParams.previewFpsRange[1] * kFpsToApiScale));
+ // Update our last-seen single preview FPS, needed for disambiguating
+ // when the application is intending to use the deprecated single-FPS
+ // setting vs. the range FPS setting
+ validatedParams.lastSetPreviewFps = validatedParams.previewFps;
+ }
+
+ // PICTURE_SIZE
+ newParams.getPictureSize(&validatedParams.pictureWidth,
+ &validatedParams.pictureHeight);
+ if (validatedParams.pictureWidth == pictureWidth ||
+ validatedParams.pictureHeight == pictureHeight) {
+ camera_metadata_ro_entry_t availablePictureSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ for (i = 0; i < availablePictureSizes.count; i+=2) {
+ if ((availablePictureSizes.data.i32[i] ==
+ validatedParams.pictureWidth) &&
+ (availablePictureSizes.data.i32[i+1] ==
+ validatedParams.pictureHeight)) break;
+ }
+ if (i == availablePictureSizes.count) {
+ ALOGE("%s: Requested picture size %d x %d is not supported",
+ __FUNCTION__, validatedParams.pictureWidth,
+ validatedParams.pictureHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // JPEG_THUMBNAIL_WIDTH/HEIGHT
+ validatedParams.jpegThumbSize[0] =
+ newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
+ validatedParams.jpegThumbSize[1] =
+ newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
+ if (validatedParams.jpegThumbSize[0] != jpegThumbSize[0] ||
+ validatedParams.jpegThumbSize[1] != jpegThumbSize[1]) {
+ camera_metadata_ro_entry_t availableJpegThumbSizes =
+ staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for (i = 0; i < availableJpegThumbSizes.count; i+=2) {
+ if ((availableJpegThumbSizes.data.i32[i] ==
+ validatedParams.jpegThumbSize[0]) &&
+ (availableJpegThumbSizes.data.i32[i+1] ==
+ validatedParams.jpegThumbSize[1])) break;
+ }
+ if (i == availableJpegThumbSizes.count) {
+ ALOGE("%s: Requested JPEG thumbnail size %d x %d is not supported",
+ __FUNCTION__, validatedParams.jpegThumbSize[0],
+ validatedParams.jpegThumbSize[1]);
+ return BAD_VALUE;
+ }
+ }
+
+ // JPEG_THUMBNAIL_QUALITY
+ int quality = newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+ // also makes sure quality fits in uint8_t
+ if (quality < 0 || quality > 100) {
+ ALOGE("%s: Requested JPEG thumbnail quality %d is not supported",
+ __FUNCTION__, quality);
+ return BAD_VALUE;
+ }
+ validatedParams.jpegThumbQuality = quality;
+
+ // JPEG_QUALITY
+ quality = newParams.getInt(CameraParameters::KEY_JPEG_QUALITY);
+ // also makes sure quality fits in uint8_t
+ if (quality < 0 || quality > 100) {
+ ALOGE("%s: Requested JPEG quality %d is not supported",
+ __FUNCTION__, quality);
+ return BAD_VALUE;
+ }
+ validatedParams.jpegQuality = quality;
+
+ // ROTATION
+ validatedParams.jpegRotation =
+ newParams.getInt(CameraParameters::KEY_ROTATION);
+ if (validatedParams.jpegRotation != 0 &&
+ validatedParams.jpegRotation != 90 &&
+ validatedParams.jpegRotation != 180 &&
+ validatedParams.jpegRotation != 270) {
+ ALOGE("%s: Requested picture rotation angle %d is not supported",
+ __FUNCTION__, validatedParams.jpegRotation);
+ return BAD_VALUE;
+ }
+
+ // GPS
+
+ const char *gpsLatStr =
+ newParams.get(CameraParameters::KEY_GPS_LATITUDE);
+ if (gpsLatStr != NULL) {
+ const char *gpsLongStr =
+ newParams.get(CameraParameters::KEY_GPS_LONGITUDE);
+ const char *gpsAltitudeStr =
+ newParams.get(CameraParameters::KEY_GPS_ALTITUDE);
+ const char *gpsTimeStr =
+ newParams.get(CameraParameters::KEY_GPS_TIMESTAMP);
+ const char *gpsProcMethodStr =
+ newParams.get(CameraParameters::KEY_GPS_PROCESSING_METHOD);
+ if (gpsLongStr == NULL ||
+ gpsAltitudeStr == NULL ||
+ gpsTimeStr == NULL ||
+ gpsProcMethodStr == NULL) {
+ ALOGE("%s: Incomplete set of GPS parameters provided",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ char *endPtr;
+ errno = 0;
+ validatedParams.gpsCoordinates[0] = strtod(gpsLatStr, &endPtr);
+ if (errno || endPtr == gpsLatStr) {
+ ALOGE("%s: Malformed GPS latitude: %s", __FUNCTION__, gpsLatStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ validatedParams.gpsCoordinates[1] = strtod(gpsLongStr, &endPtr);
+ if (errno || endPtr == gpsLongStr) {
+ ALOGE("%s: Malformed GPS longitude: %s", __FUNCTION__, gpsLongStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ validatedParams.gpsCoordinates[2] = strtod(gpsAltitudeStr, &endPtr);
+ if (errno || endPtr == gpsAltitudeStr) {
+ ALOGE("%s: Malformed GPS altitude: %s", __FUNCTION__,
+ gpsAltitudeStr);
+ return BAD_VALUE;
+ }
+ errno = 0;
+ validatedParams.gpsTimestamp = strtoll(gpsTimeStr, &endPtr, 10);
+ if (errno || endPtr == gpsTimeStr) {
+ ALOGE("%s: Malformed GPS timestamp: %s", __FUNCTION__, gpsTimeStr);
+ return BAD_VALUE;
+ }
+ validatedParams.gpsProcessingMethod = gpsProcMethodStr;
+
+ validatedParams.gpsEnabled = true;
+ } else {
+ validatedParams.gpsEnabled = false;
+ }
+
+ // EFFECT
+ validatedParams.effectMode = effectModeStringToEnum(
+ newParams.get(CameraParameters::KEY_EFFECT) );
+ if (validatedParams.effectMode != effectMode) {
+ camera_metadata_ro_entry_t availableEffectModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
+ for (i = 0; i < availableEffectModes.count; i++) {
+ if (validatedParams.effectMode == availableEffectModes.data.u8[i]) break;
+ }
+ if (i == availableEffectModes.count) {
+ ALOGE("%s: Requested effect mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_EFFECT) );
+ return BAD_VALUE;
+ }
+ }
+
+ // ANTIBANDING
+ validatedParams.antibandingMode = abModeStringToEnum(
+ newParams.get(CameraParameters::KEY_ANTIBANDING) );
+ if (validatedParams.antibandingMode != antibandingMode) {
+ camera_metadata_ro_entry_t availableAbModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
+ for (i = 0; i < availableAbModes.count; i++) {
+ if (validatedParams.antibandingMode == availableAbModes.data.u8[i])
+ break;
+ }
+ if (i == availableAbModes.count) {
+ ALOGE("%s: Requested antibanding mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_ANTIBANDING));
+ return BAD_VALUE;
+ }
+ }
+
+ // SCENE_MODE
+ validatedParams.sceneMode = sceneModeStringToEnum(
+ newParams.get(CameraParameters::KEY_SCENE_MODE) );
+ if (validatedParams.sceneMode != sceneMode &&
+ validatedParams.sceneMode !=
+ ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) {
+ camera_metadata_ro_entry_t availableSceneModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ for (i = 0; i < availableSceneModes.count; i++) {
+ if (validatedParams.sceneMode == availableSceneModes.data.u8[i])
+ break;
+ }
+ if (i == availableSceneModes.count) {
+ ALOGE("%s: Requested scene mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_SCENE_MODE));
+ return BAD_VALUE;
+ }
+ }
+ bool sceneModeSet =
+ validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+
+ // FLASH_MODE
+ if (sceneModeSet) {
+ validatedParams.flashMode =
+ fastInfo.sceneModeOverrides.
+ valueFor(validatedParams.sceneMode).flashMode;
+ } else {
+ validatedParams.flashMode = FLASH_MODE_INVALID;
+ }
+ if (validatedParams.flashMode == FLASH_MODE_INVALID) {
+ validatedParams.flashMode = flashModeStringToEnum(
+ newParams.get(CameraParameters::KEY_FLASH_MODE) );
+ }
+
+ if (validatedParams.flashMode != flashMode) {
+ camera_metadata_ro_entry_t flashAvailable =
+ staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 1, 1);
+ if (!flashAvailable.data.u8[0] &&
+ validatedParams.flashMode != Parameters::FLASH_MODE_OFF) {
+ ALOGE("%s: Requested flash mode \"%s\" is not supported: "
+ "No flash on device", __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ } else if (validatedParams.flashMode == Parameters::FLASH_MODE_RED_EYE) {
+ camera_metadata_ro_entry_t availableAeModes =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ for (i = 0; i < availableAeModes.count; i++) {
+ if (validatedParams.flashMode == availableAeModes.data.u8[i])
+ break;
+ }
+ if (i == availableAeModes.count) {
+ ALOGE("%s: Requested flash mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ }
+ } else if (validatedParams.flashMode == -1) {
+ ALOGE("%s: Requested flash mode \"%s\" is unknown",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FLASH_MODE));
+ return BAD_VALUE;
+ }
+ // Update in case of override
+ newParams.set(CameraParameters::KEY_FLASH_MODE,
+ flashModeEnumToString(validatedParams.flashMode));
+ }
+
+ // WHITE_BALANCE
+ if (sceneModeSet) {
+ validatedParams.wbMode =
+ fastInfo.sceneModeOverrides.
+ valueFor(validatedParams.sceneMode).wbMode;
+ } else {
+ validatedParams.wbMode = ANDROID_CONTROL_AWB_MODE_OFF;
+ }
+ if (validatedParams.wbMode == ANDROID_CONTROL_AWB_MODE_OFF) {
+ validatedParams.wbMode = wbModeStringToEnum(
+ newParams.get(CameraParameters::KEY_WHITE_BALANCE) );
+ }
+ if (validatedParams.wbMode != wbMode) {
+ camera_metadata_ro_entry_t availableWbModes =
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES, 0, 0, false);
+ for (i = 0; i < availableWbModes.count; i++) {
+ if (validatedParams.wbMode == availableWbModes.data.u8[i]) break;
+ }
+ if (i == availableWbModes.count) {
+ ALOGE("%s: Requested white balance mode %s is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_WHITE_BALANCE));
+ return BAD_VALUE;
+ }
+ // Update in case of override
+ newParams.set(CameraParameters::KEY_WHITE_BALANCE,
+ wbModeEnumToString(validatedParams.wbMode));
+ }
+
+ // FOCUS_MODE
+ if (sceneModeSet) {
+ validatedParams.focusMode =
+ fastInfo.sceneModeOverrides.
+ valueFor(validatedParams.sceneMode).focusMode;
+ } else {
+ validatedParams.focusMode = FOCUS_MODE_INVALID;
+ }
+ if (validatedParams.focusMode == FOCUS_MODE_INVALID) {
+ validatedParams.focusMode = focusModeStringToEnum(
+ newParams.get(CameraParameters::KEY_FOCUS_MODE) );
+ }
+ if (validatedParams.focusMode != focusMode) {
+ validatedParams.currentAfTriggerId = -1;
+ if (validatedParams.focusMode != Parameters::FOCUS_MODE_FIXED) {
+ camera_metadata_ro_entry_t minFocusDistance =
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 0,
+ false);
+ if (minFocusDistance.count && minFocusDistance.data.f[0] == 0) {
+ ALOGE("%s: Requested focus mode \"%s\" is not available: "
+ "fixed focus lens",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FOCUS_MODE));
+ return BAD_VALUE;
+ } else if (validatedParams.focusMode !=
+ Parameters::FOCUS_MODE_INFINITY) {
+ camera_metadata_ro_entry_t availableFocusModes =
+ staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ for (i = 0; i < availableFocusModes.count; i++) {
+ if (validatedParams.focusMode ==
+ availableFocusModes.data.u8[i]) break;
+ }
+ if (i == availableFocusModes.count) {
+ ALOGE("%s: Requested focus mode \"%s\" is not supported",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_FOCUS_MODE));
+ return BAD_VALUE;
+ }
+ }
+ }
+ validatedParams.focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ // Always reset shadow focus mode to avoid reverting settings
+ validatedParams.shadowFocusMode = FOCUS_MODE_INVALID;
+ // Update in case of override
+ newParams.set(CameraParameters::KEY_FOCUS_MODE,
+ focusModeEnumToString(validatedParams.focusMode));
+ } else {
+ validatedParams.currentAfTriggerId = currentAfTriggerId;
+ }
+
+ // FOCUS_AREAS
+ res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
+ &validatedParams.focusingAreas);
+ size_t max3aRegions =
+ (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+ if (res == OK) res = validateAreas(validatedParams.focusingAreas,
+ max3aRegions, AREA_KIND_FOCUS);
+ if (res != OK) {
+ ALOGE("%s: Requested focus areas are malformed: %s",
+ __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
+ return BAD_VALUE;
+ }
+
+ // EXPOSURE_COMPENSATION
+ validatedParams.exposureCompensation =
+ newParams.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION);
+ camera_metadata_ro_entry_t exposureCompensationRange =
+ staticInfo(ANDROID_CONTROL_AE_COMPENSATION_RANGE);
+ if ((validatedParams.exposureCompensation <
+ exposureCompensationRange.data.i32[0]) ||
+ (validatedParams.exposureCompensation >
+ exposureCompensationRange.data.i32[1])) {
+ ALOGE("%s: Requested exposure compensation index is out of bounds: %d",
+ __FUNCTION__, validatedParams.exposureCompensation);
+ return BAD_VALUE;
+ }
+
+ // AUTO_EXPOSURE_LOCK (always supported)
+ validatedParams.autoExposureLock = boolFromString(
+ newParams.get(CameraParameters::KEY_AUTO_EXPOSURE_LOCK));
+
+ // AUTO_WHITEBALANCE_LOCK (always supported)
+ validatedParams.autoWhiteBalanceLock = boolFromString(
+ newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
+
+ // METERING_AREAS
+ res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
+ &validatedParams.meteringAreas);
+ if (res == OK) {
+ res = validateAreas(validatedParams.meteringAreas, max3aRegions,
+ AREA_KIND_METERING);
+ }
+ if (res != OK) {
+ ALOGE("%s: Requested metering areas are malformed: %s",
+ __FUNCTION__,
+ newParams.get(CameraParameters::KEY_METERING_AREAS));
+ return BAD_VALUE;
+ }
+
+ // ZOOM
+ validatedParams.zoom = newParams.getInt(CameraParameters::KEY_ZOOM);
+ if (validatedParams.zoom < 0
+ || validatedParams.zoom >= (int)NUM_ZOOM_STEPS) {
+ ALOGE("%s: Requested zoom level %d is not supported",
+ __FUNCTION__, validatedParams.zoom);
+ return BAD_VALUE;
+ }
+
+ // VIDEO_SIZE
+ newParams.getVideoSize(&validatedParams.videoWidth,
+ &validatedParams.videoHeight);
+ if (validatedParams.videoWidth != videoWidth ||
+ validatedParams.videoHeight != videoHeight) {
+ if (state == RECORD) {
+ ALOGE("%s: Video size cannot be updated when recording is active!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ for (i = 0; i < availablePreviewSizes.size(); i++) {
+ if ((availablePreviewSizes[i].width ==
+ validatedParams.videoWidth) &&
+ (availablePreviewSizes[i].height ==
+ validatedParams.videoHeight)) break;
+ }
+ if (i == availablePreviewSizes.size()) {
+ ALOGE("%s: Requested video size %d x %d is not supported",
+ __FUNCTION__, validatedParams.videoWidth,
+ validatedParams.videoHeight);
+ return BAD_VALUE;
+ }
+ }
+
+ // VIDEO_STABILIZATION
+ validatedParams.videoStabilization = boolFromString(
+ newParams.get(CameraParameters::KEY_VIDEO_STABILIZATION) );
+ camera_metadata_ro_entry_t availableVideoStabilizationModes =
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, 0, 0,
+ false);
+ if (validatedParams.videoStabilization &&
+ availableVideoStabilizationModes.count == 1) {
+ ALOGE("%s: Video stabilization not supported", __FUNCTION__);
+ }
+
+ // LIGHTFX
+ validatedParams.lightFx = lightFxStringToEnum(
+ newParams.get(CameraParameters::KEY_LIGHTFX));
+
+ /** Update internal parameters */
+
+ *this = validatedParams;
+
+ /** Update external parameters calculated from the internal ones */
+
+ // HORIZONTAL/VERTICAL FIELD OF VIEW
+ float horizFov, vertFov;
+ res = calculatePictureFovs(&horizFov, &vertFov);
+ if (res != OK) {
+ ALOGE("%s: Can't calculate FOVs", __FUNCTION__);
+ // continue so parameters are at least consistent
+ }
+ newParams.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE,
+ horizFov);
+ newParams.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE,
+ vertFov);
+ ALOGV("Current still picture FOV: %f x %f deg", horizFov, vertFov);
+
+ // Need to flatten again in case of overrides
+ paramsFlattened = newParams.flatten();
+ params = newParams;
+
+ return OK;
+}
+
+status_t Parameters::updateRequest(CameraMetadata *request) const {
+ ATRACE_CALL();
+ status_t res;
+
+ /**
+ * Mixin default important security values
+ * - android.led.transmit = defaulted ON
+ */
+ camera_metadata_ro_entry_t entry = staticInfo(ANDROID_LED_AVAILABLE_LEDS,
+ /*minimumCount*/0,
+ /*maximumCount*/0,
+ /*required*/false);
+ for(size_t i = 0; i < entry.count; ++i) {
+ uint8_t led = entry.data.u8[i];
+
+ switch(led) {
+ // Transmit LED is unconditionally on when using
+ // the android.hardware.Camera API
+ case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+ uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+ res = request->update(ANDROID_LED_TRANSMIT,
+ &transmitDefault, 1);
+ if (res != OK) return res;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Construct metadata from parameters
+ */
+
+ uint8_t metadataMode = ANDROID_REQUEST_METADATA_MODE_FULL;
+ res = request->update(ANDROID_REQUEST_METADATA_MODE,
+ &metadataMode, 1);
+ if (res != OK) return res;
+
+ camera_metadata_entry_t intent =
+ request->find(ANDROID_CONTROL_CAPTURE_INTENT);
+ if (intent.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE) {
+ res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ fastInfo.bestStillCaptureFpsRange, 2);
+ } else {
+ res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ previewFpsRange, 2);
+ }
+ if (res != OK) return res;
+
+ uint8_t reqWbLock = autoWhiteBalanceLock ?
+ ANDROID_CONTROL_AWB_LOCK_ON : ANDROID_CONTROL_AWB_LOCK_OFF;
+ res = request->update(ANDROID_CONTROL_AWB_LOCK,
+ &reqWbLock, 1);
+
+ res = request->update(ANDROID_CONTROL_EFFECT_MODE,
+ &effectMode, 1);
+ if (res != OK) return res;
+ res = request->update(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+ &antibandingMode, 1);
+ if (res != OK) return res;
+
+ // android.hardware.Camera requires that when face detect is enabled, the
+ // camera is in a face-priority mode. HAL2 splits this into separate parts
+ // (face detection statistics and face priority scene mode). Map from other
+ // to the other.
+ bool sceneModeActive =
+ sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ uint8_t reqControlMode = ANDROID_CONTROL_MODE_AUTO;
+ if (enableFaceDetect || sceneModeActive) {
+ reqControlMode = ANDROID_CONTROL_MODE_USE_SCENE_MODE;
+ }
+ res = request->update(ANDROID_CONTROL_MODE,
+ &reqControlMode, 1);
+ if (res != OK) return res;
+
+ uint8_t reqSceneMode =
+ sceneModeActive ? sceneMode :
+ enableFaceDetect ? (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY :
+ (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ res = request->update(ANDROID_CONTROL_SCENE_MODE,
+ &reqSceneMode, 1);
+ if (res != OK) return res;
+
+ uint8_t reqFlashMode = ANDROID_FLASH_MODE_OFF;
+ uint8_t reqAeMode = ANDROID_CONTROL_AE_MODE_OFF;
+ switch (flashMode) {
+ case Parameters::FLASH_MODE_OFF:
+ reqAeMode = ANDROID_CONTROL_AE_MODE_ON; break;
+ case Parameters::FLASH_MODE_AUTO:
+ reqAeMode = ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH; break;
+ case Parameters::FLASH_MODE_ON:
+ reqAeMode = ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH; break;
+ case Parameters::FLASH_MODE_TORCH:
+ reqAeMode = ANDROID_CONTROL_AE_MODE_ON;
+ reqFlashMode = ANDROID_FLASH_MODE_TORCH;
+ break;
+ case Parameters::FLASH_MODE_RED_EYE:
+ reqAeMode = ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE; break;
+ default:
+ ALOGE("%s: Camera %d: Unknown flash mode %d", __FUNCTION__,
+ cameraId, flashMode);
+ return BAD_VALUE;
+ }
+ res = request->update(ANDROID_FLASH_MODE,
+ &reqFlashMode, 1);
+ if (res != OK) return res;
+ res = request->update(ANDROID_CONTROL_AE_MODE,
+ &reqAeMode, 1);
+ if (res != OK) return res;
+
+ uint8_t reqAeLock = autoExposureLock ?
+ ANDROID_CONTROL_AE_LOCK_ON : ANDROID_CONTROL_AE_LOCK_OFF;
+ res = request->update(ANDROID_CONTROL_AE_LOCK,
+ &reqAeLock, 1);
+ if (res != OK) return res;
+
+ res = request->update(ANDROID_CONTROL_AWB_MODE,
+ &wbMode, 1);
+ if (res != OK) return res;
+
+ float reqFocusDistance = 0; // infinity focus in diopters
+ uint8_t reqFocusMode = ANDROID_CONTROL_AF_MODE_OFF;
+ switch (focusMode) {
+ case Parameters::FOCUS_MODE_AUTO:
+ case Parameters::FOCUS_MODE_MACRO:
+ case Parameters::FOCUS_MODE_CONTINUOUS_VIDEO:
+ case Parameters::FOCUS_MODE_CONTINUOUS_PICTURE:
+ case Parameters::FOCUS_MODE_EDOF:
+ reqFocusMode = focusMode;
+ break;
+ case Parameters::FOCUS_MODE_INFINITY:
+ case Parameters::FOCUS_MODE_FIXED:
+ reqFocusMode = ANDROID_CONTROL_AF_MODE_OFF;
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__,
+ cameraId, focusMode);
+ return BAD_VALUE;
+ }
+ res = request->update(ANDROID_LENS_FOCUS_DISTANCE,
+ &reqFocusDistance, 1);
+ if (res != OK) return res;
+ res = request->update(ANDROID_CONTROL_AF_MODE,
+ &reqFocusMode, 1);
+ if (res != OK) return res;
+
+ size_t reqFocusingAreasSize = focusingAreas.size() * 5;
+ int32_t *reqFocusingAreas = new int32_t[reqFocusingAreasSize];
+ for (size_t i = 0; i < reqFocusingAreasSize; i += 5) {
+ if (focusingAreas[i].weight != 0) {
+ reqFocusingAreas[i + 0] =
+ normalizedXToArray(focusingAreas[i].left);
+ reqFocusingAreas[i + 1] =
+ normalizedYToArray(focusingAreas[i].top);
+ reqFocusingAreas[i + 2] =
+ normalizedXToArray(focusingAreas[i].right);
+ reqFocusingAreas[i + 3] =
+ normalizedYToArray(focusingAreas[i].bottom);
+ } else {
+ reqFocusingAreas[i + 0] = 0;
+ reqFocusingAreas[i + 1] = 0;
+ reqFocusingAreas[i + 2] = 0;
+ reqFocusingAreas[i + 3] = 0;
+ }
+ reqFocusingAreas[i + 4] = focusingAreas[i].weight;
+ }
+ res = request->update(ANDROID_CONTROL_AF_REGIONS,
+ reqFocusingAreas, reqFocusingAreasSize);
+ if (res != OK) return res;
+ delete[] reqFocusingAreas;
+
+ res = request->update(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+ &exposureCompensation, 1);
+ if (res != OK) return res;
+
+ size_t reqMeteringAreasSize = meteringAreas.size() * 5;
+ int32_t *reqMeteringAreas = new int32_t[reqMeteringAreasSize];
+ for (size_t i = 0; i < reqMeteringAreasSize; i += 5) {
+ if (meteringAreas[i].weight != 0) {
+ reqMeteringAreas[i + 0] =
+ normalizedXToArray(meteringAreas[i].left);
+ reqMeteringAreas[i + 1] =
+ normalizedYToArray(meteringAreas[i].top);
+ reqMeteringAreas[i + 2] =
+ normalizedXToArray(meteringAreas[i].right);
+ reqMeteringAreas[i + 3] =
+ normalizedYToArray(meteringAreas[i].bottom);
+ } else {
+ reqMeteringAreas[i + 0] = 0;
+ reqMeteringAreas[i + 1] = 0;
+ reqMeteringAreas[i + 2] = 0;
+ reqMeteringAreas[i + 3] = 0;
+ }
+ reqMeteringAreas[i + 4] = meteringAreas[i].weight;
+ }
+ res = request->update(ANDROID_CONTROL_AE_REGIONS,
+ reqMeteringAreas, reqMeteringAreasSize);
+ if (res != OK) return res;
+
+ delete[] reqMeteringAreas;
+
+ /* don't include jpeg thumbnail size - it's valid for
+ it to be set to (0,0), meaning 'no thumbnail' */
+ CropRegion crop = calculateCropRegion( (CropRegion::Outputs)(
+ CropRegion::OUTPUT_PREVIEW |
+ CropRegion::OUTPUT_VIDEO |
+ CropRegion::OUTPUT_PICTURE ));
+ int32_t reqCropRegion[4] = {
+ static_cast<int32_t>(crop.left),
+ static_cast<int32_t>(crop.top),
+ static_cast<int32_t>(crop.width),
+ static_cast<int32_t>(crop.height)
+ };
+ res = request->update(ANDROID_SCALER_CROP_REGION,
+ reqCropRegion, 4);
+ if (res != OK) return res;
+
+ uint8_t reqVstabMode = videoStabilization ?
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON :
+ ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+ res = request->update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+ &reqVstabMode, 1);
+ if (res != OK) return res;
+
+ uint8_t reqFaceDetectMode = enableFaceDetect ?
+ fastInfo.bestFaceDetectMode :
+ (uint8_t)ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+ res = request->update(ANDROID_STATISTICS_FACE_DETECT_MODE,
+ &reqFaceDetectMode, 1);
+ if (res != OK) return res;
+
+ return OK;
+}
+
+status_t Parameters::updateRequestJpeg(CameraMetadata *request) const {
+ status_t res;
+
+ res = request->update(ANDROID_JPEG_THUMBNAIL_SIZE,
+ jpegThumbSize, 2);
+ if (res != OK) return res;
+ res = request->update(ANDROID_JPEG_THUMBNAIL_QUALITY,
+ &jpegThumbQuality, 1);
+ if (res != OK) return res;
+ res = request->update(ANDROID_JPEG_QUALITY,
+ &jpegQuality, 1);
+ if (res != OK) return res;
+ res = request->update(
+ ANDROID_JPEG_ORIENTATION,
+ &jpegRotation, 1);
+ if (res != OK) return res;
+
+ if (gpsEnabled) {
+ res = request->update(
+ ANDROID_JPEG_GPS_COORDINATES,
+ gpsCoordinates, 3);
+ if (res != OK) return res;
+ res = request->update(
+ ANDROID_JPEG_GPS_TIMESTAMP,
+ &gpsTimestamp, 1);
+ if (res != OK) return res;
+ res = request->update(
+ ANDROID_JPEG_GPS_PROCESSING_METHOD,
+ gpsProcessingMethod);
+ if (res != OK) return res;
+ } else {
+ res = request->erase(ANDROID_JPEG_GPS_COORDINATES);
+ if (res != OK) return res;
+ res = request->erase(ANDROID_JPEG_GPS_TIMESTAMP);
+ if (res != OK) return res;
+ res = request->erase(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+ if (res != OK) return res;
+ }
+ return OK;
+}
+
+
+const char* Parameters::getStateName(State state) {
+#define CASE_ENUM_TO_CHAR(x) case x: return(#x); break;
+ switch(state) {
+ CASE_ENUM_TO_CHAR(DISCONNECTED)
+ CASE_ENUM_TO_CHAR(STOPPED)
+ CASE_ENUM_TO_CHAR(WAITING_FOR_PREVIEW_WINDOW)
+ CASE_ENUM_TO_CHAR(PREVIEW)
+ CASE_ENUM_TO_CHAR(RECORD)
+ CASE_ENUM_TO_CHAR(STILL_CAPTURE)
+ CASE_ENUM_TO_CHAR(VIDEO_SNAPSHOT)
+ default:
+ return "Unknown state!";
+ break;
+ }
+#undef CASE_ENUM_TO_CHAR
+}
+
+int Parameters::formatStringToEnum(const char *format) {
+ return
+ !format ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP :
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
+ HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
+ HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
+ HAL_PIXEL_FORMAT_YV12 : // YV12
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
+ HAL_PIXEL_FORMAT_RGB_565 : // RGB565
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
+ HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
+ !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
+ HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data
+ -1;
+}
+
+const char* Parameters::formatEnumToString(int format) {
+ const char *fmt;
+ switch(format) {
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP: // NV16
+ fmt = CameraParameters::PIXEL_FORMAT_YUV422SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP: // NV21
+ fmt = CameraParameters::PIXEL_FORMAT_YUV420SP;
+ break;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: // YUY2
+ fmt = CameraParameters::PIXEL_FORMAT_YUV422I;
+ break;
+ case HAL_PIXEL_FORMAT_YV12: // YV12
+ fmt = CameraParameters::PIXEL_FORMAT_YUV420P;
+ break;
+ case HAL_PIXEL_FORMAT_RGB_565: // RGB565
+ fmt = CameraParameters::PIXEL_FORMAT_RGB565;
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888: // RGBA8888
+ fmt = CameraParameters::PIXEL_FORMAT_RGBA8888;
+ break;
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ ALOGW("Raw sensor preview format requested.");
+ fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB;
+ break;
+ default:
+ ALOGE("%s: Unknown preview format: %x",
+ __FUNCTION__, format);
+ fmt = NULL;
+ break;
+ }
+ return fmt;
+}
+
+int Parameters::wbModeStringToEnum(const char *wbMode) {
+ return
+ !wbMode ?
+ ANDROID_CONTROL_AWB_MODE_AUTO :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_AUTO) ?
+ ANDROID_CONTROL_AWB_MODE_AUTO :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_INCANDESCENT) ?
+ ANDROID_CONTROL_AWB_MODE_INCANDESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_FLUORESCENT) ?
+ ANDROID_CONTROL_AWB_MODE_FLUORESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT) ?
+ ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_DAYLIGHT) ?
+ ANDROID_CONTROL_AWB_MODE_DAYLIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT) ?
+ ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_TWILIGHT) ?
+ ANDROID_CONTROL_AWB_MODE_TWILIGHT :
+ !strcmp(wbMode, CameraParameters::WHITE_BALANCE_SHADE) ?
+ ANDROID_CONTROL_AWB_MODE_SHADE :
+ -1;
+}
+
+const char* Parameters::wbModeEnumToString(uint8_t wbMode) {
+ switch (wbMode) {
+ case ANDROID_CONTROL_AWB_MODE_AUTO:
+ return CameraParameters::WHITE_BALANCE_AUTO;
+ case ANDROID_CONTROL_AWB_MODE_INCANDESCENT:
+ return CameraParameters::WHITE_BALANCE_INCANDESCENT;
+ case ANDROID_CONTROL_AWB_MODE_FLUORESCENT:
+ return CameraParameters::WHITE_BALANCE_FLUORESCENT;
+ case ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT:
+ return CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT;
+ case ANDROID_CONTROL_AWB_MODE_DAYLIGHT:
+ return CameraParameters::WHITE_BALANCE_DAYLIGHT;
+ case ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
+ return CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT;
+ case ANDROID_CONTROL_AWB_MODE_TWILIGHT:
+ return CameraParameters::WHITE_BALANCE_TWILIGHT;
+ case ANDROID_CONTROL_AWB_MODE_SHADE:
+ return CameraParameters::WHITE_BALANCE_SHADE;
+ default:
+ ALOGE("%s: Unknown AWB mode enum: %d",
+ __FUNCTION__, wbMode);
+ return "unknown";
+ }
+}
+
+int Parameters::effectModeStringToEnum(const char *effectMode) {
+ return
+ !effectMode ?
+ ANDROID_CONTROL_EFFECT_MODE_OFF :
+ !strcmp(effectMode, CameraParameters::EFFECT_NONE) ?
+ ANDROID_CONTROL_EFFECT_MODE_OFF :
+ !strcmp(effectMode, CameraParameters::EFFECT_MONO) ?
+ ANDROID_CONTROL_EFFECT_MODE_MONO :
+ !strcmp(effectMode, CameraParameters::EFFECT_NEGATIVE) ?
+ ANDROID_CONTROL_EFFECT_MODE_NEGATIVE :
+ !strcmp(effectMode, CameraParameters::EFFECT_SOLARIZE) ?
+ ANDROID_CONTROL_EFFECT_MODE_SOLARIZE :
+ !strcmp(effectMode, CameraParameters::EFFECT_SEPIA) ?
+ ANDROID_CONTROL_EFFECT_MODE_SEPIA :
+ !strcmp(effectMode, CameraParameters::EFFECT_POSTERIZE) ?
+ ANDROID_CONTROL_EFFECT_MODE_POSTERIZE :
+ !strcmp(effectMode, CameraParameters::EFFECT_WHITEBOARD) ?
+ ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD :
+ !strcmp(effectMode, CameraParameters::EFFECT_BLACKBOARD) ?
+ ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD :
+ !strcmp(effectMode, CameraParameters::EFFECT_AQUA) ?
+ ANDROID_CONTROL_EFFECT_MODE_AQUA :
+ -1;
+}
+
+int Parameters::abModeStringToEnum(const char *abMode) {
+ return
+ !abMode ?
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_AUTO) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_OFF) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_50HZ) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ :
+ !strcmp(abMode, CameraParameters::ANTIBANDING_60HZ) ?
+ ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ :
+ -1;
+}
+
+int Parameters::sceneModeStringToEnum(const char *sceneMode) {
+ return
+ !sceneMode ?
+ ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
+ ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
+ ANDROID_CONTROL_SCENE_MODE_ACTION :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
+ ANDROID_CONTROL_SCENE_MODE_PORTRAIT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_LANDSCAPE) ?
+ ANDROID_CONTROL_SCENE_MODE_LANDSCAPE :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT) ?
+ ANDROID_CONTROL_SCENE_MODE_NIGHT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_NIGHT_PORTRAIT) ?
+ ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_THEATRE) ?
+ ANDROID_CONTROL_SCENE_MODE_THEATRE :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_BEACH) ?
+ ANDROID_CONTROL_SCENE_MODE_BEACH :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SNOW) ?
+ ANDROID_CONTROL_SCENE_MODE_SNOW :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SUNSET) ?
+ ANDROID_CONTROL_SCENE_MODE_SUNSET :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_STEADYPHOTO) ?
+ ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_FIREWORKS) ?
+ ANDROID_CONTROL_SCENE_MODE_FIREWORKS :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_SPORTS) ?
+ ANDROID_CONTROL_SCENE_MODE_SPORTS :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_PARTY) ?
+ ANDROID_CONTROL_SCENE_MODE_PARTY :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_CANDLELIGHT) ?
+ ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT :
+ !strcmp(sceneMode, CameraParameters::SCENE_MODE_BARCODE) ?
+ ANDROID_CONTROL_SCENE_MODE_BARCODE:
+ -1;
+}
+
+Parameters::Parameters::flashMode_t Parameters::flashModeStringToEnum(
+ const char *flashMode) {
+ return
+ !flashMode ?
+ Parameters::FLASH_MODE_INVALID :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
+ Parameters::FLASH_MODE_OFF :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
+ Parameters::FLASH_MODE_AUTO :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_ON) ?
+ Parameters::FLASH_MODE_ON :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_RED_EYE) ?
+ Parameters::FLASH_MODE_RED_EYE :
+ !strcmp(flashMode, CameraParameters::FLASH_MODE_TORCH) ?
+ Parameters::FLASH_MODE_TORCH :
+ Parameters::FLASH_MODE_INVALID;
+}
+
+const char *Parameters::flashModeEnumToString(flashMode_t flashMode) {
+ switch (flashMode) {
+ case FLASH_MODE_OFF:
+ return CameraParameters::FLASH_MODE_OFF;
+ case FLASH_MODE_AUTO:
+ return CameraParameters::FLASH_MODE_AUTO;
+ case FLASH_MODE_ON:
+ return CameraParameters::FLASH_MODE_ON;
+ case FLASH_MODE_RED_EYE:
+ return CameraParameters::FLASH_MODE_RED_EYE;
+ case FLASH_MODE_TORCH:
+ return CameraParameters::FLASH_MODE_TORCH;
+ default:
+ ALOGE("%s: Unknown flash mode enum %d",
+ __FUNCTION__, flashMode);
+ return "unknown";
+ }
+}
+
+Parameters::Parameters::focusMode_t Parameters::focusModeStringToEnum(
+ const char *focusMode) {
+ return
+ !focusMode ?
+ Parameters::FOCUS_MODE_INVALID :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_AUTO) ?
+ Parameters::FOCUS_MODE_AUTO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_INFINITY) ?
+ Parameters::FOCUS_MODE_INFINITY :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_MACRO) ?
+ Parameters::FOCUS_MODE_MACRO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_FIXED) ?
+ Parameters::FOCUS_MODE_FIXED :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_EDOF) ?
+ Parameters::FOCUS_MODE_EDOF :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO) ?
+ Parameters::FOCUS_MODE_CONTINUOUS_VIDEO :
+ !strcmp(focusMode, CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE) ?
+ Parameters::FOCUS_MODE_CONTINUOUS_PICTURE :
+ Parameters::FOCUS_MODE_INVALID;
+}
+
+const char *Parameters::focusModeEnumToString(focusMode_t focusMode) {
+ switch (focusMode) {
+ case FOCUS_MODE_AUTO:
+ return CameraParameters::FOCUS_MODE_AUTO;
+ case FOCUS_MODE_MACRO:
+ return CameraParameters::FOCUS_MODE_MACRO;
+ case FOCUS_MODE_CONTINUOUS_VIDEO:
+ return CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+ case FOCUS_MODE_CONTINUOUS_PICTURE:
+ return CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+ case FOCUS_MODE_EDOF:
+ return CameraParameters::FOCUS_MODE_EDOF;
+ case FOCUS_MODE_INFINITY:
+ return CameraParameters::FOCUS_MODE_INFINITY;
+ case FOCUS_MODE_FIXED:
+ return CameraParameters::FOCUS_MODE_FIXED;
+ default:
+ ALOGE("%s: Unknown focus mode enum: %d",
+ __FUNCTION__, focusMode);
+ return "unknown";
+ }
+}
+
+Parameters::Parameters::lightFxMode_t Parameters::lightFxStringToEnum(
+ const char *lightFxMode) {
+ return
+ !lightFxMode ?
+ Parameters::LIGHTFX_NONE :
+ !strcmp(lightFxMode, CameraParameters::LIGHTFX_LOWLIGHT) ?
+ Parameters::LIGHTFX_LOWLIGHT :
+ !strcmp(lightFxMode, CameraParameters::LIGHTFX_HDR) ?
+ Parameters::LIGHTFX_HDR :
+ Parameters::LIGHTFX_NONE;
+}
+
+status_t Parameters::parseAreas(const char *areasCStr,
+ Vector<Parameters::Area> *areas) {
+ static const size_t NUM_FIELDS = 5;
+ areas->clear();
+ if (areasCStr == NULL) {
+ // If no key exists, use default (0,0,0,0,0)
+ areas->push();
+ return OK;
+ }
+ String8 areasStr(areasCStr);
+ ssize_t areaStart = areasStr.find("(", 0) + 1;
+ while (areaStart != 0) {
+ const char* area = areasStr.string() + areaStart;
+ char *numEnd;
+ int vals[NUM_FIELDS];
+ for (size_t i = 0; i < NUM_FIELDS; i++) {
+ errno = 0;
+ vals[i] = strtol(area, &numEnd, 10);
+ if (errno || numEnd == area) return BAD_VALUE;
+ area = numEnd + 1;
+ }
+ areas->push(Parameters::Area(
+ vals[0], vals[1], vals[2], vals[3], vals[4]) );
+ areaStart = areasStr.find("(", areaStart) + 1;
+ }
+ return OK;
+}
+
+status_t Parameters::validateAreas(const Vector<Parameters::Area> &areas,
+ size_t maxRegions,
+ AreaKind areaKind) const {
+ // Definition of valid area can be found in
+ // include/camera/CameraParameters.h
+ if (areas.size() == 0) return BAD_VALUE;
+ if (areas.size() == 1) {
+ if (areas[0].left == 0 &&
+ areas[0].top == 0 &&
+ areas[0].right == 0 &&
+ areas[0].bottom == 0 &&
+ areas[0].weight == 0) {
+ // Single (0,0,0,0,0) entry is always valid (== driver decides)
+ return OK;
+ }
+ }
+
+ // fixed focus can only set (0,0,0,0,0) focus area
+ if (areaKind == AREA_KIND_FOCUS && focusMode == FOCUS_MODE_FIXED) {
+ return BAD_VALUE;
+ }
+
+ if (areas.size() > maxRegions) {
+ ALOGE("%s: Too many areas requested: %d",
+ __FUNCTION__, areas.size());
+ return BAD_VALUE;
+ }
+
+ for (Vector<Parameters::Area>::const_iterator a = areas.begin();
+ a != areas.end(); a++) {
+ if (a->weight < 1 || a->weight > 1000) return BAD_VALUE;
+ if (a->left < -1000 || a->left > 1000) return BAD_VALUE;
+ if (a->top < -1000 || a->top > 1000) return BAD_VALUE;
+ if (a->right < -1000 || a->right > 1000) return BAD_VALUE;
+ if (a->bottom < -1000 || a->bottom > 1000) return BAD_VALUE;
+ if (a->left >= a->right) return BAD_VALUE;
+ if (a->top >= a->bottom) return BAD_VALUE;
+ }
+ return OK;
+}
+
+bool Parameters::boolFromString(const char *boolStr) {
+ return !boolStr ? false :
+ !strcmp(boolStr, CameraParameters::TRUE) ? true :
+ false;
+}
+
+int Parameters::degToTransform(int degrees, bool mirror) {
+ if (!mirror) {
+ if (degrees == 0) return 0;
+ else if (degrees == 90) return HAL_TRANSFORM_ROT_90;
+ else if (degrees == 180) return HAL_TRANSFORM_ROT_180;
+ else if (degrees == 270) return HAL_TRANSFORM_ROT_270;
+ } else { // Do mirror (horizontal flip)
+ if (degrees == 0) { // FLIP_H and ROT_0
+ return HAL_TRANSFORM_FLIP_H;
+ } else if (degrees == 90) { // FLIP_H and ROT_90
+ return HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+ } else if (degrees == 180) { // FLIP_H and ROT_180
+ return HAL_TRANSFORM_FLIP_V;
+ } else if (degrees == 270) { // FLIP_H and ROT_270
+ return HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+ }
+ }
+ ALOGE("%s: Bad input: %d", __FUNCTION__, degrees);
+ return -1;
+}
+
+int Parameters::cropXToArray(int x) const {
+ ALOG_ASSERT(x >= 0, "Crop-relative X coordinate = '%d' is out of bounds"
+ "(lower = 0)", x);
+
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ ALOG_ASSERT(x < previewCrop.width, "Crop-relative X coordinate = '%d' "
+ "is out of bounds (upper = %f)", x, previewCrop.width);
+
+ int ret = x + previewCrop.left;
+
+ ALOG_ASSERT( (ret >= 0 && ret < fastInfo.arrayWidth),
+ "Calculated pixel array value X = '%d' is out of bounds (upper = %d)",
+ ret, fastInfo.arrayWidth);
+ return ret;
+}
+
+int Parameters::cropYToArray(int y) const {
+ ALOG_ASSERT(y >= 0, "Crop-relative Y coordinate = '%d' is out of bounds "
+ "(lower = 0)", y);
+
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ ALOG_ASSERT(y < previewCrop.height, "Crop-relative Y coordinate = '%d' is "
+ "out of bounds (upper = %f)", y, previewCrop.height);
+
+ int ret = y + previewCrop.top;
+
+ ALOG_ASSERT( (ret >= 0 && ret < fastInfo.arrayHeight),
+ "Calculated pixel array value Y = '%d' is out of bounds (upper = %d)",
+ ret, fastInfo.arrayHeight);
+
+ return ret;
+
+}
+
+int Parameters::normalizedXToCrop(int x) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return (x + 1000) * (previewCrop.width - 1) / 2000;
+}
+
+int Parameters::normalizedYToCrop(int y) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return (y + 1000) * (previewCrop.height - 1) / 2000;
+}
+
+int Parameters::arrayXToCrop(int x) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return x - previewCrop.left;
+}
+
+int Parameters::arrayYToCrop(int y) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return y - previewCrop.top;
+}
+
+int Parameters::cropXToNormalized(int x) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return x * 2000 / (previewCrop.width - 1) - 1000;
+}
+
+int Parameters::cropYToNormalized(int y) const {
+ CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ return y * 2000 / (previewCrop.height - 1) - 1000;
+}
+
+int Parameters::arrayXToNormalized(int width) const {
+ int ret = cropXToNormalized(arrayXToCrop(width));
+
+ ALOG_ASSERT(ret >= -1000, "Calculated normalized value out of "
+ "lower bounds %d", ret);
+ ALOG_ASSERT(ret <= 1000, "Calculated normalized value out of "
+ "upper bounds %d", ret);
+
+ // Work-around for HAL pre-scaling the coordinates themselves
+ if (quirks.meteringCropRegion) {
+ return width * 2000 / (fastInfo.arrayWidth - 1) - 1000;
+ }
+
+ return ret;
+}
+
+int Parameters::arrayYToNormalized(int height) const {
+ int ret = cropYToNormalized(arrayYToCrop(height));
+
+ ALOG_ASSERT(ret >= -1000, "Calculated normalized value out of lower bounds"
+ " %d", ret);
+ ALOG_ASSERT(ret <= 1000, "Calculated normalized value out of upper bounds"
+ " %d", ret);
+
+ // Work-around for HAL pre-scaling the coordinates themselves
+ if (quirks.meteringCropRegion) {
+ return height * 2000 / (fastInfo.arrayHeight - 1) - 1000;
+ }
+
+ return ret;
+}
+
+int Parameters::normalizedXToArray(int x) const {
+
+ // Work-around for HAL pre-scaling the coordinates themselves
+ if (quirks.meteringCropRegion) {
+ return (x + 1000) * (fastInfo.arrayWidth - 1) / 2000;
+ }
+
+ return cropXToArray(normalizedXToCrop(x));
+}
+
+int Parameters::normalizedYToArray(int y) const {
+ // Work-around for HAL pre-scaling the coordinates themselves
+ if (quirks.meteringCropRegion) {
+ return (y + 1000) * (fastInfo.arrayHeight - 1) / 2000;
+ }
+
+ return cropYToArray(normalizedYToCrop(y));
+}
+
+status_t Parameters::getFilteredPreviewSizes(Size limit, Vector<Size> *sizes) {
+ if (info == NULL) {
+ ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
+ return NO_INIT;
+ }
+ if (sizes == NULL) {
+ ALOGE("%s: Input size is null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ const size_t SIZE_COUNT = sizeof(Size) / sizeof(int);
+ camera_metadata_ro_entry_t availableProcessedSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, SIZE_COUNT);
+ if (availableProcessedSizes.count < SIZE_COUNT) return BAD_VALUE;
+
+ Size previewSize;
+ for (size_t i = 0; i < availableProcessedSizes.count; i += SIZE_COUNT) {
+ previewSize.width = availableProcessedSizes.data.i32[i];
+ previewSize.height = availableProcessedSizes.data.i32[i+1];
+ // Need skip the preview sizes that are too large.
+ if (previewSize.width <= limit.width &&
+ previewSize.height <= limit.height) {
+ sizes->push(previewSize);
+ }
+ }
+ if (sizes->isEmpty()) {
+ ALOGE("generated preview size list is empty!!");
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+Parameters::Size Parameters::getMaxSizeForRatio(
+ float ratio, const int32_t* sizeArray, size_t count) {
+ ALOG_ASSERT(sizeArray != NULL, "size array shouldn't be NULL");
+ ALOG_ASSERT(count >= 2 && count % 2 == 0, "count must be a positive even number");
+
+ Size maxSize = {0, 0};
+ for (size_t i = 0; i < count; i += 2) {
+ if (sizeArray[i] > 0 && sizeArray[i+1] > 0) {
+ float curRatio = static_cast<float>(sizeArray[i]) / sizeArray[i+1];
+ if (fabs(curRatio - ratio) < ASPECT_RATIO_TOLERANCE && maxSize.width < sizeArray[i]) {
+ maxSize.width = sizeArray[i];
+ maxSize.height = sizeArray[i+1];
+ }
+ }
+ }
+
+ if (maxSize.width == 0 || maxSize.height == 0) {
+ maxSize.width = sizeArray[0];
+ maxSize.height = sizeArray[1];
+ ALOGW("Unable to find the size to match the given aspect ratio %f."
+ "Fall back to %d x %d", ratio, maxSize.width, maxSize.height);
+ }
+
+ return maxSize;
+}
+
+Parameters::CropRegion Parameters::calculateCropRegion(
+ Parameters::CropRegion::Outputs outputs) const {
+
+ float zoomLeft, zoomTop, zoomWidth, zoomHeight;
+
+ // Need to convert zoom index into a crop rectangle. The rectangle is
+ // chosen to maximize its area on the sensor
+
+ camera_metadata_ro_entry_t maxDigitalZoom =
+ staticInfo(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
+ // For each zoom step by how many pixels more do we change the zoom
+ float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
+ (NUM_ZOOM_STEPS-1);
+ // The desired activeAreaWidth/cropAreaWidth ratio (or height if h>w)
+ // via interpolating zoom step into a zoom ratio
+ float zoomRatio = 1 + zoomIncrement * zoom;
+ ALOG_ASSERT( (zoomRatio >= 1.f && zoomRatio <= maxDigitalZoom.data.f[0]),
+ "Zoom ratio calculated out of bounds. Expected 1 - %f, actual: %f",
+ maxDigitalZoom.data.f[0], zoomRatio);
+
+ ALOGV("Zoom maxDigital=%f, increment=%f, ratio=%f, previewWidth=%d, "
+ "previewHeight=%d, activeWidth=%d, activeHeight=%d",
+ maxDigitalZoom.data.f[0], zoomIncrement, zoomRatio, previewWidth,
+ previewHeight, fastInfo.arrayWidth, fastInfo.arrayHeight);
+
+ /*
+ * Assumption: On the HAL side each stream buffer calculates its crop
+ * rectangle as follows:
+ * cropRect = (zoomLeft, zoomRight,
+ * zoomWidth, zoomHeight * zoomWidth / outputWidth);
+ *
+ * Note that if zoomWidth > bufferWidth, the new cropHeight > zoomHeight
+ * (we can then get into trouble if the cropHeight > arrayHeight).
+ * By selecting the zoomRatio based on the smallest outputRatio, we
+ * guarantee this will never happen.
+ */
+
+ // Enumerate all possible output sizes, select the one with the smallest
+ // aspect ratio
+ float minOutputWidth, minOutputHeight, minOutputRatio;
+ {
+ float outputSizes[][2] = {
+ { static_cast<float>(previewWidth),
+ static_cast<float>(previewHeight) },
+ { static_cast<float>(videoWidth),
+ static_cast<float>(videoHeight) },
+ { static_cast<float>(jpegThumbSize[0]),
+ static_cast<float>(jpegThumbSize[1]) },
+ { static_cast<float>(pictureWidth),
+ static_cast<float>(pictureHeight) },
+ };
+
+ minOutputWidth = outputSizes[0][0];
+ minOutputHeight = outputSizes[0][1];
+ minOutputRatio = minOutputWidth / minOutputHeight;
+ for (unsigned int i = 0;
+ i < sizeof(outputSizes) / sizeof(outputSizes[0]);
+ ++i) {
+
+ // skip over outputs we don't want to consider for the crop region
+ if ( !((1 << i) & outputs) ) {
+ continue;
+ }
+
+ float outputWidth = outputSizes[i][0];
+ float outputHeight = outputSizes[i][1];
+ float outputRatio = outputWidth / outputHeight;
+
+ if (minOutputRatio > outputRatio) {
+ minOutputRatio = outputRatio;
+ minOutputWidth = outputWidth;
+ minOutputHeight = outputHeight;
+ }
+
+ // and then use this output ratio instead of preview output ratio
+ ALOGV("Enumerating output ratio %f = %f / %f, min is %f",
+ outputRatio, outputWidth, outputHeight, minOutputRatio);
+ }
+ }
+
+ /* Ensure that the width/height never go out of bounds
+ * by scaling across a diffent dimension if an out-of-bounds
+ * possibility exists.
+ *
+ * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by
+ * calculating the zoomWidth from zoomHeight we'll actually get a
+ * zoomheight > arrayheight
+ */
+ float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight;
+ if (minOutputRatio >= arrayRatio) {
+ // Adjust the height based on the width
+ zoomWidth = fastInfo.arrayWidth / zoomRatio;
+ zoomHeight = zoomWidth *
+ minOutputHeight / minOutputWidth;
+
+ } else {
+ // Adjust the width based on the height
+ zoomHeight = fastInfo.arrayHeight / zoomRatio;
+ zoomWidth = zoomHeight *
+ minOutputWidth / minOutputHeight;
+ }
+ // centering the zoom area within the active area
+ zoomLeft = (fastInfo.arrayWidth - zoomWidth) / 2;
+ zoomTop = (fastInfo.arrayHeight - zoomHeight) / 2;
+
+ ALOGV("Crop region calculated (x=%d,y=%d,w=%f,h=%f) for zoom=%d",
+ (int32_t)zoomLeft, (int32_t)zoomTop, zoomWidth, zoomHeight, this->zoom);
+
+
+ CropRegion crop = { zoomLeft, zoomTop, zoomWidth, zoomHeight };
+ return crop;
+}
+
+status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
+ const {
+ camera_metadata_ro_entry_t sensorSize =
+ staticInfo(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, 2, 2);
+ if (!sensorSize.count) return NO_INIT;
+
+ float arrayAspect = static_cast<float>(fastInfo.arrayWidth) /
+ fastInfo.arrayHeight;
+ float stillAspect = static_cast<float>(pictureWidth) / pictureHeight;
+ ALOGV("Array aspect: %f, still aspect: %f", arrayAspect, stillAspect);
+
+ // The crop factors from the full sensor array to the still picture crop
+ // region
+ float horizCropFactor = 1.f;
+ float vertCropFactor = 1.f;
+
+ /**
+ * Need to calculate the still image field of view based on the total pixel
+ * array field of view, and the relative aspect ratios of the pixel array
+ * and output streams.
+ *
+ * Special treatment for quirky definition of crop region and relative
+ * stream cropping.
+ */
+ if (quirks.meteringCropRegion) {
+ // Use max of preview and video as first crop
+ float previewAspect = static_cast<float>(previewWidth) / previewHeight;
+ float videoAspect = static_cast<float>(videoWidth) / videoHeight;
+ if (videoAspect > previewAspect) {
+ previewAspect = videoAspect;
+ }
+ // First crop sensor to preview aspect ratio
+ if (arrayAspect < previewAspect) {
+ vertCropFactor = arrayAspect / previewAspect;
+ } else {
+ horizCropFactor = previewAspect / arrayAspect;
+ }
+ // Second crop to still aspect ratio
+ if (stillAspect < previewAspect) {
+ horizCropFactor *= stillAspect / previewAspect;
+ } else {
+ vertCropFactor *= previewAspect / stillAspect;
+ }
+ } else {
+ /**
+ * Crop are just a function of just the still/array relative aspect
+ * ratios. Since each stream will maximize its area within the crop
+ * region, and for FOV we assume a full-sensor crop region, we only ever
+ * crop the FOV either vertically or horizontally, never both.
+ */
+ horizCropFactor = (arrayAspect > stillAspect) ?
+ (stillAspect / arrayAspect) : 1.f;
+ vertCropFactor = (arrayAspect < stillAspect) ?
+ (arrayAspect / stillAspect) : 1.f;
+ }
+ ALOGV("Horiz crop factor: %f, vert crop fact: %f",
+ horizCropFactor, vertCropFactor);
+ /**
+ * Basic field of view formula is:
+ * angle of view = 2 * arctangent ( d / 2f )
+ * where d is the physical sensor dimension of interest, and f is
+ * the focal length. This only applies to rectilinear sensors, for focusing
+ * at distances >> f, etc.
+ */
+ if (horizFov != NULL) {
+ *horizFov = 180 / M_PI * 2 *
+ atanf(horizCropFactor * sensorSize.data.f[0] /
+ (2 * fastInfo.minFocalLength));
+ }
+ if (vertFov != NULL) {
+ *vertFov = 180 / M_PI * 2 *
+ atanf(vertCropFactor * sensorSize.data.f[1] /
+ (2 * fastInfo.minFocalLength));
+ }
+ return OK;
+}
+
+int32_t Parameters::fpsFromRange(int32_t /*min*/, int32_t max) const {
+ return max;
+}
+
+}; // namespace camera2
+}; // namespace android