LegacyRequestMapper.java revision 396532ffb80f70c336b3564e5bac4c09d3be07ff
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.util.Log; 27import android.util.Range; 28import android.util.Size; 29 30import java.util.ArrayList; 31import java.util.Arrays; 32import java.util.List; 33import java.util.Objects; 34 35import static com.android.internal.util.Preconditions.*; 36import static android.hardware.camera2.CaptureRequest.*; 37 38/** 39 * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices. 40 */ 41public class LegacyRequestMapper { 42 private static final String TAG = "LegacyRequestMapper"; 43 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 44 45 /** 46 * Set the legacy parameters using the {@link LegacyRequest legacy request}. 47 * 48 * <p>The legacy request's parameters are changed as a side effect of calling this 49 * method.</p> 50 * 51 * @param legacyRequest a non-{@code null} legacy request 52 */ 53 public static void convertRequestMetadata(LegacyRequest legacyRequest) { 54 CameraCharacteristics characteristics = legacyRequest.characteristics; 55 CaptureRequest request = legacyRequest.captureRequest; 56 Size previewSize = legacyRequest.previewSize; 57 Camera.Parameters params = legacyRequest.parameters; 58 59 Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 60 61 /* 62 * scaler.cropRegion 63 */ 64 ParameterUtils.ZoomData zoomData; 65 { 66 zoomData = ParameterUtils.convertScalerCropRegion(activeArray, 67 request.get(SCALER_CROP_REGION), 68 previewSize, 69 params); 70 71 if (params.isZoomSupported()) { 72 params.setZoom(zoomData.zoomIndex); 73 } else if (VERBOSE) { 74 Log.v(TAG, "convertRequestToMetadata - zoom is not supported"); 75 } 76 } 77 78 79 /* 80 * control.ae* 81 */ 82 // control.aeAntibandingMode 83 { 84 String legacyMode; 85 Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE); 86 if (antiBandingMode != null) { 87 legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode); 88 } else { 89 legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(), 90 new String[] { 91 Parameters.ANTIBANDING_AUTO, 92 Parameters.ANTIBANDING_OFF, 93 Parameters.ANTIBANDING_50HZ, 94 Parameters.ANTIBANDING_60HZ, 95 }); 96 } 97 98 if (legacyMode != null) { 99 params.setAntibanding(legacyMode); 100 } 101 } 102 103 /* 104 * control.aeRegions, afRegions 105 */ 106 { 107 // aeRegions 108 { 109 MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); 110 int maxNumMeteringAreas = params.getMaxNumMeteringAreas(); 111 List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy( 112 activeArray, zoomData, aeRegions, maxNumMeteringAreas, 113 /*regionName*/"AE"); 114 115 params.setMeteringAreas(meteringAreaList); 116 } 117 118 // afRegions 119 { 120 MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS); 121 int maxNumFocusAreas = params.getMaxNumFocusAreas(); 122 List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy( 123 activeArray, zoomData, afRegions, maxNumFocusAreas, 124 /*regionName*/"AF"); 125 126 params.setFocusAreas(focusAreaList); 127 } 128 } 129 130 // control.aeTargetFpsRange 131 Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE); 132 if (aeFpsRange != null) { 133 int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange); 134 135 // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range? 136 boolean supported = false; 137 for(int[] range : params.getSupportedPreviewFpsRange()) { 138 if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) { 139 supported = true; 140 break; 141 } 142 } 143 if (supported) { 144 params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 145 legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 146 params.setRecordingHint(false); 147 } else { 148 Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]"); 149 params.setRecordingHint(true); 150 } 151 } 152 153 /* 154 * control 155 */ 156 157 // control.aeExposureCompensation 158 { 159 Range<Integer> compensationRange = 160 characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE); 161 int compensation = getOrDefault(request, 162 CONTROL_AE_EXPOSURE_COMPENSATION, 163 /*defaultValue*/0); 164 165 if (!compensationRange.inRange(compensation)) { 166 Log.w(TAG, 167 "convertRequestMetadata - control.aeExposureCompensation " + 168 "is out of range, ignoring value"); 169 compensation = 0; 170 } 171 172 params.setExposureCompensation(compensation); 173 } 174 175 // control.aeLock 176 { 177 Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false, 178 params.isAutoExposureLockSupported(), 179 /*allowedValue*/false); 180 181 if (aeLock != null) { 182 params.setAutoExposureLock(aeLock); 183 } 184 185 if (VERBOSE) { 186 Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock); 187 } 188 189 // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported 190 } 191 192 // control.aeMode, flash.mode 193 mapAeAndFlashMode(request, /*out*/params); 194 195 // control.awbLock 196 { 197 Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false, 198 params.isAutoWhiteBalanceLockSupported(), 199 /*allowedValue*/false); 200 201 if (awbLock != null) { 202 params.setAutoWhiteBalanceLock(awbLock); 203 } 204 205 // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported 206 } 207 } 208 209 private static List<Camera.Area> convertMeteringRegionsToLegacy( 210 Rect activeArray, ParameterUtils.ZoomData zoomData, 211 MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) { 212 if (meteringRegions == null || maxNumMeteringAreas <= 0) { 213 if (maxNumMeteringAreas > 0) { 214 return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT); 215 } else { 216 return null; 217 } 218 } 219 220 // Add all non-zero weight regions to the list 221 List<MeteringRectangle> meteringRectangleList = new ArrayList<>(); 222 for (MeteringRectangle rect : meteringRegions) { 223 if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) { 224 meteringRectangleList.add(rect); 225 } 226 } 227 228 // Ignore any regions beyond our maximum supported count 229 int countMeteringAreas = 230 Math.min(maxNumMeteringAreas, meteringRectangleList.size()); 231 List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas); 232 233 for (int i = 0; i < countMeteringAreas; ++i) { 234 MeteringRectangle rect = meteringRectangleList.get(i); 235 236 ParameterUtils.MeteringData meteringData = 237 ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData); 238 meteringAreaList.add(meteringData.meteringArea); 239 } 240 241 if (maxNumMeteringAreas < meteringRectangleList.size()) { 242 Log.w(TAG, 243 "convertMeteringRegionsToLegacy - Too many requested " + regionName + 244 " regions, ignoring all beyond the first " + maxNumMeteringAreas); 245 } 246 247 if (VERBOSE) { 248 Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = " 249 + ParameterUtils.stringFromAreaList(meteringAreaList)); 250 } 251 252 return meteringAreaList; 253 } 254 255 private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) { 256 int flashMode = getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF); 257 int aeMode = getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON); 258 259 List<String> supportedFlashModes = p.getSupportedFlashModes(); 260 261 String flashModeSetting = null; 262 263 // Flash is OFF by default, on cameras that support flash 264 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) { 265 flashModeSetting = Parameters.FLASH_MODE_OFF; 266 } 267 268 /* 269 * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it 270 */ 271 272 // Ignore flash.mode controls unless aeMode == ON 273 if (aeMode == CONTROL_AE_MODE_ON) { 274 if (flashMode == FLASH_MODE_TORCH) { 275 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) { 276 flashModeSetting = Parameters.FLASH_MODE_TORCH; 277 } else { 278 Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" + 279 "camera does not support it"); 280 } 281 } else if (flashMode == FLASH_MODE_SINGLE) { 282 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 283 flashModeSetting = Parameters.FLASH_MODE_ON; 284 } else { 285 Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" + 286 "camera does not support it"); 287 } 288 } else { 289 // Use the default FLASH_MODE_OFF 290 } 291 } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) { 292 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 293 flashModeSetting = Parameters.FLASH_MODE_ON; 294 } else { 295 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" + 296 "camera does not support it"); 297 } 298 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) { 299 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) { 300 flashModeSetting = Parameters.FLASH_MODE_AUTO; 301 } else { 302 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" + 303 "camera does not support it"); 304 } 305 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) { 306 if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) { 307 flashModeSetting = Parameters.FLASH_MODE_RED_EYE; 308 } else { 309 Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;" 310 + "camera does not support it"); 311 } 312 } else { 313 // Default to aeMode == ON, flash = OFF 314 } 315 316 if (flashModeSetting != null) { 317 p.setFlashMode(flashModeSetting); 318 } 319 320 if (VERBOSE) { 321 Log.v(TAG, 322 "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting 323 + ", requested (api2) " + flashMode 324 + ", supported (api1) " + ListUtils.listToString(supportedFlashModes)); 325 } 326 } 327 328 /** 329 * Returns null if the anti-banding mode enum is not supported. 330 */ 331 private static String convertAeAntiBandingModeToLegacy(int mode) { 332 switch (mode) { 333 case CONTROL_AE_ANTIBANDING_MODE_OFF: { 334 return Parameters.ANTIBANDING_OFF; 335 } 336 case CONTROL_AE_ANTIBANDING_MODE_50HZ: { 337 return Parameters.ANTIBANDING_50HZ; 338 } 339 case CONTROL_AE_ANTIBANDING_MODE_60HZ: { 340 return Parameters.ANTIBANDING_60HZ; 341 } 342 case CONTROL_AE_ANTIBANDING_MODE_AUTO: { 343 return Parameters.ANTIBANDING_AUTO; 344 } 345 default: { 346 return null; 347 } 348 } 349 } 350 351 private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) { 352 int[] legacyFps = new int[2]; 353 legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower(); 354 legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper(); 355 return legacyFps; 356 } 357 358 /** Return the value set by the key, or the {@code defaultValue} if no value was set. */ 359 private static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) { 360 checkNotNull(r, "r must not be null"); 361 checkNotNull(key, "key must not be null"); 362 checkNotNull(defaultValue, "defaultValue must not be null"); 363 364 T value = r.get(key); 365 if (value == null) { 366 return defaultValue; 367 } else { 368 return value; 369 } 370 } 371 372 /** 373 * Return {@code null} if the value is not supported, otherwise return the retrieved key's 374 * value from the request (or the default value if it wasn't set). 375 * 376 * <p>If the fetched value in the request is equivalent to {@code allowedValue}, 377 * then omit the warning (e.g. turning off AF lock on a camera 378 * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p> 379 * 380 * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p. 381 */ 382 private static <T> T getIfSupported( 383 CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported, 384 T allowedValue) { 385 T val = getOrDefault(r, key, defaultValue); 386 387 if (!isSupported) { 388 if (!Objects.equals(val, allowedValue)) { 389 Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val); 390 } 391 return null; 392 } 393 394 return val; 395 } 396} 397