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