1 /* 2 * Copyright 2021 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.hardware.camera2.cts.CameraTestUtils; 21 import android.hardware.camera2.cts.helpers.StaticMetadata; 22 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase; 23 import android.hardware.camera2.params.OutputConfiguration; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.CaptureRequest; 26 import android.hardware.camera2.CaptureResult; 27 import android.media.Image; 28 import android.media.ImageReader; 29 import android.os.Build; 30 import android.os.ConditionVariable; 31 import android.util.Log; 32 import android.util.Size; 33 34 import java.util.ArrayList; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 import com.android.compatibility.common.util.PropertyUtil; 40 41 import org.junit.runner.RunWith; 42 import org.junit.runners.Parameterized; 43 import org.junit.Test; 44 45 import static android.hardware.camera2.cts.CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS; 46 import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback; 47 import static junit.framework.Assert.*; 48 49 /** 50 * <p>Basic test for image capture using CONTROL_ZOOM_RATIO. It uses CameraDevice as 51 * producer, and camera sends image data to an imageReader. Image formats 52 * being tested are JPEG and RAW.</p> 53 */ 54 @RunWith(Parameterized.class) 55 public class ZoomCaptureTest extends Camera2AndroidTestCase { 56 private static final String TAG = "ZoomCaptureTest"; 57 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 58 59 private SimpleImageListener mListener; 60 61 @Override setUp()62 public void setUp() throws Exception { 63 super.setUp(); 64 } 65 66 @Override tearDown()67 public void tearDown() throws Exception { 68 super.tearDown(); 69 } 70 71 @Test testJpegZoomCapture()72 public void testJpegZoomCapture() throws Exception { 73 for (String id : mCameraIdsUnderTest) { 74 try { 75 Log.v(TAG, "Testing jpeg zoom capture for Camera " + id); 76 openDevice(id); 77 bufferFormatZoomTestByCamera(ImageFormat.JPEG); 78 } finally { 79 closeDevice(id); 80 } 81 } 82 } 83 84 @Test testRawZoomCapture()85 public void testRawZoomCapture() throws Exception { 86 for (String id : mCameraIdsUnderTest) { 87 try { 88 Log.v(TAG, "Testing raw zoom capture for camera " + id); 89 openDevice(id); 90 91 bufferFormatZoomTestByCamera(ImageFormat.RAW_SENSOR); 92 } finally { 93 closeDevice(id); 94 } 95 } 96 } 97 bufferFormatZoomTestByCamera(int format)98 private void bufferFormatZoomTestByCamera(int format) throws Exception { 99 Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format, 100 StaticMetadata.StreamDirection.Output); 101 if (availableSizes.length == 0) { 102 return; 103 } 104 105 List<Float> candidateZoomRatios = CameraTestUtils.getCandidateZoomRatios(mStaticInfo); 106 Set<String> physicalCameraIds = null; 107 if (mStaticInfo.isLogicalMultiCamera()) { 108 physicalCameraIds = mStaticInfo.getCharacteristics().getPhysicalCameraIds(); 109 } 110 try { 111 mListener = new SimpleImageListener(); 112 // Pick the largest image size: 113 Size maxSize = CameraTestUtils.getMaxSize(availableSizes); 114 createDefaultImageReader(maxSize, format, 1, mListener); 115 116 checkImageReaderSessionConfiguration( 117 "Camera capture session validation for format: " + format + "failed"); 118 119 ArrayList<OutputConfiguration> outputConfigs = new ArrayList<>(); 120 OutputConfiguration config = new OutputConfiguration(mReader.getSurface()); 121 outputConfigs.add(config); 122 123 CaptureRequest.Builder requestBuilder = prepareCaptureRequestForConfigs( 124 outputConfigs, CameraDevice.TEMPLATE_PREVIEW); 125 126 Set<String> activePhysicalIdsSeen = new HashSet<String>(); 127 boolean checkActivePhysicalIdConsistency = 128 PropertyUtil.getFirstApiLevel() >= Build.VERSION_CODES.S; 129 for (Float zoomRatio : candidateZoomRatios) { 130 if (VERBOSE) { 131 Log.v(TAG, "Testing format " + format + " zoomRatio " + zoomRatio + 132 " for camera " + mCamera.getId()); 133 } 134 135 requestBuilder.set(CaptureRequest.CONTROL_ZOOM_RATIO, zoomRatio); 136 CaptureRequest request = requestBuilder.build(); 137 138 SimpleCaptureCallback listener = new SimpleCaptureCallback(); 139 startCapture(request, false /*repeating*/, listener, mHandler); 140 141 // Validate images. 142 mListener.waitForAnyImageAvailable(CAPTURE_WAIT_TIMEOUT_MS); 143 Image img = mReader.acquireNextImage(); 144 assertNotNull("Unable to acquire the latest image", img); 145 CameraTestUtils.validateImage(img, maxSize.getWidth(), maxSize.getHeight(), format, 146 mDebugFileNameBase); 147 img.close(); 148 149 // Validate capture result. 150 if (mStaticInfo.isActivePhysicalCameraIdSupported()) { 151 CaptureResult result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS); 152 String activePhysicalId = result.get( 153 CaptureResult.LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID); 154 if (checkActivePhysicalIdConsistency) { 155 assertNotNull("Camera " + mCamera.getId() + 156 " result metadata must contain ACTIVE_PHYSICAL_ID", 157 activePhysicalId); 158 assertTrue("Camera " + mCamera.getId() + " must be logical " + 159 "camera if activePhysicalId exists in capture result", 160 physicalCameraIds != null && physicalCameraIds.size() != 0); 161 mCollector.expectTrue("Camera " + mCamera.getId() + " activePhysicalId " + 162 activePhysicalId + "must be among valid physical Ids " + 163 physicalCameraIds.toString(), 164 physicalCameraIds.contains(activePhysicalId)); 165 166 activePhysicalIdsSeen.add(activePhysicalId); 167 } 168 } 169 } 170 // stop capture. 171 stopCapture(/*fast*/false); 172 173 if (activePhysicalIdsSeen.size() > 0 && format == ImageFormat.RAW_SENSOR) { 174 mCollector.expectTrue("Logical camera's activePhysicalCamera should not " + 175 " change at different zoom levels.", activePhysicalIdsSeen.size() == 1); 176 } 177 } finally { 178 closeDefaultImageReader(); 179 } 180 } 181 182 private final class SimpleImageListener implements ImageReader.OnImageAvailableListener { 183 private final ConditionVariable imageAvailable = new ConditionVariable(); 184 @Override onImageAvailable(ImageReader reader)185 public void onImageAvailable(ImageReader reader) { 186 imageAvailable.open(); 187 } 188 waitForAnyImageAvailable(long timeout)189 public void waitForAnyImageAvailable(long timeout) { 190 if (imageAvailable.block(timeout)) { 191 imageAvailable.close(); 192 } else { 193 fail("wait for image available timed out after " + timeout + "ms"); 194 } 195 } 196 } 197 } 198