/* * 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 #include #include #include #include #include #include #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; camera_metadata_ro_entry_t availableProcessedSizes = staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2); if (!availableProcessedSizes.count) return NO_INIT; // TODO: Pick more intelligently previewWidth = availableProcessedSizes.data.i32[0]; previewHeight = availableProcessedSizes.data.i32[1]; 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 < availableProcessedSizes.count; i += 2) { if (i != 0) supportedPreviewSizes += ","; supportedPreviewSizes += String8::format("%dx%d", availableProcessedSizes.data.i32[i], availableProcessedSizes.data.i32[i+1]); } 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; // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats 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]); params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE, previewFps); { SortedVector 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; // TODO: Pick default thumbnail size sensibly jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0]; jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1]; 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; gpsProcessingMethod = "unknown"; // GPS fields in CameraParameters are not set by implementation wbMode = ANDROID_CONTROL_AWB_AUTO; params.set(CameraParameters::KEY_WHITE_BALANCE, CameraParameters::WHITE_BALANCE_AUTO); camera_metadata_ro_entry_t availableWhiteBalanceModes = staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES); { 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_AUTO: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_AUTO; break; case ANDROID_CONTROL_AWB_INCANDESCENT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_INCANDESCENT; break; case ANDROID_CONTROL_AWB_FLUORESCENT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_FLUORESCENT; break; case ANDROID_CONTROL_AWB_WARM_FLUORESCENT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT; break; case ANDROID_CONTROL_AWB_DAYLIGHT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_DAYLIGHT; break; case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT; break; case ANDROID_CONTROL_AWB_TWILIGHT: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_TWILIGHT; break; case ANDROID_CONTROL_AWB_SHADE: supportedWhiteBalance += CameraParameters::WHITE_BALANCE_SHADE; break; // Skipping values not mappable to v1 API case ANDROID_CONTROL_AWB_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_OFF; params.set(CameraParameters::KEY_EFFECT, CameraParameters::EFFECT_NONE); camera_metadata_ro_entry_t availableEffects = staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS); if (!availableEffects.count) return NO_INIT; { 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_OFF: supportedEffects += CameraParameters::EFFECT_NONE; break; case ANDROID_CONTROL_EFFECT_MONO: supportedEffects += CameraParameters::EFFECT_MONO; break; case ANDROID_CONTROL_EFFECT_NEGATIVE: supportedEffects += CameraParameters::EFFECT_NEGATIVE; break; case ANDROID_CONTROL_EFFECT_SOLARIZE: supportedEffects += CameraParameters::EFFECT_SOLARIZE; break; case ANDROID_CONTROL_EFFECT_SEPIA: supportedEffects += CameraParameters::EFFECT_SEPIA; break; case ANDROID_CONTROL_EFFECT_POSTERIZE: supportedEffects += CameraParameters::EFFECT_POSTERIZE; break; case ANDROID_CONTROL_EFFECT_WHITEBOARD: supportedEffects += CameraParameters::EFFECT_WHITEBOARD; break; case ANDROID_CONTROL_EFFECT_BLACKBOARD: supportedEffects += CameraParameters::EFFECT_BLACKBOARD; break; case ANDROID_CONTROL_EFFECT_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_AUTO; params.set(CameraParameters::KEY_ANTIBANDING, CameraParameters::ANTIBANDING_AUTO); camera_metadata_ro_entry_t availableAntibandingModes = staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES); if (!availableAntibandingModes.count) return NO_INIT; { 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_OFF: supportedAntibanding += CameraParameters::ANTIBANDING_OFF; break; case ANDROID_CONTROL_AE_ANTIBANDING_50HZ: supportedAntibanding += CameraParameters::ANTIBANDING_50HZ; break; case ANDROID_CONTROL_AE_ANTIBANDING_60HZ: supportedAntibanding += CameraParameters::ANTIBANDING_60HZ; break; case ANDROID_CONTROL_AE_ANTIBANDING_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); if (!availableSceneModes.count) return NO_INIT; { 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); } } camera_metadata_ro_entry_t flashAvailable = staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1); if (!flashAvailable.count) return NO_INIT; camera_metadata_ro_entry_t availableAeModes = staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES); if (!availableAeModes.count) return NO_INIT; if (flashAvailable.data.u8[0]) { 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_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_MINIMUM_FOCUS_DISTANCE, 1, 1); if (!minFocusDistance.count) return NO_INIT; camera_metadata_ro_entry_t availableAfModes = staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES); if (!availableAfModes.count) return NO_INIT; if (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_AUTO: supportedFocusModes += CameraParameters::FOCUS_MODE_AUTO; break; case ANDROID_CONTROL_AF_MACRO: supportedFocusModes += CameraParameters::FOCUS_MODE_MACRO; break; case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO: supportedFocusModes += CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO; break; case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE: supportedFocusModes += CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE; break; case ANDROID_CONTROL_AF_EDOF: supportedFocusModes += CameraParameters::FOCUS_MODE_EDOF; break; // Not supported in old API case ANDROID_CONTROL_AF_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); } 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_AVAILABLE_FOCAL_LENGTHS); if (!availableFocalLengths.count) return NO_INIT; float minFocalLength = availableFocalLengths.data.f[0]; params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength); camera_metadata_ro_entry_t sensorSize = staticInfo(ANDROID_SENSOR_PHYSICAL_SIZE, 2, 2); if (!sensorSize.count) return NO_INIT; // The fields of view here assume infinity focus, maximum wide angle float horizFov = 180 / M_PI * 2 * atanf(sensorSize.data.f[0] / (2 * minFocalLength)); float vertFov = 180 / M_PI * 2 * atanf(sensorSize.data.f[1] / (2 * minFocalLength)); 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_EXP_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_EXP_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_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(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); params.set(CameraParameters::KEY_RECORDING_HINT, CameraParameters::FALSE); params.set(CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED, CameraParameters::TRUE); params.set(CameraParameters::KEY_VIDEO_STABILIZATION, CameraParameters::FALSE); camera_metadata_ro_entry_t availableVideoStabilizationModes = staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES); if (!availableVideoStabilizationModes.count) return NO_INIT; 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; currentAfTriggerId = -1; precaptureTriggerCounter = 1; previewCallbackFlags = 0; 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_ACTIVE_ARRAY_SIZE, 2, 2); if (!activeArraySize.count) return NO_INIT; int32_t arrayWidth = activeArraySize.data.i32[0]; int32_t arrayHeight = activeArraySize.data.i32[1]; camera_metadata_ro_entry_t availableFaceDetectModes = staticInfo(ANDROID_STATS_AVAILABLE_FACE_DETECT_MODES); if (!availableFaceDetectModes.count) return NO_INIT; uint8_t bestFaceDetectMode = ANDROID_STATS_FACE_DETECTION_OFF; for (size_t i = 0 ; i < availableFaceDetectModes.count; i++) { switch (availableFaceDetectModes.data.u8[i]) { case ANDROID_STATS_FACE_DETECTION_OFF: break; case ANDROID_STATS_FACE_DETECTION_SIMPLE: if (bestFaceDetectMode != ANDROID_STATS_FACE_DETECTION_FULL) { bestFaceDetectMode = ANDROID_STATS_FACE_DETECTION_SIMPLE; } break; case ANDROID_STATS_FACE_DETECTION_FULL: bestFaceDetectMode = ANDROID_STATS_FACE_DETECTION_FULL; break; default: ALOGE("%s: Camera %d: Unknown face detect mode %d:", __FUNCTION__, cameraId, availableFaceDetectModes.data.u8[i]); return NO_INIT; } } camera_metadata_ro_entry_t maxFacesDetected = staticInfo(ANDROID_STATS_MAX_FACE_COUNT, 1, 1); if (!maxFacesDetected.count) return NO_INIT; int32_t maxFaces = maxFacesDetected.data.i32[0]; camera_metadata_ro_entry_t availableSceneModes = staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES); camera_metadata_ro_entry_t sceneModeOverrides = staticInfo(ANDROID_CONTROL_SCENE_MODE_OVERRIDES); camera_metadata_ro_entry_t minFocusDistance = staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE); bool fixedLens = (minFocusDistance.data.f[0] == 0); 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_ON: modes.flashMode = FLASH_MODE_OFF; break; case ANDROID_CONTROL_AE_ON_AUTO_FLASH: modes.flashMode = FLASH_MODE_AUTO; break; case ANDROID_CONTROL_AE_ON_ALWAYS_FLASH: modes.flashMode = FLASH_MODE_ON; break; case ANDROID_CONTROL_AE_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_OFF: modes.focusMode = fixedLens ? FOCUS_MODE_FIXED : FOCUS_MODE_INFINITY; break; case ANDROID_CONTROL_AF_AUTO: case ANDROID_CONTROL_AF_MACRO: case ANDROID_CONTROL_AF_CONTINUOUS_VIDEO: case ANDROID_CONTROL_AF_CONTINUOUS_PICTURE: case ANDROID_CONTROL_AF_EDOF: modes.focusMode = static_cast(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.bestFaceDetectMode = bestFaceDetectMode; fastInfo.maxFaces = maxFaces; 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) const { status_t res; camera_metadata_ro_entry_t entry = info->find(tag); if (CC_UNLIKELY( entry.count == 0 )) { const char* tagSection = get_camera_metadata_section_name(tag); if (tagSection == NULL) tagSection = ""; const char* tagName = get_camera_metadata_tag_name(tag); if (tagName == NULL) tagName = ""; 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 = ""; const char* tagName = get_camera_metadata_tag_name(tag); if (tagName == NULL) tagName = ""; 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; } camera_metadata_ro_entry_t availablePreviewSizes = staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES); for (i = 0; i < availablePreviewSizes.count; i += 2 ) { if ((availablePreviewSizes.data.i32[i] == validatedParams.previewWidth) && (availablePreviewSizes.data.i32[i+1] == validatedParams.previewHeight)) break; } if (i == availablePreviewSizes.count) { 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]); 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); 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. if (!fpsRangeChanged) { validatedParams.previewFps = newParams.getPreviewFrameRate(); if (validatedParams.previewFps != previewFps || 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 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)); } // 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 validatedParams.jpegThumbQuality = newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY); if (validatedParams.jpegThumbQuality < 0 || validatedParams.jpegThumbQuality > 100) { ALOGE("%s: Requested JPEG thumbnail quality %d is not supported", __FUNCTION__, validatedParams.jpegThumbQuality); return BAD_VALUE; } // JPEG_QUALITY validatedParams.jpegQuality = newParams.getInt(CameraParameters::KEY_JPEG_QUALITY); if (validatedParams.jpegQuality < 0 || validatedParams.jpegQuality > 100) { ALOGE("%s: Requested JPEG quality %d is not supported", __FUNCTION__, validatedParams.jpegQuality); return BAD_VALUE; } // 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_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_OFF; } if (validatedParams.wbMode == ANDROID_CONTROL_AWB_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); 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_MINIMUM_FOCUS_DISTANCE); if (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; } } } // Always reset shadow focus mode to avoid reverting settings 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_EXP_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; } camera_metadata_ro_entry_t availableVideoSizes = staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES); for (i = 0; i < availableVideoSizes.count; i += 2 ) { if ((availableVideoSizes.data.i32[i] == validatedParams.videoWidth) && (availableVideoSizes.data.i32[i+1] == validatedParams.videoHeight)) break; } if (i == availableVideoSizes.count) { 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); if (validatedParams.videoStabilization && availableVideoStabilizationModes.count == 1) { ALOGE("%s: Video stabilization not supported", __FUNCTION__); } /** Update internal parameters */ *this = validatedParams; // 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; uint8_t metadataMode = ANDROID_REQUEST_METADATA_FULL; res = request->update(ANDROID_REQUEST_METADATA_MODE, &metadataMode, 1); if (res != OK) return res; 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_AUTO; if (enableFaceDetect || sceneModeActive) { reqControlMode = ANDROID_CONTROL_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_OFF; uint8_t reqAeMode = ANDROID_CONTROL_AE_OFF; switch (flashMode) { case Parameters::FLASH_MODE_OFF: reqAeMode = ANDROID_CONTROL_AE_ON; break; case Parameters::FLASH_MODE_AUTO: reqAeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH; break; case Parameters::FLASH_MODE_ON: reqAeMode = ANDROID_CONTROL_AE_ON_ALWAYS_FLASH; break; case Parameters::FLASH_MODE_TORCH: reqAeMode = ANDROID_CONTROL_AE_ON; reqFlashMode = ANDROID_FLASH_TORCH; break; case Parameters::FLASH_MODE_RED_EYE: reqAeMode = ANDROID_CONTROL_AE_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_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_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_EXP_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; res = request->update(ANDROID_CONTROL_AWB_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[3] = { crop.left, crop.top, crop.width }; res = request->update(ANDROID_SCALER_CROP_REGION, reqCropRegion, 3); if (res != OK) return res; uint8_t reqVstabMode = videoStabilization ? ANDROID_CONTROL_VIDEO_STABILIZATION_ON : ANDROID_CONTROL_VIDEO_STABILIZATION_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_STATS_FACE_DETECTION_OFF; res = request->update(ANDROID_STATS_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_AUTO : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_AUTO) ? ANDROID_CONTROL_AWB_AUTO : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_INCANDESCENT) ? ANDROID_CONTROL_AWB_INCANDESCENT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_FLUORESCENT) ? ANDROID_CONTROL_AWB_FLUORESCENT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT) ? ANDROID_CONTROL_AWB_WARM_FLUORESCENT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_DAYLIGHT) ? ANDROID_CONTROL_AWB_DAYLIGHT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT) ? ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_TWILIGHT) ? ANDROID_CONTROL_AWB_TWILIGHT : !strcmp(wbMode, CameraParameters::WHITE_BALANCE_SHADE) ? ANDROID_CONTROL_AWB_SHADE : -1; } const char* Parameters::wbModeEnumToString(uint8_t wbMode) { switch (wbMode) { case ANDROID_CONTROL_AWB_AUTO: return CameraParameters::WHITE_BALANCE_AUTO; case ANDROID_CONTROL_AWB_INCANDESCENT: return CameraParameters::WHITE_BALANCE_INCANDESCENT; case ANDROID_CONTROL_AWB_FLUORESCENT: return CameraParameters::WHITE_BALANCE_FLUORESCENT; case ANDROID_CONTROL_AWB_WARM_FLUORESCENT: return CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT; case ANDROID_CONTROL_AWB_DAYLIGHT: return CameraParameters::WHITE_BALANCE_DAYLIGHT; case ANDROID_CONTROL_AWB_CLOUDY_DAYLIGHT: return CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT; case ANDROID_CONTROL_AWB_TWILIGHT: return CameraParameters::WHITE_BALANCE_TWILIGHT; case ANDROID_CONTROL_AWB_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_OFF : !strcmp(effectMode, CameraParameters::EFFECT_NONE) ? ANDROID_CONTROL_EFFECT_OFF : !strcmp(effectMode, CameraParameters::EFFECT_MONO) ? ANDROID_CONTROL_EFFECT_MONO : !strcmp(effectMode, CameraParameters::EFFECT_NEGATIVE) ? ANDROID_CONTROL_EFFECT_NEGATIVE : !strcmp(effectMode, CameraParameters::EFFECT_SOLARIZE) ? ANDROID_CONTROL_EFFECT_SOLARIZE : !strcmp(effectMode, CameraParameters::EFFECT_SEPIA) ? ANDROID_CONTROL_EFFECT_SEPIA : !strcmp(effectMode, CameraParameters::EFFECT_POSTERIZE) ? ANDROID_CONTROL_EFFECT_POSTERIZE : !strcmp(effectMode, CameraParameters::EFFECT_WHITEBOARD) ? ANDROID_CONTROL_EFFECT_WHITEBOARD : !strcmp(effectMode, CameraParameters::EFFECT_BLACKBOARD) ? ANDROID_CONTROL_EFFECT_BLACKBOARD : !strcmp(effectMode, CameraParameters::EFFECT_AQUA) ? ANDROID_CONTROL_EFFECT_AQUA : -1; } int Parameters::abModeStringToEnum(const char *abMode) { return !abMode ? ANDROID_CONTROL_AE_ANTIBANDING_AUTO : !strcmp(abMode, CameraParameters::ANTIBANDING_AUTO) ? ANDROID_CONTROL_AE_ANTIBANDING_AUTO : !strcmp(abMode, CameraParameters::ANTIBANDING_OFF) ? ANDROID_CONTROL_AE_ANTIBANDING_OFF : !strcmp(abMode, CameraParameters::ANTIBANDING_50HZ) ? ANDROID_CONTROL_AE_ANTIBANDING_50HZ : !strcmp(abMode, CameraParameters::ANTIBANDING_60HZ) ? ANDROID_CONTROL_AE_ANTIBANDING_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"; } } status_t Parameters::parseAreas(const char *areasCStr, Vector *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 &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::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 = %d)", 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 = %d)", 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)); } 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_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] = { { previewWidth, previewHeight }, { videoWidth, videoHeight }, { jpegThumbSize[0], jpegThumbSize[1] }, { pictureWidth, 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; } int32_t Parameters::fpsFromRange(int32_t min, int32_t max) const { return max; } }; // namespace camera2 }; // namespace android