1 /* 2 * Copyright (C) 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.ImageDropperListener; 20 import static android.hardware.camera2.cts.CameraTestUtils.MAX_READER_IMAGES; 21 import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 22 import static android.hardware.camera2.cts.CameraTestUtils.assertEquals; 23 import static android.hardware.camera2.cts.CameraTestUtils.assertNotNull; 24 import static android.hardware.camera2.cts.CameraTestUtils.assertTrue; 25 import static android.hardware.camera2.cts.CameraTestUtils.fail; 26 import static android.hardware.camera2.cts.CameraTestUtils.makeImageReader; 27 import static android.hardware.cts.helpers.CameraUtils.getAvailableSurfaceTexture; 28 29 import static org.junit.Assert.assertArrayEquals; 30 31 import android.graphics.Bitmap; 32 import android.graphics.ImageFormat; 33 import android.graphics.SurfaceTexture; 34 import android.hardware.HardwareBuffer; 35 import android.hardware.camera2.CameraCharacteristics; 36 import android.hardware.camera2.CameraDevice; 37 import android.hardware.camera2.CaptureFailure; 38 import android.hardware.camera2.CaptureRequest; 39 import android.hardware.camera2.TotalCaptureResult; 40 import android.hardware.camera2.cts.CameraTestUtils.ImageVerifierListener; 41 import android.hardware.camera2.cts.helpers.StaticMetadata; 42 import android.hardware.camera2.cts.rs.BitmapUtils; 43 import android.hardware.camera2.cts.testcases.Camera2MultiViewTestCase; 44 import android.hardware.camera2.params.OutputConfiguration; 45 import android.media.Image; 46 import android.media.ImageReader; 47 import android.media.ImageWriter; 48 import android.opengl.Matrix; 49 import android.os.ConditionVariable; 50 import android.os.SystemClock; 51 import android.util.Log; 52 import android.util.Size; 53 import android.view.Surface; 54 import android.view.TextureView; 55 56 import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; 57 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.junit.runners.Parameterized; 61 62 import java.util.ArrayList; 63 import java.util.Arrays; 64 import java.util.HashMap; 65 import java.util.List; 66 67 /** 68 * CameraDevice test by using combination of SurfaceView, TextureView and ImageReader 69 */ 70 71 @RunWith(Parameterized.class) 72 public class MultiViewTest extends Camera2MultiViewTestCase { 73 private static final String TAG = "MultiViewTest"; 74 private final static long WAIT_FOR_COMMAND_TO_COMPLETE = 5000; //ms 75 private final static long PREVIEW_TIME_MS = 2000; 76 private final static long PREVIEW_FLUSH_TIME_MS = 1000; 77 private final static int NUM_SURFACE_SWITCHES = 30; 78 private final static int IMG_READER_COUNT = 2; 79 private final static int YUV_IMG_READER_COUNT = 3; 80 private final static double BITMAP_DIFF_THRESHOLD = 0.1; 81 82 @Test testTextureViewPreview()83 public void testTextureViewPreview() throws Exception { 84 for (String cameraId : getCameraIdsUnderTest()) { 85 Exception prior = null; 86 87 try { 88 openCamera(cameraId); 89 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 90 Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping"); 91 continue; 92 } 93 List<TextureView> views = Arrays.asList(mTextureView[0]); 94 textureViewPreview(cameraId, views, /*ImageReader*/null); 95 } catch (Exception e) { 96 prior = e; 97 } finally { 98 try { 99 closeCamera(cameraId); 100 } catch (Exception e) { 101 if (prior != null) { 102 Log.e(TAG, "Prior exception received: " + prior); 103 } 104 prior = e; 105 } 106 if (prior != null) throw prior; // Rethrow last exception. 107 } 108 } 109 } 110 111 @Test testTextureViewPreviewWithImageReader()112 public void testTextureViewPreviewWithImageReader() throws Exception { 113 for (String cameraId : getCameraIdsUnderTest()) { 114 Exception prior = null; 115 116 ImageVerifierListener yuvListener; 117 ImageReader yuvReader = null; 118 119 try { 120 openCamera(cameraId); 121 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 122 Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping"); 123 continue; 124 } 125 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 126 yuvListener = 127 new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888); 128 yuvReader = makeImageReader(previewSize, 129 ImageFormat.YUV_420_888, MAX_READER_IMAGES, yuvListener, mHandler); 130 int maxNumStreamsProc = 131 getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked(); 132 if (maxNumStreamsProc < 2) { 133 continue; 134 } 135 List<TextureView> views = Arrays.asList(mTextureView[0]); 136 textureViewPreview(cameraId, views, yuvReader); 137 } catch (Exception e) { 138 prior = e; 139 } finally { 140 try { 141 // Close camera device first. This will give some more time for 142 // ImageVerifierListener to finish the validation before yuvReader is closed 143 // (all image will be closed after that) 144 closeCamera(cameraId); 145 if (yuvReader != null) { 146 yuvReader.close(); 147 } 148 } catch (Exception e) { 149 if (prior != null) { 150 Log.e(TAG, "Prior exception received: " + prior); 151 } 152 prior = e; 153 } 154 if (prior != null) throw prior; // Rethrow last exception. 155 } 156 } 157 } 158 159 @Test testDualTextureViewPreview()160 public void testDualTextureViewPreview() throws Exception { 161 for (String cameraId : getCameraIdsUnderTest()) { 162 Exception prior = null; 163 try { 164 openCamera(cameraId); 165 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 166 Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping"); 167 continue; 168 } 169 int maxNumStreamsProc = 170 getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked(); 171 if (maxNumStreamsProc < 2) { 172 continue; 173 } 174 List<TextureView> views = Arrays.asList(mTextureView[0], mTextureView[1]); 175 textureViewPreview(cameraId, views, /*ImageReader*/null); 176 } catch (Exception e) { 177 prior = e; 178 } finally { 179 try { 180 closeCamera(cameraId); 181 } catch (Exception e) { 182 if (prior != null) { 183 Log.e(TAG, "Prior exception received: " + prior); 184 } 185 prior = e; 186 } 187 if (prior != null) throw prior; // Rethrow last exception. 188 } 189 } 190 } 191 192 @Test testDualTextureViewAndImageReaderPreview()193 public void testDualTextureViewAndImageReaderPreview() throws Exception { 194 for (String cameraId : getCameraIdsUnderTest()) { 195 Exception prior = null; 196 197 ImageVerifierListener yuvListener = null; 198 ImageReader yuvReader = null; 199 200 try { 201 openCamera(cameraId); 202 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 203 Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping"); 204 continue; 205 } 206 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 207 yuvListener = 208 new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888); 209 yuvReader = makeImageReader(previewSize, 210 ImageFormat.YUV_420_888, MAX_READER_IMAGES, yuvListener, mHandler); 211 int maxNumStreamsProc = 212 getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked(); 213 if (maxNumStreamsProc < 3) { 214 continue; 215 } 216 List<TextureView> views = Arrays.asList(mTextureView[0], mTextureView[1]); 217 textureViewPreview(cameraId, views, yuvReader); 218 } catch (Exception e) { 219 prior = e; 220 } finally { 221 try { 222 if (yuvListener != null) { 223 yuvListener.onReaderDestroyed(); 224 } 225 if (yuvReader != null) { 226 yuvReader.close(); 227 } 228 closeCamera(cameraId); 229 } catch (Exception e) { 230 if (prior != null) { 231 Log.e(TAG, "Prior exception received: " + prior); 232 } 233 prior = e; 234 } 235 if (prior != null) throw prior; // Rethrow last exception. 236 } 237 } 238 } 239 240 @Test testDualCameraPreview()241 public void testDualCameraPreview() throws Exception { 242 final int NUM_CAMERAS_TESTED = 2; 243 String[] cameraIdsUnderTest = getCameraIdsUnderTest(); 244 if (cameraIdsUnderTest.length < NUM_CAMERAS_TESTED) { 245 return; 246 } 247 248 try { 249 for (int i = 0; i < NUM_CAMERAS_TESTED; i++) { 250 openCamera(cameraIdsUnderTest[i]); 251 if (!getStaticInfo(cameraIdsUnderTest[i]).isColorOutputSupported()) { 252 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 253 " does not support color outputs, skipping"); 254 continue; 255 } 256 List<TextureView> views = Arrays.asList(mTextureView[i]); 257 258 startTextureViewPreview(cameraIdsUnderTest[i], views, /*ImageReader*/null); 259 } 260 // TODO: check the framerate is correct 261 SystemClock.sleep(PREVIEW_TIME_MS); 262 for (int i = 0; i < NUM_CAMERAS_TESTED; i++) { 263 if (!getStaticInfo(cameraIdsUnderTest[i]).isColorOutputSupported()) { 264 Log.i(TAG, "Camera " + cameraIdsUnderTest[i] + 265 " does not support color outputs, skipping"); 266 continue; 267 } 268 stopPreview(cameraIdsUnderTest[i]); 269 } 270 } catch (BlockingOpenException e) { 271 // The only error accepted is ERROR_MAX_CAMERAS_IN_USE, which means HAL doesn't support 272 // concurrent camera streaming 273 assertEquals("Camera device open failed", 274 CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE, e.getCode()); 275 Log.i(TAG, "Camera HAL does not support dual camera preview. Skip the test"); 276 } finally { 277 for (int i = 0; i < NUM_CAMERAS_TESTED; i++) { 278 closeCamera(cameraIdsUnderTest[i]); 279 } 280 } 281 } 282 283 /* 284 * Verify dynamic shared surface behavior. 285 */ 286 @Test testSharedSurfaceBasic()287 public void testSharedSurfaceBasic() throws Exception { 288 for (String cameraId : getCameraIdsUnderTest()) { 289 try { 290 openCamera(cameraId); 291 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 292 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 293 continue; 294 } 295 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 296 Log.i(TAG, "Camera " + cameraId + 297 " does not support color outputs, skipping"); 298 continue; 299 } 300 301 testSharedSurfaceBasicByCamera(cameraId); 302 } 303 finally { 304 closeCamera(cameraId); 305 } 306 } 307 } 308 testSharedSurfaceBasicByCamera(String cameraId)309 private void testSharedSurfaceBasicByCamera(String cameraId) throws Exception { 310 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 311 CameraPreviewListener[] previewListener = new CameraPreviewListener[2]; 312 SurfaceTexture[] previewTexture = new SurfaceTexture[2]; 313 Surface[] surfaces = new Surface[2]; 314 OutputConfiguration[] outputConfigs = new OutputConfiguration[2]; 315 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 316 317 // Create surface textures with the same size 318 for (int i = 0; i < 2; i++) { 319 previewListener[i] = new CameraPreviewListener(); 320 mTextureView[i].setSurfaceTextureListener(previewListener[i]); 321 previewTexture[i] = getAvailableSurfaceTexture( 322 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 323 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 324 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 325 // Correct the preview display rotation. 326 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 327 surfaces[i] = new Surface(previewTexture[i]); 328 outputConfigs[i] = new OutputConfiguration(surfaces[i]); 329 outputConfigs[i].enableSurfaceSharing(); 330 outputConfigurations.add(outputConfigs[i]); 331 } 332 333 startPreviewWithConfigs(cameraId, outputConfigurations, null); 334 335 boolean previewDone = 336 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 337 assertTrue("Unable to start preview", previewDone); 338 339 //try to dynamically add and remove any of the initial configured outputs 340 try { 341 outputConfigs[1].addSurface(surfaces[0]); 342 updateOutputConfiguration(cameraId, outputConfigs[1]); 343 fail("should get IllegalArgumentException due to invalid output"); 344 } catch (IllegalArgumentException e) { 345 // expected exception 346 outputConfigs[1].removeSurface(surfaces[0]); 347 } 348 349 try { 350 outputConfigs[1].removeSurface(surfaces[1]); 351 fail("should get IllegalArgumentException due to invalid output"); 352 } catch (IllegalArgumentException e) { 353 // expected exception 354 } 355 356 try { 357 outputConfigs[0].addSurface(surfaces[1]); 358 updateOutputConfiguration(cameraId, outputConfigs[0]); 359 fail("should get IllegalArgumentException due to invalid output"); 360 } catch (IllegalArgumentException e) { 361 // expected exception 362 outputConfigs[0].removeSurface(surfaces[1]); 363 } 364 365 try { 366 outputConfigs[0].removeSurface(surfaces[0]); 367 fail("should get IllegalArgumentException due to invalid output"); 368 } catch (IllegalArgumentException e) { 369 // expected exception 370 } 371 372 //Check that we are able to add a shared texture surface with different size 373 List<Size> orderedPreviewSizes = getOrderedPreviewSizes(cameraId); 374 Size textureSize = previewSize; 375 for (Size s : orderedPreviewSizes) { 376 if (!s.equals(previewSize)) { 377 textureSize = s; 378 break; 379 } 380 } 381 if (textureSize.equals(previewSize)) { 382 return; 383 } 384 SurfaceTexture outputTexture = new SurfaceTexture(/* random texture ID*/ 5); 385 outputTexture.setDefaultBufferSize(textureSize.getWidth(), textureSize.getHeight()); 386 Surface outputSurface = new Surface(outputTexture); 387 //Add a valid output surface and then verify that it cannot be added any more 388 outputConfigs[1].addSurface(outputSurface); 389 updateOutputConfiguration(cameraId, outputConfigs[1]); 390 try { 391 outputConfigs[1].addSurface(outputSurface); 392 fail("should get IllegalStateException due to duplicate output"); 393 } catch (IllegalStateException e) { 394 // expected exception 395 } 396 397 outputConfigs[0].addSurface(outputSurface); 398 try { 399 updateOutputConfiguration(cameraId, outputConfigs[0]); 400 fail("should get IllegalArgumentException due to duplicate output"); 401 } catch (IllegalArgumentException e) { 402 // expected exception 403 outputConfigs[0].removeSurface(outputSurface); 404 } 405 406 //Verify that the same surface cannot be removed twice 407 outputConfigs[1].removeSurface(outputSurface); 408 updateOutputConfiguration(cameraId, outputConfigs[1]); 409 try { 410 outputConfigs[0].removeSurface(outputSurface); 411 fail("should get IllegalArgumentException due to invalid output"); 412 } catch (IllegalArgumentException e) { 413 // expected exception 414 } 415 try { 416 outputConfigs[1].removeSurface(outputSurface); 417 fail("should get IllegalArgumentException due to invalid output"); 418 } catch (IllegalArgumentException e) { 419 // expected exception 420 } 421 422 stopPreview(cameraId); 423 } 424 425 /* 426 * Verify dynamic shared surface behavior using multiple ImageReaders. 427 */ 428 @Test testSharedSurfaceImageReaderSwitch()429 public void testSharedSurfaceImageReaderSwitch() throws Exception { 430 for (String cameraId : getCameraIdsUnderTest()) { 431 try { 432 openCamera(cameraId); 433 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 434 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 435 continue; 436 } 437 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 438 Log.i(TAG, "Camera " + cameraId + 439 " does not support color outputs, skipping"); 440 continue; 441 } 442 443 testSharedSurfaceImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES); 444 } 445 finally { 446 closeCamera(cameraId); 447 } 448 } 449 } 450 testSharedSurfaceImageReaderSwitch(String cameraId, int switchCount)451 private void testSharedSurfaceImageReaderSwitch(String cameraId, int switchCount) 452 throws Exception { 453 SimpleImageListener imageListeners[] = new SimpleImageListener[IMG_READER_COUNT]; 454 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 455 ImageReader imageReaders[] = new ImageReader[IMG_READER_COUNT]; 456 Surface readerSurfaces[] = new Surface[IMG_READER_COUNT]; 457 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 458 CameraPreviewListener previewListener = new CameraPreviewListener(); 459 mTextureView[0].setSurfaceTextureListener(previewListener); 460 SurfaceTexture previewTexture = getAvailableSurfaceTexture(WAIT_FOR_COMMAND_TO_COMPLETE, 461 mTextureView[0]); 462 assertNotNull("Unable to get preview surface texture", previewTexture); 463 previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 464 updatePreviewDisplayRotation(previewSize, mTextureView[0]); 465 Surface previewSurface = new Surface(previewTexture); 466 OutputConfiguration outputConfig = new OutputConfiguration(previewSurface); 467 outputConfig.enableSurfaceSharing(); 468 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 469 outputConfigurations.add(outputConfig); 470 471 if (outputConfig.getMaxSharedSurfaceCount() < (IMG_READER_COUNT + 1)) { 472 return; 473 } 474 475 //Start regular preview streaming 476 startPreviewWithConfigs(cameraId, outputConfigurations, null); 477 478 boolean previewDone = previewListener.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 479 assertTrue("Unable to start preview", previewDone); 480 481 //Test shared image reader outputs 482 for (int i = 0; i < IMG_READER_COUNT; i++) { 483 imageListeners[i] = new SimpleImageListener(); 484 imageReaders[i] = ImageReader.newInstance(previewSize.getWidth(), 485 previewSize.getHeight(), ImageFormat.PRIVATE, 2); 486 imageReaders[i].setOnImageAvailableListener(imageListeners[i], mHandler); 487 readerSurfaces[i] = imageReaders[i].getSurface(); 488 } 489 490 for (int j = 0; j < switchCount; j++) { 491 for (int i = 0; i < IMG_READER_COUNT; i++) { 492 outputConfig.addSurface(readerSurfaces[i]); 493 updateOutputConfiguration(cameraId, outputConfig); 494 CaptureRequest.Builder imageReaderRequestBuilder = getCaptureBuilder(cameraId, 495 CameraDevice.TEMPLATE_PREVIEW); 496 imageReaderRequestBuilder.addTarget(readerSurfaces[i]); 497 capture(cameraId, imageReaderRequestBuilder.build(), resultListener); 498 imageListeners[i].waitForAnyImageAvailable(PREVIEW_TIME_MS); 499 Image img = imageReaders[i].acquireLatestImage(); 500 assertNotNull("Invalid image acquired!", img); 501 img.close(); 502 outputConfig.removeSurface(readerSurfaces[i]); 503 updateOutputConfiguration(cameraId, outputConfig); 504 } 505 } 506 507 for (int i = 0; i < IMG_READER_COUNT; i++) { 508 imageReaders[i].close(); 509 } 510 511 stopPreview(cameraId); 512 } 513 514 /* 515 * Verify dynamic shared surface behavior using YUV ImageReaders. 516 */ 517 @Test testSharedSurfaceYUVImageReaderSwitch()518 public void testSharedSurfaceYUVImageReaderSwitch() throws Exception { 519 int YUVFormats[] = {ImageFormat.YUV_420_888, ImageFormat.YUV_422_888, 520 ImageFormat.YUV_444_888, ImageFormat.YUY2, ImageFormat.YV12, 521 ImageFormat.NV16, ImageFormat.NV21}; 522 for (String cameraId : getCameraIdsUnderTest()) { 523 try { 524 openCamera(cameraId); 525 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 526 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 527 continue; 528 } 529 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 530 Log.i(TAG, "Camera " + cameraId + 531 " does not support color outputs, skipping"); 532 continue; 533 } 534 Size frameSize = null; 535 int yuvFormat = -1; 536 for (int it : YUVFormats) { 537 Size yuvSizes[] = getStaticInfo(cameraId).getAvailableSizesForFormatChecked( 538 it, StaticMetadata.StreamDirection.Output); 539 if (yuvSizes != null) { 540 frameSize = yuvSizes[0]; 541 yuvFormat = it; 542 break; 543 } 544 } 545 546 if ((yuvFormat != -1) && (frameSize.getWidth() > 0) && 547 (frameSize.getHeight() > 0)) { 548 testSharedSurfaceYUVImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES, yuvFormat, 549 frameSize, /*blockMaxAcquired*/ false); 550 testSharedSurfaceYUVImageReaderSwitch(cameraId, NUM_SURFACE_SWITCHES, yuvFormat, 551 frameSize, /*blockMaxAcquired*/ true); 552 } else { 553 Log.i(TAG, "Camera " + cameraId + 554 " does not support YUV outputs, skipping"); 555 } 556 } 557 finally { 558 closeCamera(cameraId); 559 } 560 } 561 } 562 testSharedSurfaceYUVImageReaderSwitch(String cameraId, int switchCount, int format, Size frameSize, boolean blockMaxAcquired)563 private void testSharedSurfaceYUVImageReaderSwitch(String cameraId, int switchCount, int format, 564 Size frameSize, boolean blockMaxAcquired) throws Exception { 565 566 assertTrue("YUV_IMG_READER_COUNT should be equal or greater than 2", 567 (YUV_IMG_READER_COUNT >= 2)); 568 569 SimpleImageListener imageListeners[] = new SimpleImageListener[YUV_IMG_READER_COUNT]; 570 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 571 ImageReader imageReaders[] = new ImageReader[YUV_IMG_READER_COUNT]; 572 Surface readerSurfaces[] = new Surface[YUV_IMG_READER_COUNT]; 573 574 for (int i = 0; i < YUV_IMG_READER_COUNT; i++) { 575 imageListeners[i] = new SimpleImageListener(); 576 imageReaders[i] = ImageReader.newInstance(frameSize.getWidth(), frameSize.getHeight(), 577 format, 2); 578 imageReaders[i].setOnImageAvailableListener(imageListeners[i], mHandler); 579 readerSurfaces[i] = imageReaders[i].getSurface(); 580 } 581 582 OutputConfiguration outputConfig = new OutputConfiguration(readerSurfaces[0]); 583 outputConfig.enableSurfaceSharing(); 584 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 585 outputConfigurations.add(outputConfig); 586 if (outputConfig.getMaxSharedSurfaceCount() < YUV_IMG_READER_COUNT) { 587 return; 588 } 589 590 createSessionWithConfigs(cameraId, outputConfigurations); 591 592 // Test YUV ImageReader surface sharing. The first ImageReader will 593 // always be part of the capture request, the rest will switch on each 594 // iteration. 595 // If 'blockMaxAcquired' is enabled, the first image reader will acquire 596 // the maximum possible amount of buffers and also block a few more. 597 int maxAcquiredImages = imageReaders[0].getMaxImages(); 598 int acquiredCount = 0; 599 Image[] acquiredImages = new Image[maxAcquiredImages]; 600 for (int j = 0; j < switchCount; j++) { 601 for (int i = 1; i < YUV_IMG_READER_COUNT; i++) { 602 outputConfig.addSurface(readerSurfaces[i]); 603 updateOutputConfiguration(cameraId, outputConfig); 604 CaptureRequest.Builder imageReaderRequestBuilder = getCaptureBuilder(cameraId, 605 CameraDevice.TEMPLATE_PREVIEW); 606 imageReaderRequestBuilder.addTarget(readerSurfaces[i]); 607 if (blockMaxAcquired) { 608 if (acquiredCount <= (maxAcquiredImages + 1)) { 609 // Camera should be able to handle cases where 610 // one output blocks more buffers than the respective 611 // maximum acquired count. 612 imageReaderRequestBuilder.addTarget(readerSurfaces[0]); 613 } 614 } else { 615 imageReaderRequestBuilder.addTarget(readerSurfaces[0]); 616 } 617 capture(cameraId, imageReaderRequestBuilder.build(), resultListener); 618 imageListeners[i].waitForAnyImageAvailable(PREVIEW_TIME_MS); 619 Image img = imageReaders[i].acquireLatestImage(); 620 assertNotNull("Invalid image acquired!", img); 621 assertNotNull("Image planes are invalid!", img.getPlanes()); 622 img.close(); 623 if (blockMaxAcquired) { 624 if (acquiredCount < maxAcquiredImages) { 625 imageListeners[0].waitForAnyImageAvailable(PREVIEW_TIME_MS); 626 acquiredImages[acquiredCount] = imageReaders[0].acquireNextImage(); 627 } 628 acquiredCount++; 629 } else { 630 imageListeners[0].waitForAnyImageAvailable(PREVIEW_TIME_MS); 631 img = imageReaders[0].acquireLatestImage(); 632 assertNotNull("Invalid image acquired!", img); 633 img.close(); 634 } 635 outputConfig.removeSurface(readerSurfaces[i]); 636 updateOutputConfiguration(cameraId, outputConfig); 637 } 638 } 639 640 for (int i = 0; i < YUV_IMG_READER_COUNT; i++) { 641 imageReaders[i].close(); 642 } 643 } 644 645 /* 646 * Test the dynamic shared surface limit. 647 */ 648 @Test testSharedSurfaceLimit()649 public void testSharedSurfaceLimit() throws Exception { 650 for (String cameraId : getCameraIdsUnderTest()) { 651 try { 652 openCamera(cameraId); 653 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 654 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 655 continue; 656 } 657 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 658 Log.i(TAG, "Camera " + cameraId + 659 " does not support color outputs, skipping"); 660 continue; 661 } 662 663 testSharedSurfaceLimitByCamera(cameraId, 664 Camera2MultiViewCtsActivity.MAX_TEXTURE_VIEWS); 665 } 666 finally { 667 closeCamera(cameraId); 668 } 669 } 670 } 671 testSharedSurfaceLimitByCamera(String cameraId, int surfaceLimit)672 private void testSharedSurfaceLimitByCamera(String cameraId, int surfaceLimit) 673 throws Exception { 674 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 675 CameraPreviewListener[] previewListener = new CameraPreviewListener[surfaceLimit]; 676 SurfaceTexture[] previewTexture = new SurfaceTexture[surfaceLimit]; 677 Surface[] surfaces = new Surface[surfaceLimit]; 678 int sequenceId = -1; 679 680 // Create surface textures with the same size 681 for (int i = 0; i < surfaceLimit; i++) { 682 previewListener[i] = new CameraPreviewListener(); 683 mTextureView[i].setSurfaceTextureListener(previewListener[i]); 684 previewTexture[i] = getAvailableSurfaceTexture( 685 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 686 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 687 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 688 // Correct the preview display rotation. 689 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 690 surfaces[i] = new Surface(previewTexture[i]); 691 } 692 693 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 694 695 // Create shared outputs for the two surface textures 696 OutputConfiguration surfaceSharedOutput = new OutputConfiguration(surfaces[0]); 697 surfaceSharedOutput.enableSurfaceSharing(); 698 699 if ((surfaceLimit <= 1) || 700 (surfaceLimit < surfaceSharedOutput.getMaxSharedSurfaceCount())) { 701 return; 702 } 703 704 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 705 outputConfigurations.add(surfaceSharedOutput); 706 707 startPreviewWithConfigs(cameraId, outputConfigurations, null); 708 709 boolean previewDone = 710 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 711 assertTrue("Unable to start preview", previewDone); 712 mTextureView[0].setSurfaceTextureListener(null); 713 714 SystemClock.sleep(PREVIEW_TIME_MS); 715 716 int i = 1; 717 for (; i < surfaceLimit; i++) { 718 //Add one more output surface while preview is streaming 719 if (i >= surfaceSharedOutput.getMaxSharedSurfaceCount()){ 720 try { 721 surfaceSharedOutput.addSurface(surfaces[i]); 722 fail("should get IllegalArgumentException due to output surface limit"); 723 } catch (IllegalArgumentException e) { 724 //expected 725 break; 726 } 727 } else { 728 surfaceSharedOutput.addSurface(surfaces[i]); 729 assertTrue("Session configuration should not fail", 730 isSessionConfigurationSupported(cameraId, outputConfigurations)); 731 updateOutputConfiguration(cameraId, surfaceSharedOutput); 732 sequenceId = updateRepeatingRequest(cameraId, outputConfigurations, resultListener); 733 734 SystemClock.sleep(PREVIEW_TIME_MS); 735 } 736 } 737 738 for (; i > 0; i--) { 739 if (i >= surfaceSharedOutput.getMaxSharedSurfaceCount()) { 740 try { 741 surfaceSharedOutput.removeSurface(surfaces[i]); 742 fail("should get IllegalArgumentException due to output surface limit"); 743 } catch (IllegalArgumentException e) { 744 // expected exception 745 } 746 } else { 747 surfaceSharedOutput.removeSurface(surfaces[i]); 748 assertTrue("Session configuration should not fail", 749 isSessionConfigurationSupported(cameraId, outputConfigurations)); 750 } 751 } 752 //Remove all previously added shared outputs in one call 753 updateRepeatingRequest(cameraId, outputConfigurations, new SimpleCaptureCallback()); 754 long lastSequenceFrameNumber = resultListener.getCaptureSequenceLastFrameNumber( 755 sequenceId, PREVIEW_TIME_MS); 756 checkForLastFrameInSequence(lastSequenceFrameNumber, resultListener); 757 updateOutputConfiguration(cameraId, surfaceSharedOutput); 758 SystemClock.sleep(PREVIEW_TIME_MS); 759 760 stopPreview(cameraId); 761 } 762 763 /* 764 * Test dynamic shared surface switch behavior. 765 */ 766 @Test(timeout=60*60*1000) // timeout = 60 mins for long running tests testSharedSurfaceSwitch()767 public void testSharedSurfaceSwitch() throws Exception { 768 for (String cameraId : getCameraIdsUnderTest()) { 769 try { 770 openCamera(cameraId); 771 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 772 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 773 continue; 774 } 775 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 776 Log.i(TAG, "Camera " + cameraId + 777 " does not support color outputs, skipping"); 778 continue; 779 } 780 781 testSharedSurfaceSwitchByCamera(cameraId, NUM_SURFACE_SWITCHES); 782 } 783 finally { 784 closeCamera(cameraId); 785 } 786 } 787 } 788 testSharedSurfaceSwitchByCamera(String cameraId, int switchCount)789 private void testSharedSurfaceSwitchByCamera(String cameraId, int switchCount) 790 throws Exception { 791 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 792 CameraPreviewListener[] previewListener = new CameraPreviewListener[2]; 793 SurfaceTexture[] previewTexture = new SurfaceTexture[2]; 794 Surface[] surfaces = new Surface[2]; 795 796 // Create surface textures with the same size 797 for (int i = 0; i < 2; i++) { 798 previewListener[i] = new CameraPreviewListener(); 799 mTextureView[i].setSurfaceTextureListener(previewListener[i]); 800 previewTexture[i] = getAvailableSurfaceTexture( 801 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 802 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 803 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 804 // Correct the preview display rotation. 805 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 806 surfaces[i] = new Surface(previewTexture[i]); 807 } 808 809 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 810 811 // Create shared outputs for the two surface textures 812 OutputConfiguration surfaceSharedOutput = new OutputConfiguration(surfaces[0]); 813 surfaceSharedOutput.enableSurfaceSharing(); 814 815 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 816 outputConfigurations.add(surfaceSharedOutput); 817 818 startPreviewWithConfigs(cameraId, outputConfigurations, null); 819 820 boolean previewDone = 821 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 822 assertTrue("Unable to start preview", previewDone); 823 mTextureView[0].setSurfaceTextureListener(null); 824 825 for (int i = 0; i < switchCount; i++) { 826 //Add one more output surface while preview is streaming 827 surfaceSharedOutput.addSurface(surfaces[1]); 828 updateOutputConfiguration(cameraId, surfaceSharedOutput); 829 int sequenceId = updateRepeatingRequest(cameraId, outputConfigurations, resultListener); 830 831 SystemClock.sleep(100); 832 833 //Try to remove the shared surface while while we still have active requests that 834 //use it as output. 835 surfaceSharedOutput.removeSurface(surfaces[1]); 836 try { 837 updateOutputConfiguration(cameraId, surfaceSharedOutput); 838 fail("should get IllegalArgumentException due to pending requests"); 839 } catch (IllegalArgumentException e) { 840 // expected exception 841 } 842 843 //Wait for all pending requests to arrive and remove the shared output during active 844 //streaming 845 updateRepeatingRequest(cameraId, outputConfigurations, new SimpleCaptureCallback()); 846 long lastSequenceFrameNumber = resultListener.getCaptureSequenceLastFrameNumber( 847 sequenceId, PREVIEW_TIME_MS); 848 checkForLastFrameInSequence(lastSequenceFrameNumber, resultListener); 849 updateOutputConfiguration(cameraId, surfaceSharedOutput); 850 851 } 852 853 stopPreview(cameraId); 854 } 855 856 857 /* 858 * Two output Surface of the same size are configured: one from TextureView and 859 * the other is ImageReader with usage flag USAGE_GPU_SAMPLED_IMAGE. The 860 * ImageReader queues Image to a ImageWriter of the same usage flag, the 861 * ImageWriter then is connected to another TextureView. Verify the Bitmap 862 * from the first TextureView is identical to the second TextureView. 863 */ 864 @Test testTextureImageWriterReaderOperation()865 public void testTextureImageWriterReaderOperation() throws Exception { 866 for (String id : getCameraIdsUnderTest()) { 867 ImageReader reader = null; 868 ImageWriter writer = null; 869 Surface writerOutput = null; 870 try { 871 Log.i(TAG, "Testing Camera " + id); 872 openCamera(id); 873 874 if (!getStaticInfo(id).isColorOutputSupported()) { 875 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 876 continue; 877 } 878 879 int maxNumStreamsProc = 880 getStaticInfo(id).getMaxNumOutputStreamsProcessedChecked(); 881 if (maxNumStreamsProc < 2) { 882 continue; 883 } 884 885 // mTextureView[0..2] each shared 1/3 of the horizontal space but their size can 886 // differ up to one pixel if the total width is not divisible by 3. Here we try to 887 // pick two of them that have matching size. 888 Size size0 = new Size(mTextureView[0].getWidth(), mTextureView[0].getHeight()); 889 Size size1 = new Size(mTextureView[1].getWidth(), mTextureView[1].getHeight()); 890 Size size2 = new Size(mTextureView[2].getWidth(), mTextureView[2].getHeight()); 891 Log.v(TAG, "Size0: " + size0 + ", Size1: " + size1 + ", size2: " + size2); 892 893 int viewIdx0 = 0; 894 int viewIdx1 = 1; 895 if (!size0.equals(size1)) { 896 assertTrue("No matching view sizes! Size0: " + size0 + 897 ", Size1: " + size1 + ", size2: " + size2, 898 size0.equals(size2) || size1.equals(size2)); 899 if (size0.equals(size2)) { 900 viewIdx0 = 0; 901 viewIdx1 = 2; 902 } else { 903 viewIdx0 = 1; 904 viewIdx1 = 2; 905 } 906 } 907 908 Size previewSize = getOrderedPreviewSizes(id).get(0); 909 List<TextureView> views = Arrays.asList(mTextureView[viewIdx0]); 910 911 // view[0] is normal camera -> TextureView path 912 // view[1] is camera -> ImageReader -> TextureView path 913 SurfaceTexture surfaceTexture0 = getAvailableSurfaceTexture( 914 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[viewIdx0]); 915 assertNotNull("Unable to get preview surface texture 0", surfaceTexture0); 916 surfaceTexture0.setDefaultBufferSize( 917 previewSize.getWidth(), previewSize.getHeight()); 918 919 SurfaceTexture surfaceTexture1 = getAvailableSurfaceTexture( 920 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[viewIdx1]); 921 assertNotNull("Unable to get preview surface texture 1", surfaceTexture1); 922 surfaceTexture1.setDefaultBufferSize( 923 previewSize.getWidth(), previewSize.getHeight()); 924 925 updatePreviewDisplayRotation(previewSize, mTextureView[viewIdx1]); 926 927 reader = ImageReader.newInstance( 928 previewSize.getWidth(), previewSize.getHeight(), 929 ImageFormat.PRIVATE, 930 MAX_READER_IMAGES, 931 HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); 932 933 writerOutput = new Surface(surfaceTexture1); 934 writer = ImageWriter.newInstance( 935 writerOutput, MAX_READER_IMAGES, 936 ImageFormat.PRIVATE); 937 938 ImageWriterQueuer writerInput = new ImageWriterQueuer(writer); 939 940 reader.setOnImageAvailableListener(writerInput, mHandler); 941 942 startTextureViewPreview(id, views, reader); 943 SystemClock.sleep(PREVIEW_TIME_MS); 944 stopRepeating(id); 945 // Extra sleep to make sure all previous preview frames are delivered to 946 // SurfaceTexture 947 SystemClock.sleep(PREVIEW_FLUSH_TIME_MS); 948 949 Surface preview = new Surface(surfaceTexture0); 950 CaptureRequest.Builder requestBuilder = getCaptureBuilder(id, 951 CameraDevice.TEMPLATE_PREVIEW); 952 requestBuilder.addTarget(reader.getSurface()); 953 requestBuilder.addTarget(preview); 954 SimpleCaptureCallback resultListener = new SimpleCaptureCallback(); 955 CameraPreviewListener stListener0 = new CameraPreviewListener(); 956 CameraPreviewListener stListener1 = new CameraPreviewListener(); 957 mTextureView[viewIdx0].setSurfaceTextureListener(stListener0); 958 mTextureView[viewIdx1].setSurfaceTextureListener(stListener1); 959 960 // do a single capture 961 capture(id, requestBuilder.build(), resultListener); 962 // wait for capture done 963 boolean previewDone = stListener0.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 964 assertTrue("Unable to start preview", previewDone); 965 previewDone = stListener1.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 966 assertTrue("Unable to start preview", previewDone); 967 968 // get bitmap from both TextureView and compare 969 Bitmap bitmap0 = mTextureView[viewIdx0].getBitmap(); 970 Bitmap bitmap1 = mTextureView[viewIdx1].getBitmap(); 971 BitmapUtils.BitmapCompareResult result = 972 BitmapUtils.compareBitmap(bitmap0, bitmap1); 973 974 Log.i(TAG, "Bitmap difference is " + result.mDiff); 975 assertTrue(String.format( 976 "Bitmap difference exceeds threshold: diff %f > threshold %f", 977 result.mDiff, BITMAP_DIFF_THRESHOLD), 978 result.mDiff <= BITMAP_DIFF_THRESHOLD); 979 980 assertTrue(String.format( 981 "Bitmap from direct Textureview is flat. All pixels are (%f, %f, %f)", 982 result.mLhsAverage[0], result.mLhsAverage[1], result.mLhsAverage[2]), 983 !result.mLhsFlat); 984 985 assertTrue(String.format( 986 "Bitmap from ImageWriter Textureview is flat. All pixels are (%f, %f, %f)", 987 result.mRhsAverage[0], result.mRhsAverage[1], result.mRhsAverage[2]), 988 !result.mRhsFlat); 989 } finally { 990 if (reader != null) { 991 reader.close(); 992 } 993 if (writer != null) { 994 writer.close(); 995 } 996 if (writerOutput != null) { 997 writerOutput.release(); 998 } 999 closeCamera(id); 1000 } 1001 } 1002 } 1003 1004 public static class ImageWriterQueuer implements ImageReader.OnImageAvailableListener { 1005 @Override onImageAvailable(ImageReader reader)1006 public void onImageAvailable(ImageReader reader) { 1007 Image image = null; 1008 try { 1009 image = reader.acquireNextImage(); 1010 } finally { 1011 if (image != null && mWriter != null) { 1012 mWriter.queueInputImage(image); 1013 } 1014 } 1015 } 1016 ImageWriterQueuer(ImageWriter writer)1017 public ImageWriterQueuer(ImageWriter writer) { 1018 mWriter = writer; 1019 } 1020 private ImageWriter mWriter = null; 1021 } 1022 checkForLastFrameInSequence(long lastSequenceFrameNumber, SimpleCaptureCallback listener)1023 private void checkForLastFrameInSequence(long lastSequenceFrameNumber, 1024 SimpleCaptureCallback listener) throws Exception { 1025 // Find the last frame number received in results and failures. 1026 long lastFrameNumber = -1; 1027 while (listener.hasMoreResults()) { 1028 TotalCaptureResult result = listener.getTotalCaptureResult(PREVIEW_TIME_MS); 1029 if (lastFrameNumber < result.getFrameNumber()) { 1030 lastFrameNumber = result.getFrameNumber(); 1031 } 1032 } 1033 1034 while (listener.hasMoreFailures()) { 1035 ArrayList<CaptureFailure> failures = listener.getCaptureFailures( 1036 /*maxNumFailures*/ 1); 1037 for (CaptureFailure failure : failures) { 1038 if (lastFrameNumber < failure.getFrameNumber()) { 1039 lastFrameNumber = failure.getFrameNumber(); 1040 } 1041 } 1042 } 1043 1044 // Verify the last frame number received from capture sequence completed matches the 1045 // the last frame number of the results and failures. 1046 assertEquals(String.format("Last frame number from onCaptureSequenceCompleted " + 1047 "(%d) doesn't match the last frame number received from " + 1048 "results/failures (%d)", lastSequenceFrameNumber, lastFrameNumber), 1049 lastSequenceFrameNumber, lastFrameNumber); 1050 } 1051 1052 /* 1053 * Verify behavior of sharing surfaces within one OutputConfiguration 1054 */ 1055 @Test testSharedSurfaces()1056 public void testSharedSurfaces() throws Exception { 1057 for (String cameraId : getCameraIdsUnderTest()) { 1058 try { 1059 openCamera(cameraId); 1060 if (getStaticInfo(cameraId).isHardwareLevelLegacy()) { 1061 Log.i(TAG, "Camera " + cameraId + " is legacy, skipping"); 1062 continue; 1063 } 1064 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 1065 Log.i(TAG, "Camera " + cameraId + 1066 " does not support color outputs, skipping"); 1067 continue; 1068 } 1069 1070 testSharedSurfacesConfigByCamera(cameraId); 1071 1072 testSharedSurfacesCaptureSessionByCamera(cameraId); 1073 1074 testSharedDeferredSurfacesByCamera(cameraId); 1075 } 1076 finally { 1077 closeCamera(cameraId); 1078 } 1079 } 1080 } 1081 1082 /* 1083 * Verify behavior of mirroring mode 1084 */ 1085 @Test testTextureViewPreviewWithMirroring()1086 public void testTextureViewPreviewWithMirroring() throws Exception { 1087 // 4x4 GL-style matrices, as returned by SurfaceTexture#getTransformMatrix(). Note they're 1088 // transforming texture coordinates ([0,1]^2), so the origin for the transforms is 1089 // (0.5, 0.5), not (0,0). 1090 final float[] MIRROR_HORIZONTAL_MATRIX = new float[] { 1091 -1.0f, 0.0f, 0.0f, 0.0f, 1092 0.0f, 1.0f, 0.0f, 0.0f, 1093 0.0f, 0.0f, 1.0f, 0.0f, 1094 1.0f, 0.0f, 0.0f, 1.0f, 1095 }; 1096 final float[] MIRROR_VERTICAL_MATRIX = new float[] { 1097 1.0f, 0.0f, 0.0f, 0.0f, 1098 0.0f, -1.0f, 0.0f, 0.0f, 1099 0.0f, 0.0f, 1.0f, 0.0f, 1100 0.0f, 1.0f, 0.0f, 1.0f, 1101 }; 1102 1103 for (String cameraId : getCameraIdsUnderTest()) { 1104 Exception prior = null; 1105 1106 try { 1107 openCamera(cameraId); 1108 if (!getStaticInfo(cameraId).isColorOutputSupported()) { 1109 Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping"); 1110 continue; 1111 } 1112 1113 int[] supportedModes = { 1114 OutputConfiguration.MIRROR_MODE_AUTO, 1115 OutputConfiguration.MIRROR_MODE_NONE, 1116 OutputConfiguration.MIRROR_MODE_H, 1117 OutputConfiguration.MIRROR_MODE_V }; 1118 1119 HashMap<Integer, float[]> transformsPerMode = new HashMap<>(); 1120 for (int mode : supportedModes) { 1121 float[] transform = 1122 textureViewPreviewWithMirroring(cameraId, mTextureView[0], mode); 1123 transformsPerMode.put(mode, transform); 1124 } 1125 1126 int lensFacing = getStaticInfo(cameraId).getLensFacingChecked(); 1127 if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) { 1128 assertArrayEquals("Front camera's transform matrix must be the same between " 1129 + "AUTO and horizontal mirroring mode", 1130 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_AUTO), 1131 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_H), 0.0f); 1132 } else { 1133 assertArrayEquals("Rear/external camera's transform matrix must be the same " 1134 + "between AUTO and NONE mirroring mode", 1135 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_AUTO), 1136 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_NONE), 0.0f); 1137 } 1138 1139 float[] horizontalMirroredTransform = new float[16]; 1140 Matrix.multiplyMM(horizontalMirroredTransform, 0, 1141 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_NONE), 0, 1142 MIRROR_HORIZONTAL_MATRIX, 0); 1143 assertArrayEquals("Camera " + cameraId + " transform matrix in horizontal mode " 1144 + "contradicts with NONE mode", 1145 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_H), 1146 horizontalMirroredTransform, 0.0f); 1147 1148 float[] verticalMirroredTransform = new float[16]; 1149 Matrix.multiplyMM(verticalMirroredTransform, 0, 1150 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_NONE), 0, 1151 MIRROR_VERTICAL_MATRIX, 0); 1152 assertArrayEquals("Camera " + cameraId + " transform matrix in vertical mode " 1153 + "contradicts with NONE mode", 1154 transformsPerMode.get(OutputConfiguration.MIRROR_MODE_V), 1155 verticalMirroredTransform, 0.0f); 1156 } catch (Exception e) { 1157 prior = e; 1158 } finally { 1159 try { 1160 closeCamera(cameraId); 1161 } catch (Exception e) { 1162 if (prior != null) { 1163 Log.e(TAG, "Prior exception received: " + prior); 1164 } 1165 prior = e; 1166 } 1167 if (prior != null) throw prior; // Rethrow last exception. 1168 } 1169 } 1170 } 1171 textureViewPreviewWithMirroring(String cameraId, TextureView textureView, int mirrorMode)1172 private float[] textureViewPreviewWithMirroring(String cameraId, 1173 TextureView textureView, int mirrorMode) throws Exception { 1174 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 1175 CameraPreviewListener previewListener = 1176 new CameraPreviewListener(); 1177 textureView.setSurfaceTextureListener(previewListener); 1178 SurfaceTexture previewTexture = getAvailableSurfaceTexture( 1179 WAIT_FOR_COMMAND_TO_COMPLETE, textureView); 1180 assertNotNull("Unable to get preview surface texture", previewTexture); 1181 previewTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 1182 // Correct the preview display rotation. 1183 updatePreviewDisplayRotation(previewSize, textureView); 1184 1185 OutputConfiguration outputConfig = new OutputConfiguration(new Surface(previewTexture)); 1186 outputConfig.setMirrorMode(mirrorMode); 1187 List<OutputConfiguration> outputConfigs = new ArrayList<>(); 1188 outputConfigs.add(outputConfig); 1189 startPreviewWithConfigs(cameraId, outputConfigs, null); 1190 1191 boolean previewDone = 1192 previewListener.waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1193 assertTrue("Unable to start preview", previewDone); 1194 1195 SystemClock.sleep(PREVIEW_TIME_MS); 1196 1197 float[] transform = previewListener.getPreviewTransform(); 1198 assertNotNull("Failed to get preview transform"); 1199 1200 textureView.setSurfaceTextureListener(null); 1201 stopPreview(cameraId); 1202 1203 return transform; 1204 } 1205 1206 /** 1207 * Start camera preview using input texture views and/or one image reader 1208 */ startTextureViewPreview( String cameraId, List<TextureView> views, ImageReader imageReader)1209 private void startTextureViewPreview( 1210 String cameraId, List<TextureView> views, ImageReader imageReader) 1211 throws Exception { 1212 int numPreview = views.size(); 1213 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 1214 CameraPreviewListener[] previewListener = 1215 new CameraPreviewListener[numPreview]; 1216 SurfaceTexture[] previewTexture = new SurfaceTexture[numPreview]; 1217 List<Surface> surfaces = new ArrayList<Surface>(); 1218 1219 // Prepare preview surface. 1220 int i = 0; 1221 for (TextureView view : views) { 1222 previewListener[i] = new CameraPreviewListener(); 1223 view.setSurfaceTextureListener(previewListener[i]); 1224 previewTexture[i] = getAvailableSurfaceTexture(WAIT_FOR_COMMAND_TO_COMPLETE, view); 1225 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 1226 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 1227 // Correct the preview display rotation. 1228 updatePreviewDisplayRotation(previewSize, view); 1229 surfaces.add(new Surface(previewTexture[i])); 1230 i++; 1231 } 1232 if (imageReader != null) { 1233 surfaces.add(imageReader.getSurface()); 1234 } 1235 1236 startPreview(cameraId, surfaces, null); 1237 1238 i = 0; 1239 for (TextureView view : views) { 1240 boolean previewDone = 1241 previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1242 assertTrue("Unable to start preview " + i, previewDone); 1243 view.setSurfaceTextureListener(null); 1244 i++; 1245 } 1246 } 1247 1248 /** 1249 * Test camera preview using input texture views and/or one image reader 1250 */ textureViewPreview( String cameraId, List<TextureView> views, ImageReader testImagerReader)1251 private void textureViewPreview( 1252 String cameraId, List<TextureView> views, ImageReader testImagerReader) 1253 throws Exception { 1254 startTextureViewPreview(cameraId, views, testImagerReader); 1255 1256 // TODO: check the framerate is correct 1257 SystemClock.sleep(PREVIEW_TIME_MS); 1258 1259 stopPreview(cameraId); 1260 } 1261 1262 /* 1263 * Verify behavior of OutputConfiguration when sharing surfaces 1264 */ testSharedSurfacesConfigByCamera(String cameraId)1265 private void testSharedSurfacesConfigByCamera(String cameraId) throws Exception { 1266 List<Size> orderedPreviewSizes = getOrderedPreviewSizes(cameraId); 1267 Size previewSize = orderedPreviewSizes.get(0); 1268 1269 SurfaceTexture[] previewTexture = new SurfaceTexture[2]; 1270 Surface[] surfaces = new Surface[2]; 1271 1272 // Create surface textures with the same size 1273 for (int i = 0; i < 2; i++) { 1274 previewTexture[i] = getAvailableSurfaceTexture( 1275 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 1276 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 1277 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 1278 // Correct the preview display rotation. 1279 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 1280 surfaces[i] = new Surface(previewTexture[i]); 1281 } 1282 1283 // Verify that outputConfiguration can be created with 2 surfaces with the same setting. 1284 OutputConfiguration previewConfiguration = new OutputConfiguration( 1285 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]); 1286 previewConfiguration.enableSurfaceSharing(); 1287 previewConfiguration.addSurface(surfaces[1]); 1288 List<Surface> previewSurfaces = previewConfiguration.getSurfaces(); 1289 List<Surface> inputSurfaces = Arrays.asList(surfaces); 1290 assertTrue( 1291 String.format("Surfaces returned from getSurfaces() don't match those passed in"), 1292 previewSurfaces.equals(inputSurfaces)); 1293 1294 if (orderedPreviewSizes.size() > 1) { 1295 // Verify that createCaptureSession fails if 2 surfaces are different size 1296 SurfaceTexture outputTexture2 = new SurfaceTexture(/* random texture ID*/ 5); 1297 Size previewSize2 = orderedPreviewSizes.get(1); 1298 outputTexture2.setDefaultBufferSize(previewSize2.getWidth(), 1299 previewSize2.getHeight()); 1300 Surface outputSurface2 = new Surface(outputTexture2); 1301 OutputConfiguration configuration = new OutputConfiguration( 1302 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]); 1303 configuration.enableSurfaceSharing(); 1304 configuration.addSurface(outputSurface2); 1305 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 1306 outputConfigurations.add(configuration); 1307 verifyCreateSessionWithConfigsFailure(cameraId, outputConfigurations); 1308 } 1309 OutputConfiguration configuration; 1310 // Verify that outputConfiguration throws exception if 2 surfaces are different format 1311 ImageReader imageReader = makeImageReader(previewSize, ImageFormat.YUV_420_888, 1312 MAX_READER_IMAGES, new ImageDropperListener(), mHandler); 1313 try { 1314 configuration = new OutputConfiguration(OutputConfiguration.SURFACE_GROUP_ID_NONE, 1315 surfaces[0]); 1316 configuration.enableSurfaceSharing(); 1317 configuration.addSurface(imageReader.getSurface()); 1318 fail("No error for invalid output config created from different format surfaces"); 1319 } catch (IllegalArgumentException e) { 1320 // expected 1321 } 1322 1323 // Verify that outputConfiguration can be created with deferred surface with the same 1324 // setting. 1325 OutputConfiguration deferredPreviewConfigure = new OutputConfiguration( 1326 previewSize, SurfaceTexture.class); 1327 deferredPreviewConfigure.addSurface(surfaces[0]); 1328 assertTrue(String.format("Number of surfaces %d doesn't match expected value 1", 1329 deferredPreviewConfigure.getSurfaces().size()), 1330 deferredPreviewConfigure.getSurfaces().size() == 1); 1331 assertEquals("Surface 0 in OutputConfiguration doesn't match input", 1332 deferredPreviewConfigure.getSurfaces().get(0), surfaces[0]); 1333 1334 // Verify that outputConfiguration throws exception if deferred surface and non-deferred 1335 // surface properties don't match 1336 try { 1337 configuration = new OutputConfiguration(previewSize, SurfaceTexture.class); 1338 configuration.addSurface(imageReader.getSurface()); 1339 fail("No error for invalid output config created deferred class with different type"); 1340 } catch (IllegalArgumentException e) { 1341 // expected; 1342 } 1343 } 1344 testSharedSurfacesCaptureSessionByCamera(String cameraId)1345 private void testSharedSurfacesCaptureSessionByCamera(String cameraId) throws Exception { 1346 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 1347 CameraPreviewListener[] previewListener = new CameraPreviewListener[2]; 1348 SurfaceTexture[] previewTexture = new SurfaceTexture[2]; 1349 Surface[] surfaces = new Surface[2]; 1350 1351 // Create surface textures with the same size 1352 for (int i = 0; i < 2; i++) { 1353 previewListener[i] = new CameraPreviewListener(); 1354 mTextureView[i].setSurfaceTextureListener(previewListener[i]); 1355 previewTexture[i] = getAvailableSurfaceTexture( 1356 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 1357 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 1358 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 1359 // Correct the preview display rotation. 1360 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 1361 surfaces[i] = new Surface(previewTexture[i]); 1362 } 1363 1364 // Create shared outputs for the two surface textures 1365 OutputConfiguration surfaceSharedOutput = new OutputConfiguration( 1366 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]); 1367 surfaceSharedOutput.enableSurfaceSharing(); 1368 surfaceSharedOutput.addSurface(surfaces[1]); 1369 1370 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 1371 outputConfigurations.add(surfaceSharedOutput); 1372 1373 startPreviewWithConfigs(cameraId, outputConfigurations, null); 1374 1375 for (int i = 0; i < 2; i++) { 1376 boolean previewDone = 1377 previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1378 assertTrue("Unable to start preview " + i, previewDone); 1379 mTextureView[i].setSurfaceTextureListener(null); 1380 } 1381 1382 SystemClock.sleep(PREVIEW_TIME_MS); 1383 1384 stopPreview(cameraId); 1385 } 1386 testSharedDeferredSurfacesByCamera(String cameraId)1387 private void testSharedDeferredSurfacesByCamera(String cameraId) throws Exception { 1388 Size previewSize = getOrderedPreviewSizes(cameraId).get(0); 1389 CameraPreviewListener[] previewListener = new CameraPreviewListener[2]; 1390 SurfaceTexture[] previewTexture = new SurfaceTexture[2]; 1391 Surface[] surfaces = new Surface[2]; 1392 1393 // Create surface textures with the same size 1394 for (int i = 0; i < 2; i++) { 1395 previewListener[i] = new CameraPreviewListener(); 1396 mTextureView[i].setSurfaceTextureListener(previewListener[i]); 1397 previewTexture[i] = getAvailableSurfaceTexture( 1398 WAIT_FOR_COMMAND_TO_COMPLETE, mTextureView[i]); 1399 assertNotNull("Unable to get preview surface texture", previewTexture[i]); 1400 previewTexture[i].setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); 1401 // Correct the preview display rotation. 1402 updatePreviewDisplayRotation(previewSize, mTextureView[i]); 1403 surfaces[i] = new Surface(previewTexture[i]); 1404 } 1405 1406 // 1407 // Create deferred outputConfiguration, addSurface, createCaptureSession, addSurface, and 1408 // finalizeOutputConfigurations. 1409 // 1410 1411 OutputConfiguration surfaceSharedOutput = new OutputConfiguration( 1412 previewSize, SurfaceTexture.class); 1413 surfaceSharedOutput.enableSurfaceSharing(); 1414 surfaceSharedOutput.addSurface(surfaces[0]); 1415 1416 List<OutputConfiguration> outputConfigurations = new ArrayList<>(); 1417 outputConfigurations.add(surfaceSharedOutput); 1418 1419 // Run preview with one surface, and verify at least one frame is received. 1420 startPreviewWithConfigs(cameraId, outputConfigurations, null); 1421 boolean previewDone = 1422 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1423 assertTrue("Unable to start preview 0", previewDone); 1424 1425 SystemClock.sleep(PREVIEW_TIME_MS); 1426 1427 // Add deferred surface to the output configuration 1428 surfaceSharedOutput.addSurface(surfaces[1]); 1429 List<OutputConfiguration> deferredConfigs = new ArrayList<OutputConfiguration>(); 1430 deferredConfigs.add(surfaceSharedOutput); 1431 1432 // Run preview with both surfaces, and verify at least one frame is received for each 1433 // surface. 1434 finalizeOutputConfigs(cameraId, deferredConfigs, null); 1435 previewDone = 1436 previewListener[1].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1437 assertTrue("Unable to start preview 1", previewDone); 1438 1439 stopPreview(cameraId); 1440 1441 previewListener[0].reset(); 1442 previewListener[1].reset(); 1443 1444 // 1445 // Create outputConfiguration with a surface, createCaptureSession, addSurface, and 1446 // finalizeOutputConfigurations. 1447 // 1448 1449 surfaceSharedOutput = new OutputConfiguration( 1450 OutputConfiguration.SURFACE_GROUP_ID_NONE, surfaces[0]); 1451 surfaceSharedOutput.enableSurfaceSharing(); 1452 outputConfigurations.clear(); 1453 outputConfigurations.add(surfaceSharedOutput); 1454 1455 startPreviewWithConfigs(cameraId, outputConfigurations, null); 1456 previewDone = 1457 previewListener[0].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1458 assertTrue("Unable to start preview 0", previewDone); 1459 1460 // Add deferred surface to the output configuration, and continue running preview 1461 surfaceSharedOutput.addSurface(surfaces[1]); 1462 deferredConfigs.clear(); 1463 deferredConfigs.add(surfaceSharedOutput); 1464 finalizeOutputConfigs(cameraId, deferredConfigs, null); 1465 previewDone = 1466 previewListener[1].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1467 assertTrue("Unable to start preview 1", previewDone); 1468 1469 SystemClock.sleep(PREVIEW_TIME_MS); 1470 stopPreview(cameraId); 1471 1472 previewListener[0].reset(); 1473 previewListener[1].reset(); 1474 1475 // 1476 // Create deferred output configuration, createCaptureSession, addSurface, addSurface, and 1477 // finalizeOutputConfigurations. 1478 1479 surfaceSharedOutput = new OutputConfiguration( 1480 previewSize, SurfaceTexture.class); 1481 surfaceSharedOutput.enableSurfaceSharing(); 1482 outputConfigurations.clear(); 1483 outputConfigurations.add(surfaceSharedOutput); 1484 createSessionWithConfigs(cameraId, outputConfigurations); 1485 1486 // Add 2 surfaces to the output configuration, and run preview 1487 surfaceSharedOutput.addSurface(surfaces[0]); 1488 surfaceSharedOutput.addSurface(surfaces[1]); 1489 deferredConfigs.clear(); 1490 deferredConfigs.add(surfaceSharedOutput); 1491 finalizeOutputConfigs(cameraId, deferredConfigs, null); 1492 for (int i = 0; i < 2; i++) { 1493 previewDone = 1494 previewListener[i].waitForPreviewDone(WAIT_FOR_COMMAND_TO_COMPLETE); 1495 assertTrue("Unable to start preview " + i, previewDone); 1496 } 1497 1498 SystemClock.sleep(PREVIEW_TIME_MS); 1499 stopPreview(cameraId); 1500 } 1501 1502 private final class SimpleImageListener implements ImageReader.OnImageAvailableListener { 1503 private final ConditionVariable imageAvailable = new ConditionVariable(); 1504 @Override onImageAvailable(ImageReader reader)1505 public void onImageAvailable(ImageReader reader) { 1506 imageAvailable.open(); 1507 } 1508 waitForAnyImageAvailable(long timeout)1509 public void waitForAnyImageAvailable(long timeout) { 1510 if (imageAvailable.block(timeout)) { 1511 imageAvailable.close(); 1512 } else { 1513 fail("wait for image available timed out after " + timeout + "ms"); 1514 } 1515 } 1516 } 1517 } 1518