1 /* 2 * Copyright 2013 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 17 package android.hardware.camera2.cts; 18 19 import android.content.Context; 20 import android.graphics.ImageFormat; 21 import android.hardware.camera2.CameraCaptureSession; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CameraDevice; 24 import android.hardware.camera2.CaptureRequest; 25 import android.hardware.camera2.CaptureResult; 26 import android.hardware.camera2.TotalCaptureResult; 27 import android.media.Image; 28 import android.media.ImageReader; 29 import android.os.SystemClock; 30 import android.platform.test.annotations.AppModeFull; 31 import android.util.Pair; 32 import android.util.Size; 33 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 34 import android.hardware.camera2.cts.helpers.StaticMetadata; 35 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 36 37 import static android.hardware.camera2.cts.CameraTestUtils.*; 38 import static android.hardware.camera2.cts.helpers.CameraSessionUtils.*; 39 40 import android.util.Log; 41 import android.view.Surface; 42 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.HashMap; 46 import java.util.HashSet; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Set; 50 import java.util.concurrent.LinkedBlockingQueue; 51 import java.util.concurrent.TimeUnit; 52 53 @AppModeFull 54 public class CaptureResultTest extends Camera2AndroidTestCase { 55 private static final String TAG = "CaptureResultTest"; 56 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 57 private static final int MAX_NUM_IMAGES = MAX_READER_IMAGES; 58 private static final int NUM_FRAMES_VERIFIED = 30; 59 private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000; 60 61 62 // List tracking the failed test keys. 63 64 @Override 65 public void setContext(Context context) { 66 super.setContext(context); 67 68 /** 69 * Workaround for mockito and JB-MR2 incompatibility 70 * 71 * Avoid java.lang.IllegalArgumentException: dexcache == null 72 * https://code.google.com/p/dexmaker/issues/detail?id=2 73 */ 74 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 75 } 76 77 @Override 78 protected void setUp() throws Exception { 79 super.setUp(); 80 } 81 82 @Override 83 protected void tearDown() throws Exception { 84 super.tearDown(); 85 } 86 87 /** 88 * <p> 89 * Basic non-null check test for multiple capture results. 90 * </p> 91 * <p> 92 * When capturing many frames, some camera devices may return some results that have null keys 93 * randomly, which is an API violation and could cause application crash randomly. This test 94 * runs a typical flexible yuv capture many times, and checks if there is any null entries in 95 * a capture result. 96 * </p> 97 */ 98 public void testCameraCaptureResultAllKeys() throws Exception { 99 for (String id : mCameraIds) { 100 try { 101 openDevice(id); 102 if (mStaticInfo.isColorOutputSupported()) { 103 // Create image reader and surface. 104 Size size = mOrderedPreviewSizes.get(0); 105 createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES, 106 new ImageDropperListener()); 107 } else { 108 Size size = getMaxDepthSize(id, mCameraManager); 109 createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES, 110 new ImageDropperListener()); 111 } 112 113 // Configure output streams. 114 List<Surface> outputSurfaces = new ArrayList<Surface>(1); 115 outputSurfaces.add(mReaderSurface); 116 createSession(outputSurfaces); 117 118 CaptureRequest.Builder requestBuilder = 119 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 120 assertNotNull("Failed to create capture request", requestBuilder); 121 requestBuilder.addTarget(mReaderSurface); 122 123 // Start capture 124 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 125 startCapture(requestBuilder.build(), /*repeating*/true, captureListener, mHandler); 126 127 // Verify results 128 validateCaptureResult(mCollector, captureListener, mStaticInfo, mAllStaticInfo, 129 null/*requestedPhysicalIds*/, requestBuilder, NUM_FRAMES_VERIFIED); 130 131 stopCapture(/*fast*/false); 132 } finally { 133 closeDevice(id); 134 closeDefaultImageReader(); 135 } 136 } 137 } 138 139 /** 140 * Check partial results conform to its specification. 141 * <p> 142 * The test is skipped if partial result is not supported on device. </p> 143 * <p>Test summary:<ul> 144 * <li>1. Number of partial results is less than or equal to 145 * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}. 146 * <li>2. Each key appeared in partial results must be unique across all partial results. 147 * <li>3. All keys appeared in partial results must be present in TotalCaptureResult 148 * <li>4. Also test onCaptureComplete callback always happen after onCaptureStart or 149 * onCaptureProgressed callbacks. 150 * </ul></p> 151 */ 152 public void testPartialResult() throws Exception { 153 final int NUM_FRAMES_TESTED = 30; 154 final int WAIT_FOR_RESULT_TIMOUT_MS = 2000; 155 for (String id : mCameraIds) { 156 try { 157 openDevice(id); 158 159 // Skip the test if partial result is not supported 160 int partialResultCount = mStaticInfo.getPartialResultCount(); 161 if (partialResultCount == 1) { 162 continue; 163 } 164 165 // Create image reader and surface. 166 if (mStaticInfo.isColorOutputSupported()) { 167 Size size = mOrderedPreviewSizes.get(0); 168 createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES, 169 new ImageDropperListener()); 170 } else { 171 Size size = getMaxDepthSize(id, mCameraManager); 172 createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES, 173 new ImageDropperListener()); 174 } 175 176 // Configure output streams. 177 List<Surface> outputSurfaces = new ArrayList<Surface>(1); 178 outputSurfaces.add(mReaderSurface); 179 createSession(outputSurfaces); 180 181 CaptureRequest.Builder requestBuilder = 182 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 183 assertNotNull("Failed to create capture request", requestBuilder); 184 requestBuilder.addTarget(mReaderSurface); 185 TotalAndPartialResultListener listener = 186 new TotalAndPartialResultListener(); 187 188 // Start capture 189 for (Integer frame = 0; frame < NUM_FRAMES_TESTED; frame++) { 190 // Set a different tag for each request so the listener can group 191 // partial results by each request 192 requestBuilder.setTag(frame); 193 startCapture( 194 requestBuilder.build(), /*repeating*/false, 195 listener, mHandler); 196 } 197 198 // Verify capture results 199 for (int frame = 0; frame < NUM_FRAMES_TESTED; frame++) { 200 Pair<TotalCaptureResult, List<CaptureResult>> resultPair = 201 listener.getCaptureResultPairs(WAIT_FOR_RESULT_TIMOUT_MS); 202 203 List<CaptureResult> partialResults = resultPair.second; 204 205 if (partialResults == null) { 206 // HAL only sends total result is legal 207 partialResults = new ArrayList<>(); 208 } 209 210 TotalCaptureResult totalResult = resultPair.first; 211 212 mCollector.expectLessOrEqual("Too many partial results", 213 partialResultCount, partialResults.size()); 214 Set<CaptureResult.Key<?>> appearedPartialKeys = 215 new HashSet<CaptureResult.Key<?>>(); 216 for (CaptureResult partialResult : partialResults) { 217 List<CaptureResult.Key<?>> partialKeys = partialResult.getKeys(); 218 mCollector.expectValuesUnique("Partial result keys: ", partialKeys); 219 for (CaptureResult.Key<?> key : partialKeys) { 220 mCollector.expectTrue( 221 String.format("Key %s appears in multiple partial results", 222 key.getName()), 223 !appearedPartialKeys.contains(key)); 224 } 225 appearedPartialKeys.addAll(partialKeys); 226 } 227 228 // Test total result against the partial results 229 List<CaptureResult.Key<?>> totalResultKeys = totalResult.getKeys(); 230 mCollector.expectTrue( 231 "TotalCaptureResult must be a super set of partial capture results", 232 totalResultKeys.containsAll(appearedPartialKeys)); 233 234 List<CaptureResult> totalResultPartials = totalResult.getPartialResults(); 235 mCollector.expectEquals("TotalCaptureResult's partial results must match " + 236 "the ones observed by #onCaptureProgressed", 237 partialResults, totalResultPartials); 238 239 if (VERBOSE) { 240 Log.v(TAG, "testPartialResult - Observed " + 241 partialResults.size() + "; queried for " + 242 totalResultPartials.size()); 243 } 244 } 245 246 int errorCode = listener.getErrorCode(); 247 if ((errorCode & TotalAndPartialResultListener.ERROR_DUPLICATED_REQUEST) != 0) { 248 mCollector.addMessage("Listener received multiple onCaptureComplete" + 249 " callback for the same request"); 250 } 251 if ((errorCode & TotalAndPartialResultListener.ERROR_WRONG_CALLBACK_ORDER) != 0) { 252 mCollector.addMessage("Listener received onCaptureStart or" + 253 " onCaptureProgressed after onCaptureComplete"); 254 } 255 256 stopCapture(/*fast*/false); 257 } finally { 258 closeDevice(id); 259 closeDefaultImageReader(); 260 } 261 } 262 } 263 264 /** 265 * Check that the timestamps passed in the results, buffers, and capture callbacks match for 266 * a single request, and increase monotonically 267 */ 268 public void testResultTimestamps() throws Exception { 269 for (String id : mCameraIds) { 270 ImageReader previewReader = null; 271 ImageReader jpegReader = null; 272 273 SimpleImageReaderListener jpegListener = new SimpleImageReaderListener(); 274 SimpleImageReaderListener prevListener = new SimpleImageReaderListener(); 275 try { 276 openDevice(id); 277 if (!mStaticInfo.isColorOutputSupported()) { 278 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 279 continue; 280 } 281 282 CaptureRequest.Builder previewBuilder = 283 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 284 CaptureRequest.Builder multiBuilder = 285 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 286 287 // Create image reader and surface. 288 Size previewSize = mOrderedPreviewSizes.get(0); 289 Size jpegSize = mOrderedStillSizes.get(0); 290 291 // Create ImageReaders. 292 previewReader = makeImageReader(previewSize, ImageFormat.YUV_420_888, 293 MAX_NUM_IMAGES, prevListener, mHandler); 294 jpegReader = makeImageReader(jpegSize, ImageFormat.JPEG, 295 MAX_NUM_IMAGES, jpegListener, mHandler); 296 297 // Configure output streams with preview and jpeg streams. 298 List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList( 299 previewReader.getSurface(), jpegReader.getSurface())); 300 301 SessionListener mockSessionListener = getMockSessionListener(); 302 303 CameraCaptureSession session = configureAndVerifySession(mockSessionListener, 304 mCamera, outputSurfaces, mHandler); 305 306 // Configure the requests. 307 previewBuilder.addTarget(previewReader.getSurface()); 308 multiBuilder.addTarget(previewReader.getSurface()); 309 multiBuilder.addTarget(jpegReader.getSurface()); 310 311 if (mStaticInfo.isEnableZslSupported()) { 312 // Turn off ZSL to ensure timestamps are increasing 313 previewBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false); 314 multiBuilder.set(CaptureRequest.CONTROL_ENABLE_ZSL, false); 315 } 316 317 CaptureCallback mockCaptureCallback = getMockCaptureListener(); 318 319 // Capture targeting only preview 320 Pair<TotalCaptureResult, Long> result = captureAndVerifyResult(mockCaptureCallback, 321 session, previewBuilder.build(), mHandler); 322 323 // Check if all timestamps are the same 324 Image prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 325 validateTimestamps("Result 1", result.first, 326 prevImage, result.second); 327 prevImage.close(); 328 329 // Capture targeting both jpeg and preview 330 Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback, 331 session, multiBuilder.build(), mHandler); 332 333 // Check if all timestamps are the same 334 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 335 Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 336 validateTimestamps("Result 2 Preview", result2.first, 337 prevImage, result2.second); 338 validateTimestamps("Result 2 Jpeg", result2.first, 339 jpegImage, result2.second); 340 prevImage.close(); 341 jpegImage.close(); 342 343 // Check if timestamps are increasing 344 mCollector.expectGreater("Timestamps must be increasing.", result.second, 345 result2.second); 346 347 // Capture two preview frames 348 long startTime = SystemClock.elapsedRealtimeNanos(); 349 Pair<TotalCaptureResult, Long> result3 = captureAndVerifyResult(mockCaptureCallback, 350 session, previewBuilder.build(), mHandler); 351 Pair<TotalCaptureResult, Long> result4 = captureAndVerifyResult(mockCaptureCallback, 352 session, previewBuilder.build(), mHandler); 353 long clockDiff = SystemClock.elapsedRealtimeNanos() - startTime; 354 long resultDiff = result4.second - result3.second; 355 356 // Check if all timestamps are the same 357 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 358 validateTimestamps("Result 3", result3.first, 359 prevImage, result3.second); 360 prevImage.close(); 361 prevImage = prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 362 validateTimestamps("Result 4", result4.first, 363 prevImage, result4.second); 364 prevImage.close(); 365 366 // Check that the timestamps monotonically increase at a reasonable rate 367 mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.", 368 resultDiff, clockDiff); 369 mCollector.expectGreater("Timestamps must be increasing.", result3.second, 370 result4.second); 371 } finally { 372 closeDevice(id); 373 closeImageReader(previewReader); 374 closeImageReader(jpegReader); 375 } 376 } 377 } 378 379 private void validateTimestamps(String msg, TotalCaptureResult result, Image resultImage, 380 long captureTime) { 381 mCollector.expectKeyValueEquals(result, CaptureResult.SENSOR_TIMESTAMP, captureTime); 382 mCollector.expectEquals(msg + ": Capture timestamp must be same as resultImage timestamp", 383 resultImage.getTimestamp(), captureTime); 384 } 385 386 public static void validateCaptureResult(CameraErrorCollector errorCollector, 387 SimpleCaptureCallback captureListener, StaticMetadata staticInfo, 388 Map<String, StaticMetadata> allStaticInfo, List<String> requestedPhysicalIds, 389 CaptureRequest.Builder requestBuilder, int numFramesVerified) throws Exception { 390 // List that includes all public keys from CaptureResult 391 List<CaptureResult.Key<?>> allKeys = getAllCaptureResultKeys(); 392 // Get the waived keys for current camera device 393 List<CaptureResult.Key<?>> waiverKeys = getWaiverKeysForCamera(staticInfo); 394 if (requestedPhysicalIds == null) { 395 requestedPhysicalIds = new ArrayList<String>(); 396 } 397 398 HashMap<String, List<CaptureResult.Key<?>>> physicalWaiverKeys = new HashMap<>(); 399 for (String physicalId : requestedPhysicalIds) { 400 StaticMetadata physicalStaticInfo = allStaticInfo.get(physicalId); 401 physicalWaiverKeys.put(physicalId, getWaiverKeysForCamera(physicalStaticInfo)); 402 } 403 404 TotalCaptureResult result = null; 405 for (int i = 0; i < numFramesVerified; i++) { 406 result = captureListener.getTotalCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS); 407 Map<String, CaptureResult> physicalCaptureResults = result.getPhysicalCameraResults(); 408 errorCollector.expectEquals("Number of physical result metadata doesn't match " + 409 physicalCaptureResults.size() + " vs " + requestedPhysicalIds.size(), 410 physicalCaptureResults.size(), requestedPhysicalIds.size()); 411 412 validateOneCaptureResult(errorCollector, waiverKeys, allKeys, requestBuilder, result, 413 null/*cameraId*/, i); 414 for (String physicalId : requestedPhysicalIds) { 415 validateOneCaptureResult(errorCollector, physicalWaiverKeys.get(physicalId), 416 allKeys, null/*requestBuilder*/, physicalCaptureResults.get(physicalId), 417 physicalId, i); 418 } 419 } 420 } 421 422 private static void validateOneCaptureResult(CameraErrorCollector errorCollector, 423 List<CaptureResult.Key<?>> skippedKeys, List<CaptureResult.Key<?>> allKeys, 424 CaptureRequest.Builder requestBuilder, CaptureResult result, String cameraId, 425 int resultCount) throws Exception { 426 String failMsg = "Failed capture result " + resultCount + " test"; 427 String cameraIdString = " "; 428 if (cameraId != null) { 429 cameraIdString += "for physical camera " + cameraId; 430 } 431 boolean verifyMatchRequest = (requestBuilder != null); 432 for (CaptureResult.Key<?> key : allKeys) { 433 if (!skippedKeys.contains(key)) { 434 /** 435 * Check the critical tags here. 436 * TODO: Can use the same key for request and result when request/result 437 * becomes symmetric (b/14059883). Then below check can be wrapped into 438 * a generic function. 439 */ 440 String msg = failMsg + cameraIdString + "for key " + key.getName(); 441 if (verifyMatchRequest) { 442 if (key.equals(CaptureResult.CONTROL_AE_MODE)) { 443 errorCollector.expectEquals(msg, 444 requestBuilder.get(CaptureRequest.CONTROL_AE_MODE), 445 result.get(CaptureResult.CONTROL_AE_MODE)); 446 } else if (key.equals(CaptureResult.CONTROL_AF_MODE)) { 447 errorCollector.expectEquals(msg, 448 requestBuilder.get(CaptureRequest.CONTROL_AF_MODE), 449 result.get(CaptureResult.CONTROL_AF_MODE)); 450 } else if (key.equals(CaptureResult.CONTROL_AWB_MODE)) { 451 errorCollector.expectEquals(msg, 452 requestBuilder.get(CaptureRequest.CONTROL_AWB_MODE), 453 result.get(CaptureResult.CONTROL_AWB_MODE)); 454 } else if (key.equals(CaptureResult.CONTROL_MODE)) { 455 errorCollector.expectEquals(msg, 456 requestBuilder.get(CaptureRequest.CONTROL_MODE), 457 result.get(CaptureResult.CONTROL_MODE)); 458 } else if (key.equals(CaptureResult.STATISTICS_FACE_DETECT_MODE)) { 459 errorCollector.expectEquals(msg, 460 requestBuilder.get(CaptureRequest.STATISTICS_FACE_DETECT_MODE), 461 result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE)); 462 } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) { 463 errorCollector.expectEquals(msg, 464 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE), 465 result.get(CaptureResult.NOISE_REDUCTION_MODE)); 466 } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) { 467 errorCollector.expectEquals(msg, 468 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE), 469 result.get(CaptureResult.NOISE_REDUCTION_MODE)); 470 } else if (key.equals(CaptureResult.REQUEST_PIPELINE_DEPTH)) { 471 472 } else if (key.equals(CaptureResult.STATISTICS_OIS_DATA_MODE)) { 473 errorCollector.expectEquals(msg, 474 requestBuilder.get(CaptureRequest.STATISTICS_OIS_DATA_MODE), 475 result.get(CaptureResult.STATISTICS_OIS_DATA_MODE)); 476 } else { 477 // Only do non-null check for the rest of keys. 478 errorCollector.expectKeyValueNotNull(failMsg, result, key); 479 } 480 } else { 481 // Only do non-null check for the rest of keys. 482 errorCollector.expectKeyValueNotNull(failMsg, result, key); 483 } 484 } else { 485 // These keys should always be null 486 if (key.equals(CaptureResult.CONTROL_AE_REGIONS)) { 487 errorCollector.expectNull( 488 "Capture result contains AE regions but aeMaxRegions is 0" 489 + cameraIdString, 490 result.get(CaptureResult.CONTROL_AE_REGIONS)); 491 } else if (key.equals(CaptureResult.CONTROL_AWB_REGIONS)) { 492 errorCollector.expectNull( 493 "Capture result contains AWB regions but awbMaxRegions is 0" 494 + cameraIdString, 495 result.get(CaptureResult.CONTROL_AWB_REGIONS)); 496 } else if (key.equals(CaptureResult.CONTROL_AF_REGIONS)) { 497 errorCollector.expectNull( 498 "Capture result contains AF regions but afMaxRegions is 0" 499 + cameraIdString, 500 result.get(CaptureResult.CONTROL_AF_REGIONS)); 501 } 502 } 503 } 504 } 505 506 /* 507 * Add waiver keys per camera device hardware level and capability. 508 * 509 * Must be called after camera device is opened. 510 */ 511 private static List<CaptureResult.Key<?>> getWaiverKeysForCamera(StaticMetadata staticInfo) { 512 List<CaptureResult.Key<?>> waiverKeys = new ArrayList<>(); 513 514 // Global waiver keys 515 waiverKeys.add(CaptureResult.JPEG_GPS_LOCATION); 516 waiverKeys.add(CaptureResult.JPEG_ORIENTATION); 517 waiverKeys.add(CaptureResult.JPEG_QUALITY); 518 waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY); 519 waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE); 520 521 // Keys only present when corresponding control is on are being 522 // verified in its own functional test 523 // Only present in certain tonemap mode. Test in CaptureRequestTest. 524 waiverKeys.add(CaptureResult.TONEMAP_CURVE); 525 waiverKeys.add(CaptureResult.TONEMAP_GAMMA); 526 waiverKeys.add(CaptureResult.TONEMAP_PRESET_CURVE); 527 // Only present when test pattern mode is SOLID_COLOR. 528 // TODO: verify this key in test pattern test later 529 waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA); 530 // Only present when STATISTICS_LENS_SHADING_MAP_MODE is ON 531 waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP); 532 // Only present when STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES is ON 533 waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP); 534 // Only present when face detection is on 535 waiverKeys.add(CaptureResult.STATISTICS_FACES); 536 // Only present in reprocessing capture result. 537 waiverKeys.add(CaptureResult.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR); 538 539 //Keys not required if RAW is not supported 540 if (!staticInfo.isCapabilitySupported( 541 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 542 waiverKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT); 543 waiverKeys.add(CaptureResult.SENSOR_GREEN_SPLIT); 544 waiverKeys.add(CaptureResult.SENSOR_NOISE_PROFILE); 545 } 546 547 //Keys for depth output capability 548 if (!staticInfo.isCapabilitySupported( 549 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT)) { 550 waiverKeys.add(CaptureResult.LENS_POSE_ROTATION); 551 waiverKeys.add(CaptureResult.LENS_POSE_TRANSLATION); 552 } 553 554 //Keys for lens distortion correction 555 boolean distortionCorrectionSupported = false; 556 int[] distortionModes = staticInfo.getCharacteristics().get( 557 CameraCharacteristics.DISTORTION_CORRECTION_AVAILABLE_MODES); 558 if (distortionModes == null) { 559 waiverKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE); 560 } else { 561 boolean gotNonOff = false; 562 for (int mode : distortionModes) { 563 if (mode != CaptureRequest.DISTORTION_CORRECTION_MODE_OFF) { 564 gotNonOff = true; 565 distortionCorrectionSupported = true; 566 break; 567 } 568 } 569 if (!gotNonOff) { 570 waiverKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE); 571 } 572 } 573 574 // These keys must present on either DEPTH or distortion correction devices 575 if (!staticInfo.isCapabilitySupported( 576 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) && 577 !distortionCorrectionSupported) { 578 waiverKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION); 579 waiverKeys.add(CaptureResult.LENS_RADIAL_DISTORTION); 580 waiverKeys.add(CaptureResult.LENS_DISTORTION); 581 } 582 583 584 // Waived if RAW output is not supported 585 int[] outputFormats = staticInfo.getAvailableFormats( 586 StaticMetadata.StreamDirection.Output); 587 boolean supportRaw = false; 588 for (int format : outputFormats) { 589 if (format == ImageFormat.RAW_SENSOR || format == ImageFormat.RAW10 || 590 format == ImageFormat.RAW12 || format == ImageFormat.RAW_PRIVATE) { 591 supportRaw = true; 592 break; 593 } 594 } 595 if (!supportRaw) { 596 waiverKeys.add(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST); 597 } 598 599 // Waived if MONOCHROME capability 600 if (!staticInfo.isCapabilitySupported( 601 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME)) { 602 waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE); 603 waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM); 604 waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS); 605 } 606 607 if (staticInfo.getAeMaxRegionsChecked() == 0) { 608 waiverKeys.add(CaptureResult.CONTROL_AE_REGIONS); 609 } 610 if (staticInfo.getAwbMaxRegionsChecked() == 0) { 611 waiverKeys.add(CaptureResult.CONTROL_AWB_REGIONS); 612 } 613 if (staticInfo.getAfMaxRegionsChecked() == 0) { 614 waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS); 615 } 616 617 // Keys for dynamic black/white levels 618 if (!staticInfo.isOpticalBlackRegionSupported()) { 619 waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 620 waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL); 621 } 622 623 if (!staticInfo.isEnableZslSupported()) { 624 waiverKeys.add(CaptureResult.CONTROL_ENABLE_ZSL); 625 } 626 627 if (!staticInfo.isAfSceneChangeSupported()) { 628 waiverKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE); 629 } 630 631 if (!staticInfo.isOisDataModeSupported()) { 632 waiverKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE); 633 waiverKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES); 634 } 635 636 if (staticInfo.isHardwareLevelAtLeastFull()) { 637 return waiverKeys; 638 } 639 640 /* 641 * Hardware Level = LIMITED or LEGACY 642 */ 643 // Key not present if certain control is not supported 644 if (!staticInfo.isColorCorrectionSupported()) { 645 waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS); 646 waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE); 647 waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM); 648 } 649 650 if (!staticInfo.isManualColorAberrationControlSupported()) { 651 waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE); 652 } 653 654 if (!staticInfo.isManualToneMapSupported()) { 655 waiverKeys.add(CaptureResult.TONEMAP_MODE); 656 } 657 658 if (!staticInfo.isEdgeModeControlSupported()) { 659 waiverKeys.add(CaptureResult.EDGE_MODE); 660 } 661 662 if (!staticInfo.isHotPixelMapModeControlSupported()) { 663 waiverKeys.add(CaptureResult.HOT_PIXEL_MODE); 664 } 665 666 if (!staticInfo.isNoiseReductionModeControlSupported()) { 667 waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE); 668 } 669 670 if (!staticInfo.isManualLensShadingMapSupported()) { 671 waiverKeys.add(CaptureResult.SHADING_MODE); 672 } 673 674 //Keys not required if neither MANUAL_SENSOR nor READ_SENSOR_SETTINGS is supported 675 if (!staticInfo.isCapabilitySupported( 676 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) && 677 !staticInfo.isCapabilitySupported( 678 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) { 679 waiverKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME); 680 waiverKeys.add(CaptureResult.SENSOR_SENSITIVITY); 681 waiverKeys.add(CaptureResult.LENS_FOCUS_DISTANCE); 682 waiverKeys.add(CaptureResult.LENS_APERTURE); 683 } 684 685 if (!staticInfo.isCapabilitySupported( 686 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) { 687 waiverKeys.add(CaptureResult.SENSOR_FRAME_DURATION); 688 waiverKeys.add(CaptureResult.BLACK_LEVEL_LOCK); 689 waiverKeys.add(CaptureResult.LENS_FOCUS_RANGE); 690 waiverKeys.add(CaptureResult.LENS_STATE); 691 waiverKeys.add(CaptureResult.LENS_FILTER_DENSITY); 692 } 693 694 if (staticInfo.isHardwareLevelLimited() && staticInfo.isColorOutputSupported()) { 695 return waiverKeys; 696 } 697 698 /* 699 * Hardware Level = EXTERNAL 700 */ 701 if (staticInfo.isExternalCamera()) { 702 waiverKeys.add(CaptureResult.LENS_FOCAL_LENGTH); 703 waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE); 704 waiverKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW); 705 } 706 707 if (staticInfo.isExternalCamera() && staticInfo.isColorOutputSupported()) { 708 return waiverKeys; 709 } 710 711 /* 712 * Hardware Level = LEGACY or no regular output is supported 713 */ 714 waiverKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER); 715 waiverKeys.add(CaptureResult.CONTROL_AE_STATE); 716 waiverKeys.add(CaptureResult.CONTROL_AWB_STATE); 717 waiverKeys.add(CaptureResult.FLASH_STATE); 718 waiverKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE); 719 waiverKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW); 720 waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE); 721 waiverKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER); 722 waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE); 723 waiverKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE); 724 waiverKeys.add(CaptureResult.CONTROL_AF_TRIGGER); 725 726 if (staticInfo.isHardwareLevelLegacy()) { 727 return waiverKeys; 728 } 729 730 /* 731 * Regular output not supported, only depth, waive color-output-related keys 732 */ 733 waiverKeys.add(CaptureResult.CONTROL_SCENE_MODE); 734 waiverKeys.add(CaptureResult.CONTROL_EFFECT_MODE); 735 waiverKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE); 736 waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE); 737 waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE); 738 waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE); 739 waiverKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE); 740 waiverKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION); 741 waiverKeys.add(CaptureResult.CONTROL_AE_LOCK); 742 waiverKeys.add(CaptureResult.CONTROL_AE_MODE); 743 waiverKeys.add(CaptureResult.CONTROL_AF_MODE); 744 waiverKeys.add(CaptureResult.CONTROL_AWB_MODE); 745 waiverKeys.add(CaptureResult.CONTROL_AWB_LOCK); 746 waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE); 747 waiverKeys.add(CaptureResult.FLASH_MODE); 748 waiverKeys.add(CaptureResult.SCALER_CROP_REGION); 749 750 return waiverKeys; 751 } 752 753 /** 754 * A capture listener implementation for collecting both partial and total results. 755 * 756 * <p> This is not a full-blown class and has some implicit assumptions. The class groups 757 * capture results by capture request, so the user must guarantee each request this listener 758 * is listening is unique. This class is not thread safe, so don't attach an instance object 759 * with multiple handlers.</p> 760 * */ 761 private static class TotalAndPartialResultListener 762 extends CameraCaptureSession.CaptureCallback { 763 static final int ERROR_DUPLICATED_REQUEST = 1 << 0; 764 static final int ERROR_WRONG_CALLBACK_ORDER = 1 << 1; 765 766 private final LinkedBlockingQueue<Pair<TotalCaptureResult, List<CaptureResult>> > mQueue = 767 new LinkedBlockingQueue<>(); 768 private final HashMap<CaptureRequest, List<CaptureResult>> mPartialResultsMap = 769 new HashMap<CaptureRequest, List<CaptureResult>>(); 770 private final HashSet<CaptureRequest> completedRequests = new HashSet<>(); 771 private int errorCode = 0; 772 773 @Override 774 public void onCaptureStarted( 775 CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) 776 { 777 checkCallbackOrder(request); 778 createMapEntryIfNecessary(request); 779 } 780 781 @Override 782 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 783 TotalCaptureResult result) { 784 try { 785 List<CaptureResult> partialResultsList = mPartialResultsMap.get(request); 786 if (partialResultsList == null) { 787 Log.w(TAG, "onCaptureCompleted: unknown request"); 788 } 789 mQueue.put(new Pair<TotalCaptureResult, List<CaptureResult>>( 790 result, partialResultsList)); 791 mPartialResultsMap.remove(request); 792 boolean newEntryAdded = completedRequests.add(request); 793 if (!newEntryAdded) { 794 Integer frame = (Integer) request.getTag(); 795 Log.e(TAG, "Frame " + frame + "ERROR_DUPLICATED_REQUEST"); 796 errorCode |= ERROR_DUPLICATED_REQUEST; 797 } 798 } catch (InterruptedException e) { 799 throw new UnsupportedOperationException( 800 "Can't handle InterruptedException in onCaptureCompleted"); 801 } 802 } 803 804 @Override 805 public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, 806 CaptureResult partialResult) { 807 createMapEntryIfNecessary(request); 808 List<CaptureResult> partialResultsList = mPartialResultsMap.get(request); 809 partialResultsList.add(partialResult); 810 } 811 812 private void createMapEntryIfNecessary(CaptureRequest request) { 813 if (!mPartialResultsMap.containsKey(request)) { 814 // create a new entry in the map 815 mPartialResultsMap.put(request, new ArrayList<CaptureResult>()); 816 } 817 } 818 819 private void checkCallbackOrder(CaptureRequest request) { 820 if (completedRequests.contains(request)) { 821 Integer frame = (Integer) request.getTag(); 822 Log.e(TAG, "Frame " + frame + "ERROR_WRONG_CALLBACK_ORDER"); 823 errorCode |= ERROR_WRONG_CALLBACK_ORDER; 824 } 825 } 826 827 public Pair<TotalCaptureResult, List<CaptureResult>> getCaptureResultPairs(long timeout) { 828 try { 829 Pair<TotalCaptureResult, List<CaptureResult>> result = 830 mQueue.poll(timeout, TimeUnit.MILLISECONDS); 831 assertNotNull("Wait for a capture result timed out in " + timeout + "ms", result); 832 return result; 833 } catch (InterruptedException e) { 834 throw new UnsupportedOperationException("Unhandled interrupted exception", e); 835 } 836 } 837 838 public int getErrorCode() { 839 return errorCode; 840 } 841 } 842 843 /** 844 * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out 845 * @hide keys. 846 * 847 */ 848 849 /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ 850 * The key entries below this point are generated from metadata 851 * definitions in /system/media/camera/docs. Do not modify by hand or 852 * modify the comment blocks at the start or end. 853 *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/ 854 855 private static List<CaptureResult.Key<?>> getAllCaptureResultKeys() { 856 ArrayList<CaptureResult.Key<?>> resultKeys = new ArrayList<CaptureResult.Key<?>>(); 857 resultKeys.add(CaptureResult.COLOR_CORRECTION_MODE); 858 resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM); 859 resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS); 860 resultKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE); 861 resultKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE); 862 resultKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION); 863 resultKeys.add(CaptureResult.CONTROL_AE_LOCK); 864 resultKeys.add(CaptureResult.CONTROL_AE_MODE); 865 resultKeys.add(CaptureResult.CONTROL_AE_REGIONS); 866 resultKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE); 867 resultKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER); 868 resultKeys.add(CaptureResult.CONTROL_AF_MODE); 869 resultKeys.add(CaptureResult.CONTROL_AF_REGIONS); 870 resultKeys.add(CaptureResult.CONTROL_AF_TRIGGER); 871 resultKeys.add(CaptureResult.CONTROL_AWB_LOCK); 872 resultKeys.add(CaptureResult.CONTROL_AWB_MODE); 873 resultKeys.add(CaptureResult.CONTROL_AWB_REGIONS); 874 resultKeys.add(CaptureResult.CONTROL_CAPTURE_INTENT); 875 resultKeys.add(CaptureResult.CONTROL_EFFECT_MODE); 876 resultKeys.add(CaptureResult.CONTROL_MODE); 877 resultKeys.add(CaptureResult.CONTROL_SCENE_MODE); 878 resultKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE); 879 resultKeys.add(CaptureResult.CONTROL_AE_STATE); 880 resultKeys.add(CaptureResult.CONTROL_AF_STATE); 881 resultKeys.add(CaptureResult.CONTROL_AWB_STATE); 882 resultKeys.add(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST); 883 resultKeys.add(CaptureResult.CONTROL_ENABLE_ZSL); 884 resultKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE); 885 resultKeys.add(CaptureResult.EDGE_MODE); 886 resultKeys.add(CaptureResult.FLASH_MODE); 887 resultKeys.add(CaptureResult.FLASH_STATE); 888 resultKeys.add(CaptureResult.HOT_PIXEL_MODE); 889 resultKeys.add(CaptureResult.JPEG_GPS_LOCATION); 890 resultKeys.add(CaptureResult.JPEG_ORIENTATION); 891 resultKeys.add(CaptureResult.JPEG_QUALITY); 892 resultKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY); 893 resultKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE); 894 resultKeys.add(CaptureResult.LENS_APERTURE); 895 resultKeys.add(CaptureResult.LENS_FILTER_DENSITY); 896 resultKeys.add(CaptureResult.LENS_FOCAL_LENGTH); 897 resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE); 898 resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE); 899 resultKeys.add(CaptureResult.LENS_POSE_ROTATION); 900 resultKeys.add(CaptureResult.LENS_POSE_TRANSLATION); 901 resultKeys.add(CaptureResult.LENS_FOCUS_RANGE); 902 resultKeys.add(CaptureResult.LENS_STATE); 903 resultKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION); 904 resultKeys.add(CaptureResult.LENS_RADIAL_DISTORTION); 905 resultKeys.add(CaptureResult.LENS_DISTORTION); 906 resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE); 907 resultKeys.add(CaptureResult.REQUEST_PIPELINE_DEPTH); 908 resultKeys.add(CaptureResult.SCALER_CROP_REGION); 909 resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME); 910 resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION); 911 resultKeys.add(CaptureResult.SENSOR_SENSITIVITY); 912 resultKeys.add(CaptureResult.SENSOR_TIMESTAMP); 913 resultKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT); 914 resultKeys.add(CaptureResult.SENSOR_NOISE_PROFILE); 915 resultKeys.add(CaptureResult.SENSOR_GREEN_SPLIT); 916 resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA); 917 resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE); 918 resultKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW); 919 resultKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL); 920 resultKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL); 921 resultKeys.add(CaptureResult.SHADING_MODE); 922 resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE); 923 resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE); 924 resultKeys.add(CaptureResult.STATISTICS_FACES); 925 resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP); 926 resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER); 927 resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP); 928 resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE); 929 resultKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE); 930 resultKeys.add(CaptureResult.STATISTICS_OIS_SAMPLES); 931 resultKeys.add(CaptureResult.TONEMAP_CURVE); 932 resultKeys.add(CaptureResult.TONEMAP_MODE); 933 resultKeys.add(CaptureResult.TONEMAP_GAMMA); 934 resultKeys.add(CaptureResult.TONEMAP_PRESET_CURVE); 935 resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK); 936 resultKeys.add(CaptureResult.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR); 937 resultKeys.add(CaptureResult.DISTORTION_CORRECTION_MODE); 938 939 return resultKeys; 940 } 941 942 /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~ 943 * End generated code 944 *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/ 945 } 946