LegacyResultMapper.java revision 733341bf0db89c93ee1341ddfca9b0c49731c836
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.CaptureResult; 25import android.hardware.camera2.impl.CameraMetadataNative; 26import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle; 27import android.hardware.camera2.legacy.ParameterUtils.ZoomData; 28import android.hardware.camera2.params.MeteringRectangle; 29import android.hardware.camera2.utils.ListUtils; 30import android.hardware.camera2.utils.ParamsUtils; 31import android.util.Log; 32import android.util.Size; 33 34import java.util.ArrayList; 35import java.util.List; 36 37import static com.android.internal.util.Preconditions.*; 38import static android.hardware.camera2.CaptureResult.*; 39 40/** 41 * Provide legacy-specific implementations of camera2 CaptureResult for legacy devices. 42 */ 43@SuppressWarnings("deprecation") 44public class LegacyResultMapper { 45 private static final String TAG = "LegacyResultMapper"; 46 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 47 48 private LegacyRequest mCachedRequest = null; 49 private CameraMetadataNative mCachedResult = null; 50 51 /** 52 * Generate capture result metadata from the legacy camera request. 53 * 54 * <p>This method caches and reuses the result from the previous call to this method if 55 * the {@code parameters} of the subsequent {@link LegacyRequest} passed to this method 56 * have not changed.</p> 57 * 58 * @param legacyRequest a non-{@code null} legacy request containing the latest parameters 59 * @param timestamp the timestamp to use for this result in nanoseconds. 60 * 61 * @return {@link CameraMetadataNative} object containing result metadata. 62 */ 63 public CameraMetadataNative cachedConvertResultMetadata( 64 LegacyRequest legacyRequest, long timestamp) { 65 CameraMetadataNative result; 66 boolean cached; 67 68 /* 69 * Attempt to look up the result from the cache if the parameters haven't changed 70 */ 71 if (mCachedRequest != null && legacyRequest.parameters.same(mCachedRequest.parameters)) { 72 result = new CameraMetadataNative(mCachedResult); 73 cached = true; 74 } else { 75 result = convertResultMetadata(legacyRequest, timestamp); 76 cached = false; 77 78 // Always cache a *copy* of the metadata result, 79 // since api2's client side takes ownership of it after it receives a result 80 mCachedRequest = legacyRequest; 81 mCachedResult = new CameraMetadataNative(result); 82 } 83 84 /* 85 * Unconditionally set fields that change in every single frame 86 */ 87 { 88 // sensor.timestamp 89 result.set(SENSOR_TIMESTAMP, timestamp); 90 } 91 92 if (VERBOSE) { 93 Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached + 94 " timestamp = " + timestamp); 95 96 Log.v(TAG, "----- beginning of result dump ------"); 97 result.dumpToLog(); 98 Log.v(TAG, "----- end of result dump ------"); 99 } 100 101 return result; 102 } 103 104 /** 105 * Generate capture result metadata from the legacy camera request. 106 * 107 * @param legacyRequest a non-{@code null} legacy request containing the latest parameters 108 * @param timestamp the timestamp to use for this result in nanoseconds. 109 * 110 * @return a {@link CameraMetadataNative} object containing result metadata. 111 */ 112 private static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest, 113 long timestamp) { 114 CameraCharacteristics characteristics = legacyRequest.characteristics; 115 CaptureRequest request = legacyRequest.captureRequest; 116 Size previewSize = legacyRequest.previewSize; 117 Camera.Parameters params = legacyRequest.parameters; 118 119 CameraMetadataNative result = new CameraMetadataNative(); 120 121 Rect activeArraySize = characteristics.get( 122 CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 123 ZoomData zoomData = ParameterUtils.convertScalerCropRegion(activeArraySize, 124 request.get(CaptureRequest.SCALER_CROP_REGION), previewSize, params); 125 126 /* 127 * control 128 */ 129 130 /* 131 * control.ae* 132 */ 133 mapAe(result, characteristics, request, activeArraySize, zoomData, /*out*/params); 134 135 /* 136 * control.af* 137 */ 138 mapAf(result, activeArraySize, zoomData, /*out*/params); 139 140 /* 141 * control.awb* 142 */ 143 mapAwb(result, /*out*/params); 144 145 146 /* 147 * control.mode 148 */ 149 { 150 int controlMode = ParamsUtils.getOrDefault(request, CaptureRequest.CONTROL_MODE, 151 CONTROL_MODE_AUTO); 152 if (controlMode == CaptureResult.CONTROL_MODE_USE_SCENE_MODE) { 153 result.set(CONTROL_MODE, CONTROL_MODE_USE_SCENE_MODE); 154 } else { 155 result.set(CONTROL_MODE, CONTROL_MODE_AUTO); 156 } 157 } 158 159 /* 160 * control.sceneMode 161 */ 162 { 163 String legacySceneMode = params.getSceneMode(); 164 int mode = LegacyMetadataMapper.convertSceneModeFromLegacy(legacySceneMode); 165 if (mode != LegacyMetadataMapper.UNKNOWN_MODE) { 166 result.set(CaptureResult.CONTROL_SCENE_MODE, mode); 167 } else { 168 Log.w(TAG, "Unknown scene mode " + legacySceneMode + 169 " returned by camera HAL, setting to disabled."); 170 result.set(CaptureResult.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED); 171 } 172 } 173 174 175 /* 176 * control.effectMode 177 */ 178 { 179 String legacyEffectMode = params.getColorEffect(); 180 int mode = LegacyMetadataMapper.convertEffectModeFromLegacy(legacyEffectMode); 181 if (mode != LegacyMetadataMapper.UNKNOWN_MODE) { 182 result.set(CaptureResult.CONTROL_EFFECT_MODE, mode); 183 } else { 184 Log.w(TAG, "Unknown effect mode " + legacyEffectMode + 185 " returned by camera HAL, setting to off."); 186 result.set(CaptureResult.CONTROL_EFFECT_MODE, CONTROL_EFFECT_MODE_OFF); 187 } 188 } 189 190 /* 191 * flash 192 */ 193 { 194 // flash.mode, flash.state mapped in mapAeAndFlashMode 195 } 196 197 /* 198 * lens 199 */ 200 // lens.focusDistance 201 { 202 if (Parameters.FOCUS_MODE_INFINITY.equals(params.getFocusMode())) { 203 result.set(CaptureResult.LENS_FOCUS_DISTANCE, 0.0f); 204 } 205 } 206 207 // lens.focalLength 208 result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength()); 209 210 /* 211 * request 212 */ 213 // request.pipelineDepth 214 result.set(REQUEST_PIPELINE_DEPTH, 215 characteristics.get(CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH)); 216 217 /* 218 * scaler 219 */ 220 mapScaler(result, zoomData, /*out*/params); 221 222 /* 223 * sensor 224 */ 225 // sensor.timestamp varies every frame; mapping is done in #cachedConvertResultMetadata 226 { 227 // Unconditionally no test patterns 228 result.set(SENSOR_TEST_PATTERN_MODE, SENSOR_TEST_PATTERN_MODE_OFF); 229 } 230 231 // TODO: Remaining result metadata tags conversions. 232 return result; 233 } 234 235 private static void mapAe(CameraMetadataNative m, 236 CameraCharacteristics characteristics, 237 CaptureRequest request, Rect activeArray, ZoomData zoomData, /*out*/Parameters p) { 238 // control.aeAntiBandingMode 239 { 240 int antiBandingMode = LegacyMetadataMapper.convertAntiBandingModeOrDefault( 241 p.getAntibanding()); 242 m.set(CONTROL_AE_ANTIBANDING_MODE, antiBandingMode); 243 } 244 245 // control.aeExposureCompensation 246 { 247 m.set(CONTROL_AE_EXPOSURE_COMPENSATION, p.getExposureCompensation()); 248 } 249 250 // control.aeLock 251 { 252 boolean lock = p.isAutoExposureLockSupported() ? p.getAutoExposureLock() : false; 253 m.set(CONTROL_AE_LOCK, lock); 254 if (VERBOSE) { 255 Log.v(TAG, 256 "mapAe - android.control.aeLock = " + lock + 257 ", supported = " + p.isAutoExposureLockSupported()); 258 } 259 260 Boolean requestLock = request.get(CaptureRequest.CONTROL_AE_LOCK); 261 if (requestLock != null && requestLock != lock) { 262 Log.w(TAG, 263 "mapAe - android.control.aeLock was requested to " + requestLock + 264 " but resulted in " + lock); 265 } 266 } 267 268 // control.aeMode, flash.mode, flash.state 269 mapAeAndFlashMode(m, characteristics, p); 270 271 // control.aeState 272 if (LegacyMetadataMapper.LIE_ABOUT_AE_STATE) { 273 // Lie to pass CTS temporarily. 274 // TODO: Implement precapture trigger, after which we can report CONVERGED ourselves 275 m.set(CONTROL_AE_STATE, CONTROL_AE_STATE_CONVERGED); 276 } 277 278 // control.aeRegions 279 { 280 if (VERBOSE) { 281 String meteringAreas = p.get("metering-areas"); 282 Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas); 283 } 284 285 MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray, 286 zoomData, p.getMeteringAreas(), "AE"); 287 288 m.set(CONTROL_AE_REGIONS, meteringRectArray); 289 } 290 291 } 292 293 private static void mapAf(CameraMetadataNative m, 294 Rect activeArray, ZoomData zoomData, Camera.Parameters p) { 295 // control.afMode 296 m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode())); 297 298 // control.afRegions 299 { 300 if (VERBOSE) { 301 String focusAreas = p.get("focus-areas"); 302 Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas); 303 } 304 305 MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray, 306 zoomData, p.getFocusAreas(), "AF"); 307 308 m.set(CONTROL_AF_REGIONS, meteringRectArray); 309 } 310 } 311 312 private static void mapAwb(CameraMetadataNative m, Camera.Parameters p) { 313 // control.awbLock 314 { 315 boolean lock = p.isAutoWhiteBalanceLockSupported() ? 316 p.getAutoWhiteBalanceLock() : false; 317 m.set(CONTROL_AWB_LOCK, lock); 318 } 319 320 // control.awbMode 321 { 322 int awbMode = convertLegacyAwbMode(p.getWhiteBalance()); 323 m.set(CONTROL_AWB_MODE, awbMode); 324 } 325 } 326 327 private static MeteringRectangle[] getMeteringRectangles(Rect activeArray, ZoomData zoomData, 328 List<Camera.Area> meteringAreaList, String regionName) { 329 List<MeteringRectangle> meteringRectList = new ArrayList<>(); 330 if (meteringAreaList != null) { 331 for (Camera.Area area : meteringAreaList) { 332 WeightedRectangle rect = 333 ParameterUtils.convertCameraAreaToActiveArrayRectangle( 334 activeArray, zoomData, area); 335 336 meteringRectList.add(rect.toMetering()); 337 } 338 } 339 340 if (VERBOSE) { 341 Log.v(TAG, 342 "Metering rectangles for " + regionName + ": " 343 + ListUtils.listToString(meteringRectList)); 344 } 345 346 return meteringRectList.toArray(new MeteringRectangle[0]); 347 } 348 349 /** Map results for control.aeMode, flash.mode, flash.state */ 350 private static void mapAeAndFlashMode(CameraMetadataNative m, 351 CameraCharacteristics characteristics, Parameters p) { 352 // Default: AE mode on but flash never fires 353 int flashMode = FLASH_MODE_OFF; 354 // If there is no flash on this camera, the state is always unavailable 355 // , otherwise it's only known for TORCH/SINGLE modes 356 Integer flashState = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE) 357 ? null : FLASH_STATE_UNAVAILABLE; 358 int aeMode = CONTROL_AE_MODE_ON; 359 360 String flashModeSetting = p.getFlashMode(); 361 362 if (flashModeSetting != null) { 363 switch (flashModeSetting) { 364 case Parameters.FLASH_MODE_OFF: 365 break; // ok, using default 366 case Parameters.FLASH_MODE_AUTO: 367 aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH; 368 break; 369 case Parameters.FLASH_MODE_ON: 370 // flashMode = SINGLE + aeMode = ON is indistinguishable from ON_ALWAYS_FLASH 371 flashMode = FLASH_MODE_SINGLE; 372 aeMode = CONTROL_AE_MODE_ON_ALWAYS_FLASH; 373 flashState = FLASH_STATE_FIRED; 374 break; 375 case Parameters.FLASH_MODE_RED_EYE: 376 aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE; 377 break; 378 case Parameters.FLASH_MODE_TORCH: 379 flashMode = FLASH_MODE_TORCH; 380 flashState = FLASH_STATE_FIRED; 381 break; 382 default: 383 Log.w(TAG, 384 "mapAeAndFlashMode - Ignoring unknown flash mode " + p.getFlashMode()); 385 } 386 } 387 388 // flash.state 389 m.set(FLASH_STATE, flashState); 390 // flash.mode 391 m.set(FLASH_MODE, flashMode); 392 // control.aeMode 393 m.set(CONTROL_AE_MODE, aeMode); 394 } 395 396 private static int convertLegacyAfMode(String mode) { 397 if (mode == null) { 398 Log.w(TAG, "convertLegacyAfMode - no AF mode, default to OFF"); 399 return CONTROL_AF_MODE_OFF; 400 } 401 402 switch (mode) { 403 case Parameters.FOCUS_MODE_AUTO: 404 return CONTROL_AF_MODE_AUTO; 405 case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE: 406 return CONTROL_AF_MODE_CONTINUOUS_PICTURE; 407 case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO: 408 return CONTROL_AF_MODE_CONTINUOUS_VIDEO; 409 case Parameters.FOCUS_MODE_EDOF: 410 return CONTROL_AF_MODE_EDOF; 411 case Parameters.FOCUS_MODE_MACRO: 412 return CONTROL_AF_MODE_MACRO; 413 case Parameters.FOCUS_MODE_FIXED: 414 return CONTROL_AF_MODE_OFF; 415 case Parameters.FOCUS_MODE_INFINITY: 416 return CONTROL_AF_MODE_OFF; 417 default: 418 Log.w(TAG, "convertLegacyAfMode - unknown mode " + mode + " , ignoring"); 419 return CONTROL_AF_MODE_OFF; 420 } 421 } 422 423 private static int convertLegacyAwbMode(String mode) { 424 if (mode == null) { 425 // OK: camera1 api may not support changing WB modes; assume AUTO 426 return CONTROL_AWB_MODE_AUTO; 427 } 428 429 switch (mode) { 430 case Camera.Parameters.WHITE_BALANCE_AUTO: 431 return CONTROL_AWB_MODE_AUTO; 432 case Camera.Parameters.WHITE_BALANCE_INCANDESCENT: 433 return CONTROL_AWB_MODE_INCANDESCENT; 434 case Camera.Parameters.WHITE_BALANCE_FLUORESCENT: 435 return CONTROL_AWB_MODE_FLUORESCENT; 436 case Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT: 437 return CONTROL_AWB_MODE_WARM_FLUORESCENT; 438 case Camera.Parameters.WHITE_BALANCE_DAYLIGHT: 439 return CONTROL_AWB_MODE_DAYLIGHT; 440 case Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT: 441 return CONTROL_AWB_MODE_CLOUDY_DAYLIGHT; 442 case Camera.Parameters.WHITE_BALANCE_TWILIGHT: 443 return CONTROL_AWB_MODE_TWILIGHT; 444 case Camera.Parameters.WHITE_BALANCE_SHADE: 445 return CONTROL_AWB_MODE_SHADE; 446 default: 447 Log.w(TAG, "convertAwbMode - unrecognized WB mode " + mode); 448 return CONTROL_AWB_MODE_AUTO; 449 } 450 } 451 452 /** Map results for scaler.* */ 453 private static void mapScaler(CameraMetadataNative m, 454 ZoomData zoomData, 455 /*out*/Parameters p) { 456 /* 457 * scaler.cropRegion 458 */ 459 { 460 m.set(SCALER_CROP_REGION, zoomData.reportedCrop); 461 } 462 } 463} 464