1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.cts; 18 19 import android.graphics.ImageFormat; 20 import android.graphics.Rect; 21 import android.hardware.camera2.CameraCaptureSession; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CameraDevice; 24 import android.hardware.camera2.CaptureRequest; 25 import android.hardware.camera2.CaptureResult; 26 import android.hardware.camera2.DngCreator; 27 import android.hardware.camera2.cts.helpers.StaticMetadata; 28 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 29 import android.location.Location; 30 import android.media.ExifInterface; 31 import android.media.Image; 32 import android.media.ImageReader; 33 import android.util.Log; 34 import android.util.Pair; 35 import android.util.Size; 36 import android.view.Surface; 37 38 import java.io.ByteArrayOutputStream; 39 import java.io.FileOutputStream; 40 import java.util.ArrayList; 41 import java.util.List; 42 43 import static android.hardware.camera2.cts.CameraTestUtils.configureCameraSession; 44 import static android.hardware.camera2.cts.helpers.AssertHelpers.*; 45 46 /** 47 * Tests for the DngCreator API. 48 */ 49 public class DngCreatorTest extends Camera2AndroidTestCase { 50 private static final String TAG = "DngCreatorTest"; 51 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 52 private static final String DEBUG_DNG_FILE = "raw16.dng"; 53 54 @Override setUp()55 protected void setUp() throws Exception { 56 super.setUp(); 57 } 58 59 @Override tearDown()60 protected void tearDown() throws Exception { 61 super.tearDown(); 62 } 63 64 /** 65 * Test basic raw capture and DNG saving functionality for each of the available cameras. 66 * 67 * <p> 68 * For each camera, capture a single RAW16 image at the first capture size reported for 69 * the raw format on that device, and save that image as a DNG file. No further validation 70 * is done. 71 * </p> 72 * 73 * <p> 74 * Note: Enabling adb shell setprop log.tag.DngCreatorTest VERBOSE will also cause the 75 * raw image captured for the first reported camera device to be saved to an output file. 76 * </p> 77 */ testSingleImageBasic()78 public void testSingleImageBasic() throws Exception { 79 for (int i = 0; i < mCameraIds.length; i++) { 80 String deviceId = mCameraIds[i]; 81 ImageReader captureReader = null; 82 FileOutputStream fileStream = null; 83 ByteArrayOutputStream outputStream = null; 84 try { 85 openDevice(deviceId); 86 87 if (!mStaticInfo.isCapabilitySupported( 88 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 89 Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] + 90 ". Skip the test."); 91 continue; 92 } 93 94 Size[] targetCaptureSizes = 95 mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 96 StaticMetadata.StreamDirection.Output); 97 98 assertTrue("No capture sizes available for RAW format!", 99 targetCaptureSizes.length != 0); 100 Rect activeArray = mStaticInfo.getActiveArraySizeChecked(); 101 Size activeArraySize = new Size(activeArray.width(), activeArray.height()); 102 assertTrue("Missing ActiveArraySize", activeArray.width() > 0 && 103 activeArray.height() > 0); 104 // TODO: Allow PixelArraySize also. 105 assertArrayContains("Available sizes for RAW format must include ActiveArraySize", 106 targetCaptureSizes, activeArraySize); 107 108 // Create capture image reader 109 CameraTestUtils.SimpleImageReaderListener captureListener 110 = new CameraTestUtils.SimpleImageReaderListener(); 111 captureReader = createImageReader(activeArraySize, ImageFormat.RAW_SENSOR, 2, 112 captureListener); 113 Pair<Image, CaptureResult> resultPair = captureSingleRawShot(activeArraySize, 114 captureReader, captureListener); 115 CameraCharacteristics characteristics = mStaticInfo.getCharacteristics(); 116 117 // Test simple writeImage, no header checks 118 DngCreator dngCreator = new DngCreator(characteristics, resultPair.second); 119 outputStream = new ByteArrayOutputStream(); 120 dngCreator.writeImage(outputStream, resultPair.first); 121 122 if (VERBOSE) { 123 String filePath = DEBUG_FILE_NAME_BASE + "camera_" + deviceId + "_" + 124 DEBUG_DNG_FILE; 125 // Write out captured DNG file for the first camera device if setprop is enabled 126 fileStream = new FileOutputStream(filePath); 127 fileStream.write(outputStream.toByteArray()); 128 fileStream.flush(); 129 fileStream.close(); 130 Log.v(TAG, "Test DNG file for camera " + deviceId + " saved to " + filePath); 131 } 132 } finally { 133 closeDevice(deviceId); 134 closeImageReader(captureReader); 135 136 if (outputStream != null) { 137 outputStream.close(); 138 } 139 140 if (fileStream != null) { 141 fileStream.close(); 142 } 143 } 144 } 145 } 146 147 /** 148 * Test basic raw capture and DNG saving with a thumbnail, rotation, usercomment, and GPS tags 149 * set. 150 * 151 * <p> 152 * For each camera, capture a single RAW16 image at the first capture size reported for 153 * the raw format on that device, and save that image as a DNG file. No further validation 154 * is done. 155 * </p> 156 * 157 * <p> 158 * Note: Enabling adb shell setprop log.tag.DngCreatorTest VERBOSE will also cause the 159 * raw image captured for the first reported camera device to be saved to an output file. 160 * </p> 161 */ testSingleImageThumbnail()162 public void testSingleImageThumbnail() throws Exception { 163 for (int i = 0; i < mCameraIds.length; i++) { 164 String deviceId = mCameraIds[i]; 165 List<ImageReader> captureReaders = new ArrayList<ImageReader>(); 166 List<CameraTestUtils.SimpleImageReaderListener> captureListeners = 167 new ArrayList<CameraTestUtils.SimpleImageReaderListener>(); 168 FileOutputStream fileStream = null; 169 ByteArrayOutputStream outputStream = null; 170 try { 171 openDevice(deviceId); 172 173 if (!mStaticInfo.isCapabilitySupported( 174 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) { 175 Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] + 176 ". Skip the test."); 177 continue; 178 } 179 180 Size[] targetCaptureSizes = 181 mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 182 StaticMetadata.StreamDirection.Output); 183 184 assertTrue("No capture sizes available for RAW format!", 185 targetCaptureSizes.length != 0); 186 Rect activeArray = mStaticInfo.getActiveArraySizeChecked(); 187 Size activeArraySize = new Size(activeArray.width(), activeArray.height()); 188 assertTrue("Missing ActiveArraySize", activeArray.width() > 0 && 189 activeArray.height() > 0); 190 // TODO: Allow PixelArraySize also. 191 assertArrayContains("Available sizes for RAW format must include ActiveArraySize", 192 targetCaptureSizes, activeArraySize); 193 194 Size[] targetPreviewSizes = 195 mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888, 196 StaticMetadata.StreamDirection.Output); 197 // Get smallest preview size 198 Size previewSize = mOrderedPreviewSizes.get(mOrderedPreviewSizes.size() - 1); 199 200 // Create capture image reader 201 CameraTestUtils.SimpleImageReaderListener captureListener 202 = new CameraTestUtils.SimpleImageReaderListener(); 203 captureReaders.add(createImageReader(activeArraySize, ImageFormat.RAW_SENSOR, 2, 204 captureListener)); 205 captureListeners.add(captureListener); 206 207 CameraTestUtils.SimpleImageReaderListener previewListener 208 = new CameraTestUtils.SimpleImageReaderListener(); 209 210 captureReaders.add(createImageReader(previewSize, ImageFormat.YUV_420_888, 2, 211 previewListener)); 212 captureListeners.add(previewListener); 213 214 Pair<List<Image>, CaptureResult> resultPair = captureSingleRawShot(activeArraySize, 215 captureReaders, captureListeners); 216 CameraCharacteristics characteristics = mStaticInfo.getCharacteristics(); 217 218 // Test simple writeImage, no header checks 219 DngCreator dngCreator = new DngCreator(characteristics, resultPair.second); 220 Location l = new Location("test"); 221 l.reset(); 222 l.setLatitude(37.420016); 223 l.setLongitude(-122.081987); 224 l.setTime(System.currentTimeMillis()); 225 dngCreator.setLocation(l); 226 227 dngCreator.setDescription("helloworld"); 228 dngCreator.setOrientation(ExifInterface.ORIENTATION_FLIP_VERTICAL); 229 dngCreator.setThumbnail(resultPair.first.get(1)); 230 outputStream = new ByteArrayOutputStream(); 231 dngCreator.writeImage(outputStream, resultPair.first.get(0)); 232 233 if (VERBOSE) { 234 String filePath = DEBUG_FILE_NAME_BASE + "camera_" + deviceId + "_" + 235 DEBUG_DNG_FILE; 236 // Write out captured DNG file for the first camera device if setprop is enabled 237 fileStream = new FileOutputStream(filePath); 238 fileStream.write(outputStream.toByteArray()); 239 fileStream.flush(); 240 fileStream.close(); 241 Log.v(TAG, "Test DNG file for camera " + deviceId + " saved to " + filePath); 242 } 243 } finally { 244 closeDevice(deviceId); 245 for (ImageReader r : captureReaders) { 246 closeImageReader(r); 247 } 248 249 if (outputStream != null) { 250 outputStream.close(); 251 } 252 253 if (fileStream != null) { 254 fileStream.close(); 255 } 256 } 257 } 258 } 259 captureSingleRawShot(Size s, ImageReader captureReader, CameraTestUtils.SimpleImageReaderListener captureListener)260 private Pair<Image, CaptureResult> captureSingleRawShot(Size s, ImageReader captureReader, 261 CameraTestUtils.SimpleImageReaderListener captureListener) throws Exception { 262 List<ImageReader> readers = new ArrayList<ImageReader>(); 263 readers.add(captureReader); 264 List<CameraTestUtils.SimpleImageReaderListener> listeners = 265 new ArrayList<CameraTestUtils.SimpleImageReaderListener>(); 266 listeners.add(captureListener); 267 Pair<List<Image>, CaptureResult> res = captureSingleRawShot(s, readers, listeners); 268 return new Pair<Image, CaptureResult>(res.first.get(0), res.second); 269 } 270 271 /** 272 * Capture a single raw image. 273 * 274 * <p>Capture an raw image for a given size.</p> 275 * 276 * @param s The size of the raw image to capture. Must be one of the available sizes for this 277 * device. 278 * @return a pair containing the {@link Image} and {@link CaptureResult} used for this capture. 279 */ captureSingleRawShot(Size s, List<ImageReader> captureReaders, List<CameraTestUtils.SimpleImageReaderListener> captureListeners)280 private Pair<List<Image>, CaptureResult> captureSingleRawShot(Size s, List<ImageReader> captureReaders, 281 List<CameraTestUtils.SimpleImageReaderListener> captureListeners) throws Exception { 282 if (VERBOSE) { 283 Log.v(TAG, "captureSingleRawShot - Capturing raw image."); 284 } 285 286 Size maxYuvSz = mOrderedPreviewSizes.get(0); 287 Size[] targetCaptureSizes = 288 mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR, 289 StaticMetadata.StreamDirection.Output); 290 291 // Validate size 292 boolean validSize = false; 293 for (int i = 0; i < targetCaptureSizes.length; ++i) { 294 if (targetCaptureSizes[i].equals(s)) { 295 validSize = true; 296 break; 297 } 298 } 299 assertTrue("Capture size is supported.", validSize); 300 301 302 // Capture images. 303 List<Surface> outputSurfaces = new ArrayList<Surface>(); 304 for (ImageReader captureReader : captureReaders) { 305 Surface captureSurface = captureReader.getSurface(); 306 outputSurfaces.add(captureSurface); 307 } 308 309 CaptureRequest.Builder request = prepareCaptureRequestForSurfaces(outputSurfaces); 310 request.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 311 CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON); 312 CameraTestUtils.SimpleCaptureCallback resultListener = 313 new CameraTestUtils.SimpleCaptureCallback(); 314 315 startCapture(request.build(), /*repeating*/false, resultListener, mHandler); 316 317 // Verify capture result and images 318 CaptureResult result = resultListener.getCaptureResult(CAPTURE_WAIT_TIMEOUT_MS); 319 320 List<Image> resultImages = new ArrayList<Image>(); 321 for (CameraTestUtils.SimpleImageReaderListener captureListener : captureListeners) { 322 Image captureImage = captureListener.getImage(CAPTURE_WAIT_TIMEOUT_MS); 323 324 /*CameraTestUtils.validateImage(captureImage, s.getWidth(), s.getHeight(), 325 ImageFormat.RAW_SENSOR, null);*/ 326 resultImages.add(captureImage); 327 } 328 // Stop capture, delete the streams. 329 stopCapture(/*fast*/false); 330 331 return new Pair<List<Image>, CaptureResult>(resultImages, result); 332 } 333 prepareCaptureRequestForSurfaces(List<Surface> surfaces)334 private CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces) 335 throws Exception { 336 createSession(surfaces); 337 338 CaptureRequest.Builder captureBuilder = 339 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 340 assertNotNull("Fail to get captureRequest", captureBuilder); 341 for (Surface surface : surfaces) { 342 captureBuilder.addTarget(surface); 343 } 344 345 return captureBuilder; 346 } 347 } 348