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