1 /* 2 * Copyright 2015 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 static junit.framework.Assert.*; 22 23 import static org.junit.Assume.assumeNotNull; 24 import static org.junit.Assume.assumeTrue; 25 26 import android.graphics.ImageFormat; 27 import android.graphics.SurfaceTexture; 28 import android.hardware.DataSpace; 29 import android.hardware.HardwareBuffer; 30 import android.hardware.SyncFence; 31 import android.hardware.camera2.CameraDevice; 32 import android.hardware.camera2.CaptureRequest; 33 import android.hardware.camera2.CaptureResult; 34 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 35 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 36 import android.media.Image; 37 import android.media.Image.Plane; 38 import android.media.ImageReader; 39 import android.media.ImageWriter; 40 import android.util.Log; 41 import android.util.Size; 42 import android.view.Surface; 43 44 import com.android.cts.hardware.SyncFenceUtil; 45 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.junit.runners.Parameterized; 49 50 import java.nio.ByteBuffer; 51 import java.util.ArrayList; 52 import java.util.Arrays; 53 import java.util.List; 54 55 /** 56 * <p> 57 * Basic test for ImageWriter APIs. ImageWriter takes the images produced by 58 * camera (via ImageReader), then the data is consumed by either camera input 59 * interface or ImageReader. 60 * </p> 61 */ 62 @RunWith(Parameterized.class) 63 public class ImageWriterTest extends Camera2AndroidTestCase { 64 private static final String TAG = "ImageWriterTest"; 65 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 66 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 67 // Max number of images can be accessed simultaneously from ImageReader. 68 private static final int MAX_NUM_IMAGES = 3; 69 private static final int CAMERA_PRIVATE_FORMAT = ImageFormat.PRIVATE; 70 private static final int BUFFER_WIDTH = 640; 71 private static final int BUFFER_HEIGHT = 480; 72 private ImageReader mReaderForWriter; 73 private ImageWriter mWriter; 74 75 @Override tearDown()76 public void tearDown() throws Exception { 77 try { 78 closeImageReader(mReaderForWriter); 79 } finally { 80 mReaderForWriter = null; 81 if (mWriter != null) { 82 mWriter.close(); 83 mWriter = null; 84 } 85 } 86 87 super.tearDown(); 88 } 89 90 /** 91 * <p> 92 * Basic YUV420_888 format ImageWriter ImageReader test that checks the 93 * images produced by camera can be passed correctly by ImageWriter. 94 * </p> 95 * <p> 96 * {@link ImageReader} reads the images produced by {@link CameraDevice}. 97 * The images are then passed to ImageWriter, which produces new images that 98 * are consumed by the second image reader. The images from first 99 * ImageReader should be identical with the images from the second 100 * ImageReader. This validates the basic image input interface of the 101 * ImageWriter. Below is the data path tested: 102 * <li>Explicit data copy: Dequeue an image from ImageWriter, copy the image 103 * data from first ImageReader into this image, then queue this image back 104 * to ImageWriter. This validates the ImageWriter explicit buffer copy 105 * interface.</li> 106 * </p> 107 */ 108 @Test testYuvImageWriterReaderOperation()109 public void testYuvImageWriterReaderOperation() throws Exception { 110 for (String id : mCameraIdsUnderTest) { 111 try { 112 Log.i(TAG, "Testing Camera " + id); 113 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 114 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 115 continue; 116 } 117 openDevice(id); 118 readerWriterFormatTestByCamera(ImageFormat.YUV_420_888, false); 119 } finally { 120 closeDevice(id); 121 } 122 } 123 } 124 125 /** 126 * <p> 127 * Similar to testYuvImageWriterReaderOperation, but use the alternative 128 * factory method of ImageReader and ImageWriter. 129 * </p> 130 */ 131 @Test testYuvImageWriterReaderOperationAlt()132 public void testYuvImageWriterReaderOperationAlt() throws Exception { 133 for (String id : mCameraIdsUnderTest) { 134 try { 135 Log.i(TAG, "Testing Camera " + id); 136 if (!mAllStaticInfo.get(id).isColorOutputSupported()) { 137 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping"); 138 continue; 139 } 140 openDevice(id); 141 readerWriterFormatTestByCamera(ImageFormat.YUV_420_888, true); 142 } finally { 143 closeDevice(id); 144 } 145 } 146 } 147 148 @Test testAbandonedSurfaceExceptions()149 public void testAbandonedSurfaceExceptions() throws Exception { 150 final int READER_WIDTH = 1920; 151 final int READER_HEIGHT = 1080; 152 final int READER_FORMAT = ImageFormat.YUV_420_888; 153 154 // Verify that if the image writer's input surface is abandoned, dequeueing an image 155 // throws IllegalStateException 156 ImageReader reader = ImageReader.newInstance(READER_WIDTH, READER_HEIGHT, READER_FORMAT, 157 MAX_NUM_IMAGES); 158 ImageWriter writer = ImageWriter.newInstance(reader.getSurface(), MAX_NUM_IMAGES); 159 160 // Close image reader to abandon the input surface. 161 reader.close(); 162 163 Image image; 164 try { 165 image = writer.dequeueInputImage(); 166 fail("Should get an IllegalStateException"); 167 } catch (IllegalStateException e) { 168 // Expected 169 } finally { 170 writer.close(); 171 } 172 173 // Verify that if the image writer's input surface is abandoned, queueing an image 174 // throws IllegalStateException 175 reader = ImageReader.newInstance(READER_WIDTH, READER_HEIGHT, READER_FORMAT, 176 MAX_NUM_IMAGES); 177 writer = ImageWriter.newInstance(reader.getSurface(), MAX_NUM_IMAGES); 178 image = writer.dequeueInputImage(); 179 180 // Close image reader to abandon the input surface. 181 reader.close(); 182 183 try { 184 writer.queueInputImage(image); 185 fail("Should get an IllegalStateException"); 186 } catch (IllegalStateException e) { 187 // Expected 188 } finally { 189 writer.close(); 190 } 191 } 192 193 @Test testWriterReaderBlobFormats()194 public void testWriterReaderBlobFormats() throws Exception { 195 int[] READER_TEST_FORMATS = {ImageFormat.JPEG, ImageFormat.DEPTH_JPEG, 196 ImageFormat.HEIC, ImageFormat.DEPTH_POINT_CLOUD}; 197 198 for (int format : READER_TEST_FORMATS) { 199 ImageReader reader = ImageReader.newInstance(640, 480, format, 1 /*maxImages*/); 200 ImageWriter writer = ImageWriter.newInstance(reader.getSurface(), 1 /*maxImages*/); 201 writer.close(); 202 reader.close(); 203 } 204 } 205 206 @Test testWriterFormatOverride()207 public void testWriterFormatOverride() throws Exception { 208 int[] TEXTURE_TEST_FORMATS = {ImageFormat.YV12, ImageFormat.YUV_420_888}; 209 SurfaceTexture texture = new SurfaceTexture(false); 210 texture.setDefaultBufferSize(BUFFER_WIDTH, BUFFER_HEIGHT); 211 Surface surface = new Surface(texture); 212 213 // Make sure that the default newInstance is still valid. 214 ImageWriter defaultWriter = ImageWriter.newInstance(surface, MAX_NUM_IMAGES); 215 Image defaultImage = defaultWriter.dequeueInputImage(); 216 defaultWriter.close(); 217 218 for (int format : TEXTURE_TEST_FORMATS) { 219 // Override default buffer format of Surface texture to test format 220 ImageWriter writer = ImageWriter.newInstance(surface, MAX_NUM_IMAGES, format); 221 Image image = writer.dequeueInputImage(); 222 Log.i(TAG, "testing format " + format + ", got input image format " + 223 image.getFormat()); 224 assertTrue(image.getFormat() == format); 225 writer.close(); 226 } 227 } 228 229 @Test testWriterWithImageFormatOverride()230 public void testWriterWithImageFormatOverride() throws Exception { 231 final int imageReaderFormat = ImageFormat.YUV_420_888; 232 final int imageWriterFormat = ImageFormat.YV12; 233 final int dataSpace = DataSpace.DATASPACE_JFIF; 234 final int hardwareBufferFormat = ImageFormat.YV12; 235 try ( 236 ImageReader reader = new ImageReader 237 .Builder(BUFFER_WIDTH, BUFFER_HEIGHT) 238 .setImageFormat(imageReaderFormat) 239 .build(); 240 ImageWriter writer = new ImageWriter 241 .Builder(reader.getSurface()) 242 .setImageFormat(imageWriterFormat) 243 .build(); 244 Image outputImage = writer.dequeueInputImage() 245 ) { 246 assertEquals(1, reader.getMaxImages()); 247 assertEquals(imageReaderFormat, reader.getImageFormat()); 248 assertEquals(dataSpace, reader.getDataSpace()); 249 250 assertEquals(HardwareBuffer.USAGE_CPU_READ_OFTEN, reader.getUsage()); 251 assertEquals(dataSpace, writer.getDataSpace()); 252 assertEquals(imageWriterFormat, writer.getFormat()); 253 254 assertEquals(BUFFER_WIDTH, outputImage.getWidth()); 255 assertEquals(BUFFER_HEIGHT, outputImage.getHeight()); 256 assertEquals(imageWriterFormat, outputImage.getFormat()); 257 assertEquals(dataSpace, outputImage.getDataSpace()); 258 } 259 } 260 261 @Test testWriterBuilderDefault()262 public void testWriterBuilderDefault() throws Exception { 263 try ( 264 ImageReader reader = new ImageReader 265 .Builder(BUFFER_WIDTH, BUFFER_HEIGHT) 266 .setImageFormat(ImageFormat.HEIC) 267 .setDefaultHardwareBufferFormat(HardwareBuffer.RGBA_8888) 268 .setDefaultDataSpace(DataSpace.DATASPACE_BT709) 269 .build(); 270 ImageWriter writer = new ImageWriter 271 .Builder(reader.getSurface()) 272 .build(); 273 Image outputImage = writer.dequeueInputImage() 274 ) { 275 assertEquals(1, reader.getMaxImages()); // default maxImages 276 assertEquals(HardwareBuffer.USAGE_CPU_READ_OFTEN, reader.getUsage()); // default usage 277 assertEquals(HardwareBuffer.RGBA_8888, reader.getHardwareBufferFormat()); 278 assertEquals(DataSpace.DATASPACE_BT709, reader.getDataSpace()); 279 280 assertEquals(BUFFER_WIDTH, outputImage.getWidth()); 281 assertEquals(BUFFER_HEIGHT, outputImage.getHeight()); 282 assertEquals(HardwareBuffer.RGBA_8888, outputImage.getFormat()); 283 } 284 } 285 286 @Test testWriterBuilderSetImageFormatAndSize()287 public void testWriterBuilderSetImageFormatAndSize() throws Exception { 288 SurfaceTexture texture = new SurfaceTexture(false); 289 texture.setDefaultBufferSize(BUFFER_WIDTH, BUFFER_HEIGHT); 290 Surface surface = new Surface(texture); 291 final int imageWriterWidth = 20; 292 final int imageWriterHeight = 50; 293 294 long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE; 295 try ( 296 ImageWriter writer = new ImageWriter 297 .Builder(surface) 298 .setWidthAndHeight(imageWriterWidth, imageWriterHeight) 299 .setMaxImages(MAX_NUM_IMAGES) 300 .setImageFormat(ImageFormat.YV12) 301 .setUsage(usage) 302 .build(); 303 Image image = writer.dequeueInputImage() 304 ) { 305 // ImageFormat.YV12 HAL dataspace is DataSpace.DATASPACE_JFIF 306 assertEquals(imageWriterWidth, writer.getWidth()); 307 assertEquals(imageWriterHeight, writer.getHeight()); 308 assertEquals(MAX_NUM_IMAGES, writer.getMaxImages()); 309 assertEquals(DataSpace.DATASPACE_JFIF, writer.getDataSpace()); 310 assertEquals(usage, writer.getUsage()); 311 312 assertEquals(DataSpace.DATASPACE_JFIF, image.getDataSpace()); 313 assertEquals(ImageFormat.YV12, image.getFormat()); 314 assertEquals(imageWriterWidth, image.getWidth()); 315 } 316 } 317 318 @Test testWriterBuilderSetHardwareBufferFormatAndDataSpace()319 public void testWriterBuilderSetHardwareBufferFormatAndDataSpace() throws Exception { 320 SurfaceTexture texture = new SurfaceTexture(false); 321 texture.setDefaultBufferSize(BUFFER_WIDTH, BUFFER_HEIGHT); 322 Surface surface = new Surface(texture); 323 324 long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT; 325 try ( 326 ImageWriter writer = new ImageWriter 327 .Builder(surface) 328 .setImageFormat(ImageFormat.YV12) 329 .setHardwareBufferFormat(HardwareBuffer.RGBA_8888) 330 .setDataSpace(DataSpace.DATASPACE_BT709) 331 .setUsage(usage) 332 .build(); 333 Image image = writer.dequeueInputImage() 334 ) { 335 assertEquals(BUFFER_WIDTH, writer.getWidth()); 336 assertEquals(BUFFER_HEIGHT, writer.getHeight()); 337 assertEquals(DataSpace.DATASPACE_BT709, writer.getDataSpace()); 338 assertEquals(HardwareBuffer.RGBA_8888, writer.getHardwareBufferFormat()); 339 assertEquals(usage, writer.getUsage()); 340 341 assertEquals(DataSpace.DATASPACE_BT709, image.getDataSpace()); 342 assertEquals(BUFFER_WIDTH, image.getWidth()); 343 assertEquals(BUFFER_HEIGHT, image.getHeight()); 344 } 345 } 346 347 @Test testWriterBuilderWithBLOB()348 public void testWriterBuilderWithBLOB() throws Exception { 349 SurfaceTexture texture = new SurfaceTexture(false); 350 texture.setDefaultBufferSize(BUFFER_WIDTH, BUFFER_HEIGHT); 351 Surface surface = new Surface(texture); 352 353 long usage = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT; 354 try ( 355 ImageWriter writer = new ImageWriter 356 .Builder(surface) 357 .setHardwareBufferFormat(HardwareBuffer.BLOB) 358 .setDataSpace(DataSpace.DATASPACE_JFIF) 359 .setUsage(usage) 360 .build(); 361 ) { 362 assertEquals(BUFFER_WIDTH, writer.getWidth()); 363 assertEquals(BUFFER_HEIGHT, writer.getHeight()); 364 assertEquals(DataSpace.DATASPACE_JFIF, writer.getDataSpace()); 365 assertEquals(HardwareBuffer.BLOB, writer.getHardwareBufferFormat()); 366 assertEquals(ImageFormat.JPEG, writer.getFormat()); 367 } 368 } 369 370 @Test testGetFence()371 public void testGetFence() throws Exception { 372 try ( 373 ImageReader reader = new ImageReader 374 .Builder(20, 45) 375 .setMaxImages(2) 376 .setImageFormat(ImageFormat.YUV_420_888) 377 .build(); 378 ImageWriter writer = new ImageWriter 379 .Builder(reader.getSurface()) 380 .build(); 381 Image outputImage = writer.dequeueInputImage() 382 ) { 383 assertEquals(false, outputImage.getFence().isValid()); 384 } 385 } 386 387 @Test testSetFence()388 public void testSetFence() throws Exception { 389 SyncFence fence = SyncFenceUtil.createUselessFence(); 390 assumeNotNull(fence); 391 392 SurfaceTexture texture = new SurfaceTexture(false); 393 texture.setDefaultBufferSize(BUFFER_WIDTH, BUFFER_HEIGHT); 394 Surface surface = new Surface(texture); 395 // fence may not be valid on cuttlefish using swiftshader 396 assumeTrue(fence.isValid()); 397 398 try ( 399 ImageWriter writer = new ImageWriter 400 .Builder(surface) 401 .build(); 402 Image outputImage = writer.dequeueInputImage() 403 ) { 404 outputImage.setFence(fence); 405 assertEquals(fence.getSignalTime(), outputImage.getFence().getSignalTime()); 406 } 407 } 408 409 @Test testGetPlanesAndFence()410 public void testGetPlanesAndFence() throws Exception { 411 try ( 412 ImageReader reader = new ImageReader 413 .Builder(BUFFER_WIDTH, BUFFER_HEIGHT) 414 .build(); 415 ImageWriter writer = new ImageWriter 416 .Builder(reader.getSurface()) 417 .build(); 418 Image outputImage = writer.dequeueInputImage(); 419 ) { 420 outputImage.getPlanes(); 421 assertEquals(false, outputImage.getFence().isValid()); 422 } 423 } 424 readerWriterFormatTestByCamera(int format, boolean altFactoryMethod)425 private void readerWriterFormatTestByCamera(int format, boolean altFactoryMethod) 426 throws Exception { 427 List<Size> sizes = getSortedSizesForFormat(mCamera.getId(), mCameraManager, format, null); 428 Size maxSize = sizes.get(0); 429 if (VERBOSE) { 430 Log.v(TAG, "Testing size " + maxSize); 431 } 432 433 // Create ImageReader for camera output. 434 SimpleImageReaderListener listenerForCamera = new SimpleImageReaderListener(); 435 if (altFactoryMethod) { 436 createDefaultImageReader(maxSize, format, MAX_NUM_IMAGES, 437 HardwareBuffer.USAGE_CPU_READ_OFTEN, listenerForCamera); 438 } else { 439 createDefaultImageReader(maxSize, format, MAX_NUM_IMAGES, listenerForCamera); 440 } 441 442 if (VERBOSE) { 443 Log.v(TAG, "Created camera output ImageReader"); 444 } 445 446 // Create ImageReader for ImageWriter output 447 SimpleImageReaderListener listenerForWriter = new SimpleImageReaderListener(); 448 if (altFactoryMethod) { 449 mReaderForWriter = createImageReader( 450 maxSize, format, MAX_NUM_IMAGES, 451 HardwareBuffer.USAGE_CPU_READ_OFTEN, listenerForWriter); 452 } else { 453 mReaderForWriter = createImageReader( 454 maxSize, format, MAX_NUM_IMAGES, listenerForWriter); 455 } 456 457 if (VERBOSE) { 458 Log.v(TAG, "Created ImageWriter output ImageReader"); 459 } 460 461 // Create ImageWriter 462 Surface surface = mReaderForWriter.getSurface(); 463 assertNotNull("Surface from ImageReader shouldn't be null", surface); 464 if (altFactoryMethod) { 465 mWriter = ImageWriter.newInstance(surface, MAX_NUM_IMAGES, format); 466 } else { 467 mWriter = ImageWriter.newInstance(surface, MAX_NUM_IMAGES); 468 } 469 SimpleImageWriterListener writerImageListener = new SimpleImageWriterListener(mWriter); 470 mWriter.setOnImageReleasedListener(writerImageListener, mHandler); 471 472 // Start capture: capture 2 images. 473 List<Surface> outputSurfaces = new ArrayList<Surface>(); 474 outputSurfaces.add(mReader.getSurface()); 475 CaptureRequest.Builder requestBuilder = prepareCaptureRequestForSurfaces(outputSurfaces, 476 CameraDevice.TEMPLATE_PREVIEW); 477 SimpleCaptureCallback captureListener = new SimpleCaptureCallback(); 478 // Capture 1st image. 479 startCapture(requestBuilder.build(), /*repeating*/false, captureListener, mHandler); 480 // Capture 2nd image. 481 startCapture(requestBuilder.build(), /*repeating*/false, captureListener, mHandler); 482 if (VERBOSE) { 483 Log.v(TAG, "Submitted 2 captures"); 484 } 485 486 // Image from the first ImageReader. 487 Image cameraImage = null; 488 // ImageWriter input image. 489 Image inputImage = null; 490 // Image from the second ImageReader. 491 Image outputImage = null; 492 assertTrue("ImageWriter max images should be " + MAX_NUM_IMAGES, 493 mWriter.getMaxImages() == MAX_NUM_IMAGES); 494 if (format == CAMERA_PRIVATE_FORMAT) { 495 assertTrue("First ImageReader format should be PRIVATE", 496 mReader.getImageFormat() == CAMERA_PRIVATE_FORMAT); 497 assertTrue("Second ImageReader should be PRIVATE", 498 mReaderForWriter.getImageFormat() == CAMERA_PRIVATE_FORMAT); 499 assertTrue("Format of first ImageReader should be PRIVATE", 500 mReader.getImageFormat() == CAMERA_PRIVATE_FORMAT); 501 assertTrue(" Format of second ImageReader should be PRIVATE", 502 mReaderForWriter.getImageFormat() == CAMERA_PRIVATE_FORMAT); 503 assertTrue(" Format of ImageWriter should be PRIVATE", 504 mWriter.getFormat() == CAMERA_PRIVATE_FORMAT); 505 506 // Validate 2 images 507 validateOpaqueImages(maxSize, listenerForCamera, listenerForWriter, captureListener, 508 /*numImages*/2, writerImageListener); 509 } else { 510 // Test case 1: Explicit data copy, only applicable for explicit formats. 511 512 // Get 1st image from first ImageReader, and copy the data to ImageWrtier input image 513 cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 514 inputImage = mWriter.dequeueInputImage(); 515 inputImage.setTimestamp(cameraImage.getTimestamp()); 516 if (VERBOSE) { 517 Log.v(TAG, "Image is being copied"); 518 } 519 imageCopy(cameraImage, inputImage); 520 if (VERBOSE) { 521 Log.v(TAG, "Image copy is done"); 522 } 523 mCollector.expectTrue( 524 "ImageWriter 1st input image should match camera 1st output image", 525 isImageStronglyEqual(inputImage, cameraImage)); 526 527 if (DEBUG) { 528 String inputFileName = mDebugFileNameBase + "/" + maxSize + "_image1_input.yuv"; 529 dumpFile(inputFileName, getDataFromImage(inputImage)); 530 } 531 532 // Image should be closed after queueInputImage call 533 Plane closedPlane = inputImage.getPlanes()[0]; 534 ByteBuffer closedBuffer = closedPlane.getBuffer(); 535 mWriter.queueInputImage(inputImage); 536 imageInvalidAccessTestAfterClose(inputImage, closedPlane, closedBuffer); 537 538 outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 539 mCollector.expectTrue("ImageWriter 1st output image should match 1st camera image", 540 isImageStronglyEqual(cameraImage, outputImage)); 541 if (DEBUG) { 542 String img1FileName = mDebugFileNameBase + "/" + maxSize + "_image1_camera.yuv"; 543 String outputImg1FileName = mDebugFileNameBase + "/" + maxSize 544 + "_image1_output.yuv"; 545 dumpFile(img1FileName, getDataFromImage(cameraImage)); 546 dumpFile(outputImg1FileName, getDataFromImage(outputImage)); 547 } 548 // No need to close inputImage, as it is sent to the surface after queueInputImage; 549 cameraImage.close(); 550 outputImage.close(); 551 552 // Make sure ImageWriter listener callback is fired. 553 writerImageListener.waitForImageReleased(CAPTURE_IMAGE_TIMEOUT_MS); 554 555 // Test case 2: Directly inject the image into ImageWriter: works for all formats. 556 557 // Get 2nd image and queue it directly to ImageWrier 558 cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 559 // make a copy of image1 data, as it will be closed after queueInputImage; 560 byte[] img1Data = getDataFromImage(cameraImage); 561 if (DEBUG) { 562 String img2FileName = mDebugFileNameBase + "/" + maxSize + "_image2_camera.yuv"; 563 dumpFile(img2FileName, img1Data); 564 } 565 566 // Image should be closed after queueInputImage call 567 closedPlane = cameraImage.getPlanes()[0]; 568 closedBuffer = closedPlane.getBuffer(); 569 mWriter.queueInputImage(cameraImage); 570 imageInvalidAccessTestAfterClose(cameraImage, closedPlane, closedBuffer); 571 572 outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 573 byte[] outputImageData = getDataFromImage(outputImage); 574 575 mCollector.expectTrue("ImageWriter 2nd output image should match camera " 576 + "2nd output image", Arrays.equals(img1Data, outputImageData)); 577 578 if (DEBUG) { 579 String outputImgFileName = mDebugFileNameBase + "/" + maxSize + 580 "_image2_output.yuv"; 581 dumpFile(outputImgFileName, outputImageData); 582 } 583 // No need to close inputImage, as it is sent to the surface after queueInputImage; 584 outputImage.close(); 585 586 // Make sure ImageWriter listener callback is fired. 587 writerImageListener.waitForImageReleased(CAPTURE_IMAGE_TIMEOUT_MS); 588 } 589 590 stopCapture(/*fast*/false); 591 mReader.close(); 592 mReader = null; 593 mReaderForWriter.close(); 594 mReaderForWriter = null; 595 mWriter.close(); 596 mWriter = null; 597 } 598 validateOpaqueImages(Size maxSize, SimpleImageReaderListener listenerForCamera, SimpleImageReaderListener listenerForWriter, SimpleCaptureCallback captureListener, int numImages, SimpleImageWriterListener writerListener)599 private void validateOpaqueImages(Size maxSize, SimpleImageReaderListener listenerForCamera, 600 SimpleImageReaderListener listenerForWriter, SimpleCaptureCallback captureListener, 601 int numImages, SimpleImageWriterListener writerListener) throws Exception { 602 Image cameraImage; 603 Image outputImage; 604 for (int i = 0; i < numImages; i++) { 605 cameraImage = listenerForCamera.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 606 CaptureResult result = captureListener.getCaptureResult(CAPTURE_IMAGE_TIMEOUT_MS); 607 validateOpaqueImage(cameraImage, "Opaque image " + i + "from camera: ", maxSize, 608 result); 609 mWriter.queueInputImage(cameraImage); 610 // Image should be closed after queueInputImage 611 imageInvalidAccessTestAfterClose(cameraImage, 612 /*closedPlane*/null, /*closedBuffer*/null); 613 outputImage = listenerForWriter.getImage(CAPTURE_IMAGE_TIMEOUT_MS); 614 validateOpaqueImage(outputImage, "First Opaque image output by ImageWriter: ", 615 maxSize, result); 616 outputImage.close(); 617 writerListener.waitForImageReleased(CAPTURE_IMAGE_TIMEOUT_MS); 618 } 619 } 620 validateOpaqueImage(Image image, String msg, Size imageSize, CaptureResult result)621 private void validateOpaqueImage(Image image, String msg, Size imageSize, 622 CaptureResult result) { 623 assertNotNull("Opaque image Capture result should not be null", result != null); 624 mCollector.expectImageProperties(msg + "Opaque ", image, CAMERA_PRIVATE_FORMAT, 625 imageSize, result.get(CaptureResult.SENSOR_TIMESTAMP)); 626 mCollector.expectTrue(msg + "Opaque image number planes should be zero", 627 image.getPlanes().length == 0); 628 } 629 } 630