LegacyRequestMapper.java revision df6242e374b81e802a38cb891477f05d3e4b3cbc
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; 33 34import static com.android.internal.util.Preconditions.*; 35import static android.hardware.camera2.CaptureRequest.*; 36 37/** 38 * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices. 39 */ 40public class LegacyRequestMapper { 41 private static final String TAG = "LegacyRequestMapper"; 42 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 43 44 /** The default normalized camera area spans the entire size of the preview viewport */ 45 private static final Camera.Area CAMERA_AREA_DEFAULT = 46 new Camera.Area( 47 new Rect(/*left*/-1000, /*top*/-1000, /*right*/1000, /*bottom*/1000), 48 /*weight*/1); 49 50 /** 51 * Set the legacy parameters using the {@link LegacyRequest legacy request}. 52 * 53 * <p>The legacy request's parameters are changed as a side effect of calling this 54 * method.</p> 55 * 56 * @param legacyRequest a non-{@code null} legacy request 57 */ 58 public static void convertRequestMetadata(LegacyRequest legacyRequest) { 59 CameraCharacteristics characteristics = legacyRequest.characteristics; 60 CaptureRequest request = legacyRequest.captureRequest; 61 Size previewSize = legacyRequest.previewSize; 62 Camera.Parameters params = legacyRequest.parameters; 63 64 /* 65 * scaler.cropRegion 66 */ 67 { 68 Rect activeArraySize = characteristics.get( 69 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 70 Rect activeArraySizeOnly = new Rect( 71 /*left*/0, /*top*/0, 72 activeArraySize.width(), activeArraySize.height()); 73 74 Rect userCropRegion = request.get(SCALER_CROP_REGION); 75 76 if (userCropRegion == null) { 77 userCropRegion = activeArraySizeOnly; 78 } 79 80 if (VERBOSE) { 81 Log.v(TAG, "convertRequestToMetadata - user crop region was " + userCropRegion); 82 } 83 84 Rect reportedCropRegion = new Rect(); 85 Rect previewCropRegion = new Rect(); 86 int zoomIndex = ParameterUtils.getClosestAvailableZoomCrop(params, activeArraySizeOnly, 87 previewSize, userCropRegion, 88 /*out*/reportedCropRegion, /*out*/previewCropRegion); 89 90 if (VERBOSE) { 91 Log.v(TAG, "convertRequestToMetadata - zoom calculated to: " + 92 "zoomIndex = " + zoomIndex + 93 ", reported crop region = " + reportedCropRegion + 94 ", preview crop region = " + previewCropRegion); 95 } 96 if (params.isZoomSupported()) { 97 params.setZoom(zoomIndex); 98 } else if (VERBOSE) { 99 Log.v(TAG, "convertRequestToMetadata - zoom is not supported"); 100 } 101 } 102 103 104 /* 105 * control.ae* 106 */ 107 // control.aeAntibandingMode 108 { 109 String legacyMode; 110 Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE); 111 if (antiBandingMode != null) { 112 legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode); 113 } else { 114 legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(), 115 new String[] { 116 Parameters.ANTIBANDING_AUTO, 117 Parameters.ANTIBANDING_OFF, 118 Parameters.ANTIBANDING_50HZ, 119 Parameters.ANTIBANDING_60HZ, 120 }); 121 } 122 123 if (legacyMode != null) { 124 params.setAntibanding(legacyMode); 125 } 126 } 127 128 /* 129 * control.aeRegions 130 * -- ORDER OF EXECUTION MATTERS: 131 * -- This must be done after the crop region (zoom) was already set in the parameters 132 */ 133 { 134 MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS); 135 int maxNumMeteringAreas = params.getMaxNumMeteringAreas(); 136 if (aeRegions != null && maxNumMeteringAreas > 0) { 137 // Add all non-zero weight regions to the list 138 List<MeteringRectangle> meteringRectangleList = new ArrayList<>(); 139 for (MeteringRectangle rect : aeRegions) { 140 if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) { 141 meteringRectangleList.add(rect); 142 } 143 } 144 145 // Ignore any regions beyond our maximum supported count 146 int countMeteringAreas = 147 Math.min(maxNumMeteringAreas, meteringRectangleList.size()); 148 List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas); 149 Rect activeArray = characteristics.get( 150 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 151 152 for (int i = 0; i < countMeteringAreas; ++i) { 153 MeteringRectangle rect = meteringRectangleList.get(i); 154 155 Camera.Area area = convertMeteringRectangleToLegacy(activeArray, rect); 156 meteringAreaList.add(area); 157 } 158 159 params.setMeteringAreas(meteringAreaList); 160 161 if (maxNumMeteringAreas < meteringRectangleList.size()) { 162 Log.w(TAG, 163 "convertRequestToMetadata - Too many requested AE regions, " 164 + "ignoring all beyond the first " + maxNumMeteringAreas); 165 } 166 } else { 167 if (maxNumMeteringAreas > 0) { 168 params.setMeteringAreas(Arrays.asList(CAMERA_AREA_DEFAULT)); 169 } else { 170 params.setMeteringAreas(null); 171 } 172 } 173 } 174 175 // control.aeTargetFpsRange 176 Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE); 177 if (aeFpsRange != null) { 178 int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange); 179 params.setPreviewFpsRange(legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX], 180 legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX]); 181 } 182 183 /* 184 * control 185 */ 186 187 // control.aeMode, flash.mode 188 mapAeAndFlashMode(request, /*out*/params); 189 190 // control.awbLock 191 Boolean awbLock = request.get(CONTROL_AWB_LOCK); 192 params.setAutoWhiteBalanceLock(awbLock == null ? false : awbLock); 193 194 } 195 196 private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) { 197 int flashMode = getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF); 198 int aeMode = getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON); 199 200 List<String> supportedFlashModes = p.getSupportedFlashModes(); 201 202 /* 203 * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it 204 */ 205 206 // Ignore flash.mode controls unless aeMode == ON 207 if (aeMode == CONTROL_AE_MODE_ON) { 208 // Flash is OFF by default 209 p.setFlashMode(Parameters.FLASH_MODE_OFF); 210 211 if (flashMode == FLASH_MODE_TORCH && 212 ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) { 213 p.setFlashMode(Parameters.FLASH_MODE_TORCH); 214 } else if (flashMode == FLASH_MODE_SINGLE && 215 ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 216 p.setFlashMode(Parameters.FLASH_MODE_ON); 217 } 218 } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH && 219 ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) { 220 p.setFlashMode(Parameters.FLASH_MODE_ON); 221 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH && 222 ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) { 223 p.setFlashMode(Parameters.FLASH_MODE_AUTO); 224 } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE && 225 ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) { 226 p.setFlashMode(Parameters.FLASH_MODE_RED_EYE); 227 } else { 228 // Default to aeMode == ON, flash = OFF 229 p.setFlashMode(Parameters.FLASH_MODE_OFF); 230 } 231 } 232 233 /** 234 * Returns null if the anti-banding mode enum is not supported. 235 */ 236 private static String convertAeAntiBandingModeToLegacy(int mode) { 237 switch (mode) { 238 case CONTROL_AE_ANTIBANDING_MODE_OFF: { 239 return Parameters.ANTIBANDING_OFF; 240 } 241 case CONTROL_AE_ANTIBANDING_MODE_50HZ: { 242 return Parameters.ANTIBANDING_50HZ; 243 } 244 case CONTROL_AE_ANTIBANDING_MODE_60HZ: { 245 return Parameters.ANTIBANDING_60HZ; 246 } 247 case CONTROL_AE_ANTIBANDING_MODE_AUTO: { 248 return Parameters.ANTIBANDING_AUTO; 249 } 250 default: { 251 return null; 252 } 253 } 254 } 255 256 private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) { 257 int[] legacyFps = new int[2]; 258 legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower(); 259 legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper(); 260 return legacyFps; 261 } 262 263 private static Camera.Area convertMeteringRectangleToLegacy( 264 Rect activeArray, MeteringRectangle meteringRect) { 265 // TODO: use matrix transform magic here 266 267 Rect rect = new Rect(); 268 269 // TODO: Take the cropRegion (zooming) into account here 270 271 // TODO: crop to be within [-1000, 1000] range for both X and Y if the values end up too big 272 //return new Camera.Area(rect, meteringRect.getMeteringWeight()); 273 274 Log.w(TAG, "convertMeteringRectangleToLegacy - TODO: support metering rects"); 275 return CAMERA_AREA_DEFAULT; 276 } 277 278 private static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) { 279 checkNotNull(r, "r must not be null"); 280 checkNotNull(key, "key must not be null"); 281 checkNotNull(defaultValue, "defaultValue must not be null"); 282 283 T value = r.get(key); 284 if (value == null) { 285 return defaultValue; 286 } else { 287 return value; 288 } 289 } 290} 291