• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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