1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.cts; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.PREVIEW_SIZE_BOUND; 20 import static android.hardware.camera2.cts.CameraTestUtils.SessionConfigSupport; 21 import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 22 import static android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener; 23 import static android.hardware.camera2.cts.CameraTestUtils.SizeComparator; 24 import static android.hardware.camera2.cts.CameraTestUtils.StreamCombinationTargets; 25 import static android.hardware.camera2.cts.CameraTestUtils.assertEquals; 26 import static android.hardware.camera2.cts.CameraTestUtils.assertNotNull; 27 import static android.hardware.camera2.cts.CameraTestUtils.assertNull; 28 import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationSupported; 29 import static android.hardware.camera2.cts.CameraTestUtils.checkSessionConfigurationWithSurfaces; 30 import static android.hardware.camera2.cts.CameraTestUtils.configureReprocessableCameraSession; 31 import static android.hardware.camera2.cts.CameraTestUtils.fail; 32 import static android.hardware.camera2.cts.CameraTestUtils.getAscendingOrderSizes; 33 import static android.hardware.camera2.cts.CameraTestUtils.isSessionConfigSupported; 34 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.JPEG; 35 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.MAXIMUM; 36 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.MAX_RES; 37 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.PREVIEW; 38 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.PRIV; 39 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.RAW; 40 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.RECORD; 41 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.S1440P; 42 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.S720P; 43 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_PREVIEW; 44 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_PREVIEW_VIDEO_STILL; 45 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_STILL_CAPTURE; 46 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_VIDEO_CALL; 47 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_VIDEO_RECORD; 48 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.USE_CASE_CROPPED_RAW; 49 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.VGA; 50 import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.YUV; 51 52 import static junit.framework.Assert.assertFalse; 53 import static junit.framework.Assert.assertTrue; 54 55 import static org.mockito.Mockito.any; 56 import static org.mockito.Mockito.eq; 57 import static org.mockito.Mockito.isA; 58 import static org.mockito.Mockito.mock; 59 import static org.mockito.Mockito.never; 60 import static org.mockito.Mockito.timeout; 61 import static org.mockito.Mockito.verify; 62 63 import android.content.Context; 64 import android.graphics.ImageFormat; 65 import android.graphics.Rect; 66 import android.graphics.SurfaceTexture; 67 import android.hardware.camera2.CameraCaptureSession; 68 import android.hardware.camera2.CameraCharacteristics; 69 import android.hardware.camera2.CameraDevice; 70 import android.hardware.camera2.CameraManager; 71 import android.hardware.camera2.CameraMetadata; 72 import android.hardware.camera2.CaptureFailure; 73 import android.hardware.camera2.CaptureRequest; 74 import android.hardware.camera2.CaptureResult; 75 import android.hardware.camera2.TotalCaptureResult; 76 import android.hardware.camera2.cts.helpers.StaticMetadata; 77 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 78 import android.hardware.camera2.params.DynamicRangeProfiles; 79 import android.hardware.camera2.params.InputConfiguration; 80 import android.hardware.camera2.params.MandatoryStreamCombination; 81 import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; 82 import android.hardware.camera2.params.OisSample; 83 import android.hardware.camera2.params.OutputConfiguration; 84 import android.hardware.camera2.params.SessionConfiguration; 85 import android.hardware.camera2.params.StreamConfigurationMap; 86 import android.media.CamcorderProfile; 87 import android.media.Image; 88 import android.media.ImageReader; 89 import android.media.ImageWriter; 90 import android.util.Log; 91 import android.util.Pair; 92 import android.util.Size; 93 import android.view.Surface; 94 import android.view.WindowManager; 95 import android.view.WindowMetrics; 96 97 import com.android.ex.camera2.blocking.BlockingSessionCallback; 98 99 import org.junit.Test; 100 import org.junit.runner.RunWith; 101 import org.junit.runners.Parameterized; 102 103 import java.util.ArrayList; 104 import java.util.Arrays; 105 import java.util.Comparator; 106 import java.util.HashSet; 107 import java.util.Iterator; 108 import java.util.List; 109 import java.util.Map; 110 import java.util.Set; 111 112 /** 113 * Tests exercising edge cases in camera setup, configuration, and usage. 114 */ 115 116 @RunWith(Parameterized.class) 117 public class RobustnessTest extends Camera2AndroidTestCase { 118 private static final String TAG = "RobustnessTest"; 119 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 120 121 private static final int CONFIGURE_TIMEOUT = 5000; //ms 122 private static final int CAPTURE_TIMEOUT = 1500; //ms 123 124 // For testTriggerInteractions 125 private static final int PREVIEW_WARMUP_FRAMES = 60; 126 private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100; 127 private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps 128 private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10; 129 130 /** 131 * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing 132 * a dimension other than one of the supported output dimensions. The buffers produced into 133 * this surface are expected have the dimensions of the closest possible buffer size in the 134 * available stream configurations for a surface with this format. 135 */ 136 @Test testBadSurfaceDimensions()137 public void testBadSurfaceDimensions() throws Exception { 138 for (String id : mCameraIdsUnderTest) { 139 try { 140 Log.i(TAG, "Testing Camera " + id); 141 openDevice(id); 142 143 List<Size> testSizes = null; 144 int format = mStaticInfo.isColorOutputSupported() ? 145 ImageFormat.YUV_420_888 : ImageFormat.DEPTH16; 146 147 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager, 148 format, null); 149 150 // Find some size not supported by the camera 151 Size weirdSize = new Size(643, 577); 152 int count = 0; 153 while(testSizes.contains(weirdSize)) { 154 // Really, they can't all be supported... 155 weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1); 156 count++; 157 assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100); 158 } 159 160 // Setup imageReader with invalid dimension 161 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(), 162 weirdSize.getHeight(), format, 3); 163 164 // Setup ImageReaderListener 165 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 166 imageReader.setOnImageAvailableListener(imageListener, mHandler); 167 168 Surface surface = imageReader.getSurface(); 169 List<Surface> surfaces = new ArrayList<>(); 170 surfaces.add(surface); 171 172 // Setup a capture request and listener 173 CaptureRequest.Builder request = 174 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 175 request.addTarget(surface); 176 177 // Check that correct session callback is hit. 178 CameraCaptureSession.StateCallback sessionListener = 179 mock(CameraCaptureSession.StateCallback.class); 180 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera, 181 surfaces, sessionListener, mHandler); 182 183 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 184 onConfigured(any(CameraCaptureSession.class)); 185 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()). 186 onReady(any(CameraCaptureSession.class)); 187 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class)); 188 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class)); 189 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class)); 190 191 CameraCaptureSession.CaptureCallback captureListener = 192 mock(CameraCaptureSession.CaptureCallback.class); 193 session.capture(request.build(), captureListener, mHandler); 194 195 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()). 196 onCaptureCompleted(any(CameraCaptureSession.class), 197 any(CaptureRequest.class), any(TotalCaptureResult.class)); 198 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class), 199 any(CaptureRequest.class), any(CaptureFailure.class)); 200 201 Image image = imageListener.getImage(CAPTURE_TIMEOUT); 202 int imageWidth = image.getWidth(); 203 int imageHeight = image.getHeight(); 204 Size actualSize = new Size(imageWidth, imageHeight); 205 206 assertTrue("Camera does not contain outputted image resolution " + actualSize, 207 testSizes.contains(actualSize)); 208 imageReader.close(); 209 } finally { 210 closeDevice(id); 211 } 212 } 213 } 214 215 /** 216 * Test for making sure the mandatory stream combinations work as expected. 217 */ 218 @Test testMandatoryOutputCombinations()219 public void testMandatoryOutputCombinations() throws Exception { 220 testMandatoryOutputCombinations(/*maxResolution*/false); 221 } 222 223 /** 224 * Test for making sure the mandatory stream combinations work as expected. 225 */ testMandatoryOutputCombinations(boolean maxResolution)226 private void testMandatoryOutputCombinations(boolean maxResolution) throws Exception { 227 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 228 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS; 229 230 if (maxResolution) { 231 ck = CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS; 232 } 233 for (String id : mCameraIdsUnderTest) { 234 openDevice(id); 235 MandatoryStreamCombination[] combinations = mStaticInfo.getCharacteristics().get(ck); 236 237 if (combinations == null) { 238 String maxResolutionStr = maxResolution ? " " : " maximum resolution "; 239 Log.i(TAG, "No mandatory" + maxResolutionStr + "stream combinations for camera: " + 240 id + " skip test"); 241 closeDevice(id); 242 continue; 243 } 244 245 try { 246 for (MandatoryStreamCombination combination : combinations) { 247 if (!combination.isReprocessable()) { 248 if (maxResolution) { 249 testMandatoryStreamCombination(id, mStaticInfo, 250 /*physicalCameraId*/ null, combination, /*substituteY8*/false, 251 /*substituteHeic*/false, /*maxResolution*/true); 252 } else { 253 testMandatoryStreamCombination(id, mStaticInfo, 254 null/*physicalCameraId*/, combination); 255 } 256 } 257 } 258 259 // Make sure mandatory stream combinations for each physical camera work 260 // as expected. 261 if (mStaticInfo.isLogicalMultiCamera()) { 262 Set<String> physicalCameraIds = 263 mStaticInfo.getCharacteristics().getPhysicalCameraIds(); 264 for (String physicalId : physicalCameraIds) { 265 if (Arrays.asList(mCameraIdsUnderTest).contains(physicalId)) { 266 // If physicalId is advertised in camera ID list, do not need to test 267 // its stream combination through logical camera. 268 continue; 269 } 270 StaticMetadata physicalStaticInfo = mAllStaticInfo.get(physicalId); 271 272 MandatoryStreamCombination[] phyCombinations = 273 physicalStaticInfo.getCharacteristics().get(ck); 274 275 if (phyCombinations == null) { 276 Log.i(TAG, "No mandatory stream combinations for physical camera device: " + id + " skip test"); 277 continue; 278 } 279 280 for (MandatoryStreamCombination combination : phyCombinations) { 281 if (!combination.isReprocessable()) { 282 if (maxResolution) { 283 testMandatoryStreamCombination(id, physicalStaticInfo, 284 physicalId, combination, /*substituteY8*/false, 285 /*substituteHeic*/false, /*maxResolution*/true); 286 } else { 287 testMandatoryStreamCombination(id, physicalStaticInfo, 288 physicalId, combination); 289 } 290 } 291 } 292 } 293 } 294 295 } finally { 296 closeDevice(id); 297 } 298 } 299 } 300 301 302 /** 303 * Test for making sure the mandatory stream combinations work as expected. 304 */ 305 @Test testMandatoryMaximumResolutionOutputCombinations()306 public void testMandatoryMaximumResolutionOutputCombinations() throws Exception { 307 testMandatoryOutputCombinations(/*maxResolution*/ true); 308 } 309 310 /** 311 * Test for making sure the mandatory use case stream combinations work as expected. 312 */ 313 @Test testMandatoryUseCaseOutputCombinations()314 public void testMandatoryUseCaseOutputCombinations() throws Exception { 315 for (String id : mCameraIdsUnderTest) { 316 StaticMetadata info = mAllStaticInfo.get(id); 317 CameraCharacteristics chars = info.getCharacteristics(); 318 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 319 CameraCharacteristics.SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS; 320 MandatoryStreamCombination[] combinations = chars.get(ck); 321 322 if (!info.isCapabilitySupported( 323 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) { 324 assertNull(combinations); 325 Log.i(TAG, "Camera id " + id + " doesn't support stream use case, skip test"); 326 continue; 327 } 328 329 assertNotNull(combinations); 330 openDevice(id); 331 332 try { 333 Rect preCorrectionActiveArrayRect = info.getPreCorrectedActiveArraySizeChecked(); 334 for (MandatoryStreamCombination combination : combinations) { 335 Log.i(TAG, "Testing fixed mandatory output combination with stream use case: " + 336 combination.getDescription() + " on camera: " + id); 337 CaptureRequest.Builder requestBuilder = 338 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 339 testMandatoryOutputCombinationWithPresetKeys(id, combination, requestBuilder, 340 preCorrectionActiveArrayRect); 341 } 342 } finally { 343 closeDevice(id); 344 } 345 } 346 } 347 348 @Test testMandatoryPreviewStabilizationOutputCombinations()349 public void testMandatoryPreviewStabilizationOutputCombinations() throws Exception { 350 for (String id : mCameraIdsUnderTest) { 351 StaticMetadata info = mAllStaticInfo.get(id); 352 boolean previewStabilizationSupported = isPreviewStabilizationSupported(info); 353 CameraCharacteristics chars = info.getCharacteristics(); 354 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 355 CameraCharacteristics 356 .SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS; 357 MandatoryStreamCombination[] combinations = chars.get(ck); 358 359 if (combinations == null) { 360 assertFalse("Preview stabilization supported by camera id: " + id 361 + " but null mandatory streams", previewStabilizationSupported); 362 Log.i(TAG, "Camera id " + id + " doesn't support preview stabilization, skip test"); 363 continue; 364 } else { 365 assertTrue("Preview stabilization not supported by camera id: " + id 366 + " but non-null mandatory streams", previewStabilizationSupported); 367 } 368 369 openDevice(id); 370 371 try { 372 for (MandatoryStreamCombination combination : combinations) { 373 Log.i(TAG, "Testing fixed mandatory output combination with preview" 374 + "stabilization case: " + combination.getDescription() + " on camera: " 375 + id); 376 CaptureRequest.Builder requestBuilder = 377 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 378 requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, 379 CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION); 380 testMandatoryOutputCombinationWithPresetKeys(id, combination, requestBuilder, 381 /*preCorrectionActiveArrayRect*/null); 382 } 383 } finally { 384 closeDevice(id); 385 } 386 } 387 } 388 isPreviewStabilizationSupported(StaticMetadata info)389 private boolean isPreviewStabilizationSupported(StaticMetadata info) { 390 int[] availableVideoStabilizationModes = info.getAvailableVideoStabilizationModesChecked(); 391 if (availableVideoStabilizationModes == null) { 392 return false; 393 } 394 for (int mode : availableVideoStabilizationModes) { 395 if (mode == CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) { 396 return true; 397 } 398 } 399 return false; 400 } 401 testMandatoryOutputCombinationWithPresetKeys(String cameraId, MandatoryStreamCombination combination, CaptureRequest.Builder requestBuilderWithKeys, Rect preCorrectionActiveArrayRect)402 private void testMandatoryOutputCombinationWithPresetKeys(String cameraId, 403 MandatoryStreamCombination combination, CaptureRequest.Builder requestBuilderWithKeys, 404 Rect preCorrectionActiveArrayRect) { 405 final int TIMEOUT_FOR_RESULT_MS = 1000; 406 final int MIN_RESULT_COUNT = 3; 407 408 // Setup outputs 409 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 410 List<Surface> outputSurfaces = new ArrayList<Surface>(); 411 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 412 StreamCombinationTargets targets = new StreamCombinationTargets(); 413 414 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 415 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 416 /*substituteY8*/ false, /*substituteHeic*/false, 417 /*physicalCameraId*/ null, 418 /*multiResStreamConfig*/null, mHandler, 419 /*dynamicRangeProfiles*/ null); 420 421 boolean haveSession = false; 422 try { 423 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 424 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 425 true/*defaultSupport*/, 426 String.format("Session configuration query from combination: %s failed", 427 combination.getDescription())); 428 429 createSessionByConfigs(outputConfigs); 430 haveSession = true; 431 for (Surface s : outputSurfaces) { 432 requestBuilderWithKeys.addTarget(s); 433 } 434 boolean croppedRawUseCase = false; 435 for (OutputConfiguration c : outputConfigs) { 436 if (c.getStreamUseCase() == 437 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW) { 438 croppedRawUseCase = true; 439 break; 440 } 441 } 442 443 CaptureRequest request = requestBuilderWithKeys.build(); 444 CameraTestUtils.SimpleCaptureCallback captureCallback = 445 new CameraTestUtils.SimpleCaptureCallback(); 446 447 448 mCameraSession.setRepeatingRequest(request, captureCallback, mHandler); 449 450 for (int i = 0; i < MIN_RESULT_COUNT; i++) { 451 // Makes sure that we received an onCaptureCompleted and not an onCaptureFailed. 452 TotalCaptureResult result = 453 captureCallback.getTotalCaptureResultForRequest(request, 454 /*numResultsWait*/ 0); 455 validateResultMandatoryConditions(result, croppedRawUseCase, 456 preCorrectionActiveArrayRect); 457 } 458 if (captureCallback.hasMoreFailures()) { 459 mCollector.addMessage("No capture failures expected, but there was a failure"); 460 } 461 462 } catch (Throwable e) { 463 mCollector.addMessage( 464 String.format("Closing down for combination: %s failed due to: %s", 465 combination.getDescription(), e.getMessage())); 466 } 467 468 if (haveSession) { 469 try { 470 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 471 cameraId, combination.getDescription())); 472 stopCapture(/*fast*/false); 473 } catch (Throwable e) { 474 mCollector.addMessage( 475 String.format("Closing down for combination: %s failed due to: %s", 476 combination.getDescription(), e.getMessage())); 477 } 478 } 479 480 targets.close(); 481 } 482 validateResultMandatoryConditions(TotalCaptureResult result, boolean croppedRawUseCase, Rect preCorrectionActiveArrayRect)483 private void validateResultMandatoryConditions(TotalCaptureResult result, 484 boolean croppedRawUseCase, Rect preCorrectionActiveArrayRect) { 485 // validate more conditions here 486 if (croppedRawUseCase) { 487 Rect rawCropRegion = result.get(CaptureResult.SCALER_RAW_CROP_REGION); 488 if (rawCropRegion == null) { 489 mCollector.addMessage("SCALER_RAW_CROP_REGION should not be null " + 490 "when CROPPED_RAW stream use case is used."); 491 } 492 if (!(preCorrectionActiveArrayRect.width() >= rawCropRegion.width() 493 && preCorrectionActiveArrayRect.height() >= rawCropRegion.height())) { 494 mCollector.addMessage("RAW_CROP_REGION dimensions should be <= pre correction" 495 + " array dimensions. SCALER_RAW_CROP_REGION : " 496 + rawCropRegion.flattenToString() + " pre correction active array is " 497 + preCorrectionActiveArrayRect.flattenToString()); 498 } 499 } 500 } 501 testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, String physicalCameraId, MandatoryStreamCombination combination)502 private void testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, 503 String physicalCameraId, MandatoryStreamCombination combination) throws Exception { 504 // Check whether substituting YUV_888 format with Y8 format 505 boolean substituteY8 = false; 506 if (staticInfo.isMonochromeWithY8()) { 507 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 508 for (MandatoryStreamInformation streamInfo : streamsInfo) { 509 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 510 substituteY8 = true; 511 break; 512 } 513 } 514 } 515 516 // Check whether substituting JPEG format with HEIC format 517 boolean substituteHeic = false; 518 if (staticInfo.isHeicSupported()) { 519 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 520 for (MandatoryStreamInformation streamInfo : streamsInfo) { 521 if (streamInfo.getFormat() == ImageFormat.JPEG) { 522 substituteHeic = true; 523 break; 524 } 525 } 526 } 527 528 // Test camera output combination 529 String log = "Testing mandatory stream combination: " + combination.getDescription() + 530 " on camera: " + cameraId; 531 if (physicalCameraId != null) { 532 log += ", physical sub-camera: " + physicalCameraId; 533 } 534 Log.i(TAG, log); 535 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 536 /*substituteY8*/false, /*substituteHeic*/false, /*maxResolution*/false); 537 538 if (substituteY8) { 539 Log.i(TAG, log + " with Y8"); 540 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 541 /*substituteY8*/true, /*substituteHeic*/false, /*maxResolution*/false); 542 } 543 544 if (substituteHeic) { 545 Log.i(TAG, log + " with HEIC"); 546 testMandatoryStreamCombination(cameraId, staticInfo, physicalCameraId, combination, 547 /*substituteY8*/false, /*substituteHeic*/true, /**maxResolution*/ false); 548 } 549 } 550 testMandatoryStreamCombination(String cameraId, StaticMetadata staticInfo, String physicalCameraId, MandatoryStreamCombination combination, boolean substituteY8, boolean substituteHeic, boolean ultraHighResolution)551 private void testMandatoryStreamCombination(String cameraId, 552 StaticMetadata staticInfo, String physicalCameraId, 553 MandatoryStreamCombination combination, 554 boolean substituteY8, boolean substituteHeic, boolean ultraHighResolution) 555 throws Exception { 556 // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS 557 // TODO: This needs to be adjusted based on feedback 558 final int TIMEOUT_MULTIPLIER = ultraHighResolution ? 2 : 1; 559 final int TIMEOUT_FOR_RESULT_MS = 560 ((staticInfo.isHardwareLevelLegacy()) ? 2000 : 1000) * TIMEOUT_MULTIPLIER; 561 final int MIN_RESULT_COUNT = 3; 562 563 // Set up outputs 564 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 565 List<Surface> outputSurfaces = new ArrayList<Surface>(); 566 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 567 StreamCombinationTargets targets = new StreamCombinationTargets(); 568 569 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 570 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 571 substituteY8, substituteHeic, physicalCameraId, /*multiResStreamConfig*/null, 572 mHandler); 573 574 boolean haveSession = false; 575 try { 576 CaptureRequest.Builder requestBuilder = 577 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 578 CaptureRequest.Builder uhRequestBuilder = 579 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 580 581 for (Surface s : outputSurfaces) { 582 requestBuilder.addTarget(s); 583 } 584 585 for (Surface s : uhOutputSurfaces) { 586 uhRequestBuilder.addTarget(s); 587 } 588 // We need to explicitly set the sensor pixel mode to default since we're mixing default 589 // and max resolution requests in the same capture session. 590 requestBuilder.set(CaptureRequest.SENSOR_PIXEL_MODE, 591 CameraMetadata.SENSOR_PIXEL_MODE_DEFAULT); 592 if (ultraHighResolution) { 593 uhRequestBuilder.set(CaptureRequest.SENSOR_PIXEL_MODE, 594 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION); 595 } 596 CameraCaptureSession.CaptureCallback mockCaptureCallback = 597 mock(CameraCaptureSession.CaptureCallback.class); 598 599 if (physicalCameraId == null) { 600 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 601 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 602 true/*defaultSupport*/, String.format( 603 "Session configuration query from combination: %s failed", 604 combination.getDescription())); 605 } else { 606 SessionConfigSupport sessionConfigSupport = isSessionConfigSupported( 607 mCamera, mHandler, outputConfigs, /*inputConfig*/ null, 608 SessionConfiguration.SESSION_REGULAR, false/*defaultSupport*/); 609 assertTrue( 610 String.format("Session configuration query from combination: %s failed", 611 combination.getDescription()), !sessionConfigSupport.error); 612 if (!sessionConfigSupport.callSupported) { 613 return; 614 } 615 assertTrue( 616 String.format("Session configuration must be supported for combination: " + 617 "%s", combination.getDescription()), sessionConfigSupport.configSupported); 618 } 619 620 createSessionByConfigs(outputConfigs); 621 haveSession = true; 622 CaptureRequest request = requestBuilder.build(); 623 CaptureRequest uhRequest = uhRequestBuilder.build(); 624 mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler); 625 if (ultraHighResolution) { 626 mCameraSession.capture(uhRequest, mockCaptureCallback, mHandler); 627 } 628 verify(mockCaptureCallback, 629 timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT)) 630 .onCaptureCompleted( 631 eq(mCameraSession), 632 eq(request), 633 isA(TotalCaptureResult.class)); 634 if (ultraHighResolution) { 635 verify(mockCaptureCallback, 636 timeout(TIMEOUT_FOR_RESULT_MS).atLeast(1)) 637 .onCaptureCompleted( 638 eq(mCameraSession), 639 eq(uhRequest), 640 isA(TotalCaptureResult.class)); 641 } 642 643 verify(mockCaptureCallback, never()). 644 onCaptureFailed( 645 eq(mCameraSession), 646 eq(request), 647 isA(CaptureFailure.class)); 648 649 } catch (Throwable e) { 650 mCollector.addMessage(String.format("Mandatory stream combination: %s failed due: %s", 651 combination.getDescription(), e.getMessage())); 652 } 653 if (haveSession) { 654 try { 655 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 656 cameraId, combination.getDescription())); 657 stopCapture(/*fast*/false); 658 } catch (Throwable e) { 659 mCollector.addMessage( 660 String.format("Closing down for combination: %s failed due to: %s", 661 combination.getDescription(), e.getMessage())); 662 } 663 } 664 665 targets.close(); 666 } 667 668 /** 669 * Test for making sure the required 10-bit stream combinations work as expected. 670 * Since we have too many possible combinations between different 8-bit vs. 10-bit as well 671 * as 10-bit dynamic profiles and in order to maximize the coverage within some reasonable 672 * amount of iterations, the test case will configure 8-bit and 10-bit outputs randomly. In case 673 * we have 10-bit output, then the dynamic range profile will also be randomly picked. 674 */ 675 @Test testMandatory10BitStreamCombinations()676 public void testMandatory10BitStreamCombinations() throws Exception { 677 for (String id : mCameraIdsUnderTest) { 678 openDevice(id); 679 CameraCharacteristics chars = mStaticInfo.getCharacteristics(); 680 if (!CameraTestUtils.hasCapability( 681 chars, CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 682 Log.i(TAG, "Camera id " + id + " doesn't support 10-bit output, skip test"); 683 closeDevice(id); 684 continue; 685 } 686 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 687 CameraCharacteristics.SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS; 688 689 MandatoryStreamCombination[] combinations = chars.get(ck); 690 assertNotNull(combinations); 691 692 try { 693 for (MandatoryStreamCombination combination : combinations) { 694 Log.i(TAG, "Testing fixed mandatory 10-bit output stream combination: " + 695 combination.getDescription() + " on camera: " + id); 696 DynamicRangeProfiles profiles = mStaticInfo.getCharacteristics().get( 697 CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES); 698 assertNotNull(profiles); 699 700 // First we want to make sure that a fixed set of 10-bit streams 701 // is functional 702 for (Long profile : profiles.getSupportedProfiles()) { 703 if (profile != DynamicRangeProfiles.STANDARD) { 704 ArrayList<Long> testProfiles = new ArrayList<Long>(); 705 testProfiles.add(profile); 706 testMandatory10BitStreamCombination(id, combination, profiles, 707 testProfiles); 708 } 709 } 710 711 Log.i(TAG, "Testing random mandatory 10-bit output stream combination: " + 712 combination.getDescription() + " on camera: " + id); 713 // Next try out a random mix of standard 8-bit and 10-bit profiles. 714 // The number of possible combinations is quite big and testing them 715 // all on physical hardware can become unfeasible. 716 ArrayList<Long> testProfiles = new ArrayList<>( 717 profiles.getSupportedProfiles()); 718 testMandatory10BitStreamCombination(id, combination, profiles, testProfiles); 719 } 720 } finally { 721 closeDevice(id); 722 } 723 } 724 } 725 testMandatory10BitStreamCombination(String cameraId, MandatoryStreamCombination combination, DynamicRangeProfiles profiles, List<Long> testProfiles)726 private void testMandatory10BitStreamCombination(String cameraId, 727 MandatoryStreamCombination combination, DynamicRangeProfiles profiles, 728 List<Long> testProfiles) { 729 final int TIMEOUT_FOR_RESULT_MS = 1000; 730 final int MIN_RESULT_COUNT = 3; 731 732 // Setup outputs 733 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 734 List<Surface> outputSurfaces = new ArrayList<Surface>(); 735 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 736 StreamCombinationTargets targets = new StreamCombinationTargets(); 737 738 CameraTestUtils.setupConfigurationTargets(combination.getStreamsInformation(), 739 targets, outputConfigs, outputSurfaces, uhOutputSurfaces, MIN_RESULT_COUNT, 740 /*substituteY8*/ false, /*substituteHeic*/false, 741 /*physicalCameraId*/ null, 742 /*multiResStreamConfig*/null, mHandler, 743 testProfiles); 744 745 try { 746 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, 747 /*inputConfig*/ null, SessionConfiguration.SESSION_REGULAR, 748 true/*defaultSupport*/, 749 String.format("Session configuration query from combination: %s failed", 750 combination.getDescription())); 751 752 createSessionByConfigs(outputConfigs); 753 754 boolean constraintPresent = false; 755 List<Surface> constrainedOutputs = new ArrayList<>(outputSurfaces); 756 757 while (!outputSurfaces.isEmpty()) { 758 CaptureRequest.Builder requestBuilder = 759 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 760 // Check to see how many outputs can be combined in to a single request including 761 // the first output surface and respecting the advertised constraints 762 Iterator<OutputConfiguration> it = outputConfigs.iterator(); 763 OutputConfiguration config = it.next(); 764 HashSet<Long> currentProfiles = new HashSet<>(); 765 currentProfiles.add(config.getDynamicRangeProfile()); 766 requestBuilder.addTarget(config.getSurface()); 767 outputSurfaces.remove(config.getSurface()); 768 it.remove(); 769 while (it.hasNext()) { 770 config = it.next(); 771 Long currentProfile = config.getDynamicRangeProfile(); 772 Set<Long> newLimitations = profiles.getProfileCaptureRequestConstraints( 773 currentProfile); 774 if (newLimitations.isEmpty() || (newLimitations.containsAll(currentProfiles))) { 775 currentProfiles.add(currentProfile); 776 requestBuilder.addTarget(config.getSurface()); 777 outputSurfaces.remove(config.getSurface()); 778 it.remove(); 779 } else if (!constraintPresent && !newLimitations.isEmpty() && 780 !newLimitations.containsAll(currentProfiles)) { 781 constraintPresent = true; 782 } 783 } 784 785 CaptureRequest request = requestBuilder.build(); 786 CameraCaptureSession.CaptureCallback mockCaptureCallback = 787 mock(CameraCaptureSession.CaptureCallback.class); 788 mCameraSession.capture(request, mockCaptureCallback, mHandler); 789 verify(mockCaptureCallback, 790 timeout(TIMEOUT_FOR_RESULT_MS).atLeastOnce()) 791 .onCaptureCompleted( 792 eq(mCameraSession), 793 eq(request), 794 isA(TotalCaptureResult.class)); 795 796 verify(mockCaptureCallback, never()). 797 onCaptureFailed( 798 eq(mCameraSession), 799 eq(request), 800 isA(CaptureFailure.class)); 801 } 802 803 if (constraintPresent) { 804 // Capture requests that include output surfaces with dynamic range profiles that 805 // cannot be combined must throw a corresponding exception 806 CaptureRequest.Builder requestBuilder = 807 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 808 for (Surface s : constrainedOutputs) { 809 requestBuilder.addTarget(s); 810 } 811 812 CaptureRequest request = requestBuilder.build(); 813 CameraCaptureSession.CaptureCallback mockCaptureCallback = 814 mock(CameraCaptureSession.CaptureCallback.class); 815 try { 816 mCameraSession.capture(request, mockCaptureCallback, mHandler); 817 fail("Capture request to outputs with incompatible dynamic range profiles " 818 + "must always fail!"); 819 } catch (IllegalArgumentException e) { 820 // Expected 821 } 822 } 823 824 Log.i(TAG, String.format("Done with camera %s, combination: %s, closing session", 825 cameraId, combination.getDescription())); 826 } catch (Throwable e) { 827 mCollector.addMessage( 828 String.format("Closing down for combination: %s failed due to: %s", 829 combination.getDescription(), e.getMessage())); 830 } 831 832 targets.close(); 833 } 834 835 /** 836 * Test for making sure the required reprocess input/output combinations for each hardware 837 * level and capability work as expected. 838 */ 839 @Test testMandatoryReprocessConfigurations()840 public void testMandatoryReprocessConfigurations() throws Exception { 841 testMandatoryReprocessConfigurations(/*maxResolution*/false); 842 } 843 844 /** 845 * Test for making sure the required reprocess input/output combinations for each hardware 846 * level and capability work as expected. 847 */ 848 @Test testMandatoryMaximumResolutionReprocessConfigurations()849 public void testMandatoryMaximumResolutionReprocessConfigurations() throws Exception { 850 testMandatoryReprocessConfigurations(/*maxResolution*/true); 851 } 852 853 /** 854 * Test for making sure the required reprocess input/output combinations for each hardware 855 * level and capability work as expected. 856 */ testMandatoryReprocessConfigurations(boolean maxResolution)857 public void testMandatoryReprocessConfigurations(boolean maxResolution) throws Exception { 858 for (String id : mCameraIdsUnderTest) { 859 openDevice(id); 860 CameraCharacteristics chars = mStaticInfo.getCharacteristics(); 861 if (maxResolution && !CameraTestUtils.hasCapability( 862 chars, CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING)) { 863 Log.i(TAG, "Camera id " + id + "doesn't support REMOSAIC_REPROCESSING, skip test"); 864 closeDevice(id); 865 continue; 866 } 867 CameraCharacteristics.Key<MandatoryStreamCombination []> ck = 868 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS; 869 870 if (maxResolution) { 871 ck = CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS; 872 } 873 874 MandatoryStreamCombination[] combinations = chars.get(ck); 875 if (combinations == null) { 876 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 877 closeDevice(id); 878 continue; 879 } 880 881 try { 882 for (MandatoryStreamCombination combination : combinations) { 883 if (combination.isReprocessable()) { 884 Log.i(TAG, "Testing mandatory reprocessable stream combination: " + 885 combination.getDescription() + " on camera: " + id); 886 testMandatoryReprocessableStreamCombination(id, combination, maxResolution); 887 } 888 } 889 } finally { 890 closeDevice(id); 891 } 892 } 893 } 894 testMandatoryReprocessableStreamCombination(String cameraId, MandatoryStreamCombination combination, boolean maxResolution)895 private void testMandatoryReprocessableStreamCombination(String cameraId, 896 MandatoryStreamCombination combination, boolean maxResolution) throws Exception { 897 // Test reprocess stream combination 898 testMandatoryReprocessableStreamCombination(cameraId, combination, 899 /*substituteY8*/false, /*substituteHeic*/false, maxResolution/*maxResolution*/); 900 if (maxResolution) { 901 // Maximum resolution mode doesn't guarantee HEIC and Y8 streams. 902 return; 903 } 904 905 // Test substituting YUV_888 format with Y8 format in reprocess stream combination. 906 if (mStaticInfo.isMonochromeWithY8()) { 907 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 908 boolean substituteY8 = false; 909 for (MandatoryStreamInformation streamInfo : streamsInfo) { 910 if (streamInfo.getFormat() == ImageFormat.YUV_420_888) { 911 substituteY8 = true; 912 } 913 } 914 if (substituteY8) { 915 testMandatoryReprocessableStreamCombination(cameraId, combination, 916 /*substituteY8*/true, /*substituteHeic*/false, false/*maxResolution*/); 917 } 918 } 919 920 if (mStaticInfo.isHeicSupported()) { 921 List<MandatoryStreamInformation> streamsInfo = combination.getStreamsInformation(); 922 boolean substituteHeic = false; 923 for (MandatoryStreamInformation streamInfo : streamsInfo) { 924 if (streamInfo.getFormat() == ImageFormat.JPEG) { 925 substituteHeic = true; 926 } 927 } 928 if (substituteHeic) { 929 testMandatoryReprocessableStreamCombination(cameraId, combination, 930 /*substituteY8*/false, /*substituteHeic*/true, false/*maxResolution*/); 931 } 932 } 933 } 934 testMandatoryReprocessableStreamCombination(String cameraId, MandatoryStreamCombination combination, boolean substituteY8, boolean substituteHeic, boolean maxResolution)935 private void testMandatoryReprocessableStreamCombination(String cameraId, 936 MandatoryStreamCombination combination, boolean substituteY8, 937 boolean substituteHeic, boolean maxResolution) throws Exception { 938 939 final int TIMEOUT_MULTIPLIER = maxResolution ? 2 : 1; 940 final int TIMEOUT_FOR_RESULT_MS = 5000 * TIMEOUT_MULTIPLIER; 941 final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3; 942 943 StreamCombinationTargets targets = new StreamCombinationTargets(); 944 ArrayList<Surface> defaultOutputSurfaces = new ArrayList<>(); 945 ArrayList<Surface> allOutputSurfaces = new ArrayList<>(); 946 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 947 List<Surface> uhOutputSurfaces = new ArrayList<Surface>(); 948 ImageReader inputReader = null; 949 ImageWriter inputWriter = null; 950 SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener(); 951 SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback(); 952 SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback(); 953 954 List<MandatoryStreamInformation> streamInfo = combination.getStreamsInformation(); 955 assertTrue("Reprocessable stream combinations should have at least 3 or more streams", 956 (streamInfo != null) && (streamInfo.size() >= 3)); 957 958 assertTrue("The first mandatory stream information in a reprocessable combination must " + 959 "always be input", streamInfo.get(0).isInput()); 960 961 List<Size> inputSizes = streamInfo.get(0).getAvailableSizes(); 962 int inputFormat = streamInfo.get(0).getFormat(); 963 if (substituteY8 && (inputFormat == ImageFormat.YUV_420_888)) { 964 inputFormat = ImageFormat.Y8; 965 } 966 967 Log.i(TAG, "testMandatoryReprocessableStreamCombination: " + 968 combination.getDescription() + ", substituteY8 = " + substituteY8 + 969 ", substituteHeic = " + substituteHeic); 970 try { 971 // The second stream information entry is the ZSL stream, which is configured 972 // separately. 973 List<MandatoryStreamInformation> mandatoryStreamInfos = null; 974 mandatoryStreamInfos = new ArrayList<MandatoryStreamInformation>(); 975 mandatoryStreamInfos = streamInfo.subList(2, streamInfo.size()); 976 CameraTestUtils.setupConfigurationTargets(mandatoryStreamInfos, targets, 977 outputConfigs, defaultOutputSurfaces, uhOutputSurfaces, 978 NUM_REPROCESS_CAPTURES_PER_CONFIG, 979 substituteY8, substituteHeic, null/*overridePhysicalCameraId*/, 980 /*multiResStreamConfig*/null, mHandler); 981 allOutputSurfaces.addAll(defaultOutputSurfaces); 982 allOutputSurfaces.addAll(uhOutputSurfaces); 983 InputConfiguration inputConfig = new InputConfiguration(inputSizes.get(0).getWidth(), 984 inputSizes.get(0).getHeight(), inputFormat); 985 986 // For each config, YUV and JPEG outputs will be tested. (For YUV/Y8 reprocessing, 987 // the YUV/Y8 ImageReader for input is also used for output.) 988 final boolean inputIsYuv = inputConfig.getFormat() == ImageFormat.YUV_420_888; 989 final boolean inputIsY8 = inputConfig.getFormat() == ImageFormat.Y8; 990 final boolean useYuv = inputIsYuv || targets.mYuvTargets.size() > 0; 991 final boolean useY8 = inputIsY8 || targets.mY8Targets.size() > 0; 992 final int totalNumReprocessCaptures = NUM_REPROCESS_CAPTURES_PER_CONFIG * 993 (maxResolution ? 1 : (((inputIsYuv || inputIsY8) ? 1 : 0) + 994 (substituteHeic ? targets.mHeicTargets.size() : targets.mJpegTargets.size()) + 995 (useYuv ? targets.mYuvTargets.size() : targets.mY8Targets.size()))); 996 997 // It needs 1 input buffer for each reprocess capture + the number of buffers 998 // that will be used as outputs. 999 inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(), 1000 inputConfig.getFormat(), 1001 totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG); 1002 inputReader.setOnImageAvailableListener(inputReaderListener, mHandler); 1003 allOutputSurfaces.add(inputReader.getSurface()); 1004 1005 checkSessionConfigurationWithSurfaces(mCamera, mHandler, allOutputSurfaces, 1006 inputConfig, SessionConfiguration.SESSION_REGULAR, /*defaultSupport*/ true, 1007 String.format("Session configuration query %s failed", 1008 combination.getDescription())); 1009 1010 // Verify we can create a reprocessable session with the input and all outputs. 1011 BlockingSessionCallback sessionListener = new BlockingSessionCallback(); 1012 CameraCaptureSession session = configureReprocessableCameraSession(mCamera, 1013 inputConfig, allOutputSurfaces, sessionListener, mHandler); 1014 inputWriter = ImageWriter.newInstance(session.getInputSurface(), 1015 totalNumReprocessCaptures); 1016 1017 // Prepare a request for reprocess input 1018 CaptureRequest.Builder builder = mCamera.createCaptureRequest( 1019 CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG); 1020 builder.addTarget(inputReader.getSurface()); 1021 if (maxResolution) { 1022 builder.set(CaptureRequest.SENSOR_PIXEL_MODE, 1023 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION); 1024 } 1025 1026 for (int i = 0; i < totalNumReprocessCaptures; i++) { 1027 session.capture(builder.build(), inputCaptureListener, mHandler); 1028 } 1029 1030 List<CaptureRequest> reprocessRequests = new ArrayList<>(); 1031 List<Surface> reprocessOutputs = new ArrayList<>(); 1032 1033 if (maxResolution) { 1034 if (uhOutputSurfaces.size() == 0) { // RAW -> RAW reprocessing 1035 reprocessOutputs.add(inputReader.getSurface()); 1036 } else { 1037 for (Surface surface : uhOutputSurfaces) { 1038 reprocessOutputs.add(surface); 1039 } 1040 } 1041 } else { 1042 if (inputIsYuv || inputIsY8) { 1043 reprocessOutputs.add(inputReader.getSurface()); 1044 } 1045 1046 for (ImageReader reader : targets.mJpegTargets) { 1047 reprocessOutputs.add(reader.getSurface()); 1048 } 1049 1050 for (ImageReader reader : targets.mHeicTargets) { 1051 reprocessOutputs.add(reader.getSurface()); 1052 } 1053 1054 for (ImageReader reader : targets.mYuvTargets) { 1055 reprocessOutputs.add(reader.getSurface()); 1056 } 1057 1058 for (ImageReader reader : targets.mY8Targets) { 1059 reprocessOutputs.add(reader.getSurface()); 1060 } 1061 } 1062 1063 for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 1064 for (Surface output : reprocessOutputs) { 1065 TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult( 1066 TIMEOUT_FOR_RESULT_MS); 1067 builder = mCamera.createReprocessCaptureRequest(result); 1068 inputWriter.queueInputImage( 1069 inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS)); 1070 builder.addTarget(output); 1071 reprocessRequests.add(builder.build()); 1072 } 1073 } 1074 1075 session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler); 1076 1077 for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) { 1078 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult( 1079 TIMEOUT_FOR_RESULT_MS); 1080 } 1081 } catch (Throwable e) { 1082 mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s", 1083 combination.getDescription(), e.getMessage())); 1084 } finally { 1085 inputReaderListener.drain(); 1086 reprocessOutputCaptureListener.drain(); 1087 targets.close(); 1088 1089 if (inputReader != null) { 1090 inputReader.close(); 1091 } 1092 1093 if (inputWriter != null) { 1094 inputWriter.close(); 1095 } 1096 } 1097 } 1098 1099 @Test testBasicTriggerSequence()1100 public void testBasicTriggerSequence() throws Exception { 1101 1102 for (String id : mCameraIdsUnderTest) { 1103 Log.i(TAG, String.format("Testing Camera %s", id)); 1104 1105 try { 1106 // Legacy devices do not support precapture trigger; don't test devices that 1107 // can't focus 1108 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1109 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1110 continue; 1111 } 1112 // Depth-only devices won't support AE 1113 if (!staticInfo.isColorOutputSupported()) { 1114 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1115 continue; 1116 } 1117 1118 openDevice(id); 1119 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1120 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1121 1122 for (int afMode : availableAfModes) { 1123 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1124 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1125 // Only test AF modes that have meaningful trigger behavior 1126 continue; 1127 } 1128 1129 for (int aeMode : availableAeModes) { 1130 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1131 // Only test AE modes that have meaningful trigger behavior 1132 continue; 1133 } 1134 1135 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1136 1137 CaptureRequest.Builder previewRequest = 1138 prepareTriggerTestSession(preview, aeMode, afMode); 1139 1140 SimpleCaptureCallback captureListener = 1141 new CameraTestUtils.SimpleCaptureCallback(); 1142 1143 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1144 mHandler); 1145 1146 // Cancel triggers 1147 1148 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1149 1150 // 1151 // Standard sequence - AF trigger then AE trigger 1152 1153 if (VERBOSE) { 1154 Log.v(TAG, String.format("Triggering AF")); 1155 } 1156 1157 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1158 CaptureRequest.CONTROL_AF_TRIGGER_START); 1159 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1160 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1161 1162 CaptureRequest triggerRequest = previewRequest.build(); 1163 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1164 1165 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1166 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1167 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1168 boolean focusComplete = false; 1169 1170 for (int i = 0; 1171 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 1172 i++) { 1173 1174 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1175 1176 CaptureResult focusResult = captureListener.getCaptureResult( 1177 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1178 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 1179 } 1180 1181 assertTrue("Focusing never completed!", focusComplete); 1182 1183 // Standard sequence - Part 2 AE trigger 1184 1185 if (VERBOSE) { 1186 Log.v(TAG, String.format("Triggering AE")); 1187 } 1188 1189 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1190 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1191 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1192 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1193 1194 triggerRequest = previewRequest.build(); 1195 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1196 1197 triggerResult = captureListener.getCaptureResultForRequest( 1198 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1199 1200 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1201 1202 boolean precaptureComplete = false; 1203 1204 for (int i = 0; 1205 i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete; 1206 i++) { 1207 1208 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1209 1210 CaptureResult precaptureResult = captureListener.getCaptureResult( 1211 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1212 aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE); 1213 } 1214 1215 assertTrue("Precapture sequence never completed!", precaptureComplete); 1216 1217 for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) { 1218 CaptureResult postPrecaptureResult = captureListener.getCaptureResult( 1219 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1220 aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE); 1221 assertTrue("Late transition to PRECAPTURE state seen", 1222 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1223 } 1224 1225 // Done 1226 1227 stopCapture(/*fast*/ false); 1228 preview.release(); 1229 } 1230 1231 } 1232 1233 } finally { 1234 closeDevice(id); 1235 } 1236 } 1237 1238 } 1239 1240 @Test testSimultaneousTriggers()1241 public void testSimultaneousTriggers() throws Exception { 1242 for (String id : mCameraIdsUnderTest) { 1243 Log.i(TAG, String.format("Testing Camera %s", id)); 1244 1245 try { 1246 // Legacy devices do not support precapture trigger; don't test devices that 1247 // can't focus 1248 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1249 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1250 continue; 1251 } 1252 // Depth-only devices won't support AE 1253 if (!staticInfo.isColorOutputSupported()) { 1254 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1255 continue; 1256 } 1257 1258 openDevice(id); 1259 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1260 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1261 1262 for (int afMode : availableAfModes) { 1263 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1264 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1265 // Only test AF modes that have meaningful trigger behavior 1266 continue; 1267 } 1268 1269 for (int aeMode : availableAeModes) { 1270 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1271 // Only test AE modes that have meaningful trigger behavior 1272 continue; 1273 } 1274 1275 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1276 1277 CaptureRequest.Builder previewRequest = 1278 prepareTriggerTestSession(preview, aeMode, afMode); 1279 1280 SimpleCaptureCallback captureListener = 1281 new CameraTestUtils.SimpleCaptureCallback(); 1282 1283 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1284 mHandler); 1285 1286 // Cancel triggers 1287 1288 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1289 1290 // 1291 // Trigger AF and AE together 1292 1293 if (VERBOSE) { 1294 Log.v(TAG, String.format("Triggering AF and AE together")); 1295 } 1296 1297 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1298 CaptureRequest.CONTROL_AF_TRIGGER_START); 1299 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1300 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1301 1302 CaptureRequest triggerRequest = previewRequest.build(); 1303 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1304 1305 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1306 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1307 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1308 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1309 1310 boolean precaptureComplete = false; 1311 boolean focusComplete = false; 1312 1313 for (int i = 0; 1314 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1315 !(focusComplete && precaptureComplete); 1316 i++) { 1317 1318 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1319 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1320 1321 CaptureResult sequenceResult = captureListener.getCaptureResult( 1322 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1323 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1324 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1325 } 1326 1327 assertTrue("Precapture sequence never completed!", precaptureComplete); 1328 assertTrue("Focus sequence never completed!", focusComplete); 1329 1330 // Done 1331 1332 stopCapture(/*fast*/ false); 1333 preview.release(); 1334 1335 } 1336 } 1337 } finally { 1338 closeDevice(id); 1339 } 1340 } 1341 } 1342 1343 @Test testAfThenAeTrigger()1344 public void testAfThenAeTrigger() throws Exception { 1345 for (String id : mCameraIdsUnderTest) { 1346 Log.i(TAG, String.format("Testing Camera %s", id)); 1347 1348 try { 1349 // Legacy devices do not support precapture trigger; don't test devices that 1350 // can't focus 1351 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1352 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1353 continue; 1354 } 1355 // Depth-only devices won't support AE 1356 if (!staticInfo.isColorOutputSupported()) { 1357 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1358 continue; 1359 } 1360 1361 openDevice(id); 1362 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1363 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1364 1365 for (int afMode : availableAfModes) { 1366 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1367 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1368 // Only test AF modes that have meaningful trigger behavior 1369 continue; 1370 } 1371 1372 for (int aeMode : availableAeModes) { 1373 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1374 // Only test AE modes that have meaningful trigger behavior 1375 continue; 1376 } 1377 1378 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1379 1380 CaptureRequest.Builder previewRequest = 1381 prepareTriggerTestSession(preview, aeMode, afMode); 1382 1383 SimpleCaptureCallback captureListener = 1384 new CameraTestUtils.SimpleCaptureCallback(); 1385 1386 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1387 mHandler); 1388 1389 // Cancel triggers 1390 1391 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1392 1393 // 1394 // AF with AE a request later 1395 1396 if (VERBOSE) { 1397 Log.v(TAG, "Trigger AF, then AE trigger on next request"); 1398 } 1399 1400 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1401 CaptureRequest.CONTROL_AF_TRIGGER_START); 1402 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1403 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1404 1405 CaptureRequest triggerRequest = previewRequest.build(); 1406 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1407 1408 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1409 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1410 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1411 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1412 1413 CaptureRequest triggerRequest2 = previewRequest.build(); 1414 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1415 1416 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1417 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1418 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1419 1420 boolean precaptureComplete = false; 1421 boolean focusComplete = false; 1422 1423 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1424 1425 triggerResult = captureListener.getCaptureResultForRequest( 1426 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1427 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1428 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1429 1430 for (int i = 0; 1431 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1432 !(focusComplete && precaptureComplete); 1433 i++) { 1434 1435 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1436 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1437 1438 CaptureResult sequenceResult = captureListener.getCaptureResult( 1439 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1440 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1441 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1442 } 1443 1444 assertTrue("Precapture sequence never completed!", precaptureComplete); 1445 assertTrue("Focus sequence never completed!", focusComplete); 1446 1447 // Done 1448 1449 stopCapture(/*fast*/ false); 1450 preview.release(); 1451 1452 } 1453 } 1454 } finally { 1455 closeDevice(id); 1456 } 1457 } 1458 } 1459 1460 @Test testAeThenAfTrigger()1461 public void testAeThenAfTrigger() throws Exception { 1462 for (String id : mCameraIdsUnderTest) { 1463 Log.i(TAG, String.format("Testing Camera %s", id)); 1464 1465 try { 1466 // Legacy devices do not support precapture trigger; don't test devices that 1467 // can't focus 1468 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1469 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1470 continue; 1471 } 1472 // Depth-only devices won't support AE 1473 if (!staticInfo.isColorOutputSupported()) { 1474 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1475 continue; 1476 } 1477 1478 openDevice(id); 1479 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1480 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1481 1482 for (int afMode : availableAfModes) { 1483 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1484 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1485 // Only test AF modes that have meaningful trigger behavior 1486 continue; 1487 } 1488 1489 for (int aeMode : availableAeModes) { 1490 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1491 // Only test AE modes that have meaningful trigger behavior 1492 continue; 1493 } 1494 1495 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1496 1497 CaptureRequest.Builder previewRequest = 1498 prepareTriggerTestSession(preview, aeMode, afMode); 1499 1500 SimpleCaptureCallback captureListener = 1501 new CameraTestUtils.SimpleCaptureCallback(); 1502 1503 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1504 mHandler); 1505 1506 // Cancel triggers 1507 1508 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1509 1510 // 1511 // AE with AF a request later 1512 1513 if (VERBOSE) { 1514 Log.v(TAG, "Trigger AE, then AF trigger on next request"); 1515 } 1516 1517 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1518 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1519 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1520 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1521 1522 CaptureRequest triggerRequest = previewRequest.build(); 1523 mCameraSession.capture(triggerRequest, captureListener, mHandler); 1524 1525 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1526 CaptureRequest.CONTROL_AF_TRIGGER_START); 1527 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1528 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1529 1530 CaptureRequest triggerRequest2 = previewRequest.build(); 1531 mCameraSession.capture(triggerRequest2, captureListener, mHandler); 1532 1533 CaptureResult triggerResult = captureListener.getCaptureResultForRequest( 1534 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1535 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1536 1537 boolean precaptureComplete = false; 1538 boolean focusComplete = false; 1539 1540 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1541 1542 triggerResult = captureListener.getCaptureResultForRequest( 1543 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1544 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1545 aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1546 1547 for (int i = 0; 1548 i < MAX_TRIGGER_SEQUENCE_FRAMES && 1549 !(focusComplete && precaptureComplete); 1550 i++) { 1551 1552 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1553 precaptureComplete = verifyAeSequence(aeState, precaptureComplete); 1554 1555 CaptureResult sequenceResult = captureListener.getCaptureResult( 1556 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1557 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE); 1558 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE); 1559 } 1560 1561 assertTrue("Precapture sequence never completed!", precaptureComplete); 1562 assertTrue("Focus sequence never completed!", focusComplete); 1563 1564 // Done 1565 1566 stopCapture(/*fast*/ false); 1567 preview.release(); 1568 1569 } 1570 } 1571 } finally { 1572 closeDevice(id); 1573 } 1574 } 1575 } 1576 1577 @Test testAeAndAfCausality()1578 public void testAeAndAfCausality() throws Exception { 1579 1580 for (String id : mCameraIdsUnderTest) { 1581 Log.i(TAG, String.format("Testing Camera %s", id)); 1582 1583 try { 1584 // Legacy devices do not support precapture trigger; don't test devices that 1585 // can't focus 1586 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1587 if (staticInfo.isHardwareLevelLegacy() || !staticInfo.hasFocuser()) { 1588 continue; 1589 } 1590 // Depth-only devices won't support AE 1591 if (!staticInfo.isColorOutputSupported()) { 1592 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 1593 continue; 1594 } 1595 1596 openDevice(id); 1597 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1598 int[] availableAeModes = mStaticInfo.getAeAvailableModesChecked(); 1599 final int maxPipelineDepth = mStaticInfo.getCharacteristics().get( 1600 CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH); 1601 1602 for (int afMode : availableAfModes) { 1603 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF || 1604 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) { 1605 // Only test AF modes that have meaningful trigger behavior 1606 continue; 1607 } 1608 for (int aeMode : availableAeModes) { 1609 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) { 1610 // Only test AE modes that have meaningful trigger behavior 1611 continue; 1612 } 1613 1614 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1615 1616 CaptureRequest.Builder previewRequest = 1617 prepareTriggerTestSession(preview, aeMode, afMode); 1618 1619 SimpleCaptureCallback captureListener = 1620 new CameraTestUtils.SimpleCaptureCallback(); 1621 1622 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener, 1623 mHandler); 1624 1625 List<CaptureRequest> triggerRequests = 1626 new ArrayList<CaptureRequest>(maxPipelineDepth+1); 1627 for (int i = 0; i < maxPipelineDepth; i++) { 1628 triggerRequests.add(previewRequest.build()); 1629 } 1630 1631 // Cancel triggers 1632 cancelTriggersAndWait(previewRequest, captureListener, afMode); 1633 1634 // 1635 // Standard sequence - Part 1 AF trigger 1636 1637 if (VERBOSE) { 1638 Log.v(TAG, String.format("Triggering AF")); 1639 } 1640 1641 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1642 CaptureRequest.CONTROL_AF_TRIGGER_START); 1643 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1644 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE); 1645 triggerRequests.add(previewRequest.build()); 1646 1647 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1648 1649 TotalCaptureResult[] triggerResults = 1650 captureListener.getTotalCaptureResultsForRequests( 1651 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1652 for (int i = 0; i < maxPipelineDepth; i++) { 1653 TotalCaptureResult triggerResult = triggerResults[i]; 1654 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1655 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1656 1657 verifyStartingAfState(afMode, afState); 1658 assertTrue(String.format("In AF mode %s, previous AF_TRIGGER must not " 1659 + "be START before TRIGGER_START", 1660 StaticMetadata.getAfModeName(afMode)), 1661 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_START); 1662 } 1663 1664 int afState = 1665 triggerResults[maxPipelineDepth].get(CaptureResult.CONTROL_AF_STATE); 1666 boolean focusComplete = false; 1667 for (int i = 0; 1668 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete; 1669 i++) { 1670 1671 focusComplete = verifyAfSequence(afMode, afState, focusComplete); 1672 1673 CaptureResult focusResult = captureListener.getCaptureResult( 1674 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 1675 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE); 1676 } 1677 1678 assertTrue("Focusing never completed!", focusComplete); 1679 1680 // Standard sequence - Part 2 AE trigger 1681 1682 if (VERBOSE) { 1683 Log.v(TAG, String.format("Triggering AE")); 1684 } 1685 // Remove AF trigger request 1686 triggerRequests.remove(maxPipelineDepth); 1687 1688 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1689 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 1690 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 1691 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1692 triggerRequests.add(previewRequest.build()); 1693 1694 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1695 1696 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1697 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1698 1699 for (int i = 0; i < maxPipelineDepth; i++) { 1700 TotalCaptureResult triggerResult = triggerResults[i]; 1701 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE); 1702 int aeTrigger = triggerResult.get( 1703 CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER); 1704 1705 assertTrue(String.format("In AE mode %s, previous AE_TRIGGER must not " 1706 + "be START before TRIGGER_START", 1707 StaticMetadata.getAeModeName(aeMode)), 1708 aeTrigger != CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_START); 1709 assertTrue(String.format("In AE mode %s, previous AE_STATE must not be" 1710 + " PRECAPTURE_TRIGGER before TRIGGER_START", 1711 StaticMetadata.getAeModeName(aeMode)), 1712 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 1713 } 1714 1715 // Stand sequence - Part 3 Cancel AF trigger 1716 if (VERBOSE) { 1717 Log.v(TAG, String.format("Cancel AF trigger")); 1718 } 1719 // Remove AE trigger request 1720 triggerRequests.remove(maxPipelineDepth); 1721 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 1722 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 1723 triggerRequests.add(previewRequest.build()); 1724 1725 mCameraSession.captureBurst(triggerRequests, captureListener, mHandler); 1726 triggerResults = captureListener.getTotalCaptureResultsForRequests( 1727 triggerRequests, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES); 1728 for (int i = 0; i < maxPipelineDepth; i++) { 1729 TotalCaptureResult triggerResult = triggerResults[i]; 1730 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE); 1731 int afTrigger = triggerResult.get(CaptureResult.CONTROL_AF_TRIGGER); 1732 1733 assertTrue( 1734 String.format("In AF mode %s, previous AF_TRIGGER must not " + 1735 "be CANCEL before TRIGGER_CANCEL", 1736 StaticMetadata.getAfModeName(afMode)), 1737 afTrigger != CaptureResult.CONTROL_AF_TRIGGER_CANCEL); 1738 assertTrue( 1739 String.format("In AF mode %s, previous AF_STATE must be LOCKED" 1740 + " before CANCEL, but is %s", 1741 StaticMetadata.getAfModeName(afMode), 1742 StaticMetadata.AF_STATE_NAMES[afState]), 1743 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 1744 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 1745 } 1746 1747 stopCapture(/*fast*/ false); 1748 preview.release(); 1749 } 1750 1751 } 1752 1753 } finally { 1754 closeDevice(id); 1755 } 1756 } 1757 1758 } 1759 1760 @Test testAbandonRepeatingRequestSurface()1761 public void testAbandonRepeatingRequestSurface() throws Exception { 1762 for (String id : mCameraIdsUnderTest) { 1763 Log.i(TAG, String.format( 1764 "Testing Camera %s for abandoning surface of a repeating request", id)); 1765 1766 StaticMetadata staticInfo = mAllStaticInfo.get(id); 1767 if (!staticInfo.isColorOutputSupported()) { 1768 Log.i(TAG, "Camera " + id + " does not support color output, skipping"); 1769 continue; 1770 } 1771 1772 openDevice(id); 1773 1774 try { 1775 1776 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1777 Surface previewSurface = new Surface(preview); 1778 1779 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1780 SimpleCaptureCallback captureListener = new CameraTestUtils.SimpleCaptureCallback(); 1781 1782 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1783 captureListener, mHandler); 1784 1785 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 1786 captureListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1787 } 1788 1789 // Abandon preview surface. 1790 preview.release(); 1791 1792 // Check onCaptureSequenceCompleted is received. 1793 long sequenceLastFrameNumber = captureListener.getCaptureSequenceLastFrameNumber( 1794 sequenceId, CAPTURE_TIMEOUT); 1795 1796 mCameraSession.stopRepeating(); 1797 1798 // Find the last frame number received in results and failures. 1799 long lastFrameNumber = -1; 1800 while (captureListener.hasMoreResults()) { 1801 TotalCaptureResult result = captureListener.getTotalCaptureResult( 1802 CAPTURE_TIMEOUT); 1803 if (lastFrameNumber < result.getFrameNumber()) { 1804 lastFrameNumber = result.getFrameNumber(); 1805 } 1806 } 1807 1808 while (captureListener.hasMoreFailures()) { 1809 ArrayList<CaptureFailure> failures = captureListener.getCaptureFailures( 1810 /*maxNumFailures*/ 1); 1811 for (CaptureFailure failure : failures) { 1812 if (lastFrameNumber < failure.getFrameNumber()) { 1813 lastFrameNumber = failure.getFrameNumber(); 1814 } 1815 } 1816 } 1817 1818 // Verify the last frame number received from capture sequence completed matches the 1819 // the last frame number of the results and failures. 1820 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " + 1821 "(%d) doesn't match the last frame number received from " + 1822 "results/failures (%d)", sequenceLastFrameNumber, lastFrameNumber), 1823 sequenceLastFrameNumber, lastFrameNumber); 1824 } finally { 1825 closeDevice(id); 1826 } 1827 } 1828 } 1829 1830 @Test testConfigureInvalidSensorPixelModes()1831 public void testConfigureInvalidSensorPixelModes() throws Exception { 1832 for (String id : mCameraIdsUnderTest) { 1833 // Go through given, stream configuration map, add the incorrect sensor pixel mode 1834 // to an OutputConfiguration, make sure the session configuration fails. 1835 CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(id); 1836 StreamConfigurationMap defaultStreamConfigMap = 1837 chars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 1838 StreamConfigurationMap maxStreamConfigMap = 1839 chars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 1840 openDevice(id); 1841 try { 1842 verifyBasicSensorPixelModes(id, maxStreamConfigMap, defaultStreamConfigMap, 1843 /*maxResolution*/ false); 1844 verifyBasicSensorPixelModes(id, maxStreamConfigMap, defaultStreamConfigMap, 1845 /*maxResolution*/ true); 1846 } finally { 1847 closeDevice(id); 1848 } 1849 } 1850 } 1851 1852 @Test testConfigureAbandonedSurface()1853 public void testConfigureAbandonedSurface() throws Exception { 1854 for (String id : mCameraIdsUnderTest) { 1855 Log.i(TAG, String.format( 1856 "Testing Camera %s for configuring abandoned surface", id)); 1857 1858 openDevice(id); 1859 try { 1860 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1861 Surface previewSurface = new Surface(preview); 1862 1863 // Abandon preview SurfaceTexture. 1864 preview.release(); 1865 1866 try { 1867 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1868 fail("Configuring abandoned surfaces must fail!"); 1869 } catch (IllegalArgumentException e) { 1870 // expected 1871 Log.i(TAG, "normal session check passed"); 1872 } 1873 1874 // Try constrained high speed session/requests 1875 if (!mStaticInfo.isConstrainedHighSpeedVideoSupported()) { 1876 continue; 1877 } 1878 1879 List<Surface> surfaces = new ArrayList<>(); 1880 surfaces.add(previewSurface); 1881 CameraCaptureSession.StateCallback sessionListener = 1882 mock(CameraCaptureSession.StateCallback.class); 1883 1884 try { 1885 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1886 sessionListener, mHandler); 1887 fail("Configuring abandoned surfaces in high speed session must fail!"); 1888 } catch (IllegalArgumentException e) { 1889 // expected 1890 Log.i(TAG, "high speed session check 1 passed"); 1891 } 1892 1893 // Also try abandone the Surface directly 1894 previewSurface.release(); 1895 1896 try { 1897 mCamera.createConstrainedHighSpeedCaptureSession(surfaces, 1898 sessionListener, mHandler); 1899 fail("Configuring abandoned surfaces in high speed session must fail!"); 1900 } catch (IllegalArgumentException e) { 1901 // expected 1902 Log.i(TAG, "high speed session check 2 passed"); 1903 } 1904 } finally { 1905 closeDevice(id); 1906 } 1907 } 1908 } 1909 1910 @Test testAfSceneChange()1911 public void testAfSceneChange() throws Exception { 1912 final int NUM_FRAMES_VERIFIED = 3; 1913 1914 for (String id : mCameraIdsUnderTest) { 1915 Log.i(TAG, String.format("Testing Camera %s for AF scene change", id)); 1916 1917 StaticMetadata staticInfo = 1918 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1919 if (!staticInfo.isAfSceneChangeSupported()) { 1920 continue; 1921 } 1922 1923 openDevice(id); 1924 1925 try { 1926 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1927 Surface previewSurface = new Surface(preview); 1928 1929 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1930 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1931 1932 int[] availableAfModes = mStaticInfo.getAfAvailableModesChecked(); 1933 1934 // Test AF scene change in each AF mode. 1935 for (int afMode : availableAfModes) { 1936 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 1937 1938 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1939 previewListener, mHandler); 1940 1941 // Verify that AF scene change is NOT_DETECTED or DETECTED. 1942 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1943 TotalCaptureResult result = 1944 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1945 mCollector.expectKeyValueIsIn(result, 1946 CaptureResult.CONTROL_AF_SCENE_CHANGE, 1947 CaptureResult.CONTROL_AF_SCENE_CHANGE_DETECTED, 1948 CaptureResult.CONTROL_AF_SCENE_CHANGE_NOT_DETECTED); 1949 } 1950 1951 mCameraSession.stopRepeating(); 1952 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 1953 previewListener.drain(); 1954 } 1955 } finally { 1956 closeDevice(id); 1957 } 1958 } 1959 } 1960 1961 @Test testOisDataMode()1962 public void testOisDataMode() throws Exception { 1963 final int NUM_FRAMES_VERIFIED = 3; 1964 1965 for (String id : mCameraIdsUnderTest) { 1966 Log.i(TAG, String.format("Testing Camera %s for OIS mode", id)); 1967 1968 StaticMetadata staticInfo = 1969 new StaticMetadata(mCameraManager.getCameraCharacteristics(id)); 1970 if (!staticInfo.isOisDataModeSupported()) { 1971 continue; 1972 } 1973 1974 openDevice(id); 1975 1976 try { 1977 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1); 1978 Surface previewSurface = new Surface(preview); 1979 1980 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 1981 SimpleCaptureCallback previewListener = new CameraTestUtils.SimpleCaptureCallback(); 1982 1983 int[] availableOisDataModes = staticInfo.getCharacteristics().get( 1984 CameraCharacteristics.STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES); 1985 1986 // Test each OIS data mode 1987 for (int oisMode : availableOisDataModes) { 1988 previewRequest.set(CaptureRequest.STATISTICS_OIS_DATA_MODE, oisMode); 1989 1990 int sequenceId = mCameraSession.setRepeatingRequest(previewRequest.build(), 1991 previewListener, mHandler); 1992 1993 // Check OIS data in each mode. 1994 for (int i = 0; i < NUM_FRAMES_VERIFIED; i++) { 1995 TotalCaptureResult result = 1996 previewListener.getTotalCaptureResult(CAPTURE_TIMEOUT); 1997 1998 OisSample[] oisSamples = result.get(CaptureResult.STATISTICS_OIS_SAMPLES); 1999 2000 if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_OFF) { 2001 mCollector.expectKeyValueEquals(result, 2002 CaptureResult.STATISTICS_OIS_DATA_MODE, 2003 CaptureResult.STATISTICS_OIS_DATA_MODE_OFF); 2004 mCollector.expectTrue("OIS samples reported in OIS_DATA_MODE_OFF", 2005 oisSamples == null || oisSamples.length == 0); 2006 2007 } else if (oisMode == CameraCharacteristics.STATISTICS_OIS_DATA_MODE_ON) { 2008 mCollector.expectKeyValueEquals(result, 2009 CaptureResult.STATISTICS_OIS_DATA_MODE, 2010 CaptureResult.STATISTICS_OIS_DATA_MODE_ON); 2011 mCollector.expectTrue("OIS samples not reported in OIS_DATA_MODE_ON", 2012 oisSamples != null && oisSamples.length != 0); 2013 } else { 2014 mCollector.addMessage(String.format("Invalid OIS mode: %d", oisMode)); 2015 } 2016 } 2017 2018 mCameraSession.stopRepeating(); 2019 previewListener.getCaptureSequenceLastFrameNumber(sequenceId, CAPTURE_TIMEOUT); 2020 previewListener.drain(); 2021 } 2022 } finally { 2023 closeDevice(id); 2024 } 2025 } 2026 } 2027 preparePreviewTestSession(SurfaceTexture preview)2028 private CaptureRequest.Builder preparePreviewTestSession(SurfaceTexture preview) 2029 throws Exception { 2030 Surface previewSurface = new Surface(preview); 2031 2032 preview.setDefaultBufferSize(640, 480); 2033 2034 ArrayList<Surface> sessionOutputs = new ArrayList<>(); 2035 sessionOutputs.add(previewSurface); 2036 2037 createSession(sessionOutputs); 2038 2039 CaptureRequest.Builder previewRequest = 2040 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 2041 2042 previewRequest.addTarget(previewSurface); 2043 2044 return previewRequest; 2045 } 2046 prepareTriggerTestSession( SurfaceTexture preview, int aeMode, int afMode)2047 private CaptureRequest.Builder prepareTriggerTestSession( 2048 SurfaceTexture preview, int aeMode, int afMode) throws Exception { 2049 Log.i(TAG, String.format("Testing AE mode %s, AF mode %s", 2050 StaticMetadata.getAeModeName(aeMode), 2051 StaticMetadata.getAfModeName(afMode))); 2052 2053 CaptureRequest.Builder previewRequest = preparePreviewTestSession(preview); 2054 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode); 2055 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode); 2056 2057 return previewRequest; 2058 } 2059 cancelTriggersAndWait(CaptureRequest.Builder previewRequest, SimpleCaptureCallback captureListener, int afMode)2060 private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest, 2061 SimpleCaptureCallback captureListener, int afMode) throws Exception { 2062 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, 2063 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 2064 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 2065 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL); 2066 2067 CaptureRequest triggerRequest = previewRequest.build(); 2068 mCameraSession.capture(triggerRequest, captureListener, mHandler); 2069 2070 // Wait for a few frames to initialize 3A 2071 2072 CaptureResult previewResult = null; 2073 int afState; 2074 int aeState; 2075 2076 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) { 2077 previewResult = captureListener.getCaptureResult( 2078 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS); 2079 if (VERBOSE) { 2080 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 2081 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 2082 Log.v(TAG, String.format("AF state: %s, AE state: %s", 2083 StaticMetadata.AF_STATE_NAMES[afState], 2084 StaticMetadata.AE_STATE_NAMES[aeState])); 2085 } 2086 } 2087 2088 // Verify starting states 2089 2090 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE); 2091 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE); 2092 2093 verifyStartingAfState(afMode, afState); 2094 2095 // After several frames, AE must no longer be in INACTIVE state 2096 assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " + 2097 "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]), 2098 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING || 2099 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED || 2100 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED); 2101 } 2102 configsContain(StreamConfigurationMap configs, int format, Size size)2103 private boolean configsContain(StreamConfigurationMap configs, int format, Size size) { 2104 Size[] sizes = configs.getOutputSizes(format); 2105 if (sizes == null) { 2106 return false; 2107 } 2108 return Arrays.asList(sizes).contains(size); 2109 } 2110 verifyBasicSensorPixelModes(String id, StreamConfigurationMap maxResConfigs, StreamConfigurationMap defaultConfigs, boolean maxResolution)2111 private void verifyBasicSensorPixelModes(String id, StreamConfigurationMap maxResConfigs, 2112 StreamConfigurationMap defaultConfigs, boolean maxResolution) throws Exception { 2113 // Go through StreamConfiguration map, set up OutputConfiguration and add the opposite 2114 // sensorPixelMode. 2115 final int MIN_RESULT_COUNT = 3; 2116 assertTrue("Default stream config map must be present for id: " + id, 2117 defaultConfigs != null); 2118 if (maxResConfigs == null) { 2119 Log.i(TAG, "camera id " + id + " has no StreamConfigurationMap for max resolution " + 2120 ", skipping verifyBasicSensorPixelModes"); 2121 return; 2122 } 2123 StreamConfigurationMap chosenConfigs = maxResolution ? maxResConfigs : defaultConfigs; 2124 StreamConfigurationMap otherConfigs = maxResolution ? defaultConfigs : maxResConfigs; 2125 OutputConfiguration outputConfig = null; 2126 for (int format : chosenConfigs.getOutputFormats()) { 2127 Size targetSize = CameraTestUtils.getMaxSize(chosenConfigs.getOutputSizes(format)); 2128 if (configsContain(otherConfigs, format, targetSize)) { 2129 // Since both max res and default stream configuration maps contain this size, 2130 // both sensor pixel modes are valid. 2131 Log.v(TAG, "camera id " + id + " 'other' configs with maxResolution" + 2132 maxResolution + " contains the format: " + format + " size: " + targetSize + 2133 " skipping"); 2134 continue; 2135 } 2136 // Create outputConfiguration with this size and format 2137 SimpleImageReaderListener imageListener = new SimpleImageReaderListener(); 2138 SurfaceTexture textureTarget = null; 2139 ImageReader readerTarget = null; 2140 if (format == ImageFormat.PRIVATE) { 2141 textureTarget = new SurfaceTexture(1); 2142 textureTarget.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight()); 2143 outputConfig = new OutputConfiguration(new Surface(textureTarget)); 2144 } else { 2145 readerTarget = ImageReader.newInstance(targetSize.getWidth(), 2146 targetSize.getHeight(), format, MIN_RESULT_COUNT); 2147 readerTarget.setOnImageAvailableListener(imageListener, mHandler); 2148 outputConfig = new OutputConfiguration(readerTarget.getSurface()); 2149 } 2150 try { 2151 int invalidSensorPixelMode = 2152 maxResolution ? CameraMetadata.SENSOR_PIXEL_MODE_DEFAULT : 2153 CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION; 2154 2155 outputConfig.addSensorPixelModeUsed(invalidSensorPixelMode); 2156 CameraCaptureSession.StateCallback sessionListener = 2157 mock(CameraCaptureSession.StateCallback.class); 2158 List<OutputConfiguration> outputs = new ArrayList<>(); 2159 outputs.add(outputConfig); 2160 CameraCaptureSession session = 2161 CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputs, 2162 sessionListener, mHandler); 2163 String desc = "verifyBasicSensorPixelModes : Format : " + format + " size: " + 2164 targetSize.toString() + " maxResolution : " + maxResolution; 2165 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce().description(desc)). 2166 onConfigureFailed(any(CameraCaptureSession.class)); 2167 verify(sessionListener, never().description(desc)). 2168 onConfigured(any(CameraCaptureSession.class)); 2169 2170 // Remove the invalid sensor pixel mode, session configuration should succeed 2171 sessionListener = mock(CameraCaptureSession.StateCallback.class); 2172 outputConfig.removeSensorPixelModeUsed(invalidSensorPixelMode); 2173 CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputs, 2174 sessionListener, mHandler); 2175 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce().description(desc)). 2176 onConfigured(any(CameraCaptureSession.class)); 2177 verify(sessionListener, never().description(desc)). 2178 onConfigureFailed(any(CameraCaptureSession.class)); 2179 } finally { 2180 if (textureTarget != null) { 2181 textureTarget.release(); 2182 } 2183 2184 if (readerTarget != null) { 2185 readerTarget.close(); 2186 } 2187 } 2188 } 2189 } 2190 verifyStartingAfState(int afMode, int afState)2191 private void verifyStartingAfState(int afMode, int afState) { 2192 switch (afMode) { 2193 case CaptureResult.CONTROL_AF_MODE_AUTO: 2194 case CaptureResult.CONTROL_AF_MODE_MACRO: 2195 assertTrue(String.format("AF state not INACTIVE, is %s", 2196 StaticMetadata.AF_STATE_NAMES[afState]), 2197 afState == CaptureResult.CONTROL_AF_STATE_INACTIVE); 2198 break; 2199 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 2200 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 2201 // After several frames, AF must no longer be in INACTIVE state 2202 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" + 2203 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s", 2204 StaticMetadata.getAfModeName(afMode), 2205 StaticMetadata.AF_STATE_NAMES[afState]), 2206 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 2207 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED || 2208 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED); 2209 break; 2210 default: 2211 fail("unexpected af mode"); 2212 } 2213 } 2214 verifyAfSequence(int afMode, int afState, boolean focusComplete)2215 private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) { 2216 if (focusComplete) { 2217 assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s", 2218 StaticMetadata.getAfModeName(afMode), 2219 StaticMetadata.AF_STATE_NAMES[afState]), 2220 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2221 afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2222 return focusComplete; 2223 } 2224 if (VERBOSE) { 2225 Log.v(TAG, String.format("AF mode: %s, AF state: %s", 2226 StaticMetadata.getAfModeName(afMode), 2227 StaticMetadata.AF_STATE_NAMES[afState])); 2228 } 2229 switch (afMode) { 2230 case CaptureResult.CONTROL_AF_MODE_AUTO: 2231 case CaptureResult.CONTROL_AF_MODE_MACRO: 2232 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2233 StaticMetadata.getAfModeName(afMode), 2234 StaticMetadata.AF_STATE_NAMES[afState]), 2235 afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN || 2236 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2237 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2238 focusComplete = 2239 (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN); 2240 break; 2241 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE: 2242 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2243 StaticMetadata.getAfModeName(afMode), 2244 StaticMetadata.AF_STATE_NAMES[afState]), 2245 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN || 2246 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2247 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2248 focusComplete = 2249 (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN); 2250 break; 2251 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO: 2252 assertTrue(String.format("AF mode %s: Unexpected AF state %s", 2253 StaticMetadata.getAfModeName(afMode), 2254 StaticMetadata.AF_STATE_NAMES[afState]), 2255 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || 2256 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED); 2257 focusComplete = true; 2258 break; 2259 default: 2260 fail("Unexpected AF mode: " + StaticMetadata.getAfModeName(afMode)); 2261 } 2262 return focusComplete; 2263 } 2264 verifyAeSequence(int aeState, boolean precaptureComplete)2265 private boolean verifyAeSequence(int aeState, boolean precaptureComplete) { 2266 if (precaptureComplete) { 2267 assertTrue("Precapture state seen after convergence", 2268 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE); 2269 return precaptureComplete; 2270 } 2271 if (VERBOSE) { 2272 Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState])); 2273 } 2274 switch (aeState) { 2275 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE: 2276 // scan still continuing 2277 break; 2278 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 2279 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 2280 // completed 2281 precaptureComplete = true; 2282 break; 2283 default: 2284 fail(String.format("Precapture sequence transitioned to " 2285 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState])); 2286 break; 2287 } 2288 return precaptureComplete; 2289 } 2290 2291 /** 2292 * Test for making sure that all expected mandatory stream combinations are present and 2293 * advertised accordingly. 2294 */ 2295 @Test testVerifyMandatoryOutputCombinationTables()2296 public void testVerifyMandatoryOutputCombinationTables() throws Exception { 2297 final int[][] legacyCombinations = { 2298 // Simple preview, GPU video processing, or no-preview video recording 2299 {PRIV, MAXIMUM}, 2300 // No-viewfinder still image capture 2301 {JPEG, MAXIMUM}, 2302 // In-application video/image processing 2303 {YUV, MAXIMUM}, 2304 // Standard still imaging. 2305 {PRIV, PREVIEW, JPEG, MAXIMUM}, 2306 // In-app processing plus still capture. 2307 {YUV, PREVIEW, JPEG, MAXIMUM}, 2308 // Standard recording. 2309 {PRIV, PREVIEW, PRIV, PREVIEW}, 2310 // Preview plus in-app processing. 2311 {PRIV, PREVIEW, YUV, PREVIEW}, 2312 // Still capture plus in-app processing. 2313 {PRIV, PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM} 2314 }; 2315 2316 final int[][] limitedCombinations = { 2317 // High-resolution video recording with preview. 2318 {PRIV, PREVIEW, PRIV, RECORD }, 2319 // High-resolution in-app video processing with preview. 2320 {PRIV, PREVIEW, YUV , RECORD }, 2321 // Two-input in-app video processing. 2322 {YUV , PREVIEW, YUV , RECORD }, 2323 // High-resolution recording with video snapshot. 2324 {PRIV, PREVIEW, PRIV, RECORD, JPEG, RECORD }, 2325 // High-resolution in-app processing with video snapshot. 2326 {PRIV, PREVIEW, YUV, RECORD, JPEG, RECORD }, 2327 // Two-input in-app processing with still capture. 2328 {YUV , PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM } 2329 }; 2330 2331 final int[][] burstCombinations = { 2332 // Maximum-resolution GPU processing with preview. 2333 {PRIV, PREVIEW, PRIV, MAXIMUM }, 2334 // Maximum-resolution in-app processing with preview. 2335 {PRIV, PREVIEW, YUV, MAXIMUM }, 2336 // Maximum-resolution two-input in-app processing. 2337 {YUV, PREVIEW, YUV, MAXIMUM }, 2338 }; 2339 2340 final int[][] fullCombinations = { 2341 // Video recording with maximum-size video snapshot. 2342 {PRIV, PREVIEW, PRIV, PREVIEW, JPEG, MAXIMUM }, 2343 // Standard video recording plus maximum-resolution in-app processing. 2344 {YUV, VGA, PRIV, PREVIEW, YUV, MAXIMUM }, 2345 // Preview plus two-input maximum-resolution in-app processing. 2346 {YUV, VGA, YUV, PREVIEW, YUV, MAXIMUM } 2347 }; 2348 2349 final int[][] rawCombinations = { 2350 // No-preview DNG capture. 2351 {RAW, MAXIMUM }, 2352 // Standard DNG capture. 2353 {PRIV, PREVIEW, RAW, MAXIMUM }, 2354 // In-app processing plus DNG capture. 2355 {YUV, PREVIEW, RAW, MAXIMUM }, 2356 // Video recording with DNG capture. 2357 {PRIV, PREVIEW, PRIV, PREVIEW, RAW, MAXIMUM}, 2358 // Preview with in-app processing and DNG capture. 2359 {PRIV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, 2360 // Two-input in-app processing plus DNG capture. 2361 {YUV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, 2362 // Still capture with simultaneous JPEG and DNG. 2363 {PRIV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM}, 2364 // In-app processing with simultaneous JPEG and DNG. 2365 {YUV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM} 2366 }; 2367 2368 final int[][] level3Combinations = { 2369 // In-app viewfinder analysis with dynamic selection of output format 2370 {PRIV, PREVIEW, PRIV, VGA, YUV, MAXIMUM, RAW, MAXIMUM}, 2371 // In-app viewfinder analysis with dynamic selection of output format 2372 {PRIV, PREVIEW, PRIV, VGA, JPEG, MAXIMUM, RAW, MAXIMUM} 2373 }; 2374 2375 final int[][] concurrentStreamCombinations = { 2376 //In-app video / image processing. 2377 {YUV, S1440P}, 2378 // In-app viewfinder analysis. 2379 {PRIV, S1440P}, 2380 // No viewfinder still image capture. 2381 {JPEG, S1440P}, 2382 // Standard still imaging. 2383 {YUV, S720P, JPEG, S1440P}, 2384 {PRIV, S720P, JPEG, S1440P}, 2385 // In-app video / processing with preview. 2386 {YUV, S720P, YUV, S1440P}, 2387 {YUV, S720P, PRIV, S1440P}, 2388 {PRIV, S720P, YUV, S1440P}, 2389 {PRIV, S720P, PRIV, S1440P} 2390 }; 2391 2392 final int[][] ultraHighResolutionsCombinations = { 2393 // Ultra high res still image capture with preview. 2394 {YUV, MAX_RES, PRIV, PREVIEW}, 2395 {YUV, MAX_RES, YUV, PREVIEW}, 2396 {JPEG, MAX_RES, PRIV, PREVIEW}, 2397 {JPEG, MAX_RES, YUV, PREVIEW}, 2398 {RAW, MAX_RES, PRIV, PREVIEW}, 2399 {RAW, MAX_RES, YUV, PREVIEW}, 2400 // Ultra high res still capture with preview + app based RECORD size analysis. 2401 {YUV, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2402 {YUV, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2403 {JPEG, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2404 {JPEG, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2405 {RAW, MAX_RES, PRIV, PREVIEW, PRIV, RECORD}, 2406 {RAW, MAX_RES, PRIV, PREVIEW, YUV, RECORD}, 2407 // Ultra high res still image capture with preview + default sensor pixel mode analysis 2408 // stream 2409 {YUV, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2410 {YUV, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2411 {YUV, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2412 {JPEG, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2413 {JPEG, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2414 {JPEG, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2415 {RAW, MAX_RES, PRIV, PREVIEW, JPEG, MAXIMUM}, 2416 {RAW, MAX_RES, PRIV, PREVIEW, YUV, MAXIMUM}, 2417 {RAW, MAX_RES, PRIV, PREVIEW, RAW, MAXIMUM}, 2418 }; 2419 2420 final int[][] tenBitOutputCombinations = { 2421 // Simple preview, GPU video processing, or no-preview video recording. 2422 {PRIV, MAXIMUM}, 2423 // In-application video/image processing. 2424 {YUV, MAXIMUM}, 2425 // Standard still imaging. 2426 {PRIV, PREVIEW, JPEG, MAXIMUM}, 2427 // Maximum-resolution in-app processing with preview. 2428 {PRIV, PREVIEW, YUV, MAXIMUM}, 2429 // Maximum-resolution two-input in-app processing. 2430 {YUV, PREVIEW, YUV, MAXIMUM}, 2431 // High-resolution video recording with preview. 2432 {PRIV, PREVIEW, PRIV, RECORD}, 2433 // High-resolution recording with in-app snapshot. 2434 {PRIV, PREVIEW, PRIV, RECORD, YUV, RECORD}, 2435 // High-resolution recording with video snapshot. 2436 {PRIV, PREVIEW, PRIV, RECORD, JPEG, RECORD} 2437 }; 2438 2439 final int[][] streamUseCaseCombinations = { 2440 // Simple preview or in-app image processing. 2441 {YUV, PREVIEW, USE_CASE_PREVIEW}, 2442 {PRIV, PREVIEW, USE_CASE_PREVIEW}, 2443 // Simple video recording or in-app video processing. 2444 {YUV, RECORD, USE_CASE_VIDEO_RECORD}, 2445 {PRIV, RECORD, USE_CASE_VIDEO_RECORD}, 2446 // Simple JPEG or YUV still image capture. 2447 {YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2448 {JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2449 // Multi-purpose stream for preview, video and still image capture. 2450 {YUV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL}, 2451 {PRIV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL}, 2452 // Simple video call. 2453 {YUV, S1440P, USE_CASE_VIDEO_CALL}, 2454 {PRIV, S1440P, USE_CASE_VIDEO_CALL}, 2455 // Preview with JPEG or YUV still image capture. 2456 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2457 {PRIV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2458 // Preview with video recording or in-app video processing. 2459 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, RECORD, USE_CASE_VIDEO_RECORD}, 2460 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, RECORD, USE_CASE_VIDEO_RECORD}, 2461 // Preview with in-application image processing. 2462 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW}, 2463 // Preview with video call. 2464 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, S1440P, USE_CASE_VIDEO_CALL}, 2465 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, S1440P, USE_CASE_VIDEO_CALL}, 2466 // {Multi-purpose stream with JPEG or YUV still capture. 2467 {YUV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2468 {YUV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2469 {PRIV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2470 {PRIV, S1440P, USE_CASE_PREVIEW_VIDEO_STILL, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2471 // YUV and JPEG concurrent still image capture (for testing). 2472 {YUV, PREVIEW, USE_CASE_STILL_CAPTURE, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE}, 2473 // Preview, video record and JPEG video snapshot. 2474 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, RECORD, USE_CASE_VIDEO_RECORD, JPEG, RECORD, 2475 USE_CASE_STILL_CAPTURE}, 2476 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, RECORD, USE_CASE_VIDEO_RECORD, JPEG, RECORD, 2477 USE_CASE_STILL_CAPTURE}, 2478 // Preview, in-application image processing, and JPEG still image capture. 2479 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, 2480 USE_CASE_STILL_CAPTURE}, 2481 }; 2482 2483 final int[][] streamUseCaseCroppedRawCombinations = { 2484 // Cropped RAW still image capture without preview 2485 {RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2486 2487 // Preview / In-app processing with cropped RAW still image capture 2488 {PRIV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2489 {YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, USE_CASE_CROPPED_RAW}, 2490 2491 // Preview / In-app processing with YUV and cropped RAW still image capture 2492 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2493 USE_CASE_CROPPED_RAW}, 2494 {YUV, PREVIEW, USE_CASE_PREVIEW, YUV, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2495 USE_CASE_CROPPED_RAW}, 2496 2497 // Preview / In-app processing with JPEG and cropped RAW still image capture 2498 {PRIV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2499 USE_CASE_CROPPED_RAW}, 2500 {YUV, PREVIEW, USE_CASE_PREVIEW, JPEG, MAXIMUM, USE_CASE_STILL_CAPTURE, RAW, MAXIMUM, 2501 USE_CASE_CROPPED_RAW}, 2502 2503 // Preview with in-app processing / video recording and cropped RAW snapshot 2504 {PRIV, PREVIEW, USE_CASE_PREVIEW, PRIV, PREVIEW, USE_CASE_VIDEO_RECORD, RAW, MAXIMUM, 2505 USE_CASE_CROPPED_RAW}, 2506 {PRIV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, 2507 USE_CASE_CROPPED_RAW}, 2508 2509 // Two input in-app processing with RAW 2510 {YUV, PREVIEW, USE_CASE_PREVIEW, YUV, PREVIEW, USE_CASE_PREVIEW, RAW, MAXIMUM, 2511 USE_CASE_CROPPED_RAW}, 2512 }; 2513 2514 2515 final int[][] previewStabilizationCombinations = { 2516 // Stabilized preview, GPU video processing, or no-preview stabilized video recording. 2517 {PRIV, S1440P}, 2518 {YUV, S1440P}, 2519 // Standard still imaging with stabilized preview. 2520 {PRIV, S1440P, JPEG, MAXIMUM}, 2521 {PRIV, S1440P, YUV, MAXIMUM}, 2522 {YUV, S1440P, JPEG, MAXIMUM}, 2523 {YUV, S1440P, YUV, MAXIMUM}, 2524 // High-resolution recording with stabilized preview and recording stream. 2525 {PRIV, PREVIEW, PRIV, S1440P}, 2526 {PRIV, PREVIEW, YUV, S1440P}, 2527 {YUV, PREVIEW, PRIV, S1440P}, 2528 {YUV, PREVIEW, YUV, S1440P}, 2529 }; 2530 2531 final int[][][] tables = 2532 {legacyCombinations, limitedCombinations, burstCombinations, fullCombinations, 2533 rawCombinations, level3Combinations, concurrentStreamCombinations, 2534 ultraHighResolutionsCombinations, tenBitOutputCombinations, 2535 previewStabilizationCombinations}; 2536 2537 final int[][][] useCaseTables = {streamUseCaseCombinations, 2538 streamUseCaseCroppedRawCombinations}; 2539 2540 validityCheckConfigurationTables(tables); 2541 validityCheckConfigurationTables(useCaseTables, /*useCaseSpecified*/ true); 2542 2543 for (String id : mCameraIdsUnderTest) { 2544 openDevice(id); 2545 MandatoryStreamCombination[] combinations = 2546 mStaticInfo.getCharacteristics().get( 2547 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 2548 if ((combinations == null) || (combinations.length == 0)) { 2549 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 2550 closeDevice(id); 2551 continue; 2552 } 2553 2554 MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext); 2555 try { 2556 if (mStaticInfo.isColorOutputSupported()) { 2557 for (int[] c : legacyCombinations) { 2558 assertTrue(String.format("Expected static stream combination: %s not " 2559 + "found among the available mandatory combinations", 2560 maxSizes.combinationToString(c)), 2561 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2562 } 2563 } 2564 2565 if (!mStaticInfo.isHardwareLevelLegacy()) { 2566 if (mStaticInfo.isColorOutputSupported()) { 2567 for (int[] c : limitedCombinations) { 2568 assertTrue(String.format("Expected static stream combination: %s not " 2569 + "found among the available mandatory combinations", 2570 maxSizes.combinationToString(c)), 2571 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2572 } 2573 } 2574 2575 if (mStaticInfo.isCapabilitySupported( 2576 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) { 2577 for (int[] c : burstCombinations) { 2578 assertTrue(String.format("Expected static stream combination: %s not " 2579 + "found among the available mandatory combinations", 2580 maxSizes.combinationToString(c)), 2581 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2582 } 2583 } 2584 2585 if (mStaticInfo.isHardwareLevelAtLeastFull()) { 2586 for (int[] c : fullCombinations) { 2587 assertTrue(String.format("Expected static stream combination: %s not " 2588 + "found among the available mandatory combinations", 2589 maxSizes.combinationToString(c)), 2590 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2591 } 2592 } 2593 2594 if (mStaticInfo.isCapabilitySupported( 2595 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2596 for (int[] c : rawCombinations) { 2597 assertTrue(String.format("Expected static stream combination: %s not " 2598 + "found among the available mandatory combinations", 2599 maxSizes.combinationToString(c)), 2600 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2601 } 2602 } 2603 2604 if (mStaticInfo.isHardwareLevelAtLeast( 2605 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) { 2606 for (int[] c: level3Combinations) { 2607 assertTrue(String.format("Expected static stream combination: %s not " 2608 + "found among the available mandatory combinations ", 2609 maxSizes.combinationToString(c)), 2610 isMandatoryCombinationAvailable(c, maxSizes, combinations)); 2611 } 2612 } 2613 } 2614 2615 Set<Set<String>> concurrentCameraIdCombinations = 2616 mCameraManager.getConcurrentCameraIds(); 2617 boolean isConcurrentCamera = false; 2618 for (Set<String> concurrentCameraIdCombination : concurrentCameraIdCombinations) { 2619 if (concurrentCameraIdCombination.contains(id)) { 2620 isConcurrentCamera = true; 2621 break; 2622 } 2623 } 2624 2625 if (isConcurrentCamera && mStaticInfo.isCapabilitySupported( 2626 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) { 2627 MandatoryStreamCombination[] mandatoryConcurrentStreamCombinations = 2628 mStaticInfo.getCharacteristics().get( 2629 CameraCharacteristics 2630 .SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS); 2631 for (int[] c : concurrentStreamCombinations) { 2632 assertTrue(String.format("Expected static stream combination: %s not " 2633 + "found among the available mandatory concurrent stream " 2634 + "combinations", 2635 maxSizes.combinationToString(c)), 2636 isMandatoryCombinationAvailable(c, maxSizes, 2637 mandatoryConcurrentStreamCombinations)); 2638 } 2639 } 2640 2641 if (mStaticInfo.isCapabilitySupported( 2642 CameraCharacteristics 2643 .REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) { 2644 MandatoryStreamCombination[] maxResolutionStreamCombinations = 2645 mStaticInfo.getCharacteristics().get( 2646 CameraCharacteristics 2647 .SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS); 2648 for (int[] c : ultraHighResolutionsCombinations) { 2649 assertTrue(String.format("Expected static stream combination: %s not " 2650 + "found among the available mandatory max resolution stream " 2651 + "combinations", 2652 maxSizes.combinationToString(c)), 2653 isMandatoryCombinationAvailable(c, maxSizes, 2654 maxResolutionStreamCombinations)); 2655 } 2656 } 2657 2658 if (mStaticInfo.isCapabilitySupported( 2659 CameraCharacteristics 2660 .REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) { 2661 MandatoryStreamCombination[] mandatoryTenBitOutputCombinations = 2662 mStaticInfo.getCharacteristics().get( 2663 CameraCharacteristics 2664 .SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS); 2665 for (int[] c : tenBitOutputCombinations) { 2666 assertTrue(String.format("Expected static stream combination: %s not " 2667 + "found among the available mandatory 10 bit output " 2668 + "combinations", 2669 maxSizes.combinationToString(c)), 2670 isMandatoryCombinationAvailable(c, maxSizes, 2671 mandatoryTenBitOutputCombinations)); 2672 } 2673 } 2674 2675 if (mStaticInfo.isCapabilitySupported( 2676 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) { 2677 MandatoryStreamCombination[] mandatoryStreamUseCaseCombinations = 2678 mStaticInfo.getCharacteristics().get( 2679 CameraCharacteristics 2680 .SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS); 2681 for (int[] c : streamUseCaseCombinations) { 2682 assertTrue(String.format("Expected static stream combination: %s not " 2683 + "found among the available mandatory stream use case " 2684 + "combinations", 2685 maxSizes.combinationToString(c, /*useCaseSpecified*/ true)), 2686 isMandatoryCombinationAvailable(c, maxSizes, 2687 /*isInput*/ false, mandatoryStreamUseCaseCombinations, 2688 /*useCaseSpecified*/ true)); 2689 } 2690 2691 if (mStaticInfo.isCroppedRawStreamUseCaseSupported()) { 2692 for (int[] c : streamUseCaseCroppedRawCombinations) { 2693 assertTrue(String.format("Expected static stream combination: %s not " 2694 + "found among the available mandatory cropped RAW stream" 2695 + " use case combinations", 2696 maxSizes.combinationToString(c, /*useCaseSpecified*/ true)), 2697 isMandatoryCombinationAvailable(c, maxSizes, 2698 /*isInput*/ false, mandatoryStreamUseCaseCombinations, 2699 /*useCaseSpecified*/ true)); 2700 } 2701 } 2702 } 2703 2704 if (mStaticInfo.isPreviewStabilizationSupported()) { 2705 MandatoryStreamCombination[] mandatoryPreviewStabilizationCombinations = 2706 mStaticInfo.getCharacteristics().get( 2707 CameraCharacteristics 2708 .SCALER_MANDATORY_PREVIEW_STABILIZATION_OUTPUT_STREAM_COMBINATIONS); 2709 for (int[] c : previewStabilizationCombinations) { 2710 assertTrue(String.format("Expected static stream combination: %s not " 2711 + "found among the available mandatory preview stabilization" 2712 + "combinations", 2713 maxSizes.combinationToString(c)), 2714 isMandatoryCombinationAvailable(c, maxSizes, 2715 mandatoryPreviewStabilizationCombinations)); 2716 } 2717 } 2718 } finally { 2719 closeDevice(id); 2720 } 2721 } 2722 } 2723 2724 /** 2725 * Test for making sure that all expected reprocessable mandatory stream combinations are 2726 * present and advertised accordingly. 2727 */ 2728 @Test testVerifyReprocessMandatoryOutputCombinationTables()2729 public void testVerifyReprocessMandatoryOutputCombinationTables() throws Exception { 2730 final int[][] limitedCombinations = { 2731 // Input Outputs 2732 {PRIV, MAXIMUM, JPEG, MAXIMUM}, 2733 {YUV , MAXIMUM, JPEG, MAXIMUM}, 2734 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM}, 2735 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM}, 2736 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM}, 2737 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM}, 2738 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2739 {YUV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2740 }; 2741 2742 final int[][] fullCombinations = { 2743 // Input Outputs 2744 {YUV , MAXIMUM, PRIV, PREVIEW}, 2745 {YUV , MAXIMUM, YUV , PREVIEW}, 2746 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , RECORD}, 2747 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , RECORD}, 2748 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , MAXIMUM}, 2749 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , MAXIMUM}, 2750 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2751 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM}, 2752 }; 2753 2754 final int[][] rawCombinations = { 2755 // Input Outputs 2756 {PRIV, MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM}, 2757 {YUV , MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM}, 2758 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2759 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2760 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2761 {YUV , MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM}, 2762 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2763 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2764 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2765 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM}, 2766 }; 2767 2768 final int[][] level3Combinations = { 2769 // Input Outputs 2770 // In-app viewfinder analysis with YUV->YUV ZSL and RAW 2771 {YUV , MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM}, 2772 // In-app viewfinder analysis with PRIV->JPEG ZSL and RAW 2773 {PRIV, MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM}, 2774 // In-app viewfinder analysis with YUV->JPEG ZSL and RAW 2775 {YUV , MAXIMUM, PRIV, PREVIEW, PRIV, VGA, RAW, MAXIMUM, JPEG, MAXIMUM}, 2776 }; 2777 2778 final int[][] ultraHighResolutionCombinations = { 2779 // Input Outputs 2780 // RAW remosaic reprocessing with separate preview 2781 {RAW, MAX_RES, PRIV, PREVIEW}, 2782 {RAW, MAX_RES, YUV, PREVIEW}, 2783 // Ultra high res RAW -> JPEG / YUV with separate preview 2784 {RAW, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2785 {RAW, MAX_RES, PRIV, PREVIEW, YUV, MAX_RES}, 2786 {RAW, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2787 {RAW, MAX_RES, YUV, PREVIEW, YUV, MAX_RES}, 2788 // Ultra high res PRIV / YUV -> YUV / JPEG reprocessing with separate preview 2789 {YUV, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2790 {YUV, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2791 {PRIV, MAX_RES, YUV, PREVIEW, JPEG, MAX_RES}, 2792 {PRIV, MAX_RES, PRIV, PREVIEW, JPEG, MAX_RES}, 2793 }; 2794 2795 final int[][][] TABLES = 2796 {limitedCombinations, fullCombinations, rawCombinations, level3Combinations, 2797 ultraHighResolutionCombinations}; 2798 2799 validityCheckConfigurationTables(TABLES); 2800 2801 for (String id : mCameraIdsUnderTest) { 2802 openDevice(id); 2803 MandatoryStreamCombination[] cs = mStaticInfo.getCharacteristics().get( 2804 CameraCharacteristics.SCALER_MANDATORY_STREAM_COMBINATIONS); 2805 if ((cs == null) || (cs.length == 0)) { 2806 Log.i(TAG, "No mandatory stream combinations for camera: " + id + " skip test"); 2807 closeDevice(id); 2808 continue; 2809 } 2810 2811 boolean supportYuvReprocess = mStaticInfo.isCapabilitySupported( 2812 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 2813 boolean supportOpaqueReprocess = mStaticInfo.isCapabilitySupported( 2814 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2815 if (!supportYuvReprocess && !supportOpaqueReprocess) { 2816 Log.i(TAG, "No reprocess support for camera: " + id + " skip test"); 2817 closeDevice(id); 2818 continue; 2819 } 2820 2821 MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, mContext); 2822 try { 2823 for (int[] c : limitedCombinations) { 2824 assertTrue(String.format("Expected static reprocessable stream combination:" + 2825 "%s not found among the available mandatory combinations", 2826 maxSizes.reprocessCombinationToString(c)), 2827 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2828 } 2829 2830 if (mStaticInfo.isHardwareLevelAtLeastFull()) { 2831 for (int[] c : fullCombinations) { 2832 assertTrue(String.format( 2833 "Expected static reprocessable stream combination:" + 2834 "%s not found among the available mandatory combinations", 2835 maxSizes.reprocessCombinationToString(c)), 2836 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2837 } 2838 } 2839 2840 if (mStaticInfo.isCapabilitySupported( 2841 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 2842 for (int[] c : rawCombinations) { 2843 assertTrue(String.format( 2844 "Expected static reprocessable stream combination:" + 2845 "%s not found among the available mandatory combinations", 2846 maxSizes.reprocessCombinationToString(c)), 2847 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2848 } 2849 } 2850 2851 if (mStaticInfo.isHardwareLevelAtLeast( 2852 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3)) { 2853 for (int[] c : level3Combinations) { 2854 assertTrue(String.format( 2855 "Expected static reprocessable stream combination:" + 2856 "%s not found among the available mandatory combinations", 2857 maxSizes.reprocessCombinationToString(c)), 2858 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, cs)); 2859 } 2860 } 2861 2862 if (mStaticInfo.isCapabilitySupported( 2863 CameraCharacteristics 2864 .REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) { 2865 MandatoryStreamCombination[] maxResolutionCombinations = 2866 mStaticInfo.getCharacteristics().get( 2867 CameraCharacteristics 2868 .SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS); 2869 for (int[] c : ultraHighResolutionCombinations) { 2870 assertTrue(String.format( 2871 "Expected static reprocessable stream combination:" 2872 + "%s not found among the available mandatory max resolution" 2873 + "combinations", 2874 maxSizes.reprocessCombinationToString(c)), 2875 isMandatoryCombinationAvailable(c, maxSizes, /*isInput*/ true, 2876 maxResolutionCombinations)); 2877 } 2878 } 2879 } finally { 2880 closeDevice(id); 2881 } 2882 } 2883 } 2884 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, final MandatoryStreamCombination[] availableCombinations)2885 private boolean isMandatoryCombinationAvailable(final int[] combination, 2886 final MaxStreamSizes maxSizes, 2887 final MandatoryStreamCombination[] availableCombinations) { 2888 return isMandatoryCombinationAvailable(combination, maxSizes, /*isInput*/ false, 2889 availableCombinations, /*useCaseSpecified*/ false); 2890 } 2891 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, boolean isInput, final MandatoryStreamCombination[] availableCombinations)2892 private boolean isMandatoryCombinationAvailable(final int[] combination, 2893 final MaxStreamSizes maxSizes, boolean isInput, 2894 final MandatoryStreamCombination[] availableCombinations) { 2895 return isMandatoryCombinationAvailable(combination, maxSizes, isInput, 2896 availableCombinations, /*useCaseSpecified*/ false); 2897 } 2898 isMandatoryCombinationAvailable(final int[] combination, final MaxStreamSizes maxSizes, boolean isInput, final MandatoryStreamCombination[] availableCombinations, boolean useCaseSpecified)2899 private boolean isMandatoryCombinationAvailable(final int[] combination, 2900 final MaxStreamSizes maxSizes, boolean isInput, 2901 final MandatoryStreamCombination[] availableCombinations, boolean useCaseSpecified) { 2902 boolean supportYuvReprocess = mStaticInfo.isCapabilitySupported( 2903 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING); 2904 boolean supportOpaqueReprocess = mStaticInfo.isCapabilitySupported( 2905 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING); 2906 // Static combinations to be verified can be composed of multiple entries 2907 // that have the following layout (format, size). In case "isInput" is set, 2908 // the first stream configuration entry will contain the input format and size 2909 // as well as the first matching output. 2910 // For combinations that contain streamUseCase, the layout will be (format, size, useCase). 2911 int streamCount = useCaseSpecified ? combination.length / 3 : combination.length / 2; 2912 2913 List<Pair<Pair<Integer, Boolean>, Size>> currentCombination = 2914 new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(streamCount); 2915 List<Integer> streamUseCases = new ArrayList<Integer>(streamCount); 2916 int i = 0; 2917 while (i < combination.length) { 2918 if (isInput && (i == 0)) { 2919 // Skip the combination if the format is not supported for reprocessing. 2920 if ((combination[i] == YUV && !supportYuvReprocess) || 2921 (combination[i] == PRIV && !supportOpaqueReprocess)) { 2922 return true; 2923 } 2924 // Skip the combination if for MAX_RES size, the maximum resolution stream config 2925 // map doesn't have the given format in getInputFormats(). 2926 if (combination[i + 1] == MAX_RES) { 2927 StreamConfigurationMap maxResolutionStreamConfigMap = 2928 mStaticInfo.getCharacteristics().get( 2929 CameraCharacteristics 2930 .SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 2931 int[] inputFormats = maxResolutionStreamConfigMap.getInputFormats(); 2932 int type = combination[i]; 2933 if (!Arrays.stream(inputFormats).anyMatch(index -> index == type)) { 2934 return true; 2935 } 2936 } 2937 Size sz = maxSizes.getMaxInputSizeForFormat(combination[i], combination[i + 1]); 2938 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2939 new Boolean(true)), sz)); 2940 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2941 new Boolean(false)), sz)); 2942 } else { 2943 Size sz = maxSizes.getOutputSizeForFormat(combination[i], combination[i+1]); 2944 currentCombination.add(Pair.create(Pair.create(new Integer(combination[i]), 2945 new Boolean(false)), sz)); 2946 if (useCaseSpecified) { 2947 streamUseCases.add(combination[i + 2]); 2948 } 2949 } 2950 i += 2; 2951 if (useCaseSpecified) { 2952 i += 1; 2953 } 2954 } 2955 2956 for (MandatoryStreamCombination c : availableCombinations) { 2957 List<MandatoryStreamInformation> streamInfoList = c.getStreamsInformation(); 2958 if ((streamInfoList.size() == currentCombination.size()) && 2959 (isInput == c.isReprocessable())) { 2960 ArrayList<Pair<Pair<Integer, Boolean>, Size>> expected = 2961 new ArrayList<Pair<Pair<Integer, Boolean>, Size>>(currentCombination); 2962 ArrayList<Integer> expectedStreamUseCases = new ArrayList<Integer>(streamUseCases); 2963 2964 for (MandatoryStreamInformation streamInfo : streamInfoList) { 2965 Size maxSize = CameraTestUtils.getMaxSize( 2966 streamInfo.getAvailableSizes().toArray(new Size[0])); 2967 Pair p = Pair.create(Pair.create(new Integer(streamInfo.getFormat()), 2968 new Boolean(streamInfo.isInput())), maxSize); 2969 if (expected.contains(p)) { 2970 expected.remove(p); 2971 } 2972 if (useCaseSpecified) { 2973 int streamUseCase = (int) streamInfo.getStreamUseCase(); 2974 if (expectedStreamUseCases.contains(streamUseCase)) { 2975 expectedStreamUseCases.remove(Integer.valueOf(streamUseCase)); 2976 } 2977 } 2978 } 2979 2980 if (expected.isEmpty() && (!useCaseSpecified || expectedStreamUseCases.isEmpty())) { 2981 return true; 2982 } 2983 } 2984 } 2985 2986 return false; 2987 } 2988 2989 /** 2990 * Verify correctness of the configuration tables. 2991 */ validityCheckConfigurationTables(final int[][][] tables)2992 private void validityCheckConfigurationTables(final int[][][] tables) throws Exception { 2993 validityCheckConfigurationTables(tables, false); 2994 } 2995 validityCheckConfigurationTables(final int[][][] tables, boolean useCaseSpecified)2996 private void validityCheckConfigurationTables(final int[][][] tables, boolean useCaseSpecified) 2997 throws Exception { 2998 int tableIdx = 0; 2999 for (int[][] table : tables) { 3000 int rowIdx = 0; 3001 for (int[] row : table) { 3002 if (!useCaseSpecified) { 3003 assertTrue(String.format("Odd number of entries for table %d row %d: %s ", 3004 tableIdx, rowIdx, Arrays.toString(row)), 3005 (row.length % 2) == 0); 3006 } else { 3007 assertTrue(String.format("Incorrect number entries for table with use case " 3008 + "specified %d row %d: %s ", 3009 tableIdx, rowIdx, Arrays.toString(row)), 3010 (row.length % 3) == 0); 3011 } 3012 3013 int i = 0; 3014 while (i < row.length) { 3015 int format = row[i]; 3016 int maxSize = row[i + 1]; 3017 assertTrue(String.format("table %d row %d index %d format not valid: %d", 3018 tableIdx, rowIdx, i, format), 3019 format == PRIV || format == JPEG || format == YUV 3020 || format == RAW); 3021 assertTrue(String.format("table %d row %d index %d max size not valid: %d", 3022 tableIdx, rowIdx, i + 1, maxSize), 3023 maxSize == PREVIEW || maxSize == RECORD 3024 || maxSize == MAXIMUM || maxSize == VGA || maxSize == S720P 3025 || maxSize == S1440P || maxSize == MAX_RES); 3026 if (useCaseSpecified) { 3027 int useCase = row[i + 2]; 3028 assertTrue(String.format("table %d row %d index %d use case not valid: %d", 3029 tableIdx, rowIdx, i + 2, useCase), 3030 useCase == USE_CASE_PREVIEW 3031 || useCase == USE_CASE_PREVIEW_VIDEO_STILL 3032 || useCase == USE_CASE_STILL_CAPTURE 3033 || useCase == USE_CASE_VIDEO_CALL 3034 || useCase == USE_CASE_VIDEO_RECORD 3035 || useCase == USE_CASE_CROPPED_RAW); 3036 i += 3; 3037 } else { 3038 i += 2; 3039 } 3040 } 3041 rowIdx++; 3042 } 3043 tableIdx++; 3044 } 3045 } 3046 3047 /** 3048 * Simple holder for resolutions to use for different camera outputs and size limits. 3049 */ 3050 static class MaxStreamSizes { 3051 // Format shorthands 3052 static final int PRIV = ImageFormat.PRIVATE; 3053 static final int JPEG = ImageFormat.JPEG; 3054 static final int YUV = ImageFormat.YUV_420_888; 3055 static final int RAW = ImageFormat.RAW_SENSOR; 3056 static final int Y8 = ImageFormat.Y8; 3057 static final int HEIC = ImageFormat.HEIC; 3058 3059 // Max resolution output indices 3060 static final int PREVIEW = 0; 3061 static final int RECORD = 1; 3062 static final int MAXIMUM = 2; 3063 static final int VGA = 3; 3064 static final int VGA_FULL_FOV = 4; 3065 static final int MAX_30FPS = 5; 3066 static final int S720P = 6; 3067 static final int S1440P = 7; 3068 static final int MAX_RES = 8; 3069 static final int RESOLUTION_COUNT = 9; 3070 3071 // Max resolution input indices 3072 static final int INPUT_MAXIMUM = 0; 3073 static final int INPUT_MAX_RES = 1; 3074 static final int INPUT_RESOLUTION_COUNT = 2; 3075 3076 static final long FRAME_DURATION_30FPS_NSEC = (long) 1e9 / 30; 3077 3078 static final int USE_CASE_PREVIEW = 3079 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW; 3080 static final int USE_CASE_VIDEO_RECORD = 3081 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD; 3082 static final int USE_CASE_STILL_CAPTURE = 3083 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE; 3084 static final int USE_CASE_PREVIEW_VIDEO_STILL = 3085 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL; 3086 static final int USE_CASE_VIDEO_CALL = 3087 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL; 3088 static final int USE_CASE_CROPPED_RAW = 3089 CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW; 3090 3091 private final Size[] mMaxPrivSizes = new Size[RESOLUTION_COUNT]; 3092 private final Size[] mMaxJpegSizes = new Size[RESOLUTION_COUNT]; 3093 private final Size[] mMaxYuvSizes = new Size[RESOLUTION_COUNT]; 3094 private final Size[] mMaxY8Sizes = new Size[RESOLUTION_COUNT]; 3095 private final Size[] mMaxHeicSizes = new Size[RESOLUTION_COUNT]; 3096 private final Size mMaxRawSize; 3097 private final Size mMaxResolutionRawSize; 3098 3099 private final Size[] mMaxPrivInputSizes = new Size[INPUT_RESOLUTION_COUNT]; 3100 private final Size[] mMaxYuvInputSizes = new Size[INPUT_RESOLUTION_COUNT]; 3101 private final Size mMaxInputY8Size; 3102 MaxStreamSizes(StaticMetadata sm, String cameraId, Context context)3103 public MaxStreamSizes(StaticMetadata sm, String cameraId, Context context) { 3104 Size[] privSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.PRIVATE, 3105 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3106 Size[] yuvSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888, 3107 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3108 3109 Size[] y8Sizes = sm.getAvailableSizesForFormatChecked(ImageFormat.Y8, 3110 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3111 Size[] jpegSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.JPEG, 3112 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3113 Size[] rawSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 3114 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3115 Size[] heicSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.HEIC, 3116 StaticMetadata.StreamDirection.Output, /*fastSizes*/true, /*slowSizes*/false); 3117 3118 Size maxPreviewSize = getMaxPreviewSize(context, cameraId); 3119 3120 StreamConfigurationMap configs = sm.getCharacteristics().get( 3121 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 3122 3123 StreamConfigurationMap maxResConfigs = sm.getCharacteristics().get( 3124 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION); 3125 3126 mMaxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null; 3127 mMaxResolutionRawSize = sm.isUltraHighResolutionSensor() ? 3128 CameraTestUtils.getMaxSize( 3129 maxResConfigs.getOutputSizes(ImageFormat.RAW_SENSOR)) 3130 : null; 3131 3132 if (sm.isColorOutputSupported()) { 3133 // We don't include JPEG sizes capped at PREVIEW since for MPC 12+ devices, JPEG 3134 // sizes are necessarily > 1080p. Also the mandatory stream combinations have no 3135 // JPEG streams capped at PREVIEW. 3136 mMaxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize); 3137 mMaxYuvSizes[PREVIEW] = getMaxSize(yuvSizes, maxPreviewSize); 3138 3139 if (sm.isExternalCamera()) { 3140 mMaxPrivSizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs); 3141 mMaxYuvSizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs); 3142 mMaxJpegSizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs); 3143 } else { 3144 mMaxPrivSizes[RECORD] = getMaxRecordingSize(cameraId); 3145 mMaxYuvSizes[RECORD] = getMaxRecordingSize(cameraId); 3146 mMaxJpegSizes[RECORD] = getMaxRecordingSize(cameraId); 3147 } 3148 3149 if (sm.isUltraHighResolutionSensor()) { 3150 mMaxYuvSizes[MAX_RES] = CameraTestUtils.getMaxSize( 3151 maxResConfigs.getOutputSizes(ImageFormat.YUV_420_888)); 3152 mMaxJpegSizes[MAX_RES] = CameraTestUtils.getMaxSize( 3153 maxResConfigs.getOutputSizes(ImageFormat.JPEG)); 3154 } 3155 3156 mMaxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes); 3157 mMaxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes); 3158 mMaxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes); 3159 3160 // Must always be supported, add unconditionally 3161 final Size vgaSize = new Size(640, 480); 3162 mMaxPrivSizes[VGA] = vgaSize; 3163 mMaxYuvSizes[VGA] = vgaSize; 3164 mMaxJpegSizes[VGA] = vgaSize; 3165 3166 // Check for 720p size for PRIVATE and YUV 3167 // 720p is not mandatory for JPEG so it is not checked 3168 final Size s720pSize = new Size(1280, 720); 3169 mMaxPrivSizes[S720P] = getMaxSize(configs.getOutputSizes(ImageFormat.PRIVATE), 3170 s720pSize); 3171 mMaxYuvSizes[S720P] = getMaxSize(configs.getOutputSizes(ImageFormat.YUV_420_888), 3172 s720pSize); 3173 3174 final Size s1440pSize = new Size(1920, 1440); 3175 mMaxPrivSizes[S1440P] = getMaxSize(configs.getOutputSizes(ImageFormat.PRIVATE), 3176 s1440pSize); 3177 mMaxYuvSizes[S1440P] = getMaxSize(configs.getOutputSizes(ImageFormat.YUV_420_888), 3178 s1440pSize); 3179 mMaxJpegSizes[S1440P] = getMaxSize(configs.getOutputSizes(ImageFormat.JPEG), 3180 s1440pSize); 3181 3182 if (sm.isMonochromeWithY8()) { 3183 mMaxY8Sizes[PREVIEW] = getMaxSize(y8Sizes, maxPreviewSize); 3184 if (sm.isExternalCamera()) { 3185 mMaxY8Sizes[RECORD] = getMaxExternalRecordingSize(cameraId, configs); 3186 } else { 3187 mMaxY8Sizes[RECORD] = getMaxRecordingSize(cameraId); 3188 } 3189 mMaxY8Sizes[MAXIMUM] = CameraTestUtils.getMaxSize(y8Sizes); 3190 mMaxY8Sizes[VGA] = vgaSize; 3191 mMaxY8Sizes[S720P] = getMaxSize(configs.getOutputSizes(ImageFormat.Y8), 3192 s720pSize); 3193 mMaxY8Sizes[S1440P] = getMaxSize(configs.getOutputSizes(ImageFormat.Y8), 3194 s1440pSize); 3195 } 3196 3197 if (sm.isHeicSupported()) { 3198 mMaxHeicSizes[PREVIEW] = getMaxSize(heicSizes, maxPreviewSize); 3199 mMaxHeicSizes[RECORD] = getMaxRecordingSize(cameraId); 3200 mMaxHeicSizes[MAXIMUM] = CameraTestUtils.getMaxSize(heicSizes); 3201 mMaxHeicSizes[VGA] = vgaSize; 3202 mMaxHeicSizes[S720P] = getMaxSize(configs.getOutputSizes(ImageFormat.HEIC), 3203 s720pSize); 3204 mMaxHeicSizes[S1440P] = getMaxSize(configs.getOutputSizes(ImageFormat.HEIC), 3205 s1440pSize); 3206 } 3207 } 3208 if (sm.isColorOutputSupported() && !sm.isHardwareLevelLegacy()) { 3209 // VGA resolution, but with aspect ratio matching full res FOV 3210 float fullFovAspect = mMaxYuvSizes[MAXIMUM].getWidth() 3211 / (float) mMaxYuvSizes[MAXIMUM].getHeight(); 3212 Size vgaFullFovSize = new Size(640, (int) (640 / fullFovAspect)); 3213 3214 mMaxPrivSizes[VGA_FULL_FOV] = vgaFullFovSize; 3215 mMaxYuvSizes[VGA_FULL_FOV] = vgaFullFovSize; 3216 mMaxJpegSizes[VGA_FULL_FOV] = vgaFullFovSize; 3217 if (sm.isMonochromeWithY8()) { 3218 mMaxY8Sizes[VGA_FULL_FOV] = vgaFullFovSize; 3219 } 3220 3221 // Max resolution that runs at 30fps 3222 3223 Size maxPriv30fpsSize = null; 3224 Size maxYuv30fpsSize = null; 3225 Size maxY830fpsSize = null; 3226 Size maxJpeg30fpsSize = null; 3227 Comparator<Size> comparator = new SizeComparator(); 3228 for (Map.Entry<Size, Long> e : 3229 sm.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.PRIVATE). 3230 entrySet()) { 3231 Size s = e.getKey(); 3232 Long minDuration = e.getValue(); 3233 Log.d(TAG, String.format("Priv Size: %s, duration %d limit %d", s, minDuration, 3234 FRAME_DURATION_30FPS_NSEC)); 3235 if (minDuration <= FRAME_DURATION_30FPS_NSEC) { 3236 if (maxPriv30fpsSize == null || 3237 comparator.compare(maxPriv30fpsSize, s) < 0) { 3238 maxPriv30fpsSize = s; 3239 } 3240 } 3241 } 3242 assertTrue("No PRIVATE resolution available at 30fps!", maxPriv30fpsSize != null); 3243 3244 for (Map.Entry<Size, Long> e : 3245 sm.getAvailableMinFrameDurationsForFormatChecked( 3246 ImageFormat.YUV_420_888). 3247 entrySet()) { 3248 Size s = e.getKey(); 3249 Long minDuration = e.getValue(); 3250 Log.d(TAG, String.format("YUV Size: %s, duration %d limit %d", s, minDuration, 3251 FRAME_DURATION_30FPS_NSEC)); 3252 if (minDuration <= FRAME_DURATION_30FPS_NSEC) { 3253 if (maxYuv30fpsSize == null || 3254 comparator.compare(maxYuv30fpsSize, s) < 0) { 3255 maxYuv30fpsSize = s; 3256 } 3257 } 3258 } 3259 assertTrue("No YUV_420_888 resolution available at 30fps!", 3260 maxYuv30fpsSize != null); 3261 3262 if (sm.isMonochromeWithY8()) { 3263 for (Map.Entry<Size, Long> e : 3264 sm.getAvailableMinFrameDurationsForFormatChecked( 3265 ImageFormat.Y8). 3266 entrySet()) { 3267 Size s = e.getKey(); 3268 Long minDuration = e.getValue(); 3269 Log.d(TAG, String.format("Y8 Size: %s, duration %d limit %d", 3270 s, minDuration, FRAME_DURATION_30FPS_NSEC)); 3271 if (minDuration <= FRAME_DURATION_30FPS_NSEC) { 3272 if (maxY830fpsSize == null || 3273 comparator.compare(maxY830fpsSize, s) < 0) { 3274 maxY830fpsSize = s; 3275 } 3276 } 3277 } 3278 assertTrue("No Y8 resolution available at 30fps!", maxY830fpsSize != null); 3279 } 3280 3281 for (Map.Entry<Size, Long> e : 3282 sm.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.JPEG). 3283 entrySet()) { 3284 Size s = e.getKey(); 3285 Long minDuration = e.getValue(); 3286 Log.d(TAG, String.format("JPEG Size: %s, duration %d limit %d", s, minDuration, 3287 FRAME_DURATION_30FPS_NSEC)); 3288 if (minDuration <= FRAME_DURATION_30FPS_NSEC) { 3289 if (maxJpeg30fpsSize == null || 3290 comparator.compare(maxJpeg30fpsSize, s) < 0) { 3291 maxJpeg30fpsSize = s; 3292 } 3293 } 3294 } 3295 assertTrue("No JPEG resolution available at 30fps!", maxJpeg30fpsSize != null); 3296 3297 mMaxPrivSizes[MAX_30FPS] = maxPriv30fpsSize; 3298 mMaxYuvSizes[MAX_30FPS] = maxYuv30fpsSize; 3299 mMaxY8Sizes[MAX_30FPS] = maxY830fpsSize; 3300 mMaxJpegSizes[MAX_30FPS] = maxJpeg30fpsSize; 3301 } 3302 3303 Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE); 3304 mMaxPrivInputSizes[INPUT_MAXIMUM] = privInputSizes != null 3305 ? CameraTestUtils.getMaxSize(privInputSizes) 3306 : null; 3307 Size[] maxResPrivInputSizes = 3308 sm.isUltraHighResolutionSensor() ? 3309 maxResConfigs.getInputSizes(ImageFormat.PRIVATE) 3310 : null; 3311 mMaxPrivInputSizes[INPUT_MAX_RES] = maxResPrivInputSizes != null 3312 ? CameraTestUtils.getMaxSize(maxResPrivInputSizes) 3313 : null; 3314 3315 Size[] yuvInputSizes = configs.getInputSizes(ImageFormat.YUV_420_888); 3316 mMaxYuvInputSizes[INPUT_MAXIMUM] = yuvInputSizes != null 3317 ? CameraTestUtils.getMaxSize(yuvInputSizes) 3318 : null; 3319 Size[] maxResYuvInputSizes = sm.isUltraHighResolutionSensor() ? 3320 maxResConfigs.getInputSizes(ImageFormat.YUV_420_888) 3321 : null; 3322 mMaxYuvInputSizes[INPUT_MAX_RES] = maxResYuvInputSizes != null 3323 ? CameraTestUtils.getMaxSize(maxResYuvInputSizes) 3324 : null; 3325 3326 Size[] y8InputSizes = configs.getInputSizes(ImageFormat.Y8); 3327 mMaxInputY8Size = y8InputSizes != null 3328 ? CameraTestUtils.getMaxSize(y8InputSizes) 3329 : null; 3330 } 3331 getOutputSizeForFormat(int format, int resolutionIndex)3332 public final Size getOutputSizeForFormat(int format, int resolutionIndex) { 3333 if (resolutionIndex >= RESOLUTION_COUNT) { 3334 return new Size(0, 0); 3335 } 3336 3337 switch (format) { 3338 case PRIV: 3339 return mMaxPrivSizes[resolutionIndex]; 3340 case YUV: 3341 return mMaxYuvSizes[resolutionIndex]; 3342 case JPEG: 3343 return mMaxJpegSizes[resolutionIndex]; 3344 case Y8: 3345 return mMaxY8Sizes[resolutionIndex]; 3346 case HEIC: 3347 return mMaxHeicSizes[resolutionIndex]; 3348 case RAW: 3349 if (resolutionIndex == MAX_RES) { 3350 return mMaxResolutionRawSize; 3351 } 3352 return mMaxRawSize; 3353 default: 3354 return new Size(0, 0); 3355 } 3356 } 3357 getMaxInputSizeForFormat(int format, int resolutionIndex)3358 public final Size getMaxInputSizeForFormat(int format, int resolutionIndex) { 3359 int inputResolutionIndex = getInputResolutionIndex(resolutionIndex); 3360 if (inputResolutionIndex >= INPUT_RESOLUTION_COUNT || inputResolutionIndex == -1) { 3361 return new Size(0, 0); 3362 } 3363 switch (format) { 3364 case PRIV: 3365 return mMaxPrivInputSizes[inputResolutionIndex]; 3366 case YUV: 3367 return mMaxYuvInputSizes[inputResolutionIndex]; 3368 case Y8: 3369 return mMaxInputY8Size; 3370 case RAW: 3371 return mMaxResolutionRawSize; 3372 default: 3373 return new Size(0, 0); 3374 } 3375 } 3376 combinationToString(int[] combination)3377 public static String combinationToString(int[] combination) { 3378 return combinationToString(combination, /*useCaseSpecified*/ false); 3379 } 3380 combinationToString(int[] combination, boolean useCaseSpecified)3381 public static String combinationToString(int[] combination, boolean useCaseSpecified) { 3382 StringBuilder b = new StringBuilder("{ "); 3383 int i = 0; 3384 while (i < combination.length) { 3385 int format = combination[i]; 3386 int sizeLimit = combination[i + 1]; 3387 3388 appendFormatSize(b, format, sizeLimit); 3389 if (useCaseSpecified) { 3390 int streamUseCase = combination[i + 2]; 3391 appendStreamUseCase(b, streamUseCase); 3392 i += 1; 3393 } 3394 i += 2; 3395 b.append(" "); 3396 } 3397 b.append("}"); 3398 return b.toString(); 3399 } 3400 reprocessCombinationToString(int[] reprocessCombination)3401 public static String reprocessCombinationToString(int[] reprocessCombination) { 3402 // reprocessConfig[0..1] is the input configuration 3403 StringBuilder b = new StringBuilder("Input: "); 3404 appendFormatSize(b, reprocessCombination[0], reprocessCombination[1]); 3405 3406 // reprocessCombnation[0..1] is also output combination to be captured as reprocess 3407 // input. 3408 b.append(", Outputs: { "); 3409 for (int i = 0; i < reprocessCombination.length; i += 2) { 3410 int format = reprocessCombination[i]; 3411 int sizeLimit = reprocessCombination[i + 1]; 3412 3413 appendFormatSize(b, format, sizeLimit); 3414 b.append(" "); 3415 } 3416 b.append("}"); 3417 return b.toString(); 3418 } 3419 getInputResolutionIndex(int resolutionIndex)3420 int getInputResolutionIndex(int resolutionIndex) { 3421 switch (resolutionIndex) { 3422 case MAXIMUM: 3423 return INPUT_MAXIMUM; 3424 case MAX_RES: 3425 return INPUT_MAX_RES; 3426 } 3427 return -1; 3428 } 3429 appendFormatSize(StringBuilder b, int format, int size)3430 private static void appendFormatSize(StringBuilder b, int format, int size) { 3431 switch (format) { 3432 case PRIV: 3433 b.append("[PRIV, "); 3434 break; 3435 case JPEG: 3436 b.append("[JPEG, "); 3437 break; 3438 case YUV: 3439 b.append("[YUV, "); 3440 break; 3441 case Y8: 3442 b.append("[Y8, "); 3443 break; 3444 case RAW: 3445 b.append("[RAW, "); 3446 break; 3447 default: 3448 b.append("[UNK, "); 3449 break; 3450 } 3451 3452 switch (size) { 3453 case PREVIEW: 3454 b.append("PREVIEW]"); 3455 break; 3456 case RECORD: 3457 b.append("RECORD]"); 3458 break; 3459 case MAXIMUM: 3460 b.append("MAXIMUM]"); 3461 break; 3462 case VGA: 3463 b.append("VGA]"); 3464 break; 3465 case VGA_FULL_FOV: 3466 b.append("VGA_FULL_FOV]"); 3467 break; 3468 case MAX_30FPS: 3469 b.append("MAX_30FPS]"); 3470 break; 3471 case S720P: 3472 b.append("S720P]"); 3473 break; 3474 case S1440P: 3475 b.append("S1440P]"); 3476 break; 3477 case MAX_RES: 3478 b.append("MAX_RES]"); 3479 break; 3480 default: 3481 b.append("UNK]"); 3482 break; 3483 } 3484 } 3485 appendStreamUseCase(StringBuilder b, int streamUseCase)3486 private static void appendStreamUseCase(StringBuilder b, int streamUseCase) { 3487 b.append(", "); 3488 switch (streamUseCase) { 3489 case USE_CASE_PREVIEW: 3490 b.append("USE_CASE_PREVIEW"); 3491 break; 3492 case USE_CASE_PREVIEW_VIDEO_STILL: 3493 b.append("USE_CASE_PREVIEW_VIDEO_STILL"); 3494 break; 3495 case USE_CASE_STILL_CAPTURE: 3496 b.append("USE_CASE_STILL_CAPTURE"); 3497 break; 3498 case USE_CASE_VIDEO_CALL: 3499 b.append("USE_CASE_VIDEO_CALL"); 3500 break; 3501 case USE_CASE_VIDEO_RECORD: 3502 b.append("USE_CASE_VIDEO_RECORD"); 3503 break; 3504 case USE_CASE_CROPPED_RAW: 3505 b.append("USE_CASE_CROPPED_RAW"); 3506 break; 3507 default: 3508 b.append("UNK STREAM_USE_CASE"); 3509 break; 3510 } 3511 b.append(";"); 3512 } 3513 } 3514 getMaxRecordingSize(String cameraId)3515 private static Size getMaxRecordingSize(String cameraId) { 3516 int id = Integer.valueOf(cameraId); 3517 3518 int quality = 3519 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P) ? 3520 CamcorderProfile.QUALITY_2160P : 3521 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P) ? 3522 CamcorderProfile.QUALITY_1080P : 3523 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_720P) ? 3524 CamcorderProfile.QUALITY_720P : 3525 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_480P) ? 3526 CamcorderProfile.QUALITY_480P : 3527 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QVGA) ? 3528 CamcorderProfile.QUALITY_QVGA : 3529 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_CIF) ? 3530 CamcorderProfile.QUALITY_CIF : 3531 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QCIF) ? 3532 CamcorderProfile.QUALITY_QCIF : 3533 -1; 3534 3535 assertTrue("No recording supported for camera id " + cameraId, quality != -1); 3536 3537 CamcorderProfile maxProfile = CamcorderProfile.get(id, quality); 3538 return new Size(maxProfile.videoFrameWidth, maxProfile.videoFrameHeight); 3539 } 3540 getMaxExternalRecordingSize( String cameraId, StreamConfigurationMap config)3541 private static Size getMaxExternalRecordingSize( 3542 String cameraId, StreamConfigurationMap config) { 3543 final Size FULLHD = new Size(1920, 1080); 3544 3545 Size[] videoSizeArr = config.getOutputSizes(android.media.MediaRecorder.class); 3546 List<Size> sizes = new ArrayList<Size>(); 3547 for (Size sz: videoSizeArr) { 3548 if (sz.getWidth() <= FULLHD.getWidth() && sz.getHeight() <= FULLHD.getHeight()) { 3549 sizes.add(sz); 3550 } 3551 } 3552 List<Size> videoSizes = getAscendingOrderSizes(sizes, /*ascending*/false); 3553 for (Size sz : videoSizes) { 3554 long minFrameDuration = config.getOutputMinFrameDuration( 3555 android.media.MediaRecorder.class, sz); 3556 // Give some margin for rounding error 3557 if (minFrameDuration < (1e9 / 29.9)) { 3558 Log.i(TAG, "External camera " + cameraId + " has max video size:" + sz); 3559 return sz; 3560 } 3561 } 3562 fail("Camera " + cameraId + " does not support any 30fps video output"); 3563 return FULLHD; // doesn't matter what size is returned here 3564 } 3565 3566 /** 3567 * Get maximum size in list that's equal or smaller to than the bound. 3568 * Returns null if no size is smaller than or equal to the bound. 3569 */ getMaxSize(Size[] sizes, Size bound)3570 private static Size getMaxSize(Size[] sizes, Size bound) { 3571 if (sizes == null || sizes.length == 0) { 3572 throw new IllegalArgumentException("sizes was empty"); 3573 } 3574 3575 Size sz = null; 3576 for (Size size : sizes) { 3577 if (size.getWidth() <= bound.getWidth() && size.getHeight() <= bound.getHeight()) { 3578 3579 if (sz == null) { 3580 sz = size; 3581 } else { 3582 long curArea = sz.getWidth() * (long) sz.getHeight(); 3583 long newArea = size.getWidth() * (long) size.getHeight(); 3584 if ( newArea > curArea ) { 3585 sz = size; 3586 } 3587 } 3588 } 3589 } 3590 3591 assertTrue("No size under bound found: " + Arrays.toString(sizes) + " bound " + bound, 3592 sz != null); 3593 3594 return sz; 3595 } 3596 getMaxPreviewSize(Context context, String cameraId)3597 private static Size getMaxPreviewSize(Context context, String cameraId) { 3598 try { 3599 WindowManager windowManager = context.getSystemService(WindowManager.class); 3600 assertNotNull("Could not find WindowManager service.", windowManager); 3601 3602 WindowMetrics windowMetrics = windowManager.getCurrentWindowMetrics(); 3603 Rect windowBounds = windowMetrics.getBounds(); 3604 3605 int width = windowBounds.width(); 3606 int height = windowBounds.height(); 3607 3608 if (height > width) { 3609 height = width; 3610 width = windowBounds.height(); 3611 } 3612 3613 CameraManager camMgr = context.getSystemService(CameraManager.class); 3614 List<Size> orderedPreviewSizes = CameraTestUtils.getSupportedPreviewSizes( 3615 cameraId, camMgr, PREVIEW_SIZE_BOUND); 3616 3617 if (orderedPreviewSizes != null) { 3618 for (Size size : orderedPreviewSizes) { 3619 if (width >= size.getWidth() && 3620 height >= size.getHeight()) { 3621 return size; 3622 } 3623 } 3624 } 3625 } catch (Exception e) { 3626 Log.e(TAG, "getMaxPreviewSize Failed. " + e); 3627 } 3628 return PREVIEW_SIZE_BOUND; 3629 } 3630 } 3631