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