LegacyRequestMapper.java revision 8c4486c14134e81999c8e732fcee3bd7e89ffb69
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.hardware.camera2.legacy; 18 19import android.graphics.Rect; 20import android.hardware.Camera; 21import android.hardware.Camera.Parameters; 22import android.hardware.camera2.CameraCharacteristics; 23import android.hardware.camera2.CaptureRequest; 24import android.hardware.camera2.params.MeteringRectangle; 25import android.hardware.camera2.utils.ListUtils; 26import android.hardware.camera2.utils.ParamsUtils; 27import android.util.Log; 28import android.util.Range; 29import android.util.Size; 30 31import java.util.ArrayList; 32import java.util.Arrays; 33import java.util.List; 34import java.util.Objects; 35 36import static com.android.internal.util.Preconditions.*; 37import static android.hardware.camera2.CaptureRequest.*; 38 39/** 40 * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices. 41 */ 42@SuppressWarnings("deprecation") 43public class LegacyRequestMapper { 44 private static final String TAG = "LegacyRequestMapper"; 45 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 46 47 /** 48 * Set the legacy parameters using the {@link LegacyRequest legacy request}. 49 * 50 * <p>The legacy request's parameters are changed as a side effect of calling this 51 * method.</p> 52 * 53 * @param legacyRequest a non-{@code null} legacy request 54 */ 55 public static void convertRequestMetadata(LegacyRequest legacyRequest) { 56 CameraCharacteristics characteristics = legacyRequest.characteristics; 57 CaptureRequest request = legacyRequest.captureRequest; 58 Size previewSize = legacyRequest.previewSize; 59 Camera.Parameters params = legacyRequest.parameters; 60 61 Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 62 63 /* 64 * scaler.cropRegion 65 */ 66 ParameterUtils.ZoomData zoomData; 67 { 68 zoomData = ParameterUtils.convertScalerCropRegion(activeArray, 69 request.get(SCALER_CROP_REGION), 70 previewSize, 71 params); 72 73 if (params.isZoomSupported()) { 74 params.setZoom(zoomData.zoomIndex); 75 } else if (VERBOSE) { 76 Log.v(TAG, "convertRequestToMetadata - zoom is not supported"); 77 } 78 } 79 80 81 /* 82 * control.ae* 83 */ 84 // control.aeAntibandingMode 85 { 86 String legacyMode; 87 Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE); 88 if (antiBandingMode != null) { 89 legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode); 90 } else { 91 legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(), 92 new String[] { 93 Parameters.ANTIBANDING_AUTO, 94 Parameters.ANTIBANDING_OFF, 95 Parameters.ANTIBANDING_50HZ, 96 Parameters.ANTIBANDING_60HZ, 97 }); 98 } 99 100 if (legacyMode != null) { 101 params.setAntibanding(legacyMode); 102 } 103 } 104 105 /* 106 * control.aeRegions, afRegions 107 */ 108 { 109 // aeRegions 110 { 111 // Use aeRegions if available, fall back to using awbRegions if present 112 MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); 113 if (request.get(CONTROL_AWB_REGIONS) != null) { 114 Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " + 115 "supported, ignoring value"); 116 } 117 int maxNumMeteringAreas = params.getMaxNumMeteringAreas(); 118 List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy( 119 activeArray, zoomData, aeRegions, maxNumMeteringAreas, 120 /*regionName*/"AE"); 121 122 params.setMeteringAreas(meteringAreaList); 123 } 124 125 // afRegions 126 { 127 MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS); 128 int maxNumFocusAreas = params.getMaxNumFocusAreas(); 129 List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy( 130 activeArray, zoomData, afRegions, maxNumFocusAreas, 131 /*regionName*/"AF"); 132 133 params.setFocusAreas(focusAreaList); 134 } 135 } 136 137 // control.aeTargetFpsRange 138 Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE); 139 if (aeFpsRange != null) { 140 int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange); 141 142 // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range? 143 boolean supported = false; 144 for(int[] range : params.getSupportedPreviewFpsRange()) { 145 if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) { 146 supported = true; 147 break; 148 } 149 } 150 if (supported) { 151 params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 152 legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 153 } else { 154 Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); 155 } 156 } 157 158 /* 159 * control 160 */ 161 162 // control.aeExposureCompensation 163 { 164 Range<Integer> compensationRange = 165 characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE); 166 int compensation = ParamsUtils.getOrDefault(request, 167 CONTROL_AE_EXPOSURE_COMPENSATION, 168 /*defaultValue*/0); 169 170 if (!compensationRange.contains(compensation)) { 171 Log.w(TAG, 172 "convertRequestMetadata - control.aeExposureCompensation " + 173 "is out of range, ignoring value"); 174 compensation = 0; 175 } 176 177 params.setExposureCompensation(compensation); 178 } 179 180 // control.aeLock 181 { 182 Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false, 183 params.isAutoExposureLockSupported(), 184 /*allowedValue*/false); 185 186 if (aeLock != null) { 187 params.setAutoExposureLock(aeLock); 188 } 189 190 if (VERBOSE) { 191 Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock); 192 } 193 194 // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported 195 } 196 197 // control.aeMode, flash.mode 198 mapAeAndFlashMode(request, /*out*/params); 199 200 // control.afMode 201 { 202 int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE, 203 /*defaultValue*/CONTROL_AF_MODE_OFF); 204 String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode, 205 params.getSupportedFocusModes()); 206 207 if (focusMode != null) { 208 params.setFocusMode(focusMode); 209 } 210 211 if (VERBOSE) { 212 Log.v(TAG, "convertRequestToMetadata - control.afMode " 213 + afMode + " mapped to " + focusMode); 214 } 215 } 216 217 // control.awbMode 218 { 219 Integer awbMode = getIfSupported(request, CONTROL_AWB_MODE, 220 /*defaultValue*/CONTROL_AWB_MODE_AUTO, 221 params.getSupportedWhiteBalance() != null, 222 /*allowedValue*/CONTROL_AWB_MODE_AUTO); 223 224 String whiteBalanceMode = null; 225 if (awbMode != null) { // null iff AWB is not supported by camera1 api 226 whiteBalanceMode = convertAwbModeToLegacy(awbMode); 227 params.setWhiteBalance(whiteBalanceMode); 228 } 229 230 if (VERBOSE) { 231 Log.v(TAG, "convertRequestToMetadata - control.awbMode " 232 + awbMode + " mapped to " + whiteBalanceMode); 233 } 234 } 235 236 // control.awbLock 237 { 238 Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false, 239 params.isAutoWhiteBalanceLockSupported(), 240 /*allowedValue*/false); 241 242 if (awbLock != null) { 243 params.setAutoWhiteBalanceLock(awbLock); 244 } 245 246 // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported 247 } 248 249 // control.videoStabilizationMode 250 { 251 Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE, 252 /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF, 253 params.isVideoStabilizationSupported(), 254 /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF); 255 256 if (stabMode != null) { 257 params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON); 258 } 259 } 260 261 // lens.focusDistance 262 { 263 boolean infinityFocusSupported = 264 ListUtils.listContains(params.getSupportedFocusModes(), 265 Parameters.FOCUS_MODE_INFINITY); 266 Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE, 267 /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f); 268 269 if (focusDistance == null || focusDistance != 0f) { 270 Log.w(TAG, 271 "convertRequestToMetadata - Ignoring android.lens.focusDistance " 272 + infinityFocusSupported + ", only 0.0f is supported"); 273 } 274 } 275 276 // control.sceneMode, control.mode 277 { 278 // TODO: Map FACE_PRIORITY scene mode to face detection. 279 280 if (params.getSupportedSceneModes() != null) { 281 int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE, 282 /*defaultValue*/CONTROL_MODE_AUTO); 283 String modeToSet; 284 switch (controlMode) { 285 case CONTROL_MODE_USE_SCENE_MODE: { 286 int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE, 287 /*defaultValue*/CONTROL_SCENE_MODE_DISABLED); 288 String legacySceneMode = LegacyMetadataMapper. 289 convertSceneModeToLegacy(sceneMode); 290 if (legacySceneMode != null) { 291 modeToSet = legacySceneMode; 292 } else { 293 modeToSet = Parameters.SCENE_MODE_AUTO; 294 Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode); 295 } 296 break; 297 } 298 case CONTROL_MODE_AUTO: { 299 modeToSet = Parameters.SCENE_MODE_AUTO; 300 break; 301 } 302 default: { 303 Log.w(TAG, "Control mode " + controlMode + 304 " is unsupported, defaulting to AUTO"); 305 modeToSet = Parameters.SCENE_MODE_AUTO; 306 } 307 } 308 params.setSceneMode(modeToSet); 309 } 310 } 311 312 // control.effectMode 313 { 314 if (params.getSupportedColorEffects() != null) { 315 int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE, 316 /*defaultValue*/CONTROL_EFFECT_MODE_OFF); 317 String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode); 318 if (legacyEffectMode != null) { 319 params.setColorEffect(legacyEffectMode); 320 } else { 321 params.setColorEffect(Parameters.EFFECT_NONE); 322 Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode); 323 } 324 } 325 } 326 327 /* 328 * sensor 329 */ 330 331 // sensor.testPattern 332 { 333 int testPatternMode = ParamsUtils.getOrDefault(request, SENSOR_TEST_PATTERN_MODE, 334 /*defaultValue*/SENSOR_TEST_PATTERN_MODE_OFF); 335 if (testPatternMode != SENSOR_TEST_PATTERN_MODE_OFF) { 336 Log.w(TAG, "convertRequestToMetadata - ignoring sensor.testPatternMode " 337 + testPatternMode + "; only OFF is supported"); 338 } 339 } 340 } 341 342 private static List<Camera.Area> convertMeteringRegionsToLegacy( 343 Rect activeArray, ParameterUtils.ZoomData zoomData, 344 MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) { 345 if (meteringRegions == null || maxNumMeteringAreas <= 0) { 346 if (maxNumMeteringAreas > 0) { 347 return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT); 348 } else { 349 return null; 350 } 351 } 352 353 // Add all non-zero weight regions to the list 354 List<MeteringRectangle> meteringRectangleList = new ArrayList<>(); 355 for (MeteringRectangle rect : meteringRegions) { 356 if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) { 357 meteringRectangleList.add(rect); 358 } 359 } 360 361 // Ignore any regions beyond our maximum supported count 362 int countMeteringAreas = 363 Math.min(maxNumMeteringAreas, meteringRectangleList.size()); 364 List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas); 365 366 for (int i = 0; i < countMeteringAreas; ++i) { 367 MeteringRectangle rect = meteringRectangleList.get(i); 368 369 ParameterUtils.MeteringData meteringData = 370 ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData); 371 meteringAreaList.add(meteringData.meteringArea); 372 } 373 374 if (maxNumMeteringAreas < meteringRectangleList.size()) { 375 Log.w(TAG, 376 "convertMeteringRegionsToLegacy - Too many requested " + regionName + 377 " regions, ignoring all beyond the first " + maxNumMeteringAreas); 378 } 379 380 if (VERBOSE) { 381 Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = " 382 + ParameterUtils.stringFromAreaList(meteringAreaList)); 383 } 384 385 return meteringAreaList; 386 } 387 388 private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) { 389 int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF); 390 int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON); 391 392 List<String> supportedFlashModes = p.getSupportedFlashModes(); 393 394 String flashModeSetting = null; 395 396 // Flash is OFF by default, on cameras that support flash 397 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) { 398 flashModeSetting = Parameters.FLASH_MODE_OFF; 399 } 400 401 /* 402 * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it 403 */ 404 405 // Ignore flash.mode controls unless aeMode == ON 406 if (aeMode == CONTROL_AE_MODE_ON) { 407 if (flashMode == FLASH_MODE_TORCH) { 408 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) { 409 flashModeSetting = Parameters.FLASH_MODE_TORCH; 410 } else { 411 Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" + 412 "camera does not support it"); 413 } 414 } else if (flashMode == FLASH_MODE_SINGLE) { 415 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 416 flashModeSetting = Parameters.FLASH_MODE_ON; 417 } else { 418 Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" + 419 "camera does not support it"); 420 } 421 } else { 422 // Use the default FLASH_MODE_OFF 423 } 424 } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) { 425 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 426 flashModeSetting = Parameters.FLASH_MODE_ON; 427 } else { 428 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" + 429 "camera does not support it"); 430 } 431 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) { 432 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) { 433 flashModeSetting = Parameters.FLASH_MODE_AUTO; 434 } else { 435 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" + 436 "camera does not support it"); 437 } 438 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) { 439 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) { 440 flashModeSetting = Parameters.FLASH_MODE_RED_EYE; 441 } else { 442 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;" 443 + "camera does not support it"); 444 } 445 } else { 446 // Default to aeMode == ON, flash = OFF 447 } 448 449 if (flashModeSetting != null) { 450 p.setFlashMode(flashModeSetting); 451 } 452 453 if (VERBOSE) { 454 Log.v(TAG, 455 "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting 456 + ", requested (api2) " + flashMode 457 + ", supported (api1) " + ListUtils.listToString(supportedFlashModes)); 458 } 459 } 460 461 /** 462 * Returns null if the anti-banding mode enum is not supported. 463 */ 464 private static String convertAeAntiBandingModeToLegacy(int mode) { 465 switch (mode) { 466 case CONTROL_AE_ANTIBANDING_MODE_OFF: { 467 return Parameters.ANTIBANDING_OFF; 468 } 469 case CONTROL_AE_ANTIBANDING_MODE_50HZ: { 470 return Parameters.ANTIBANDING_50HZ; 471 } 472 case CONTROL_AE_ANTIBANDING_MODE_60HZ: { 473 return Parameters.ANTIBANDING_60HZ; 474 } 475 case CONTROL_AE_ANTIBANDING_MODE_AUTO: { 476 return Parameters.ANTIBANDING_AUTO; 477 } 478 default: { 479 return null; 480 } 481 } 482 } 483 484 private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) { 485 int[] legacyFps = new int[2]; 486 legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower(); 487 legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper(); 488 return legacyFps; 489 } 490 491 private static String convertAwbModeToLegacy(int mode) { 492 switch (mode) { 493 case CONTROL_AWB_MODE_AUTO: 494 return Camera.Parameters.WHITE_BALANCE_AUTO; 495 case CONTROL_AWB_MODE_INCANDESCENT: 496 return Camera.Parameters.WHITE_BALANCE_INCANDESCENT; 497 case CONTROL_AWB_MODE_FLUORESCENT: 498 return Camera.Parameters.WHITE_BALANCE_FLUORESCENT; 499 case CONTROL_AWB_MODE_WARM_FLUORESCENT: 500 return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT; 501 case CONTROL_AWB_MODE_DAYLIGHT: 502 return Camera.Parameters.WHITE_BALANCE_DAYLIGHT; 503 case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT: 504 return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT; 505 case CONTROL_AWB_MODE_TWILIGHT: 506 return Camera.Parameters.WHITE_BALANCE_TWILIGHT; 507 default: 508 Log.w(TAG, "convertAwbModeToLegacy - unrecognized control.awbMode" + mode); 509 return Camera.Parameters.WHITE_BALANCE_AUTO; 510 } 511 } 512 513 514 /** 515 * Return {@code null} if the value is not supported, otherwise return the retrieved key's 516 * value from the request (or the default value if it wasn't set). 517 * 518 * <p>If the fetched value in the request is equivalent to {@code allowedValue}, 519 * then omit the warning (e.g. turning off AF lock on a camera 520 * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p> 521 * 522 * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p. 523 */ 524 private static <T> T getIfSupported( 525 CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported, 526 T allowedValue) { 527 T val = ParamsUtils.getOrDefault(r, key, defaultValue); 528 529 if (!isSupported) { 530 if (!Objects.equals(val, allowedValue)) { 531 Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val); 532 } 533 return null; 534 } 535 536 return val; 537 } 538} 539