blob: ddae8eb6d56058c0e895710a699e010ef2c225a8 [file] [log] [blame]
Ruben Brunkc467f592014-08-19 16:37:50 -07001/*
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
17package android.hardware.camera2.cts;
18
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070019import static android.hardware.camera2.cts.CameraTestUtils.*;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -070020import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.*;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070021
Deng Bingc34adcd2015-07-02 17:56:42 +080022import android.content.Context;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070023import android.graphics.ImageFormat;
Ruben Brunkc467f592014-08-19 16:37:50 -070024import android.graphics.SurfaceTexture;
Ruben Brunkc467f592014-08-19 16:37:50 -070025import android.hardware.camera2.CameraCaptureSession;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070026import android.hardware.camera2.CameraCharacteristics;
Ruben Brunkc467f592014-08-19 16:37:50 -070027import android.hardware.camera2.CameraDevice;
Deng Bingc34adcd2015-07-02 17:56:42 +080028import android.hardware.camera2.CameraManager;
Ruben Brunkc467f592014-08-19 16:37:50 -070029import android.hardware.camera2.CaptureRequest;
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -070030import android.hardware.camera2.CaptureResult;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070031import android.hardware.camera2.TotalCaptureResult;
32import android.hardware.camera2.CaptureFailure;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -070033import android.hardware.camera2.params.InputConfiguration;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070034import android.hardware.camera2.params.StreamConfigurationMap;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070035import android.hardware.camera2.cts.helpers.StaticMetadata;
Ruben Brunkc467f592014-08-19 16:37:50 -070036import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070037import android.media.CamcorderProfile;
Unsuk Jungff9926e2015-09-12 19:50:47 +000038import android.media.Image;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070039import android.media.ImageReader;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -070040import android.media.ImageWriter;
Ruben Brunkc467f592014-08-19 16:37:50 -070041import android.util.Log;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070042import android.util.Size;
Deng Bingc34adcd2015-07-02 17:56:42 +080043import android.view.Display;
Ruben Brunkc467f592014-08-19 16:37:50 -070044import android.view.Surface;
Deng Bingc34adcd2015-07-02 17:56:42 +080045import android.view.WindowManager;
Ruben Brunkc467f592014-08-19 16:37:50 -070046
Chien-Yu Chen33f60d42015-06-16 17:05:11 -070047import com.android.ex.camera2.blocking.BlockingSessionCallback;
48
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -070049import java.util.Arrays;
Ruben Brunkc467f592014-08-19 16:37:50 -070050import java.util.ArrayList;
51import java.util.List;
52
Ruben Brunkd28ac8e2014-11-21 10:12:08 -080053import static junit.framework.Assert.assertTrue;
Ruben Brunkc467f592014-08-19 16:37:50 -070054import static org.mockito.Mockito.*;
55
56/**
57 * Tests exercising edge cases in camera setup, configuration, and usage.
58 */
59public class RobustnessTest extends Camera2AndroidTestCase {
60 private static final String TAG = "RobustnessTest";
Chien-Yu Chenf538fab2015-05-20 10:52:22 -070061 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
Ruben Brunkc467f592014-08-19 16:37:50 -070062
Ruben Brunkd28ac8e2014-11-21 10:12:08 -080063 private static final int CONFIGURE_TIMEOUT = 5000; //ms
64 private static final int CAPTURE_TIMEOUT = 1000; //ms
Ruben Brunkc467f592014-08-19 16:37:50 -070065
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -070066 // For testTriggerInteractions
67 private static final int PREVIEW_WARMUP_FRAMES = 60;
68 private static final int MAX_RESULT_STATE_CHANGE_WAIT_FRAMES = 100;
69 private static final int MAX_TRIGGER_SEQUENCE_FRAMES = 180; // 6 sec at 30 fps
70 private static final int MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES = 10;
71
Ruben Brunkc467f592014-08-19 16:37:50 -070072 /**
Ruben Brunkd28ac8e2014-11-21 10:12:08 -080073 * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing
74 * a dimension other than one of the supported output dimensions. The buffers produced into
75 * this surface are expected have the dimensions of the closest possible buffer size in the
76 * available stream configurations for a surface with this format.
Ruben Brunkc467f592014-08-19 16:37:50 -070077 */
78 public void testBadSurfaceDimensions() throws Exception {
79 for (String id : mCameraIds) {
80 try {
81 Log.i(TAG, "Testing Camera " + id);
82 openDevice(id);
83
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -070084 List<Size> testSizes = null;
85 int format = mStaticInfo.isColorOutputSupported() ?
86 ImageFormat.YUV_420_888 : ImageFormat.DEPTH16;
87
88 testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager,
89 format, null);
90
Ruben Brunkd28ac8e2014-11-21 10:12:08 -080091 // Find some size not supported by the camera
92 Size weirdSize = new Size(643, 577);
93 int count = 0;
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -070094 while(testSizes.contains(weirdSize)) {
Ruben Brunkd28ac8e2014-11-21 10:12:08 -080095 // Really, they can't all be supported...
96 weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
97 count++;
98 assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100);
99 }
100
101 // Setup imageReader with invalid dimension
102 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700103 weirdSize.getHeight(), format, 3);
Ruben Brunkd28ac8e2014-11-21 10:12:08 -0800104
Chien-Yu Chen896416d2015-02-05 12:00:40 -0800105 // Setup ImageReaderListener
106 SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
107 imageReader.setOnImageAvailableListener(imageListener, mHandler);
108
Ruben Brunkd28ac8e2014-11-21 10:12:08 -0800109 Surface surface = imageReader.getSurface();
Ruben Brunkc467f592014-08-19 16:37:50 -0700110 List<Surface> surfaces = new ArrayList<>();
111 surfaces.add(surface);
112
113 // Setup a capture request and listener
114 CaptureRequest.Builder request =
115 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
116 request.addTarget(surface);
Ruben Brunkc467f592014-08-19 16:37:50 -0700117
118 // Check that correct session callback is hit.
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700119 CameraCaptureSession.StateCallback sessionListener =
120 mock(CameraCaptureSession.StateCallback.class);
Ruben Brunkd28ac8e2014-11-21 10:12:08 -0800121 CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera,
122 surfaces, sessionListener, mHandler);
123
124 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
125 onConfigured(any(CameraCaptureSession.class));
126 verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
127 onReady(any(CameraCaptureSession.class));
128 verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
Ruben Brunkc467f592014-08-19 16:37:50 -0700129 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
Ruben Brunkc467f592014-08-19 16:37:50 -0700130 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
Ruben Brunkd28ac8e2014-11-21 10:12:08 -0800131
132 CameraCaptureSession.CaptureCallback captureListener =
133 mock(CameraCaptureSession.CaptureCallback.class);
134 session.capture(request.build(), captureListener, mHandler);
135
136 verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
137 onCaptureCompleted(any(CameraCaptureSession.class),
138 any(CaptureRequest.class), any(TotalCaptureResult.class));
139 verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
140 any(CaptureRequest.class), any(CaptureFailure.class));
141
Chien-Yu Chen896416d2015-02-05 12:00:40 -0800142 Image image = imageListener.getImage(CAPTURE_TIMEOUT);
Ruben Brunkd28ac8e2014-11-21 10:12:08 -0800143 int imageWidth = image.getWidth();
144 int imageHeight = image.getHeight();
145 Size actualSize = new Size(imageWidth, imageHeight);
146
147 assertTrue("Camera does not contain outputted image resolution " + actualSize,
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700148 testSizes.contains(actualSize));
Ruben Brunkc467f592014-08-19 16:37:50 -0700149 } finally {
150 closeDevice(id);
151 }
152 }
153 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700154
155 /**
156 * Test for making sure the required output combinations for each hardware level and capability
157 * work as expected.
158 */
159 public void testMandatoryOutputCombinations() throws Exception {
160 /**
161 * Tables for maximum sizes to try for each hardware level and capability.
162 *
163 * Keep in sync with the tables in
164 * frameworks/base/core/java/android/hardware/camera2/CameraDevice.java#createCaptureSession
165 *
166 * Each row of the table is a set of (format, max resolution) pairs, using the below consts
167 */
168
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700169 // Enum values are defined in MaxStreamSizes
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700170 final int[][] LEGACY_COMBINATIONS = {
171 {PRIV, MAXIMUM}, // Simple preview, GPU video processing, or no-preview video recording
172 {JPEG, MAXIMUM}, // No-viewfinder still image capture
173 {YUV, MAXIMUM}, // In-application video/image processing
174 {PRIV, PREVIEW, JPEG, MAXIMUM}, // Standard still imaging.
175 {YUV, PREVIEW, JPEG, MAXIMUM}, // In-app processing plus still capture.
176 {PRIV, PREVIEW, PRIV, PREVIEW}, // Standard recording.
177 {PRIV, PREVIEW, YUV, PREVIEW}, // Preview plus in-app processing.
178 {PRIV, PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM} // Still capture plus in-app processing.
179 };
180
181 final int[][] LIMITED_COMBINATIONS = {
182 {PRIV, PREVIEW, PRIV, RECORD }, // High-resolution video recording with preview.
183 {PRIV, PREVIEW, YUV , RECORD }, // High-resolution in-app video processing with preview.
184 {YUV , PREVIEW, YUV , RECORD }, // Two-input in-app video processing.
185 {PRIV, PREVIEW, PRIV, RECORD, JPEG, RECORD }, // High-resolution recording with video snapshot.
186 {PRIV, PREVIEW, YUV, RECORD, JPEG, RECORD }, // High-resolution in-app processing with video snapshot.
187 {YUV , PREVIEW, YUV, PREVIEW, JPEG, MAXIMUM } // Two-input in-app processing with still capture.
188 };
189
Eino-Ville Talvala35a52702014-11-13 13:36:58 -0800190 final int[][] BURST_COMBINATIONS = {
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700191 {PRIV, PREVIEW, PRIV, MAXIMUM }, // Maximum-resolution GPU processing with preview.
192 {PRIV, PREVIEW, YUV, MAXIMUM }, // Maximum-resolution in-app processing with preview.
193 {YUV, PREVIEW, YUV, MAXIMUM }, // Maximum-resolution two-input in-app processsing.
Eino-Ville Talvala35a52702014-11-13 13:36:58 -0800194 };
195
196 final int[][] FULL_COMBINATIONS = {
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700197 {PRIV, PREVIEW, PRIV, PREVIEW, JPEG, MAXIMUM }, //Video recording with maximum-size video snapshot.
198 {YUV, VGA, PRIV, PREVIEW, YUV, MAXIMUM }, // Standard video recording plus maximum-resolution in-app processing.
199 {YUV, VGA, YUV, PREVIEW, YUV, MAXIMUM } // Preview plus two-input maximum-resolution in-app processing.
200 };
201
202 final int[][] RAW_COMBINATIONS = {
203 {RAW, MAXIMUM }, // No-preview DNG capture.
204 {PRIV, PREVIEW, RAW, MAXIMUM }, // Standard DNG capture.
205 {YUV, PREVIEW, RAW, MAXIMUM }, // In-app processing plus DNG capture.
206 {PRIV, PREVIEW, PRIV, PREVIEW, RAW, MAXIMUM}, // Video recording with DNG capture.
207 {PRIV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, // Preview with in-app processing and DNG capture.
208 {YUV, PREVIEW, YUV, PREVIEW, RAW, MAXIMUM}, // Two-input in-app processing plus DNG capture.
209 {PRIV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM}, // Still capture with simultaneous JPEG and DNG.
210 {YUV, PREVIEW, JPEG, MAXIMUM, RAW, MAXIMUM} // In-app processing with simultaneous JPEG and DNG.
211 };
212
213 final int[][][] TABLES =
Eino-Ville Talvala35a52702014-11-13 13:36:58 -0800214 { LEGACY_COMBINATIONS, LIMITED_COMBINATIONS, BURST_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS };
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700215
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700216 sanityCheckConfigurationTables(TABLES);
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700217
218 for (String id : mCameraIds) {
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700219 openDevice(id);
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700220
221 // Find the concrete max sizes for each format/resolution combination
Yin-Chia Yeh7f2ecbd2015-07-10 09:39:13 -0700222 MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id, getContext());
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700223
Chien-Yu Chenf538fab2015-05-20 10:52:22 -0700224 String streamConfigurationMapString =
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700225 mStaticInfo.getCharacteristics().get(
226 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).toString();
Chien-Yu Chenf538fab2015-05-20 10:52:22 -0700227 if (VERBOSE) {
228 Log.v(TAG, "StreamConfigurationMap: " + streamConfigurationMapString);
229 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700230
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700231 // Always run legacy-level tests for color-supporting devices
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700232
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700233 if (mStaticInfo.isColorOutputSupported()) {
234 for (int[] config : LEGACY_COMBINATIONS) {
235 testOutputCombination(id, config, maxSizes);
236 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700237 }
238
239 // Then run higher-level tests if applicable
240
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700241 if (!mStaticInfo.isHardwareLevelLegacy()) {
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700242
243 // If not legacy, at least limited, so run limited-level tests
244
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700245 if (mStaticInfo.isColorOutputSupported()) {
246 for (int[] config : LIMITED_COMBINATIONS) {
247 testOutputCombination(id, config, maxSizes);
248 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700249 }
250
Eino-Ville Talvala35a52702014-11-13 13:36:58 -0800251 // Check for BURST_CAPTURE, FULL and RAW and run those if appropriate
252
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700253 if (mStaticInfo.isCapabilitySupported(
Eino-Ville Talvala35a52702014-11-13 13:36:58 -0800254 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
255 for (int[] config : BURST_COMBINATIONS) {
256 testOutputCombination(id, config, maxSizes);
257 }
258 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700259
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700260 if (mStaticInfo.isHardwareLevelFull()) {
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700261 for (int[] config : FULL_COMBINATIONS) {
262 testOutputCombination(id, config, maxSizes);
263 }
264 }
265
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -0700266 if (mStaticInfo.isCapabilitySupported(
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -0700267 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
268 for (int[] config : RAW_COMBINATIONS) {
269 testOutputCombination(id, config, maxSizes);
270 }
271 }
272 }
273
274 closeDevice(id);
275 }
276 }
277
278 /**
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700279 * Test for making sure the required reprocess input/output combinations for each hardware
280 * level and capability work as expected.
281 */
282 public void testMandatoryReprocessConfigurations() throws Exception {
283
284 /**
285 * For each stream combination, verify that
286 * 1. A reprocessable session can be created using the stream combination.
287 * 2. Reprocess capture requests targeting YUV and JPEG outputs are successful.
288 */
289 final int[][] LIMITED_COMBINATIONS = {
290 // Input Outputs
291 {PRIV, MAXIMUM, JPEG, MAXIMUM},
292 {YUV , MAXIMUM, JPEG, MAXIMUM},
293 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM},
294 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM},
295 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM},
296 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM},
297 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
298 {YUV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
299 };
300
301 final int[][] FULL_COMBINATIONS = {
302 // Input Outputs
303 {YUV , MAXIMUM, PRIV, PREVIEW},
304 {YUV , MAXIMUM, YUV , PREVIEW},
305 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , RECORD},
306 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , RECORD},
307 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , MAXIMUM},
308 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , MAXIMUM},
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700309 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
310 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
311 };
312
313 final int[][] RAW_COMBINATIONS = {
314 // Input Outputs
315 {PRIV, MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM},
316 {YUV , MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM},
317 {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
318 {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
319 {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
320 {YUV , MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
321 {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
322 {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
323 {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
324 {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
325 };
326
327 final int[][][] TABLES =
328 { LIMITED_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS };
329
330 sanityCheckConfigurationTables(TABLES);
331
332 for (String id : mCameraIds) {
333 CameraCharacteristics cc = mCameraManager.getCameraCharacteristics(id);
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700334 StaticMetadata staticInfo = new StaticMetadata(cc);
Yin-Chia Yeh7f2ecbd2015-07-10 09:39:13 -0700335 MaxStreamSizes maxSizes = new MaxStreamSizes(staticInfo, id, getContext());
Chien-Yu Chen33f60d42015-06-16 17:05:11 -0700336
337 // Skip the test for legacy devices.
338 if (staticInfo.isHardwareLevelLegacy()) {
339 continue;
340 }
341
342 openDevice(id);
343
344 try {
345 for (int[] config : LIMITED_COMBINATIONS) {
346 testReprocessStreamCombination(id, config, maxSizes, staticInfo);
347 }
348
349 // Check FULL devices
350 if (staticInfo.isHardwareLevelFull()) {
351 for (int[] config : FULL_COMBINATIONS) {
352 testReprocessStreamCombination(id, config, maxSizes, staticInfo);
353 }
354 }
355
356 // Check devices with RAW capability.
357 if (staticInfo.isCapabilitySupported(
358 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
359 for (int[] config : RAW_COMBINATIONS) {
360 testReprocessStreamCombination(id, config, maxSizes, staticInfo);
361 }
362 }
363 } finally {
364 closeDevice(id);
365 }
366 }
367 }
368
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -0700369 public void testBasicTriggerSequence() throws Exception {
370
371 for (String id : mCameraIds) {
372 Log.i(TAG, String.format("Testing Camera %s", id));
373
374 openDevice(id);
375 try {
376 // Legacy devices do not support precapture trigger; don't test devices that
377 // can't focus
378 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
379 continue;
380 }
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700381 // Depth-only devices won't support AE
382 if (!mStaticInfo.isColorOutputSupported()) {
383 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
384 continue;
385 }
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -0700386
387 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
388 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
389 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
390 CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
391
392 for (int afMode : availableAfModes) {
393
394 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
395 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
396 // Only test AF modes that have meaningful trigger behavior
397 continue;
398 }
399
400 for (int aeMode : availableAeModes) {
401 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) {
402 // Only test AE modes that have meaningful trigger behavior
403 continue;
404 }
405
406 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
407
408 CaptureRequest.Builder previewRequest =
409 prepareTriggerTestSession(preview, aeMode, afMode);
410
411 SimpleCaptureCallback captureListener =
412 new CameraTestUtils.SimpleCaptureCallback();
413
414 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
415 mHandler);
416
417 // Cancel triggers
418
419 cancelTriggersAndWait(previewRequest, captureListener, afMode);
420
421 //
422 // Standard sequence - AF trigger then AE trigger
423
424 if (VERBOSE) {
425 Log.v(TAG, String.format("Triggering AF"));
426 }
427
428 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
429 CaptureRequest.CONTROL_AF_TRIGGER_START);
430 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
431 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
432
433 CaptureRequest triggerRequest = previewRequest.build();
434 mCameraSession.capture(triggerRequest, captureListener, mHandler);
435
436 CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
437 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
438 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
439 boolean focusComplete = false;
440
441 for (int i = 0;
442 i < MAX_TRIGGER_SEQUENCE_FRAMES && !focusComplete;
443 i++) {
444
445 focusComplete = verifyAfSequence(afMode, afState, focusComplete);
446
447 CaptureResult focusResult = captureListener.getCaptureResult(
448 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
449 afState = focusResult.get(CaptureResult.CONTROL_AF_STATE);
450 }
451
452 assertTrue("Focusing never completed!", focusComplete);
453
454 // Standard sequence - Part 2 AE trigger
455
456 if (VERBOSE) {
457 Log.v(TAG, String.format("Triggering AE"));
458 }
459
460 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
461 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
462 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
463 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
464
465 triggerRequest = previewRequest.build();
466 mCameraSession.capture(triggerRequest, captureListener, mHandler);
467
468 triggerResult = captureListener.getCaptureResultForRequest(
469 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
470
471 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
472
473 boolean precaptureComplete = false;
474
475 for (int i = 0;
476 i < MAX_TRIGGER_SEQUENCE_FRAMES && !precaptureComplete;
477 i++) {
478
479 precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
480
481 CaptureResult precaptureResult = captureListener.getCaptureResult(
482 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
483 aeState = precaptureResult.get(CaptureResult.CONTROL_AE_STATE);
484 }
485
486 assertTrue("Precapture sequence never completed!", precaptureComplete);
487
488 for (int i = 0; i < MAX_RESULT_STATE_POSTCHANGE_WAIT_FRAMES; i++) {
489 CaptureResult postPrecaptureResult = captureListener.getCaptureResult(
490 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
491 aeState = postPrecaptureResult.get(CaptureResult.CONTROL_AE_STATE);
492 assertTrue("Late transition to PRECAPTURE state seen",
493 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
494 }
495
496 // Done
497
498 stopCapture(/*fast*/ false);
499 preview.release();
500 }
501
502 }
503
504 } finally {
505 closeDevice(id);
506 }
507 }
508
509 }
510
511 public void testSimultaneousTriggers() throws Exception {
512 for (String id : mCameraIds) {
513 Log.i(TAG, String.format("Testing Camera %s", id));
514
515 openDevice(id);
516 try {
517 // Legacy devices do not support precapture trigger; don't test devices that
518 // can't focus
519 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
520 continue;
521 }
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700522 // Depth-only devices won't support AE
523 if (!mStaticInfo.isColorOutputSupported()) {
524 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
525 continue;
526 }
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -0700527
528 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
529 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
530 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
531 CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
532
533 for (int afMode : availableAfModes) {
534
535 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
536 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
537 // Only test AF modes that have meaningful trigger behavior
538 continue;
539 }
540
541 for (int aeMode : availableAeModes) {
542 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) {
543 // Only test AE modes that have meaningful trigger behavior
544 continue;
545 }
546
547 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
548
549 CaptureRequest.Builder previewRequest =
550 prepareTriggerTestSession(preview, aeMode, afMode);
551
552 SimpleCaptureCallback captureListener =
553 new CameraTestUtils.SimpleCaptureCallback();
554
555 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
556 mHandler);
557
558 // Cancel triggers
559
560 cancelTriggersAndWait(previewRequest, captureListener, afMode);
561
562 //
563 // Trigger AF and AE together
564
565 if (VERBOSE) {
566 Log.v(TAG, String.format("Triggering AF and AE together"));
567 }
568
569 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
570 CaptureRequest.CONTROL_AF_TRIGGER_START);
571 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
572 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
573
574 CaptureRequest triggerRequest = previewRequest.build();
575 mCameraSession.capture(triggerRequest, captureListener, mHandler);
576
577 CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
578 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
579 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
580 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
581
582 boolean precaptureComplete = false;
583 boolean focusComplete = false;
584
585 for (int i = 0;
586 i < MAX_TRIGGER_SEQUENCE_FRAMES &&
587 !(focusComplete && precaptureComplete);
588 i++) {
589
590 focusComplete = verifyAfSequence(afMode, afState, focusComplete);
591 precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
592
593 CaptureResult sequenceResult = captureListener.getCaptureResult(
594 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
595 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
596 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
597 }
598
599 assertTrue("Precapture sequence never completed!", precaptureComplete);
600 assertTrue("Focus sequence never completed!", focusComplete);
601
602 // Done
603
604 stopCapture(/*fast*/ false);
605 preview.release();
606
607 }
608 }
609 } finally {
610 closeDevice(id);
611 }
612 }
613 }
614
615 public void testAfThenAeTrigger() throws Exception {
616 for (String id : mCameraIds) {
617 Log.i(TAG, String.format("Testing Camera %s", id));
618
619 openDevice(id);
620 try {
621 // Legacy devices do not support precapture trigger; don't test devices that
622 // can't focus
623 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
624 continue;
625 }
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700626 // Depth-only devices won't support AE
627 if (!mStaticInfo.isColorOutputSupported()) {
628 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
629 continue;
630 }
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -0700631
632 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
633 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
634 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
635 CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
636
637 for (int afMode : availableAfModes) {
638
639 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
640 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
641 // Only test AF modes that have meaningful trigger behavior
642 continue;
643 }
644
645 for (int aeMode : availableAeModes) {
646 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) {
647 // Only test AE modes that have meaningful trigger behavior
648 continue;
649 }
650
651 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
652
653 CaptureRequest.Builder previewRequest =
654 prepareTriggerTestSession(preview, aeMode, afMode);
655
656 SimpleCaptureCallback captureListener =
657 new CameraTestUtils.SimpleCaptureCallback();
658
659 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
660 mHandler);
661
662 // Cancel triggers
663
664 cancelTriggersAndWait(previewRequest, captureListener, afMode);
665
666 //
667 // AF with AE a request later
668
669 if (VERBOSE) {
670 Log.v(TAG, "Trigger AF, then AE trigger on next request");
671 }
672
673 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
674 CaptureRequest.CONTROL_AF_TRIGGER_START);
675 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
676 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
677
678 CaptureRequest triggerRequest = previewRequest.build();
679 mCameraSession.capture(triggerRequest, captureListener, mHandler);
680
681 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
682 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
683 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
684 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
685
686 CaptureRequest triggerRequest2 = previewRequest.build();
687 mCameraSession.capture(triggerRequest2, captureListener, mHandler);
688
689 CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
690 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
691 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
692
693 boolean precaptureComplete = false;
694 boolean focusComplete = false;
695
696 focusComplete = verifyAfSequence(afMode, afState, focusComplete);
697
698 triggerResult = captureListener.getCaptureResultForRequest(
699 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
700 afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
701 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
702
703 for (int i = 0;
704 i < MAX_TRIGGER_SEQUENCE_FRAMES &&
705 !(focusComplete && precaptureComplete);
706 i++) {
707
708 focusComplete = verifyAfSequence(afMode, afState, focusComplete);
709 precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
710
711 CaptureResult sequenceResult = captureListener.getCaptureResult(
712 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
713 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
714 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
715 }
716
717 assertTrue("Precapture sequence never completed!", precaptureComplete);
718 assertTrue("Focus sequence never completed!", focusComplete);
719
720 // Done
721
722 stopCapture(/*fast*/ false);
723 preview.release();
724
725 }
726 }
727 } finally {
728 closeDevice(id);
729 }
730 }
731 }
732
733 public void testAeThenAfTrigger() throws Exception {
734 for (String id : mCameraIds) {
735 Log.i(TAG, String.format("Testing Camera %s", id));
736
737 openDevice(id);
738 try {
739 // Legacy devices do not support precapture trigger; don't test devices that
740 // can't focus
741 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
742 continue;
743 }
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700744 // Depth-only devices won't support AE
745 if (!mStaticInfo.isColorOutputSupported()) {
746 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
747 continue;
748 }
Eino-Ville Talvaladc2570c2015-06-26 16:06:26 -0700749
750 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
751 CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
752 int[] availableAeModes = mStaticInfo.getCharacteristics().get(
753 CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
754
755 for (int afMode : availableAfModes) {
756
757 if (afMode == CameraCharacteristics.CONTROL_AF_MODE_OFF ||
758 afMode == CameraCharacteristics.CONTROL_AF_MODE_EDOF) {
759 // Only test AF modes that have meaningful trigger behavior
760 continue;
761 }
762
763 for (int aeMode : availableAeModes) {
764 if (aeMode == CameraCharacteristics.CONTROL_AE_MODE_OFF) {
765 // Only test AE modes that have meaningful trigger behavior
766 continue;
767 }
768
769 SurfaceTexture preview = new SurfaceTexture(/*random int*/ 1);
770
771 CaptureRequest.Builder previewRequest =
772 prepareTriggerTestSession(preview, aeMode, afMode);
773
774 SimpleCaptureCallback captureListener =
775 new CameraTestUtils.SimpleCaptureCallback();
776
777 mCameraSession.setRepeatingRequest(previewRequest.build(), captureListener,
778 mHandler);
779
780 // Cancel triggers
781
782 cancelTriggersAndWait(previewRequest, captureListener, afMode);
783
784 //
785 // AE with AF a request later
786
787 if (VERBOSE) {
788 Log.v(TAG, "Trigger AE, then AF trigger on next request");
789 }
790
791 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
792 CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
793 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
794 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
795
796 CaptureRequest triggerRequest = previewRequest.build();
797 mCameraSession.capture(triggerRequest, captureListener, mHandler);
798
799 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
800 CaptureRequest.CONTROL_AF_TRIGGER_START);
801 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
802 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
803
804 CaptureRequest triggerRequest2 = previewRequest.build();
805 mCameraSession.capture(triggerRequest2, captureListener, mHandler);
806
807 CaptureResult triggerResult = captureListener.getCaptureResultForRequest(
808 triggerRequest, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
809 int aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
810
811 boolean precaptureComplete = false;
812 boolean focusComplete = false;
813
814 precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
815
816 triggerResult = captureListener.getCaptureResultForRequest(
817 triggerRequest2, MAX_RESULT_STATE_CHANGE_WAIT_FRAMES);
818 int afState = triggerResult.get(CaptureResult.CONTROL_AF_STATE);
819 aeState = triggerResult.get(CaptureResult.CONTROL_AE_STATE);
820
821 for (int i = 0;
822 i < MAX_TRIGGER_SEQUENCE_FRAMES &&
823 !(focusComplete && precaptureComplete);
824 i++) {
825
826 focusComplete = verifyAfSequence(afMode, afState, focusComplete);
827 precaptureComplete = verifyAeSequence(aeState, precaptureComplete);
828
829 CaptureResult sequenceResult = captureListener.getCaptureResult(
830 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
831 afState = sequenceResult.get(CaptureResult.CONTROL_AF_STATE);
832 aeState = sequenceResult.get(CaptureResult.CONTROL_AE_STATE);
833 }
834
835 assertTrue("Precapture sequence never completed!", precaptureComplete);
836 assertTrue("Focus sequence never completed!", focusComplete);
837
838 // Done
839
840 stopCapture(/*fast*/ false);
841 preview.release();
842
843 }
844 }
845 } finally {
846 closeDevice(id);
847 }
848 }
849 }
850
851 private CaptureRequest.Builder prepareTriggerTestSession(
852 SurfaceTexture preview, int aeMode, int afMode) throws Exception {
853 Log.i(TAG, String.format("Testing AE mode %s, AF mode %s",
854 StaticMetadata.AE_MODE_NAMES[aeMode],
855 StaticMetadata.AF_MODE_NAMES[afMode]));
856
857
858 Surface previewSurface = new Surface(preview);
859
860 preview.setDefaultBufferSize(640, 480);
861
862 ArrayList<Surface> sessionOutputs = new ArrayList<>();
863 sessionOutputs.add(previewSurface);
864
865 createSession(sessionOutputs);
866
867 CaptureRequest.Builder previewRequest =
868 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
869
870 previewRequest.addTarget(previewSurface);
871
872 previewRequest.set(CaptureRequest.CONTROL_AE_MODE, aeMode);
873 previewRequest.set(CaptureRequest.CONTROL_AF_MODE, afMode);
874
875 return previewRequest;
876 }
877
878 private void cancelTriggersAndWait(CaptureRequest.Builder previewRequest,
879 SimpleCaptureCallback captureListener, int afMode) throws Exception {
880 previewRequest.set(CaptureRequest.CONTROL_AF_TRIGGER,
881 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
882 previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
883 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
884
885 CaptureRequest triggerRequest = previewRequest.build();
886 mCameraSession.capture(triggerRequest, captureListener, mHandler);
887
888 // Wait for a few frames to initialize 3A
889
890 CaptureResult previewResult = null;
891 int afState;
892 int aeState;
893
894 for (int i = 0; i < PREVIEW_WARMUP_FRAMES; i++) {
895 previewResult = captureListener.getCaptureResult(
896 CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
897 if (VERBOSE) {
898 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
899 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
900 Log.v(TAG, String.format("AF state: %s, AE state: %s",
901 StaticMetadata.AF_STATE_NAMES[afState],
902 StaticMetadata.AE_STATE_NAMES[aeState]));
903 }
904 }
905
906 // Verify starting states
907
908 afState = previewResult.get(CaptureResult.CONTROL_AF_STATE);
909 aeState = previewResult.get(CaptureResult.CONTROL_AE_STATE);
910
911 switch (afMode) {
912 case CaptureResult.CONTROL_AF_MODE_AUTO:
913 case CaptureResult.CONTROL_AF_MODE_MACRO:
914 assertTrue(String.format("AF state not INACTIVE, is %s",
915 StaticMetadata.AF_STATE_NAMES[afState]),
916 afState == CaptureResult.CONTROL_AF_STATE_INACTIVE);
917 break;
918 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
919 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
920 // After several frames, AF must no longer be in INACTIVE state
921 assertTrue(String.format("In AF mode %s, AF state not PASSIVE_SCAN" +
922 ", PASSIVE_FOCUSED, or PASSIVE_UNFOCUSED, is %s",
923 StaticMetadata.AF_MODE_NAMES[afMode],
924 StaticMetadata.AF_STATE_NAMES[afState]),
925 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
926 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED ||
927 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED);
928 break;
929 default:
930 fail("unexpected af mode");
931 }
932
933 // After several frames, AE must no longer be in INACTIVE state
934 assertTrue(String.format("AE state must be SEARCHING, CONVERGED, " +
935 "or FLASH_REQUIRED, is %s", StaticMetadata.AE_STATE_NAMES[aeState]),
936 aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING ||
937 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED ||
938 aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED);
939 }
940
941 private boolean verifyAfSequence(int afMode, int afState, boolean focusComplete) {
942 if (focusComplete) {
943 assertTrue(String.format("AF Mode %s: Focus lock lost after convergence: AF state: %s",
944 StaticMetadata.AF_MODE_NAMES[afMode],
945 StaticMetadata.AF_STATE_NAMES[afState]),
946 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
947 afState ==CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
948 return focusComplete;
949 }
950 if (VERBOSE) {
951 Log.v(TAG, String.format("AF mode: %s, AF state: %s",
952 StaticMetadata.AF_MODE_NAMES[afMode],
953 StaticMetadata.AF_STATE_NAMES[afState]));
954 }
955 switch (afMode) {
956 case CaptureResult.CONTROL_AF_MODE_AUTO:
957 case CaptureResult.CONTROL_AF_MODE_MACRO:
958 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
959 StaticMetadata.AF_MODE_NAMES[afMode],
960 StaticMetadata.AF_STATE_NAMES[afState]),
961 afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN ||
962 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
963 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
964 focusComplete =
965 (afState != CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN);
966 break;
967 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_PICTURE:
968 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
969 StaticMetadata.AF_MODE_NAMES[afMode],
970 StaticMetadata.AF_STATE_NAMES[afState]),
971 afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN ||
972 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
973 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
974 focusComplete =
975 (afState != CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN);
976 break;
977 case CaptureResult.CONTROL_AF_MODE_CONTINUOUS_VIDEO:
978 assertTrue(String.format("AF mode %s: Unexpected AF state %s",
979 StaticMetadata.AF_MODE_NAMES[afMode],
980 StaticMetadata.AF_STATE_NAMES[afState]),
981 afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
982 afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);
983 focusComplete = true;
984 break;
985 default:
986 fail("Unexpected AF mode: " + StaticMetadata.AF_MODE_NAMES[afMode]);
987 }
988 return focusComplete;
989 }
990
991 private boolean verifyAeSequence(int aeState, boolean precaptureComplete) {
992 if (precaptureComplete) {
993 assertTrue("Precapture state seen after convergence",
994 aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE);
995 return precaptureComplete;
996 }
997 if (VERBOSE) {
998 Log.v(TAG, String.format("AE state: %s", StaticMetadata.AE_STATE_NAMES[aeState]));
999 }
1000 switch (aeState) {
1001 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE:
1002 // scan still continuing
1003 break;
1004 case CaptureResult.CONTROL_AE_STATE_CONVERGED:
1005 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
1006 // completed
1007 precaptureComplete = true;
1008 break;
1009 default:
1010 fail(String.format("Precapture sequence transitioned to "
1011 + "state %s incorrectly!", StaticMetadata.AE_STATE_NAMES[aeState]));
1012 break;
1013 }
1014 return precaptureComplete;
1015 }
1016
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001017 /**
1018 * Sanity check the configuration tables.
1019 */
1020 private void sanityCheckConfigurationTables(final int[][][] tables) throws Exception {
1021 int tableIdx = 0;
1022 for (int[][] table : tables) {
1023 int rowIdx = 0;
1024 for (int[] row : table) {
1025 assertTrue(String.format("Odd number of entries for table %d row %d: %s ",
1026 tableIdx, rowIdx, Arrays.toString(row)),
1027 (row.length % 2) == 0);
1028 for (int i = 0; i < row.length; i += 2) {
1029 int format = row[i];
1030 int maxSize = row[i + 1];
1031 assertTrue(String.format("table %d row %d index %d format not valid: %d",
1032 tableIdx, rowIdx, i, format),
1033 format == PRIV || format == JPEG || format == YUV || format == RAW);
1034 assertTrue(String.format("table %d row %d index %d max size not valid: %d",
1035 tableIdx, rowIdx, i + 1, maxSize),
1036 maxSize == PREVIEW || maxSize == RECORD ||
1037 maxSize == MAXIMUM || maxSize == VGA);
1038 }
1039 rowIdx++;
1040 }
1041 tableIdx++;
1042 }
1043 }
1044
1045 /**
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001046 * Simple holder for resolutions to use for different camera outputs and size limits.
1047 */
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001048 static class MaxStreamSizes {
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001049 // Format shorthands
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001050 static final int PRIV = ImageFormat.PRIVATE;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001051 static final int JPEG = ImageFormat.JPEG;
1052 static final int YUV = ImageFormat.YUV_420_888;
1053 static final int RAW = ImageFormat.RAW_SENSOR;
1054
1055 // Max resolution indices
1056 static final int PREVIEW = 0;
1057 static final int RECORD = 1;
1058 static final int MAXIMUM = 2;
1059 static final int VGA = 3;
1060 static final int RESOLUTION_COUNT = 4;
1061
Yin-Chia Yeh7f2ecbd2015-07-10 09:39:13 -07001062 public MaxStreamSizes(StaticMetadata sm, String cameraId, Context context) {
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -07001063 Size[] privSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.PRIVATE,
1064 StaticMetadata.StreamDirection.Output);
1065 Size[] yuvSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
1066 StaticMetadata.StreamDirection.Output);
1067 Size[] jpegSizes = sm.getJpegOutputSizesChecked();
1068 Size[] rawSizes = sm.getRawOutputSizesChecked();
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001069
Deng Bingc34adcd2015-07-02 17:56:42 +08001070 Size maxPreviewSize = getMaxPreviewSize(context, cameraId);
1071
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -07001072 maxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001073
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -07001074 if (sm.isColorOutputSupported()) {
1075 maxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize);
1076 maxYuvSizes[PREVIEW] = getMaxSize(yuvSizes, maxPreviewSize);
1077 maxJpegSizes[PREVIEW] = getMaxSize(jpegSizes, maxPreviewSize);
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001078
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -07001079 maxPrivSizes[RECORD] = getMaxRecordingSize(cameraId);
1080 maxYuvSizes[RECORD] = getMaxRecordingSize(cameraId);
1081 maxJpegSizes[RECORD] = getMaxRecordingSize(cameraId);
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001082
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -07001083 maxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes);
1084 maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
1085 maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
1086
1087 // Must always be supported, add unconditionally
1088 final Size vgaSize = new Size(640, 480);
1089 maxPrivSizes[VGA] = vgaSize;
1090 maxYuvSizes[VGA] = vgaSize;
1091 maxJpegSizes[VGA] = vgaSize;
1092 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001093
Eino-Ville Talvalafc71fad2015-06-18 18:07:07 -07001094 StreamConfigurationMap configs = sm.getCharacteristics().get(
1095 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Eino-Ville Talvala6c2ebb42015-06-23 11:54:31 -07001096 Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
1097 maxInputPrivSize = privInputSizes != null ?
1098 CameraTestUtils.getMaxSize(privInputSizes) : null;
1099 Size[] yuvInputSizes = configs.getInputSizes(ImageFormat.YUV_420_888);
1100 maxInputYuvSize = yuvInputSizes != null ?
1101 CameraTestUtils.getMaxSize(yuvInputSizes) : null;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001102
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001103 }
1104
1105 public final Size[] maxPrivSizes = new Size[RESOLUTION_COUNT];
1106 public final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
1107 public final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
1108 public final Size maxRawSize;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001109 // TODO: support non maximum reprocess input.
1110 public final Size maxInputPrivSize;
1111 public final Size maxInputYuvSize;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001112
1113 static public String configToString(int[] config) {
1114 StringBuilder b = new StringBuilder("{ ");
1115 for (int i = 0; i < config.length; i += 2) {
1116 int format = config[i];
1117 int sizeLimit = config[i + 1];
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001118
1119 appendFormatSize(b, format, sizeLimit);
1120 b.append(" ");
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001121 }
1122 b.append("}");
1123 return b.toString();
1124 }
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001125
1126 static public String reprocessConfigToString(int[] reprocessConfig) {
1127 // reprocessConfig[0..1] is the input configuration
1128 StringBuilder b = new StringBuilder("Input: ");
1129 appendFormatSize(b, reprocessConfig[0], reprocessConfig[1]);
1130
1131 // reprocessConfig[0..1] is also output configuration to be captured as reprocess input.
1132 b.append(", Outputs: { ");
1133 for (int i = 0; i < reprocessConfig.length; i += 2) {
1134 int format = reprocessConfig[i];
1135 int sizeLimit = reprocessConfig[i + 1];
1136
1137 appendFormatSize(b, format, sizeLimit);
1138 b.append(" ");
1139 }
1140 b.append("}");
1141 return b.toString();
1142 }
1143
1144 static private void appendFormatSize(StringBuilder b, int format, int Size) {
1145 switch (format) {
1146 case PRIV:
1147 b.append("[PRIV, ");
1148 break;
1149 case JPEG:
1150 b.append("[JPEG, ");
1151 break;
1152 case YUV:
1153 b.append("[YUV, ");
1154 break;
1155 case RAW:
1156 b.append("[RAW, ");
1157 break;
1158 default:
1159 b.append("[UNK, ");
1160 break;
1161 }
1162
1163 switch (Size) {
1164 case PREVIEW:
1165 b.append("PREVIEW]");
1166 break;
1167 case RECORD:
1168 b.append("RECORD]");
1169 break;
1170 case MAXIMUM:
1171 b.append("MAXIMUM]");
1172 break;
1173 case VGA:
1174 b.append("VGA]");
1175 break;
1176 default:
1177 b.append("UNK]");
1178 break;
1179 }
1180 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001181 }
1182
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001183 /**
1184 * Return an InputConfiguration for a given reprocess configuration.
1185 */
1186 private InputConfiguration getInputConfig(int[] reprocessConfig, MaxStreamSizes maxSizes) {
1187 int format;
1188 Size size;
1189
1190 if (reprocessConfig[1] != MAXIMUM) {
1191 throw new IllegalArgumentException("Test only supports MAXIMUM input");
1192 }
1193
1194 switch (reprocessConfig[0]) {
1195 case PRIV:
1196 format = ImageFormat.PRIVATE;
1197 size = maxSizes.maxInputPrivSize;
1198 break;
1199 case YUV:
1200 format = ImageFormat.YUV_420_888;
1201 size = maxSizes.maxInputYuvSize;
1202 break;
1203 default:
1204 throw new IllegalArgumentException("Input format not supported: " +
1205 reprocessConfig[0]);
1206 }
1207
1208 return new InputConfiguration(size.getWidth(), size.getHeight(), format);
1209 }
1210
1211 private void testReprocessStreamCombination(String cameraId, int[] reprocessConfig,
1212 MaxStreamSizes maxSizes, StaticMetadata staticInfo) throws Exception {
1213
1214 Log.i(TAG, String.format("Testing Camera %s, reprocess config: %s", cameraId,
1215 MaxStreamSizes.reprocessConfigToString(reprocessConfig)));
1216
1217 final int TIMEOUT_FOR_RESULT_MS = 3000;
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001218 final int NUM_REPROCESS_CAPTURES_PER_CONFIG = 3;
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001219
1220 List<SurfaceTexture> privTargets = new ArrayList<>();
1221 List<ImageReader> jpegTargets = new ArrayList<>();
1222 List<ImageReader> yuvTargets = new ArrayList<>();
1223 List<ImageReader> rawTargets = new ArrayList<>();
1224 List<Surface> outputSurfaces = new ArrayList<>();
1225 ImageReader inputReader = null;
1226 ImageWriter inputWriter = null;
1227 SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener();
1228 SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback();
1229 SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback();
1230
1231 boolean supportYuvReprocess = staticInfo.isCapabilitySupported(
1232 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
1233 boolean supportOpaqueReprocess = staticInfo.isCapabilitySupported(
1234 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
1235
Eino-Ville Talvala6c2ebb42015-06-23 11:54:31 -07001236 // Skip the configuration if the format is not supported for reprocessing.
1237 if ((reprocessConfig[0] == YUV && !supportYuvReprocess) ||
1238 (reprocessConfig[0] == PRIV && !supportOpaqueReprocess)) {
1239 return;
1240 }
1241
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001242 try {
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001243 // reprocessConfig[2..] are additional outputs
1244 setupConfigurationTargets(
1245 Arrays.copyOfRange(reprocessConfig, 2, reprocessConfig.length),
1246 maxSizes, privTargets, jpegTargets, yuvTargets, rawTargets, outputSurfaces,
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001247 NUM_REPROCESS_CAPTURES_PER_CONFIG);
1248
1249 // reprocessConfig[0:1] is input
1250 InputConfiguration inputConfig = getInputConfig(
1251 Arrays.copyOfRange(reprocessConfig, 0, 2), maxSizes);
1252
1253 // For each config, YUV and JPEG outputs will be tested. (For YUV reprocessing,
1254 // the YUV ImageReader for input is also used for output.)
1255 final int totalNumReprocessCaptures = NUM_REPROCESS_CAPTURES_PER_CONFIG * (
1256 (inputConfig.getFormat() == ImageFormat.YUV_420_888 ? 1 : 0) +
1257 jpegTargets.size() + yuvTargets.size());
1258
1259 // It needs 1 input buffer for each reprocess capture + the number of buffers
1260 // that will be used as outputs.
1261 inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(),
1262 inputConfig.getFormat(),
1263 totalNumReprocessCaptures + NUM_REPROCESS_CAPTURES_PER_CONFIG);
1264 inputReader.setOnImageAvailableListener(inputReaderListener, mHandler);
1265 outputSurfaces.add(inputReader.getSurface());
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001266
1267 // Verify we can create a reprocessable session with the input and all outputs.
1268 BlockingSessionCallback sessionListener = new BlockingSessionCallback();
1269 CameraCaptureSession session = configureReprocessableCameraSession(mCamera,
1270 inputConfig, outputSurfaces, sessionListener, mHandler);
1271 inputWriter = ImageWriter.newInstance(session.getInputSurface(),
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001272 totalNumReprocessCaptures);
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001273
1274 // Prepare a request for reprocess input
1275 CaptureRequest.Builder builder = mCamera.createCaptureRequest(
1276 CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
1277 builder.addTarget(inputReader.getSurface());
1278
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001279 for (int i = 0; i < totalNumReprocessCaptures; i++) {
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001280 session.capture(builder.build(), inputCaptureListener, mHandler);
1281 }
1282
1283 List<CaptureRequest> reprocessRequests = new ArrayList<>();
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001284 List<Surface> reprocessOutputs = new ArrayList<>();
1285 if (inputConfig.getFormat() == ImageFormat.YUV_420_888) {
1286 reprocessOutputs.add(inputReader.getSurface());
1287 }
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001288
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001289 for (ImageReader reader : jpegTargets) {
1290 reprocessOutputs.add(reader.getSurface());
1291 }
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001292
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001293 for (ImageReader reader : yuvTargets) {
1294 reprocessOutputs.add(reader.getSurface());
1295 }
1296
1297 for (int i = 0; i < NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
1298 for (Surface output : reprocessOutputs) {
1299 TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult(
1300 TIMEOUT_FOR_RESULT_MS);
1301 builder = mCamera.createReprocessCaptureRequest(result);
1302 inputWriter.queueInputImage(
1303 inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS));
1304 builder.addTarget(output);
1305 reprocessRequests.add(builder.build());
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001306 }
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001307 }
1308
1309 session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler);
1310
Chien-Yu Chenc0cfb9d2015-08-24 12:14:01 -07001311 for (int i = 0; i < reprocessOutputs.size() * NUM_REPROCESS_CAPTURES_PER_CONFIG; i++) {
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001312 TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult(
1313 TIMEOUT_FOR_RESULT_MS);
1314 }
1315 } catch (Throwable e) {
1316 mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s",
1317 MaxStreamSizes.reprocessConfigToString(reprocessConfig), e.getMessage()));
1318 } finally {
1319 inputReaderListener.drain();
1320 reprocessOutputCaptureListener.drain();
1321
1322 for (SurfaceTexture target : privTargets) {
1323 target.release();
1324 }
1325
1326 for (ImageReader target : jpegTargets) {
1327 target.close();
1328 }
1329
1330 for (ImageReader target : yuvTargets) {
1331 target.close();
1332 }
1333
1334 for (ImageReader target : rawTargets) {
1335 target.close();
1336 }
1337
1338 if (inputReader != null) {
1339 inputReader.close();
1340 }
1341
1342 if (inputWriter != null) {
1343 inputWriter.close();
1344 }
1345 }
1346 }
1347
1348 private void testOutputCombination(String cameraId, int[] config, MaxStreamSizes maxSizes)
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001349 throws Exception {
1350
1351 Log.i(TAG, String.format("Testing Camera %s, config %s",
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001352 cameraId, MaxStreamSizes.configToString(config)));
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001353
Yin-Chia Yeh97807382015-09-18 16:31:37 -07001354 // Timeout is relaxed by 1 second for LEGACY devices to reduce false positive rate in CTS
1355 final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 2000 : 1000;
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001356 final int MIN_RESULT_COUNT = 3;
1357
1358 // Set up outputs
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001359 List<Surface> outputSurfaces = new ArrayList<Surface>();
Zhijun He5c13c122014-09-22 12:10:15 -07001360 List<SurfaceTexture> privTargets = new ArrayList<SurfaceTexture>();
1361 List<ImageReader> jpegTargets = new ArrayList<ImageReader>();
1362 List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
1363 List<ImageReader> rawTargets = new ArrayList<ImageReader>();
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001364
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001365 setupConfigurationTargets(config, maxSizes, privTargets, jpegTargets, yuvTargets,
1366 rawTargets, outputSurfaces, MIN_RESULT_COUNT);
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001367
1368 boolean haveSession = false;
1369 try {
1370 CaptureRequest.Builder requestBuilder =
1371 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1372
1373 for (Surface s : outputSurfaces) {
1374 requestBuilder.addTarget(s);
1375 }
1376
1377 CameraCaptureSession.CaptureCallback mockCaptureCallback =
1378 mock(CameraCaptureSession.CaptureCallback.class);
1379
1380 createSession(outputSurfaces);
1381 haveSession = true;
1382 CaptureRequest request = requestBuilder.build();
1383 mCameraSession.setRepeatingRequest(request, mockCaptureCallback, mHandler);
1384
1385 verify(mockCaptureCallback,
1386 timeout(TIMEOUT_FOR_RESULT_MS * MIN_RESULT_COUNT).atLeast(MIN_RESULT_COUNT))
1387 .onCaptureCompleted(
1388 eq(mCameraSession),
1389 eq(request),
1390 isA(TotalCaptureResult.class));
1391 verify(mockCaptureCallback, never()).
1392 onCaptureFailed(
1393 eq(mCameraSession),
1394 eq(request),
1395 isA(CaptureFailure.class));
1396
1397 } catch (Throwable e) {
1398 mCollector.addMessage(String.format("Output combination %s failed due to: %s",
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001399 MaxStreamSizes.configToString(config), e.getMessage()));
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001400 }
1401 if (haveSession) {
1402 try {
1403 Log.i(TAG, String.format("Done with camera %s, config %s, closing session",
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001404 cameraId, MaxStreamSizes.configToString(config)));
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001405 stopCapture(/*fast*/false);
1406 } catch (Throwable e) {
1407 mCollector.addMessage(
1408 String.format("Closing down for output combination %s failed due to: %s",
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001409 MaxStreamSizes.configToString(config), e.getMessage()));
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001410 }
1411 }
Zhijun He5c13c122014-09-22 12:10:15 -07001412
1413 for (SurfaceTexture target : privTargets) {
1414 target.release();
1415 }
1416 for (ImageReader target : jpegTargets) {
1417 target.close();
1418 }
1419 for (ImageReader target : yuvTargets) {
1420 target.close();
1421 }
1422 for (ImageReader target : rawTargets) {
1423 target.close();
1424 }
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001425 }
1426
Chien-Yu Chen33f60d42015-06-16 17:05:11 -07001427 private void setupConfigurationTargets(int[] outputConfigs, MaxStreamSizes maxSizes,
1428 List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
1429 List<ImageReader> yuvTargets, List<ImageReader> rawTargets,
1430 List<Surface> outputSurfaces, int numBuffers) {
1431
1432 ImageDropperListener imageDropperListener = new ImageDropperListener();
1433
1434 for (int i = 0; i < outputConfigs.length; i += 2) {
1435 int format = outputConfigs[i];
1436 int sizeLimit = outputConfigs[i + 1];
1437
1438 switch (format) {
1439 case PRIV: {
1440 Size targetSize = maxSizes.maxPrivSizes[sizeLimit];
1441 SurfaceTexture target = new SurfaceTexture(/*random int*/1);
1442 target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight());
1443 outputSurfaces.add(new Surface(target));
1444 privTargets.add(target);
1445 break;
1446 }
1447 case JPEG: {
1448 Size targetSize = maxSizes.maxJpegSizes[sizeLimit];
1449 ImageReader target = ImageReader.newInstance(
1450 targetSize.getWidth(), targetSize.getHeight(), JPEG, numBuffers);
1451 target.setOnImageAvailableListener(imageDropperListener, mHandler);
1452 outputSurfaces.add(target.getSurface());
1453 jpegTargets.add(target);
1454 break;
1455 }
1456 case YUV: {
1457 Size targetSize = maxSizes.maxYuvSizes[sizeLimit];
1458 ImageReader target = ImageReader.newInstance(
1459 targetSize.getWidth(), targetSize.getHeight(), YUV, numBuffers);
1460 target.setOnImageAvailableListener(imageDropperListener, mHandler);
1461 outputSurfaces.add(target.getSurface());
1462 yuvTargets.add(target);
1463 break;
1464 }
1465 case RAW: {
1466 Size targetSize = maxSizes.maxRawSize;
1467 ImageReader target = ImageReader.newInstance(
1468 targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
1469 target.setOnImageAvailableListener(imageDropperListener, mHandler);
1470 outputSurfaces.add(target.getSurface());
1471 rawTargets.add(target);
1472 break;
1473 }
1474 default:
1475 fail("Unknown output format " + format);
1476 }
1477 }
1478 }
1479
Eino-Ville Talvala306cf4a2014-09-03 18:07:33 -07001480 private static Size getMaxRecordingSize(String cameraId) {
1481 int id = Integer.valueOf(cameraId);
1482
1483 int quality =
1484 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_2160P) ?
1485 CamcorderProfile.QUALITY_2160P :
1486 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_1080P) ?
1487 CamcorderProfile.QUALITY_1080P :
1488 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_720P) ?
1489 CamcorderProfile.QUALITY_720P :
1490 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_480P) ?
1491 CamcorderProfile.QUALITY_480P :
1492 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QVGA) ?
1493 CamcorderProfile.QUALITY_QVGA :
1494 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_CIF) ?
1495 CamcorderProfile.QUALITY_CIF :
1496 CamcorderProfile.hasProfile(id, CamcorderProfile.QUALITY_QCIF) ?
1497 CamcorderProfile.QUALITY_QCIF :
1498 -1;
1499
1500 assertTrue("No recording supported for camera id " + cameraId, quality != -1);
1501
1502 CamcorderProfile maxProfile = CamcorderProfile.get(id, quality);
1503 return new Size(maxProfile.videoFrameWidth, maxProfile.videoFrameHeight);
1504 }
1505
1506 /**
1507 * Get maximum size in list that's equal or smaller to than the bound.
1508 * Returns null if no size is smaller than or equal to the bound.
1509 */
1510 private static Size getMaxSize(Size[] sizes, Size bound) {
1511 if (sizes == null || sizes.length == 0) {
1512 throw new IllegalArgumentException("sizes was empty");
1513 }
1514
1515 Size sz = null;
1516 for (Size size : sizes) {
1517 if (size.getWidth() <= bound.getWidth() && size.getHeight() <= bound.getHeight()) {
1518
1519 if (sz == null) {
1520 sz = size;
1521 } else {
1522 long curArea = sz.getWidth() * (long) sz.getHeight();
1523 long newArea = size.getWidth() * (long) size.getHeight();
1524 if ( newArea > curArea ) {
1525 sz = size;
1526 }
1527 }
1528 }
1529 }
1530
1531 assertTrue("No size under bound found: " + Arrays.toString(sizes) + " bound " + bound,
1532 sz != null);
1533
1534 return sz;
1535 }
1536
Deng Bingc34adcd2015-07-02 17:56:42 +08001537 private static Size getMaxPreviewSize(Context context, String cameraId) {
1538 try {
1539 WindowManager windowManager =
1540 (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
1541 Display display = windowManager.getDefaultDisplay();
1542
1543 int width = display.getWidth();
1544 int height = display.getHeight();
1545
1546 if (height > width) {
1547 height = width;
1548 width = display.getHeight();
1549 }
1550
1551 CameraManager camMgr =
1552 (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
1553 List<Size> orderedPreviewSizes = CameraTestUtils.getSupportedPreviewSizes(
1554 cameraId, camMgr, PREVIEW_SIZE_BOUND);
1555
1556 if (orderedPreviewSizes != null) {
1557 for (Size size : orderedPreviewSizes) {
1558 if (width >= size.getWidth() &&
1559 height >= size.getHeight())
1560 return size;
1561 }
1562 }
1563 } catch (Exception e) {
1564 Log.e(TAG, "getMaxPreviewSize Failed. "+e.toString());
1565 }
1566 return PREVIEW_SIZE_BOUND;
1567 }
Ruben Brunkc467f592014-08-19 16:37:50 -07001568}