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