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