blob: 9e75d948579f9e1c0d719c947a0a128fa18a24a8 [file] [log] [blame]
Zhijun He28f2b3e2014-02-26 14:15:18 -08001/*
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
19import static android.hardware.camera2.cts.CameraTestUtils.*;
Zhijun He5f4d0082014-03-19 23:02:03 -070020import static android.hardware.camera2.CameraCharacteristics.*;
Zhijun He28f2b3e2014-02-26 14:15:18 -080021
Zhijun He984ff7e2014-03-30 12:40:27 -070022import android.graphics.Point;
Zhijun Hedba6dd12014-04-29 18:41:49 -070023import android.graphics.PointF;
Zhijun He984ff7e2014-03-30 12:40:27 -070024import android.graphics.Rect;
Zhijun Hef2d26f12014-04-14 10:36:55 -070025import android.hardware.camera2.CameraCharacteristics;
Zhijun He28f2b3e2014-02-26 14:15:18 -080026import android.hardware.camera2.CameraDevice;
Zhijun He76a03012014-05-06 17:01:30 -070027import android.hardware.camera2.CameraMetadata;
Zhijun He28f2b3e2014-02-26 14:15:18 -080028import android.hardware.camera2.CaptureRequest;
29import android.hardware.camera2.CaptureResult;
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -070030import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
Zhijun He21c00db2014-03-03 08:10:26 -080031import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -070032import android.hardware.camera2.params.ColorSpaceTransform;
Ruben Brunka47c85a2014-05-27 18:56:57 -070033import android.hardware.camera2.params.Face;
34import android.hardware.camera2.params.LensShadingMap;
35import android.hardware.camera2.params.MeteringRectangle;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -070036import android.hardware.camera2.params.RggbChannelVector;
Yin-Chia Yehbb247572014-05-27 10:20:54 -070037import android.hardware.camera2.params.TonemapCurve;
Ruben Brunka47c85a2014-05-27 18:56:57 -070038
Zhijun He28f2b3e2014-02-26 14:15:18 -080039import android.util.Log;
Igor Murashkina6e6d532014-05-27 18:31:34 -070040import android.util.Range;
Igor Murashkind5a33df2014-05-14 17:01:09 -070041import android.util.Rational;
42import android.util.Size;
Zhijun He28f2b3e2014-02-26 14:15:18 -080043
Zhijun He984ff7e2014-03-30 12:40:27 -070044import java.util.ArrayList;
Zhijun He4b87bed2014-03-03 16:44:48 -080045import java.util.Arrays;
Zhijun He984ff7e2014-03-30 12:40:27 -070046import java.util.List;
Zhijun He4b87bed2014-03-03 16:44:48 -080047
Zhijun He28f2b3e2014-02-26 14:15:18 -080048/**
49 * <p>
50 * Basic test for camera CaptureRequest key controls.
51 * </p>
52 * <p>
53 * Several test categories are covered: manual sensor control, 3A control,
54 * manual ISP control and other per-frame control and synchronization.
55 * </p>
56 */
Zhijun He21c00db2014-03-03 08:10:26 -080057public class CaptureRequestTest extends Camera2SurfaceViewTestCase {
Zhijun He28f2b3e2014-02-26 14:15:18 -080058 private static final String TAG = "CaptureRequestTest";
59 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
60 private static final int NUM_FRAMES_VERIFIED = 15;
Zhijun He984ff7e2014-03-30 12:40:27 -070061 private static final int NUM_FACE_DETECTION_FRAMES_VERIFIED = 60;
Zhijun He5f4d0082014-03-19 23:02:03 -070062 /** 30ms exposure time must be supported by full capability devices. */
63 private static final long DEFAULT_EXP_TIME_NS = 30000000L;
64 private static final int DEFAULT_SENSITIVITY = 100;
Zhijun He4b87bed2014-03-03 16:44:48 -080065 private static final int RGGB_COLOR_CHANNEL_COUNT = 4;
66 private static final int MAX_SHADING_MAP_SIZE = 64 * 64 * RGGB_COLOR_CHANNEL_COUNT;
67 private static final int MIN_SHADING_MAP_SIZE = 1 * 1 * RGGB_COLOR_CHANNEL_COUNT;
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -070068 private static final long IGNORE_REQUESTED_EXPOSURE_TIME_CHECK = -1L;
Zhijun He5f4d0082014-03-19 23:02:03 -070069 private static final long EXPOSURE_TIME_BOUNDARY_50HZ_NS = 10000000L; // 10ms
Zhijun He7e80fe92014-04-24 15:46:41 -070070 private static final long EXPOSURE_TIME_BOUNDARY_60HZ_NS = 8333333L; // 8.3ms, Approximation.
Zhijun He5f4d0082014-03-19 23:02:03 -070071 private static final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000L; // 100us, Approximation.
Zhijun He8c8fb1e2014-03-20 14:57:48 -070072 private static final int SENSITIVITY_ERROR_MARGIN = 10; // 10
Zhijun He984ff7e2014-03-30 12:40:27 -070073 private static final int DEFAULT_NUM_EXPOSURE_TIME_STEPS = 3;
Zhijun He8c8fb1e2014-03-20 14:57:48 -070074 private static final int DEFAULT_NUM_SENSITIVITY_STEPS = 16;
75 private static final int DEFAULT_SENSITIVITY_STEP_SIZE = 100;
Zhijun Heed9cd312014-03-24 23:15:52 -070076 private static final int NUM_RESULTS_WAIT_TIMEOUT = 100;
Igor Murashkin9662a562014-07-07 14:30:49 -070077 private static final int NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY = 8;
Zhijun Hef2d26f12014-04-14 10:36:55 -070078 private static final int NUM_TEST_FOCUS_DISTANCES = 10;
Zhijun He76a03012014-05-06 17:01:30 -070079 // 5 percent error margin for calibrated device
80 private static final float FOCUS_DISTANCE_ERROR_PERCENT_CALIBRATED = 0.05f;
81 // 25 percent error margin for uncalibrated device
82 private static final float FOCUS_DISTANCE_ERROR_PERCENT_UNCALIBRATED = 0.25f;
83 // 10 percent error margin for approximate device
84 private static final float FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE = 0.10f;
Zhijun He7e80fe92014-04-24 15:46:41 -070085 private static final int ANTI_FLICKERING_50HZ = 1;
86 private static final int ANTI_FLICKERING_60HZ = 2;
Zhijun Hef2d26f12014-04-14 10:36:55 -070087
Igor Murashkin9662a562014-07-07 14:30:49 -070088 // 5 percent error margin for resulting crop regions
89 private static final float CROP_REGION_ERROR_PERCENT_DELTA = 0.05f;
90 // 1 percent error margin for centering the crop region
91 private static final float CROP_REGION_ERROR_PERCENT_CENTERED = 0.01f;
92
Zhijun He984ff7e2014-03-30 12:40:27 -070093 // Linear tone mapping curve example.
94 private static final float[] TONEMAP_CURVE_LINEAR = {0, 0, 1.0f, 1.0f};
95 // Standard sRGB tone mapping, per IEC 61966-2-1:1999, with 16 control points.
96 private static final float[] TONEMAP_CURVE_SRGB = {
97 0.0000f, 0.0000f, 0.0667f, 0.2864f, 0.1333f, 0.4007f, 0.2000f, 0.4845f,
98 0.2667f, 0.5532f, 0.3333f, 0.6125f, 0.4000f, 0.6652f, 0.4667f, 0.7130f,
99 0.5333f, 0.7569f, 0.6000f, 0.7977f, 0.6667f, 0.8360f, 0.7333f, 0.8721f,
100 0.8000f, 0.9063f, 0.8667f, 0.9389f, 0.9333f, 0.9701f, 1.0000f, 1.0000f
101 };
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700102 private final Rational ZERO_R = new Rational(0, 1);
103 private final Rational ONE_R = new Rational(1, 1);
Zhijun He28f2b3e2014-02-26 14:15:18 -0800104
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -0700105 private final int NUM_ALGORITHMS = 3; // AE, AWB and AF
106 private final int INDEX_ALGORITHM_AE = 0;
107 private final int INDEX_ALGORITHM_AWB = 1;
108 private final int INDEX_ALGORITHM_AF = 2;
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -0700109
Yin-Chia Yeh72997f82015-08-29 15:48:06 -0700110 private enum TorchSeqState {
111 RAMPING_UP,
112 FIRED,
113 RAMPING_DOWN
114 }
115
Zhijun He28f2b3e2014-02-26 14:15:18 -0800116 @Override
117 protected void setUp() throws Exception {
118 super.setUp();
Zhijun He28f2b3e2014-02-26 14:15:18 -0800119 }
120
121 @Override
122 protected void tearDown() throws Exception {
Zhijun He28f2b3e2014-02-26 14:15:18 -0800123 super.tearDown();
124 }
125
Zhijun He4b87bed2014-03-03 16:44:48 -0800126 /**
127 * Test black level lock when exposure value change.
128 * <p>
129 * When {@link CaptureRequest#BLACK_LEVEL_LOCK} is true in a request, the
130 * camera device should lock the black level. When the exposure values are changed,
131 * the camera may require reset black level Since changes to certain capture
132 * parameters (such as exposure time) may require resetting of black level
133 * compensation. However, the black level must remain locked after exposure
134 * value changes (when requests have lock ON).
135 * </p>
136 */
Zhijun He28f2b3e2014-02-26 14:15:18 -0800137 public void testBlackLevelLock() throws Exception {
138 for (int i = 0; i < mCameraIds.length; i++) {
139 try {
140 openDevice(mCameraIds[i]);
141
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700142 if (!mStaticInfo.isCapabilitySupported(
143 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
Zhijun He28f2b3e2014-02-26 14:15:18 -0800144 continue;
145 }
146
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700147 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He28f2b3e2014-02-26 14:15:18 -0800148 CaptureRequest.Builder requestBuilder =
149 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
150
151 // Start with default manual exposure time, with black level being locked.
152 requestBuilder.set(CaptureRequest.BLACK_LEVEL_LOCK, true);
153 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS, DEFAULT_SENSITIVITY);
154
Zhijun He21c00db2014-03-03 08:10:26 -0800155 Size previewSz =
Ayden Cheng76a33ba2015-07-15 13:14:17 +0800156 getMaxPreviewSize(mCamera.getId(), mCameraManager,
157 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
Zhijun He28f2b3e2014-02-26 14:15:18 -0800158
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700159 startPreview(requestBuilder, previewSz, listener);
160 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He28f2b3e2014-02-26 14:15:18 -0800161 // No lock OFF state is allowed as the exposure is not changed.
162 verifyBlackLevelLockResults(listener, NUM_FRAMES_VERIFIED, /*maxLockOffCnt*/0);
163
Zhijun He21c00db2014-03-03 08:10:26 -0800164 // Double the exposure time and gain, with black level still being locked.
Zhijun He28f2b3e2014-02-26 14:15:18 -0800165 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS * 2, DEFAULT_SENSITIVITY * 2);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700166 listener = new SimpleCaptureCallback();
Zhijun He21c00db2014-03-03 08:10:26 -0800167 startPreview(requestBuilder, previewSz, listener);
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700168 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He28f2b3e2014-02-26 14:15:18 -0800169 // Allow at most one lock OFF state as the exposure is changed once.
170 verifyBlackLevelLockResults(listener, NUM_FRAMES_VERIFIED, /*maxLockOffCnt*/1);
171
172 stopPreview();
173 } finally {
174 closeDevice();
175 }
Zhijun He4b87bed2014-03-03 16:44:48 -0800176 }
177 }
Zhijun He28f2b3e2014-02-26 14:15:18 -0800178
Zhijun He4b87bed2014-03-03 16:44:48 -0800179 /**
180 * Basic lens shading map request test.
181 * <p>
182 * When {@link CaptureRequest#SHADING_MODE} is set to OFF, no lens shading correction will
183 * be applied by the camera device, and an identity lens shading map data
184 * will be provided if {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE} is ON.
185 * </p>
186 * <p>
187 * When {@link CaptureRequest#SHADING_MODE} is set to other modes, lens shading correction
188 * will be applied by the camera device. The lens shading map data can be
189 * requested by setting {@link CaptureRequest#STATISTICS_LENS_SHADING_MAP_MODE} to ON.
190 * </p>
191 */
192 public void testLensShadingMap() throws Exception {
193 for (int i = 0; i < mCameraIds.length; i++) {
194 try {
195 openDevice(mCameraIds[i]);
196
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700197 if (!mStaticInfo.isManualLensShadingMapSupported()) {
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700198 Log.i(TAG, "Camera " + mCameraIds[i] +
199 " doesn't support lens shading controls, skipping test");
200 continue;
201 }
202
203 List<Integer> lensShadingMapModes = Arrays.asList(CameraTestUtils.toObject(
204 mStaticInfo.getAvailableLensShadingMapModesChecked()));
205
206 if (!lensShadingMapModes.contains(STATISTICS_LENS_SHADING_MAP_MODE_ON)) {
Zhijun He4b87bed2014-03-03 16:44:48 -0800207 continue;
208 }
209
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700210 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He4b87bed2014-03-03 16:44:48 -0800211 CaptureRequest.Builder requestBuilder =
212 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Zhijun He4b87bed2014-03-03 16:44:48 -0800213 requestBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
214 STATISTICS_LENS_SHADING_MAP_MODE_ON);
215
Zhijun He4b87bed2014-03-03 16:44:48 -0800216 Size previewSz =
Ayden Cheng76a33ba2015-07-15 13:14:17 +0800217 getMaxPreviewSize(mCamera.getId(), mCameraManager,
218 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700219 List<Integer> lensShadingModes = Arrays.asList(CameraTestUtils.toObject(
220 mStaticInfo.getAvailableLensShadingModesChecked()));
Zhijun He4b87bed2014-03-03 16:44:48 -0800221
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700222 // Shading map mode OFF, lensShadingMapMode ON, camera device
223 // should output unity maps.
224 if (lensShadingModes.contains(SHADING_MODE_OFF)) {
225 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_OFF);
226 listener = new SimpleCaptureCallback();
227 startPreview(requestBuilder, previewSz, listener);
228 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
229 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_OFF);
230 }
Zhijun He4b87bed2014-03-03 16:44:48 -0800231
232 // Shading map mode FAST, lensShadingMapMode ON, camera device
233 // should output valid maps.
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700234 if (lensShadingModes.contains(SHADING_MODE_FAST)) {
235 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_FAST);
Zhijun He4b87bed2014-03-03 16:44:48 -0800236
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700237 listener = new SimpleCaptureCallback();
238 startPreview(requestBuilder, previewSz, listener);
239 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
240 // Allow at most one lock OFF state as the exposure is changed once.
241 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_FAST);
242 }
Zhijun He4b87bed2014-03-03 16:44:48 -0800243
244 // Shading map mode HIGH_QUALITY, lensShadingMapMode ON, camera device
245 // should output valid maps.
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700246 if (lensShadingModes.contains(SHADING_MODE_HIGH_QUALITY)) {
247 requestBuilder.set(CaptureRequest.SHADING_MODE, SHADING_MODE_HIGH_QUALITY);
Zhijun He4b87bed2014-03-03 16:44:48 -0800248
Yin-Chia Yehdde30522015-05-26 11:58:39 -0700249 listener = new SimpleCaptureCallback();
250 startPreview(requestBuilder, previewSz, listener);
251 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
252 verifyShadingMap(listener, NUM_FRAMES_VERIFIED, SHADING_MODE_HIGH_QUALITY);
253 }
Zhijun He4b87bed2014-03-03 16:44:48 -0800254
255 stopPreview();
256 } finally {
257 closeDevice();
258 }
Zhijun He28f2b3e2014-02-26 14:15:18 -0800259 }
260 }
261
Zhijun He5f4d0082014-03-19 23:02:03 -0700262 /**
263 * Test {@link CaptureRequest#CONTROL_AE_ANTIBANDING_MODE} control.
264 * <p>
265 * Test all available anti-banding modes, check if the exposure time adjustment is
266 * correct.
267 * </p>
268 */
269 public void testAntiBandingModes() throws Exception {
270 for (int i = 0; i < mCameraIds.length; i++) {
271 try {
272 openDevice(mCameraIds[i]);
273
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700274 // Without manual sensor control, exposure time cannot be verified
275 if (!mStaticInfo.isCapabilitySupported(
276 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700277 continue;
Zhijun He5f4d0082014-03-19 23:02:03 -0700278 }
279
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700280 int[] modes = mStaticInfo.getAeAvailableAntiBandingModesChecked();
Zhijun He5f4d0082014-03-19 23:02:03 -0700281
282 Size previewSz =
Ayden Cheng76a33ba2015-07-15 13:14:17 +0800283 getMaxPreviewSize(mCamera.getId(), mCameraManager,
284 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
Zhijun He5f4d0082014-03-19 23:02:03 -0700285
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700286 for (int mode : modes) {
Zhijun He7e80fe92014-04-24 15:46:41 -0700287 antiBandingTestByMode(previewSz, mode);
Zhijun He5f4d0082014-03-19 23:02:03 -0700288 }
289 } finally {
290 closeDevice();
291 }
292 }
293
294 }
295
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700296 /**
297 * Test AE mode and lock.
298 *
299 * <p>
300 * For AE lock, when it is locked, exposure parameters shouldn't be changed.
301 * For AE modes, each mode should satisfy the per frame controls defined in
302 * API specifications.
303 * </p>
304 */
305 public void testAeModeAndLock() throws Exception {
306 for (int i = 0; i < mCameraIds.length; i++) {
307 try {
308 openDevice(mCameraIds[i]);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700309 if (!mStaticInfo.isColorOutputSupported()) {
310 Log.i(TAG, "Camera " + mCameraIds[i] +
311 " does not support color outputs, skipping");
312 continue;
313 }
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700314
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700315 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
316
317 // Update preview surface with given size for all sub-tests.
318 updatePreviewSurface(maxPreviewSz);
319
320 // Test aeMode and lock
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700321 int[] aeModes = mStaticInfo.getAeAvailableModesChecked();
322 for (int mode : aeModes) {
Zhijun He8c8fb1e2014-03-20 14:57:48 -0700323 aeModeAndLockTestByMode(mode);
324 }
325 } finally {
326 closeDevice();
327 }
328 }
329 }
330
Zhijun Heed9cd312014-03-24 23:15:52 -0700331 /** Test {@link CaptureRequest#FLASH_MODE} control.
332 * <p>
333 * For each {@link CaptureRequest#FLASH_MODE} mode, test the flash control
334 * and {@link CaptureResult#FLASH_STATE} result.
335 * </p>
336 */
337 public void testFlashControl() throws Exception {
338 for (int i = 0; i < mCameraIds.length; i++) {
339 try {
340 openDevice(mCameraIds[i]);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700341 if (!mStaticInfo.isColorOutputSupported()) {
342 Log.i(TAG, "Camera " + mCameraIds[i] +
343 " does not support color outputs, skipping");
344 continue;
345 }
Zhijun Heed9cd312014-03-24 23:15:52 -0700346
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700347 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun Heed9cd312014-03-24 23:15:52 -0700348 CaptureRequest.Builder requestBuilder =
349 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
350
351 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
352
353 startPreview(requestBuilder, maxPreviewSz, listener);
354
355 // Flash control can only be used when the AE mode is ON or OFF.
356 flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_ON);
Igor Murashkine21060a2014-07-10 18:09:21 -0700357
358 // LEGACY won't support AE mode OFF
Yin-Chia Yehddc2a102014-11-12 12:05:22 -0800359 boolean aeOffModeSupported = false;
360 for (int aeMode : mStaticInfo.getAeAvailableModesChecked()) {
361 if (aeMode == CaptureRequest.CONTROL_AE_MODE_OFF) {
362 aeOffModeSupported = true;
363 }
364 }
365 if (aeOffModeSupported) {
Igor Murashkine21060a2014-07-10 18:09:21 -0700366 flashTestByAeMode(listener, CaptureRequest.CONTROL_AE_MODE_OFF);
367 }
Zhijun Heed9cd312014-03-24 23:15:52 -0700368
369 stopPreview();
370 } finally {
371 closeDevice();
372 }
373 }
374 }
375
Zhijun He984ff7e2014-03-30 12:40:27 -0700376 /**
377 * Test face detection modes and results.
378 */
379 public void testFaceDetection() throws Exception {
380 for (int i = 0; i < mCameraIds.length; i++) {
381 try {
382 openDevice(mCameraIds[i]);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700383 if (!mStaticInfo.isColorOutputSupported()) {
384 Log.i(TAG, "Camera " + mCameraIds[i] +
385 " does not support color outputs, skipping");
386 continue;
387 }
Zhijun He984ff7e2014-03-30 12:40:27 -0700388 faceDetectionTestByCamera();
389 } finally {
390 closeDevice();
391 }
392 }
393 }
394
395 /**
396 * Test tone map modes and controls.
397 */
398 public void testToneMapControl() throws Exception {
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700399 for (String id : mCameraIds) {
Zhijun He984ff7e2014-03-30 12:40:27 -0700400 try {
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700401 openDevice(id);
402 if (!mStaticInfo.isManualToneMapSupported()) {
403 Log.i(TAG, "Camera " + id +
404 " doesn't support tone mapping controls, skipping test");
405 continue;
406 }
Zhijun He984ff7e2014-03-30 12:40:27 -0700407 toneMapTestByCamera();
408 } finally {
409 closeDevice();
410 }
411 }
412 }
413
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700414 /**
415 * Test color correction modes and controls.
416 */
417 public void testColorCorrectionControl() throws Exception {
418 for (String id : mCameraIds) {
419 try {
420 openDevice(id);
Zhijun He255d4c82015-05-04 16:11:48 -0700421 if (!mStaticInfo.isColorCorrectionSupported()) {
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700422 Log.i(TAG, "Camera " + id +
423 " doesn't support color correction controls, skipping test");
424 continue;
425 }
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700426 colorCorrectionTestByCamera();
427 } finally {
428 closeDevice();
429 }
430 }
431 }
432
Zhijun Hefd84d852014-04-13 23:11:15 -0700433 public void testEdgeModeControl() throws Exception {
434 for (String id : mCameraIds) {
435 try {
436 openDevice(id);
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700437 if (!mStaticInfo.isEdgeModeControlSupported()) {
438 Log.i(TAG, "Camera " + id +
439 " doesn't support EDGE_MODE controls, skipping test");
Zhijun Hefd84d852014-04-13 23:11:15 -0700440 continue;
441 }
442
443 edgeModesTestByCamera();
444 } finally {
445 closeDevice();
446 }
447 }
448 }
449
Zhijun Hef2d26f12014-04-14 10:36:55 -0700450 /**
451 * Test focus distance control.
452 */
453 public void testFocusDistanceControl() throws Exception {
454 for (String id : mCameraIds) {
455 try {
456 openDevice(id);
Ruben Brunk88470e42014-07-23 15:55:14 -0700457 if (!mStaticInfo.hasFocuser()) {
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700458 Log.i(TAG, "Camera " + id + " has no focuser, skipping test");
Zhijun Hef2d26f12014-04-14 10:36:55 -0700459 continue;
460 }
461
Yin-Chia Yehb54b95c2014-09-21 15:16:07 -0700462 if (!mStaticInfo.isCapabilitySupported(
463 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
464 Log.i(TAG, "Camera " + id +
465 " does not support MANUAL_SENSOR, skipping test");
466 continue;
467 }
468
Zhijun Hef2d26f12014-04-14 10:36:55 -0700469 focusDistanceTestByCamera();
470 } finally {
471 closeDevice();
472 }
473 }
474 }
475
Zhijun He99211e42014-04-17 19:09:36 -0700476 public void testNoiseReductionModeControl() throws Exception {
477 for (String id : mCameraIds) {
478 try {
479 openDevice(id);
Yin-Chia Yeha7954432014-09-21 14:58:00 -0700480 if (!mStaticInfo.isNoiseReductionModeControlSupported()) {
481 Log.i(TAG, "Camera " + id +
482 " doesn't support noise reduction mode, skipping test");
Zhijun He99211e42014-04-17 19:09:36 -0700483 continue;
484 }
485
486 noiseReductionModeTestByCamera();
487 } finally {
488 closeDevice();
489 }
490 }
491 }
492
Zhijun Hed72b9502014-04-27 17:19:23 -0700493 /**
Igor Murashkin6ab7dc52014-07-29 18:38:41 -0700494 * Test AWB lock control.
495 *
496 * <p>The color correction gain and transform shouldn't be changed when AWB is locked.</p>
Zhijun Hed72b9502014-04-27 17:19:23 -0700497 */
498 public void testAwbModeAndLock() throws Exception {
499 for (String id : mCameraIds) {
500 try {
501 openDevice(id);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700502 if (!mStaticInfo.isColorOutputSupported()) {
503 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
504 continue;
505 }
Zhijun Hed72b9502014-04-27 17:19:23 -0700506 awbModeAndLockTestByCamera();
507 } finally {
508 closeDevice();
509 }
510 }
511 }
512
513 /**
514 * Test different AF modes.
515 */
516 public void testAfModes() throws Exception {
517 for (String id : mCameraIds) {
518 try {
519 openDevice(id);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700520 if (!mStaticInfo.isColorOutputSupported()) {
521 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
522 continue;
523 }
Zhijun Hed72b9502014-04-27 17:19:23 -0700524 afModeTestByCamera();
525 } finally {
526 closeDevice();
527 }
528 }
529 }
530
Zhijun He68f3ecf2014-04-29 17:11:32 -0700531 /**
532 * Test video and optical stabilizations.
533 */
534 public void testCameraStabilizations() throws Exception {
535 for (String id : mCameraIds) {
536 try {
537 openDevice(id);
Ruben Brunk88470e42014-07-23 15:55:14 -0700538 List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys();
539 if (!(keys.contains(
540 CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES) ||
541 keys.contains(
542 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION))) {
543 Log.i(TAG, "Camera " + id + " doesn't support any stabilization modes");
Zhijun He68f3ecf2014-04-29 17:11:32 -0700544 continue;
545 }
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700546 if (!mStaticInfo.isColorOutputSupported()) {
547 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
548 continue;
549 }
Zhijun He68f3ecf2014-04-29 17:11:32 -0700550 stabilizationTestByCamera();
551 } finally {
552 closeDevice();
553 }
554 }
555 }
556
Zhijun Hedba6dd12014-04-29 18:41:49 -0700557 /**
558 * Test digitalZoom (center wise and non-center wise), validate the returned crop regions.
Zhijun He86ece7d2014-05-15 14:13:58 -0700559 * The max preview size is used for each camera.
Zhijun Hedba6dd12014-04-29 18:41:49 -0700560 */
561 public void testDigitalZoom() throws Exception {
562 for (String id : mCameraIds) {
563 try {
564 openDevice(id);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700565 if (!mStaticInfo.isColorOutputSupported()) {
566 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
567 continue;
568 }
Zhijun He86ece7d2014-05-15 14:13:58 -0700569 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
570 digitalZoomTestByCamera(maxPreviewSize);
571 } finally {
572 closeDevice();
573 }
574 }
575 }
Zhijun Hedba6dd12014-04-29 18:41:49 -0700576
Zhijun He86ece7d2014-05-15 14:13:58 -0700577 /**
578 * Test digital zoom and all preview size combinations.
579 * TODO: this and above test should all be moved to preview test class.
580 */
581 public void testDigitalZoomPreviewCombinations() throws Exception {
582 for (String id : mCameraIds) {
583 try {
584 openDevice(id);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700585 if (!mStaticInfo.isColorOutputSupported()) {
586 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
587 continue;
588 }
Zhijun He86ece7d2014-05-15 14:13:58 -0700589 digitalZoomPreviewCombinationTestByCamera();
Zhijun Hedba6dd12014-04-29 18:41:49 -0700590 } finally {
591 closeDevice();
592 }
593 }
594 }
595
Zhijun He496c0c72014-04-30 17:52:17 -0700596 /**
597 * Test scene mode controls.
598 */
599 public void testSceneModes() throws Exception {
600 for (String id : mCameraIds) {
601 try {
602 openDevice(id);
Zhijun He255d4c82015-05-04 16:11:48 -0700603 if (mStaticInfo.isSceneModeSupported()) {
604 sceneModeTestByCamera();
605 }
Zhijun He496c0c72014-04-30 17:52:17 -0700606 } finally {
607 closeDevice();
608 }
609 }
610 }
611
612 /**
613 * Test effect mode controls.
614 */
615 public void testEffectModes() throws Exception {
616 for (String id : mCameraIds) {
617 try {
618 openDevice(id);
Eino-Ville Talvalaa0d88252015-07-07 18:03:49 -0700619 if (!mStaticInfo.isColorOutputSupported()) {
620 Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
621 continue;
622 }
Zhijun He496c0c72014-04-30 17:52:17 -0700623 effectModeTestByCamera();
624 } finally {
625 closeDevice();
626 }
627 }
628 }
629
Zhijun He28f2b3e2014-02-26 14:15:18 -0800630 // TODO: add 3A state machine test.
631
Zhijun He99211e42014-04-17 19:09:36 -0700632 private void noiseReductionModeTestByCamera() throws Exception {
633 Size maxPrevSize = mOrderedPreviewSizes.get(0);
634 CaptureRequest.Builder requestBuilder =
635 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700636 int[] availableModes = mStaticInfo.getAvailableNoiseReductionModesChecked();
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700637 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
Zhijun He99211e42014-04-17 19:09:36 -0700638 startPreview(requestBuilder, maxPrevSize, resultListener);
639
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700640 for (int mode : availableModes) {
641 requestBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700642 resultListener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700643 mSession.setRepeatingRequest(requestBuilder.build(), resultListener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -0700644 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He99211e42014-04-17 19:09:36 -0700645
Igor Murashkin9662a562014-07-07 14:30:49 -0700646 verifyCaptureResultForKey(CaptureResult.NOISE_REDUCTION_MODE, mode,
Zhijun He99211e42014-04-17 19:09:36 -0700647 resultListener, NUM_FRAMES_VERIFIED);
648
649 // Test that OFF and FAST mode should not slow down the frame rate.
650 if (mode == CaptureRequest.NOISE_REDUCTION_MODE_OFF ||
651 mode == CaptureRequest.NOISE_REDUCTION_MODE_FAST) {
652 verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED);
653 }
654 }
655
656 stopPreview();
657 }
658
Zhijun Hef2d26f12014-04-14 10:36:55 -0700659 private void focusDistanceTestByCamera() throws Exception {
660 Size maxPrevSize = mOrderedPreviewSizes.get(0);
661 float[] testDistances = getFocusDistanceTestValuesInOrder();
662 CaptureRequest.Builder requestBuilder =
663 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
664 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700665 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
Zhijun Hef2d26f12014-04-14 10:36:55 -0700666 startPreview(requestBuilder, maxPrevSize, resultListener);
667
668 CaptureRequest request;
669 float[] resultDistances = new float[testDistances.length];
670 for (int i = 0; i < testDistances.length; i++) {
671 requestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, testDistances[i]);
672 request = requestBuilder.build();
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700673 resultListener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700674 mSession.setRepeatingRequest(request, resultListener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -0700675 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun Hef2d26f12014-04-14 10:36:55 -0700676 resultDistances[i] = verifyFocusDistanceControl(testDistances[i], request,
677 resultListener);
678 if (VERBOSE) {
679 Log.v(TAG, "Capture request focus distance: " + testDistances[i] + " result: "
680 + resultDistances[i]);
681 }
682 }
683
684 // Verify the monotonicity
685 mCollector.checkArrayMonotonicityAndNotAllEqual(CameraTestUtils.toObject(resultDistances),
686 /*ascendingOrder*/true);
Zhijun Hedba6dd12014-04-29 18:41:49 -0700687
Ruben Brunk88470e42014-07-23 15:55:14 -0700688 if (mStaticInfo.getCharacteristics().getKeys().
689 contains(CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE)) {
Zhijun Hedba6dd12014-04-29 18:41:49 -0700690
Ruben Brunk88470e42014-07-23 15:55:14 -0700691 // Test hyperfocal distance optionally
692 float hyperFocalDistance = mStaticInfo.getHyperfocalDistanceChecked();
693 if (hyperFocalDistance > 0) {
694 requestBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, hyperFocalDistance);
695 request = requestBuilder.build();
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700696 resultListener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700697 mSession.setRepeatingRequest(request, resultListener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -0700698 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
699
700 // Then wait for the lens.state to be stationary.
701 waitForResultValue(resultListener, CaptureResult.LENS_STATE,
702 CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT);
703 // Need get reasonably accurate value.
704 CaptureResult result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
705 Float focusDistance = getValueNotNull(result, CaptureResult.LENS_FOCUS_DISTANCE);
706 float errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_UNCALIBRATED;
707 int calibrationStatus = mStaticInfo.getFocusDistanceCalibrationChecked();
708 if (calibrationStatus ==
709 CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED) {
710 errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_CALIBRATED;
711 } else if (calibrationStatus ==
712 CameraMetadata.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE) {
713 errorMargin = FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE;
714 }
715 mCollector.expectInRange("Focus distance for hyper focal should be close enough to" +
716 "requested value", focusDistance,
717 hyperFocalDistance * (1.0f - errorMargin),
718 hyperFocalDistance * (1.0f + errorMargin)
719 );
Zhijun He76a03012014-05-06 17:01:30 -0700720 }
Zhijun Hedba6dd12014-04-29 18:41:49 -0700721 }
Zhijun Hef2d26f12014-04-14 10:36:55 -0700722 }
723
724 /**
725 * Verify focus distance control.
726 *
727 * @param distance The focus distance requested
728 * @param request The capture request to control the manual focus distance
729 * @param resultListener The capture listener to recieve capture result callbacks
730 * @return the result focus distance
731 */
732 private float verifyFocusDistanceControl(float distance, CaptureRequest request,
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700733 SimpleCaptureCallback resultListener) {
Zhijun Hef2d26f12014-04-14 10:36:55 -0700734 // Need make sure the result corresponding to the request is back, then check.
735 CaptureResult result =
736 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
737 // Then wait for the lens.state to be stationary.
738 waitForResultValue(resultListener, CaptureResult.LENS_STATE,
739 CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT);
740 // Then check the focus distance.
741 result = resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
742 Float resultDistance = getValueNotNull(result, CaptureResult.LENS_FOCUS_DISTANCE);
743 if (mStaticInfo.getFocusDistanceCalibrationChecked() ==
744 CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED) {
745 // TODO: what's more to test for CALIBRATED devices?
746 }
747
748 float minValue = 0;
749 float maxValue = mStaticInfo.getMinimumFocusDistanceChecked();
750 mCollector.expectInRange("Result focus distance is out of range",
751 resultDistance, minValue, maxValue);
752
753 return resultDistance;
754 }
755
Zhijun Heed9cd312014-03-24 23:15:52 -0700756 /**
Zhijun Hefd84d852014-04-13 23:11:15 -0700757 * Verify edge mode control results.
758 */
759 private void edgeModesTestByCamera() throws Exception {
760 Size maxPrevSize = mOrderedPreviewSizes.get(0);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700761 int[] edgeModes = mStaticInfo.getAvailableEdgeModesChecked();
Zhijun Hefd84d852014-04-13 23:11:15 -0700762 CaptureRequest.Builder requestBuilder =
763 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700764 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
Zhijun Hefd84d852014-04-13 23:11:15 -0700765 startPreview(requestBuilder, maxPrevSize, resultListener);
766
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700767 for (int mode : edgeModes) {
768 requestBuilder.set(CaptureRequest.EDGE_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700769 resultListener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700770 mSession.setRepeatingRequest(requestBuilder.build(), resultListener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -0700771 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun Hefd84d852014-04-13 23:11:15 -0700772
Igor Murashkin9662a562014-07-07 14:30:49 -0700773 verifyCaptureResultForKey(CaptureResult.EDGE_MODE, mode, resultListener,
Zhijun He99211e42014-04-17 19:09:36 -0700774 NUM_FRAMES_VERIFIED);
Zhijun Hefd84d852014-04-13 23:11:15 -0700775
Zhijun He99211e42014-04-17 19:09:36 -0700776 // Test that OFF and FAST mode should not slow down the frame rate.
777 if (mode == CaptureRequest.EDGE_MODE_OFF ||
778 mode == CaptureRequest.EDGE_MODE_FAST) {
779 verifyFpsNotSlowDown(requestBuilder, NUM_FRAMES_VERIFIED);
780 }
Zhijun Hefd84d852014-04-13 23:11:15 -0700781 }
Zhijun He99211e42014-04-17 19:09:36 -0700782
783 stopPreview();
Zhijun Hefd84d852014-04-13 23:11:15 -0700784 }
785
786 /**
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700787 * Test color correction controls.
788 *
789 * <p>Test different color correction modes. For TRANSFORM_MATRIX, only test
790 * the unit gain and identity transform.</p>
791 */
792 private void colorCorrectionTestByCamera() throws Exception {
793 CaptureRequest request;
794 CaptureResult result;
795 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
796 updatePreviewSurface(maxPreviewSz);
797 CaptureRequest.Builder manualRequestBuilder = createRequestForPreview();
798 CaptureRequest.Builder previewRequestBuilder = createRequestForPreview();
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700799 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700800
801 startPreview(previewRequestBuilder, maxPreviewSz, listener);
802
803 // Default preview result should give valid color correction metadata.
804 result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Zhijun He92b56772014-05-31 08:36:31 -0700805 validateColorCorrectionResult(result,
806 previewRequestBuilder.get(CaptureRequest.COLOR_CORRECTION_MODE));
Zhijun He255d4c82015-05-04 16:11:48 -0700807 int colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX;
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700808 // TRANSFORM_MATRIX mode
809 // Only test unit gain and identity transform
Zhijun He255d4c82015-05-04 16:11:48 -0700810 List<Integer> availableControlModes = Arrays.asList(
811 CameraTestUtils.toObject(mStaticInfo.getAvailableControlModesChecked()));
812 List<Integer> availableAwbModes = Arrays.asList(
813 CameraTestUtils.toObject(mStaticInfo.getAwbAvailableModesChecked()));
814 boolean isManualCCSupported =
815 availableControlModes.contains(CaptureRequest.CONTROL_MODE_OFF) ||
816 availableAwbModes.contains(CaptureRequest.CONTROL_AWB_MODE_OFF);
817 if (isManualCCSupported) {
818 if (!availableControlModes.contains(CaptureRequest.CONTROL_MODE_OFF)) {
819 // Only manual AWB mode is supported
820 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE,
821 CaptureRequest.CONTROL_MODE_AUTO);
822 manualRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,
823 CaptureRequest.CONTROL_AWB_MODE_OFF);
824 } else {
825 // All 3A manual controls are supported, it doesn't matter what we set for AWB mode.
826 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE,
827 CaptureRequest.CONTROL_MODE_OFF);
828 }
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700829
Zhijun He255d4c82015-05-04 16:11:48 -0700830 RggbChannelVector UNIT_GAIN = new RggbChannelVector(1.0f, 1.0f, 1.0f, 1.0f);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700831
Zhijun He255d4c82015-05-04 16:11:48 -0700832 ColorSpaceTransform IDENTITY_TRANSFORM = new ColorSpaceTransform(
833 new Rational[] {
834 ONE_R, ZERO_R, ZERO_R,
835 ZERO_R, ONE_R, ZERO_R,
836 ZERO_R, ZERO_R, ONE_R
837 });
838
839 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode);
840 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_GAINS, UNIT_GAIN);
841 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_TRANSFORM, IDENTITY_TRANSFORM);
842 request = manualRequestBuilder.build();
843 mSession.capture(request, listener, mHandler);
844 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
845 RggbChannelVector gains = result.get(CaptureResult.COLOR_CORRECTION_GAINS);
846 ColorSpaceTransform transform = result.get(CaptureResult.COLOR_CORRECTION_TRANSFORM);
847 validateColorCorrectionResult(result, colorCorrectionMode);
848 mCollector.expectEquals("control mode result/request mismatch",
849 CaptureResult.CONTROL_MODE_OFF, result.get(CaptureResult.CONTROL_MODE));
850 mCollector.expectEquals("Color correction gain result/request mismatch",
851 UNIT_GAIN, gains);
852 mCollector.expectEquals("Color correction gain result/request mismatch",
853 IDENTITY_TRANSFORM, transform);
854
855 }
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700856
857 // FAST mode
Zhijun He92b56772014-05-31 08:36:31 -0700858 colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_FAST;
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700859 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
Zhijun He92b56772014-05-31 08:36:31 -0700860 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700861 request = manualRequestBuilder.build();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700862 mSession.capture(request, listener, mHandler);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700863 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
Zhijun He92b56772014-05-31 08:36:31 -0700864 validateColorCorrectionResult(result, colorCorrectionMode);
865 mCollector.expectEquals("control mode result/request mismatch",
866 CaptureResult.CONTROL_MODE_AUTO, result.get(CaptureResult.CONTROL_MODE));
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700867
868 // HIGH_QUALITY mode
Zhijun He92b56772014-05-31 08:36:31 -0700869 colorCorrectionMode = CaptureRequest.COLOR_CORRECTION_MODE_HIGH_QUALITY;
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700870 manualRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
Zhijun He92b56772014-05-31 08:36:31 -0700871 manualRequestBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE, colorCorrectionMode);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700872 request = manualRequestBuilder.build();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700873 mSession.capture(request, listener, mHandler);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700874 result = listener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
Zhijun He92b56772014-05-31 08:36:31 -0700875 validateColorCorrectionResult(result, colorCorrectionMode);
876 mCollector.expectEquals("control mode result/request mismatch",
877 CaptureResult.CONTROL_MODE_AUTO, result.get(CaptureResult.CONTROL_MODE));
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700878 }
879
Zhijun He92b56772014-05-31 08:36:31 -0700880 private void validateColorCorrectionResult(CaptureResult result, int colorCorrectionMode) {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700881 final RggbChannelVector ZERO_GAINS = new RggbChannelVector(0, 0, 0, 0);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700882 final int TRANSFORM_SIZE = 9;
883 Rational[] zeroTransform = new Rational[TRANSFORM_SIZE];
884 Arrays.fill(zeroTransform, ZERO_R);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700885 final ColorSpaceTransform ZERO_TRANSFORM = new ColorSpaceTransform(zeroTransform);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700886
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700887 RggbChannelVector resultGain;
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700888 if ((resultGain = mCollector.expectKeyValueNotNull(result,
889 CaptureResult.COLOR_CORRECTION_GAINS)) != null) {
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700890 mCollector.expectKeyValueNotEquals(result,
891 CaptureResult.COLOR_CORRECTION_GAINS, ZERO_GAINS);
892 }
893
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700894 ColorSpaceTransform resultTransform;
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700895 if ((resultTransform = mCollector.expectKeyValueNotNull(result,
896 CaptureResult.COLOR_CORRECTION_TRANSFORM)) != null) {
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700897 mCollector.expectKeyValueNotEquals(result,
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -0700898 CaptureResult.COLOR_CORRECTION_TRANSFORM, ZERO_TRANSFORM);
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700899 }
Zhijun He92b56772014-05-31 08:36:31 -0700900
901 mCollector.expectEquals("color correction mode result/request mismatch",
902 colorCorrectionMode, result.get(CaptureResult.COLOR_CORRECTION_MODE));
Zhijun He5ca2d4f2014-04-04 17:27:59 -0700903 }
904
905 /**
Zhijun Heed9cd312014-03-24 23:15:52 -0700906 * Test flash mode control by AE mode.
907 * <p>
908 * Only allow AE mode ON or OFF, because other AE mode could run into conflict with
909 * flash manual control. This function expects the camera to already have an active
910 * repeating request and be sending results to the listener.
911 * </p>
912 *
913 * @param listener The Capture listener that is used to wait for capture result
914 * @param aeMode The AE mode for flash to test with
915 */
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -0700916 private void flashTestByAeMode(SimpleCaptureCallback listener, int aeMode) throws Exception {
Zhijun Heed9cd312014-03-24 23:15:52 -0700917 CaptureResult result;
918 final int NUM_FLASH_REQUESTS_TESTED = 10;
919 CaptureRequest.Builder requestBuilder = createRequestForPreview();
920
921 if (aeMode == CaptureRequest.CONTROL_AE_MODE_ON) {
922 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, aeMode);
923 } else if (aeMode == CaptureRequest.CONTROL_AE_MODE_OFF) {
924 changeExposure(requestBuilder, DEFAULT_EXP_TIME_NS, DEFAULT_SENSITIVITY);
925 } else {
926 throw new IllegalArgumentException("This test only works when AE mode is ON or OFF");
927 }
928
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -0700929 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Igor Murashkine21060a2014-07-10 18:09:21 -0700930 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
931
Zhijun Heed9cd312014-03-24 23:15:52 -0700932 // For camera that doesn't have flash unit, flash state should always be UNAVAILABLE.
933 if (mStaticInfo.getFlashInfoChecked() == false) {
934 for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) {
935 result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
936 mCollector.expectEquals("No flash unit available, flash state must be UNAVAILABLE"
937 + "for AE mode " + aeMode, CaptureResult.FLASH_STATE_UNAVAILABLE,
938 result.get(CaptureResult.FLASH_STATE));
939 }
940
941 return;
942 }
943
944 // Test flash SINGLE mode control. Wait for flash state to be READY first.
Igor Murashkine21060a2014-07-10 18:09:21 -0700945 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
946 waitForResultValue(listener, CaptureResult.FLASH_STATE, CaptureResult.FLASH_STATE_READY,
947 NUM_RESULTS_WAIT_TIMEOUT);
948 } // else the settings were already waited on earlier
949
Zhijun Heed9cd312014-03-24 23:15:52 -0700950 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
Zhijun He9d908142014-08-04 13:18:05 -0700951 CaptureRequest flashSinglerequest = requestBuilder.build();
Igor Murashkine21060a2014-07-10 18:09:21 -0700952
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -0700953 int flashModeSingleRequests = captureRequestsSynchronized(
954 flashSinglerequest, listener, mHandler);
Zhijun He9d908142014-08-04 13:18:05 -0700955 waitForNumResults(listener, flashModeSingleRequests - 1);
956 result = listener.getCaptureResultForRequest(flashSinglerequest, NUM_RESULTS_WAIT_TIMEOUT);
Zhijun Heed9cd312014-03-24 23:15:52 -0700957 // Result mode must be SINGLE, state must be FIRED.
958 mCollector.expectEquals("Flash mode result must be SINGLE",
959 CaptureResult.FLASH_MODE_SINGLE, result.get(CaptureResult.FLASH_MODE));
960 mCollector.expectEquals("Flash state result must be FIRED",
961 CaptureResult.FLASH_STATE_FIRED, result.get(CaptureResult.FLASH_STATE));
962
963 // Test flash TORCH mode control.
Zhijun Heed9cd312014-03-24 23:15:52 -0700964 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
Igor Murashkine21060a2014-07-10 18:09:21 -0700965 CaptureRequest torchRequest = requestBuilder.build();
966
967 int flashModeTorchRequests = captureRequestsSynchronized(torchRequest,
968 NUM_FLASH_REQUESTS_TESTED, listener, mHandler);
969 waitForNumResults(listener, flashModeTorchRequests - NUM_FLASH_REQUESTS_TESTED);
970
Zhijun Heed9cd312014-03-24 23:15:52 -0700971 // Verify the results
Yin-Chia Yeh72997f82015-08-29 15:48:06 -0700972 TorchSeqState state = TorchSeqState.RAMPING_UP;
Zhijun Heed9cd312014-03-24 23:15:52 -0700973 for (int i = 0; i < NUM_FLASH_REQUESTS_TESTED; i++) {
Igor Murashkine21060a2014-07-10 18:09:21 -0700974 result = listener.getCaptureResultForRequest(torchRequest,
Zhijun Heed9cd312014-03-24 23:15:52 -0700975 NUM_RESULTS_WAIT_TIMEOUT);
Yin-Chia Yeh72997f82015-08-29 15:48:06 -0700976 int flashMode = result.get(CaptureResult.FLASH_MODE);
977 int flashState = result.get(CaptureResult.FLASH_STATE);
978 // Result mode must be TORCH
979 mCollector.expectEquals("Flash mode result " + i + " must be TORCH",
Zhijun Heed9cd312014-03-24 23:15:52 -0700980 CaptureResult.FLASH_MODE_TORCH, result.get(CaptureResult.FLASH_MODE));
Yin-Chia Yeh72997f82015-08-29 15:48:06 -0700981 if (state == TorchSeqState.RAMPING_UP &&
982 flashState == CaptureResult.FLASH_STATE_FIRED) {
983 state = TorchSeqState.FIRED;
984 } else if (state == TorchSeqState.FIRED &&
985 flashState == CaptureResult.FLASH_STATE_PARTIAL) {
986 state = TorchSeqState.RAMPING_DOWN;
987 }
988
989 if (i == 0 && mStaticInfo.isPerFrameControlSupported()) {
990 mCollector.expectTrue(
991 "Per frame control device must enter FIRED state on first torch request",
992 state == TorchSeqState.FIRED);
993 }
994
995 if (state == TorchSeqState.FIRED) {
996 mCollector.expectEquals("Flash state result " + i + " must be FIRED",
997 CaptureResult.FLASH_STATE_FIRED, result.get(CaptureResult.FLASH_STATE));
998 } else {
999 mCollector.expectEquals("Flash state result " + i + " must be PARTIAL",
1000 CaptureResult.FLASH_STATE_PARTIAL, result.get(CaptureResult.FLASH_STATE));
1001 }
Zhijun Heed9cd312014-03-24 23:15:52 -07001002 }
Yin-Chia Yeh72997f82015-08-29 15:48:06 -07001003 mCollector.expectTrue("Torch state FIRED never seen",
1004 state == TorchSeqState.FIRED || state == TorchSeqState.RAMPING_DOWN);
Zhijun Heed9cd312014-03-24 23:15:52 -07001005
1006 // Test flash OFF mode control
1007 requestBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
Zhijun He9d908142014-08-04 13:18:05 -07001008 CaptureRequest flashOffrequest = requestBuilder.build();
Igor Murashkine21060a2014-07-10 18:09:21 -07001009
Zhijun He9d908142014-08-04 13:18:05 -07001010 int flashModeOffRequests = captureRequestsSynchronized(flashOffrequest, listener, mHandler);
1011 waitForNumResults(listener, flashModeOffRequests - 1);
1012 result = listener.getCaptureResultForRequest(flashOffrequest, NUM_RESULTS_WAIT_TIMEOUT);
Zhijun Heed9cd312014-03-24 23:15:52 -07001013 mCollector.expectEquals("Flash mode result must be OFF", CaptureResult.FLASH_MODE_OFF,
1014 result.get(CaptureResult.FLASH_MODE));
1015 }
1016
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001017 private void verifyAntiBandingMode(SimpleCaptureCallback listener, int numFramesVerified,
Zhijun He5f4d0082014-03-19 23:02:03 -07001018 int mode, boolean isAeManual, long requestExpTime) throws Exception {
Zhijun He7e80fe92014-04-24 15:46:41 -07001019 // Skip the first a couple of frames as antibanding may not be fully up yet.
1020 final int NUM_FRAMES_SKIPPED = 5;
1021 for (int i = 0; i < NUM_FRAMES_SKIPPED; i++) {
1022 listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1023 }
1024
Zhijun He5f4d0082014-03-19 23:02:03 -07001025 for (int i = 0; i < numFramesVerified; i++) {
1026 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Igor Murashkin94399742014-05-19 16:38:37 -07001027 Long resultExpTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
Zhijun He5f4d0082014-03-19 23:02:03 -07001028 assertNotNull("Exposure time shouldn't be null", resultExpTime);
1029 Integer flicker = result.get(CaptureResult.STATISTICS_SCENE_FLICKER);
1030 // Scene flicker result should be always available.
1031 assertNotNull("Scene flicker must not be null", flicker);
1032 assertTrue("Scene flicker is invalid", flicker >= STATISTICS_SCENE_FLICKER_NONE &&
1033 flicker <= STATISTICS_SCENE_FLICKER_60HZ);
1034
1035 if (isAeManual) {
Zhijun He5f4d0082014-03-19 23:02:03 -07001036 // First, round down not up, second, need close enough.
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001037 validateExposureTime(requestExpTime, resultExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001038 return;
1039 }
1040
1041 long expectedExpTime = resultExpTime; // Default, no exposure adjustment.
1042 if (mode == CONTROL_AE_ANTIBANDING_MODE_50HZ) {
1043 // result exposure time must be adjusted by 50Hz illuminant source.
1044 expectedExpTime =
Zhijun He7e80fe92014-04-24 15:46:41 -07001045 getAntiFlickeringExposureTime(ANTI_FLICKERING_50HZ, resultExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001046 } else if (mode == CONTROL_AE_ANTIBANDING_MODE_60HZ) {
1047 // result exposure time must be adjusted by 60Hz illuminant source.
1048 expectedExpTime =
Zhijun He7e80fe92014-04-24 15:46:41 -07001049 getAntiFlickeringExposureTime(ANTI_FLICKERING_60HZ, resultExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001050 } else if (mode == CONTROL_AE_ANTIBANDING_MODE_AUTO){
1051 /**
1052 * Use STATISTICS_SCENE_FLICKER to tell the illuminant source
1053 * and do the exposure adjustment.
1054 */
1055 expectedExpTime = resultExpTime;
1056 if (flicker == STATISTICS_SCENE_FLICKER_60HZ) {
Zhijun He7e80fe92014-04-24 15:46:41 -07001057 expectedExpTime =
1058 getAntiFlickeringExposureTime(ANTI_FLICKERING_60HZ, resultExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001059 } else if (flicker == STATISTICS_SCENE_FLICKER_50HZ) {
Zhijun He7e80fe92014-04-24 15:46:41 -07001060 expectedExpTime =
1061 getAntiFlickeringExposureTime(ANTI_FLICKERING_50HZ, resultExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001062 }
1063 }
1064
1065 if (Math.abs(resultExpTime - expectedExpTime) > EXPOSURE_TIME_ERROR_MARGIN_NS) {
1066 mCollector.addMessage(String.format("Result exposure time %dns diverges too much"
1067 + " from expected exposure time %dns for mode %d when AE is auto",
1068 resultExpTime, expectedExpTime, mode));
1069 }
1070 }
1071 }
1072
Zhijun He7e80fe92014-04-24 15:46:41 -07001073 private void antiBandingTestByMode(Size size, int mode)
Zhijun He5f4d0082014-03-19 23:02:03 -07001074 throws Exception {
1075 if(VERBOSE) {
1076 Log.v(TAG, "Anti-banding test for mode " + mode + " for camera " + mCamera.getId());
1077 }
1078 CaptureRequest.Builder requestBuilder =
1079 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1080
1081 requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, mode);
1082
1083 // Test auto AE mode anti-banding behavior
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001084 SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
Zhijun He7e80fe92014-04-24 15:46:41 -07001085 startPreview(requestBuilder, size, resultListener);
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -07001086 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He7e80fe92014-04-24 15:46:41 -07001087 verifyAntiBandingMode(resultListener, NUM_FRAMES_VERIFIED, mode, /*isAeManual*/false,
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -07001088 IGNORE_REQUESTED_EXPOSURE_TIME_CHECK);
Zhijun He5f4d0082014-03-19 23:02:03 -07001089
1090 // Test manual AE mode anti-banding behavior
1091 // 65ms, must be supported by full capability devices.
1092 final long TEST_MANUAL_EXP_TIME_NS = 65000000L;
Zhijun He7e80fe92014-04-24 15:46:41 -07001093 long manualExpTime = mStaticInfo.getExposureClampToRange(TEST_MANUAL_EXP_TIME_NS);
1094 changeExposure(requestBuilder, manualExpTime);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001095 resultListener = new SimpleCaptureCallback();
Zhijun He7e80fe92014-04-24 15:46:41 -07001096 startPreview(requestBuilder, size, resultListener);
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -07001097 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He7e80fe92014-04-24 15:46:41 -07001098 verifyAntiBandingMode(resultListener, NUM_FRAMES_VERIFIED, mode, /*isAeManual*/true,
1099 manualExpTime);
Zhijun He5f4d0082014-03-19 23:02:03 -07001100
1101 stopPreview();
1102 }
1103
Zhijun He28f2b3e2014-02-26 14:15:18 -08001104 /**
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001105 * Test the all available AE modes and AE lock.
1106 * <p>
1107 * For manual AE mode, test iterates through different sensitivities and
1108 * exposure times, validate the result exposure time correctness. For
1109 * CONTROL_AE_MODE_ON_ALWAYS_FLASH mode, the AE lock and flash are tested.
1110 * For the rest of the AUTO mode, AE lock is tested.
1111 * </p>
1112 *
1113 * @param mode
1114 */
1115 private void aeModeAndLockTestByMode(int mode)
1116 throws Exception {
1117 switch (mode) {
1118 case CONTROL_AE_MODE_OFF:
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001119 if (mStaticInfo.isCapabilitySupported(
1120 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1121 // Test manual exposure control.
1122 aeManualControlTest();
1123 } else {
1124 Log.w(TAG,
1125 "aeModeAndLockTestByMode - can't test AE mode OFF without " +
1126 "manual sensor control");
1127 }
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001128 break;
1129 case CONTROL_AE_MODE_ON:
1130 case CONTROL_AE_MODE_ON_AUTO_FLASH:
1131 case CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE:
1132 case CONTROL_AE_MODE_ON_ALWAYS_FLASH:
1133 // Test AE lock for above AUTO modes.
1134 aeAutoModeTestLock(mode);
1135 break;
1136 default:
1137 throw new UnsupportedOperationException("Unhandled AE mode " + mode);
1138 }
1139 }
1140
1141 /**
1142 * Test AE auto modes.
1143 * <p>
1144 * Use single request rather than repeating request to test AE lock per frame control.
1145 * </p>
1146 */
1147 private void aeAutoModeTestLock(int mode) throws Exception {
1148 CaptureRequest.Builder requestBuilder =
1149 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001150 if (mStaticInfo.isAeLockSupported()) {
1151 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
1152 }
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001153 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mode);
1154 configurePreviewOutput(requestBuilder);
1155
Zhijun Hec61ac102014-07-25 17:40:05 -07001156 final int MAX_NUM_CAPTURES_DURING_LOCK = 5;
1157 for (int i = 1; i <= MAX_NUM_CAPTURES_DURING_LOCK; i++) {
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001158 autoAeMultipleCapturesThenTestLock(requestBuilder, mode, i);
1159 }
1160 }
1161
1162 /**
1163 * Issue multiple auto AE captures, then lock AE, validate the AE lock vs.
Zhijun Hec61ac102014-07-25 17:40:05 -07001164 * the first capture result after the AE lock. The right AE lock behavior is:
1165 * When it is locked, it locks to the current exposure value, and all subsequent
1166 * request with lock ON will have the same exposure value locked.
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001167 */
1168 private void autoAeMultipleCapturesThenTestLock(
Zhijun Hec61ac102014-07-25 17:40:05 -07001169 CaptureRequest.Builder requestBuilder, int aeMode, int numCapturesDuringLock)
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001170 throws Exception {
Zhijun Hec61ac102014-07-25 17:40:05 -07001171 if (numCapturesDuringLock < 1) {
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001172 throw new IllegalArgumentException("numCapturesBeforeLock must be no less than 1");
1173 }
1174 if (VERBOSE) {
1175 Log.v(TAG, "Camera " + mCamera.getId() + ": Testing auto AE mode and lock for mode "
Zhijun Hec61ac102014-07-25 17:40:05 -07001176 + aeMode + " with " + numCapturesDuringLock + " captures before lock");
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001177 }
1178
Zhijun Hec61ac102014-07-25 17:40:05 -07001179 final int NUM_CAPTURES_BEFORE_LOCK = 2;
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001180 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001181
Zhijun Hec61ac102014-07-25 17:40:05 -07001182 CaptureResult[] resultsDuringLock = new CaptureResult[numCapturesDuringLock];
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001183 boolean canSetAeLock = mStaticInfo.isAeLockSupported();
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001184
1185 // Reset the AE lock to OFF, since we are reusing this builder many times
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001186 if (canSetAeLock) {
1187 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
1188 }
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001189
Zhijun Hec61ac102014-07-25 17:40:05 -07001190 // Just send several captures with auto AE, lock off.
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001191 CaptureRequest request = requestBuilder.build();
Zhijun Hec61ac102014-07-25 17:40:05 -07001192 for (int i = 0; i < NUM_CAPTURES_BEFORE_LOCK; i++) {
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001193 mSession.capture(request, listener, mHandler);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001194 }
Zhijun Hec61ac102014-07-25 17:40:05 -07001195 waitForNumResults(listener, NUM_CAPTURES_BEFORE_LOCK);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001196
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001197 if (!canSetAeLock) {
1198 // Without AE lock, the remaining tests items won't work
1199 return;
1200 }
1201
Zhijun Hec61ac102014-07-25 17:40:05 -07001202 // Then fire several capture to lock the AE.
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001203 requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
1204
Zhijun Hec61ac102014-07-25 17:40:05 -07001205 int requestCount = captureRequestsSynchronized(
1206 requestBuilder.build(), numCapturesDuringLock, listener, mHandler);
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001207
Zhijun Hec61ac102014-07-25 17:40:05 -07001208 int[] sensitivities = new int[numCapturesDuringLock];
1209 long[] expTimes = new long[numCapturesDuringLock];
1210 Arrays.fill(sensitivities, -1);
1211 Arrays.fill(expTimes, -1L);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001212
1213 // Get the AE lock on result and validate the exposure values.
Zhijun Hec61ac102014-07-25 17:40:05 -07001214 waitForNumResults(listener, requestCount - numCapturesDuringLock);
1215 for (int i = 0; i < resultsDuringLock.length; i++) {
1216 resultsDuringLock[i] = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1217 }
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001218
Zhijun Hec61ac102014-07-25 17:40:05 -07001219 for (int i = 0; i < numCapturesDuringLock; i++) {
1220 mCollector.expectKeyValueEquals(
1221 resultsDuringLock[i], CaptureResult.CONTROL_AE_LOCK, true);
1222 }
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001223
1224 // Can't read manual sensor/exposure settings without manual sensor
1225 if (mStaticInfo.isCapabilitySupported(
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001226 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
Zhijun Hec61ac102014-07-25 17:40:05 -07001227 int sensitivityLocked =
1228 getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_SENSITIVITY);
1229 long expTimeLocked =
1230 getValueNotNull(resultsDuringLock[0], CaptureResult.SENSOR_EXPOSURE_TIME);
1231 for (int i = 1; i < resultsDuringLock.length; i++) {
1232 mCollector.expectKeyValueEquals(
1233 resultsDuringLock[i], CaptureResult.SENSOR_EXPOSURE_TIME, expTimeLocked);
1234 mCollector.expectKeyValueEquals(
1235 resultsDuringLock[i], CaptureResult.SENSOR_SENSITIVITY, sensitivityLocked);
1236 }
Igor Murashkin0d572cb2014-07-10 16:45:27 -07001237 }
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001238 }
1239
1240 /**
1241 * Iterate through exposure times and sensitivities for manual AE control.
1242 * <p>
1243 * Use single request rather than repeating request to test manual exposure
1244 * value change per frame control.
1245 * </p>
1246 */
1247 private void aeManualControlTest()
1248 throws Exception {
1249 CaptureRequest.Builder requestBuilder =
1250 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1251
1252 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF);
1253 configurePreviewOutput(requestBuilder);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001254 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001255
1256 long[] expTimes = getExposureTimeTestValues();
1257 int[] sensitivities = getSensitivityTestValues();
1258 // Submit single request at a time, then verify the result.
1259 for (int i = 0; i < expTimes.length; i++) {
1260 for (int j = 0; j < sensitivities.length; j++) {
1261 if (VERBOSE) {
1262 Log.v(TAG, "Camera " + mCamera.getId() + ": Testing sensitivity "
1263 + sensitivities[j] + ", exposure time " + expTimes[i] + "ns");
1264 }
1265
1266 changeExposure(requestBuilder, expTimes[i], sensitivities[j]);
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001267 mSession.capture(requestBuilder.build(), listener, mHandler);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001268
Yin-Chia Yeh39f8f4b2015-07-17 12:29:31 -07001269 // make sure timeout is long enough for long exposure time
1270 long timeout = WAIT_FOR_RESULT_TIMEOUT_MS + expTimes[i];
1271 CaptureResult result = listener.getCaptureResult(timeout);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001272 long resultExpTime = getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME);
1273 int resultSensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
1274 validateExposureTime(expTimes[i], resultExpTime);
1275 validateSensitivity(sensitivities[j], resultSensitivity);
Zhijun He984ff7e2014-03-30 12:40:27 -07001276 validateFrameDurationForCapture(result);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001277 }
1278 }
1279 // TODO: Add another case to test where we can submit all requests, then wait for
1280 // results, which will hide the pipeline latency. this is not only faster, but also
1281 // test high speed per frame control and synchronization.
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001282 }
1283
Zhijun He984ff7e2014-03-30 12:40:27 -07001284
Zhijun He8c8fb1e2014-03-20 14:57:48 -07001285 /**
Zhijun He28f2b3e2014-02-26 14:15:18 -08001286 * Verify black level lock control.
1287 */
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001288 private void verifyBlackLevelLockResults(SimpleCaptureCallback listener, int numFramesVerified,
Zhijun He28f2b3e2014-02-26 14:15:18 -08001289 int maxLockOffCnt) throws Exception {
1290 int noLockCnt = 0;
1291 for (int i = 0; i < numFramesVerified; i++) {
1292 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1293 Boolean blackLevelLock = result.get(CaptureResult.BLACK_LEVEL_LOCK);
1294 assertNotNull("Black level lock result shouldn't be null", blackLevelLock);
1295
1296 // Count the lock == false result, which could possibly occur at most once.
1297 if (blackLevelLock == false) {
1298 noLockCnt++;
1299 }
1300
1301 if(VERBOSE) {
1302 Log.v(TAG, "Black level lock result: " + blackLevelLock);
1303 }
1304 }
1305 assertTrue("Black level lock OFF occurs " + noLockCnt + " times, expect at most "
1306 + maxLockOffCnt + " for camera " + mCamera.getId(), noLockCnt <= maxLockOffCnt);
1307 }
1308
Zhijun He4b87bed2014-03-03 16:44:48 -08001309 /**
1310 * Verify shading map for different shading modes.
1311 */
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001312 private void verifyShadingMap(SimpleCaptureCallback listener, int numFramesVerified,
Ruben Brunka47c85a2014-05-27 18:56:57 -07001313 int shadingMode) throws Exception {
Zhijun He4b87bed2014-03-03 16:44:48 -08001314
1315 for (int i = 0; i < numFramesVerified; i++) {
1316 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Zhijun He6c3f5632014-04-11 10:36:14 -07001317 mCollector.expectEquals("Shading mode result doesn't match request",
1318 shadingMode, result.get(CaptureResult.SHADING_MODE));
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -07001319 LensShadingMap mapObj = result.get(
1320 CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
Ruben Brunka47c85a2014-05-27 18:56:57 -07001321 assertNotNull("Map object must not be null", mapObj);
1322 int numElementsInMap = mapObj.getGainFactorCount();
1323 float[] map = new float[numElementsInMap];
1324 mapObj.copyGainFactors(map, /*offset*/0);
Zhijun He4b87bed2014-03-03 16:44:48 -08001325 assertNotNull("Map must not be null", map);
Zhijun He4b87bed2014-03-03 16:44:48 -08001326 assertFalse(String.format(
1327 "Map size %d should be less than %d", numElementsInMap, MAX_SHADING_MAP_SIZE),
1328 numElementsInMap >= MAX_SHADING_MAP_SIZE);
1329 assertFalse(String.format("Map size %d should be no less than %d", numElementsInMap,
1330 MIN_SHADING_MAP_SIZE), numElementsInMap < MIN_SHADING_MAP_SIZE);
1331
Zhijun He6c3f5632014-04-11 10:36:14 -07001332 if (shadingMode == CaptureRequest.SHADING_MODE_FAST ||
1333 shadingMode == CaptureRequest.SHADING_MODE_HIGH_QUALITY) {
1334 // shading mode is FAST or HIGH_QUALITY, expect to receive a map with all
1335 // elements >= 1.0f
Zhijun He4b87bed2014-03-03 16:44:48 -08001336
1337 int badValueCnt = 0;
1338 // Detect the bad values of the map data.
1339 for (int j = 0; j < numElementsInMap; j++) {
1340 if (Float.isNaN(map[j]) || map[j] < 1.0f) {
1341 badValueCnt++;
1342 }
1343 }
1344 assertEquals("Number of value in the map is " + badValueCnt + " out of "
1345 + numElementsInMap, /*expected*/0, /*actual*/badValueCnt);
Zhijun He6c3f5632014-04-11 10:36:14 -07001346 } else if (shadingMode == CaptureRequest.SHADING_MODE_OFF) {
Ruben Brunka47c85a2014-05-27 18:56:57 -07001347 float[] unityMap = new float[numElementsInMap];
1348 Arrays.fill(unityMap, 1.0f);
Zhijun He6c3f5632014-04-11 10:36:14 -07001349 // shading mode is OFF, expect to receive a unity map.
Zhijun He4b87bed2014-03-03 16:44:48 -08001350 assertTrue("Result map " + Arrays.toString(map) + " must be an unity map",
1351 Arrays.equals(unityMap, map));
1352 }
1353 }
1354 }
Zhijun He28f2b3e2014-02-26 14:15:18 -08001355
Zhijun He984ff7e2014-03-30 12:40:27 -07001356 /**
1357 * Test face detection for a camera.
1358 */
1359 private void faceDetectionTestByCamera() throws Exception {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001360 int[] faceDetectModes = mStaticInfo.getAvailableFaceDetectModesChecked();
Zhijun He984ff7e2014-03-30 12:40:27 -07001361
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001362 SimpleCaptureCallback listener;
Zhijun He984ff7e2014-03-30 12:40:27 -07001363 CaptureRequest.Builder requestBuilder =
1364 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1365
1366 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001367 for (int mode : faceDetectModes) {
1368 requestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, mode);
Zhijun He984ff7e2014-03-30 12:40:27 -07001369 if (VERBOSE) {
1370 Log.v(TAG, "Start testing face detection mode " + mode);
1371 }
1372
1373 // Create a new listener for each run to avoid the results from one run spill
1374 // into another run.
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001375 listener = new SimpleCaptureCallback();
Zhijun He984ff7e2014-03-30 12:40:27 -07001376 startPreview(requestBuilder, maxPreviewSz, listener);
Igor Murashkin8772d942014-07-31 15:53:01 -07001377 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun He984ff7e2014-03-30 12:40:27 -07001378 verifyFaceDetectionResults(listener, NUM_FACE_DETECTION_FRAMES_VERIFIED, mode);
1379 }
1380
1381 stopPreview();
1382 }
1383
1384 /**
1385 * Verify face detection results for different face detection modes.
1386 *
1387 * @param listener The listener to get capture result
1388 * @param numFramesVerified Number of results to be verified
1389 * @param faceDetectionMode Face detection mode to be verified against
1390 */
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001391 private void verifyFaceDetectionResults(SimpleCaptureCallback listener, int numFramesVerified,
Zhijun He984ff7e2014-03-30 12:40:27 -07001392 int faceDetectionMode) {
1393 for (int i = 0; i < numFramesVerified; i++) {
1394 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1395 mCollector.expectEquals("Result face detection mode should match the request",
1396 faceDetectionMode, result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE));
1397
1398 Face[] faces = result.get(CaptureResult.STATISTICS_FACES);
1399 List<Integer> faceIds = new ArrayList<Integer>(faces.length);
1400 List<Integer> faceScores = new ArrayList<Integer>(faces.length);
1401 if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_OFF) {
1402 mCollector.expectEquals("Number of detection faces should always 0 for OFF mode",
1403 0, faces.length);
1404 } else if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_SIMPLE) {
1405 for (Face face : faces) {
1406 mCollector.expectNotNull("Face rectangle shouldn't be null", face.getBounds());
1407 faceScores.add(face.getScore());
1408 mCollector.expectTrue("Face id is expected to be -1 for SIMPLE mode",
1409 face.getId() == Face.ID_UNSUPPORTED);
1410 }
1411 } else if (faceDetectionMode == CaptureResult.STATISTICS_FACE_DETECT_MODE_FULL) {
1412 if (VERBOSE) {
1413 Log.v(TAG, "Number of faces detected: " + faces.length);
1414 }
1415
1416 for (Face face : faces) {
Igor Murashkin8772d942014-07-31 15:53:01 -07001417 Rect faceBound;
Zhijun He984ff7e2014-03-30 12:40:27 -07001418 boolean faceRectAvailable = mCollector.expectTrue("Face rectangle "
1419 + "shouldn't be null", face.getBounds() != null);
1420 if (!faceRectAvailable) {
1421 continue;
1422 }
1423 faceBound = face.getBounds();
1424
1425 faceScores.add(face.getScore());
1426 faceIds.add(face.getId());
1427
1428 mCollector.expectTrue("Face id is shouldn't be -1 for FULL mode",
1429 face.getId() != Face.ID_UNSUPPORTED);
1430 boolean leftEyeAvailable =
1431 mCollector.expectTrue("Left eye position shouldn't be null",
1432 face.getLeftEyePosition() != null);
1433 boolean rightEyeAvailable =
1434 mCollector.expectTrue("Right eye position shouldn't be null",
1435 face.getRightEyePosition() != null);
1436 boolean mouthAvailable =
1437 mCollector.expectTrue("Mouth position shouldn't be null",
1438 face.getMouthPosition() != null);
1439 // Eyes/mouth position should be inside of the face rect.
1440 if (leftEyeAvailable) {
1441 Point leftEye = face.getLeftEyePosition();
Igor Murashkin8772d942014-07-31 15:53:01 -07001442 mCollector.expectTrue("Left eye " + leftEye + "should be"
1443 + "inside of face rect " + faceBound,
Zhijun He984ff7e2014-03-30 12:40:27 -07001444 faceBound.contains(leftEye.x, leftEye.y));
1445 }
1446 if (rightEyeAvailable) {
1447 Point rightEye = face.getRightEyePosition();
Igor Murashkin8772d942014-07-31 15:53:01 -07001448 mCollector.expectTrue("Right eye " + rightEye + "should be"
1449 + "inside of face rect " + faceBound,
Zhijun He984ff7e2014-03-30 12:40:27 -07001450 faceBound.contains(rightEye.x, rightEye.y));
1451 }
1452 if (mouthAvailable) {
1453 Point mouth = face.getMouthPosition();
Igor Murashkin8772d942014-07-31 15:53:01 -07001454 mCollector.expectTrue("Mouth " + mouth + " should be inside of"
1455 + " face rect " + faceBound,
Zhijun He984ff7e2014-03-30 12:40:27 -07001456 faceBound.contains(mouth.x, mouth.y));
1457 }
1458 }
1459 }
Yin-Chia Yeh0e0276f2015-06-03 15:27:06 -07001460 mCollector.expectValuesInRange("Face scores are invalid", faceScores,
Zhijun He984ff7e2014-03-30 12:40:27 -07001461 Face.SCORE_MIN, Face.SCORE_MAX);
1462 mCollector.expectValuesUnique("Face ids are invalid", faceIds);
1463 }
1464 }
1465
1466 /**
1467 * Test tone map mode and result by camera
1468 */
1469 private void toneMapTestByCamera() throws Exception {
Yin-Chia Yeh51fd46b2014-08-06 15:35:16 -07001470 if (!mStaticInfo.isManualToneMapSupported()) {
Zhijun He984ff7e2014-03-30 12:40:27 -07001471 return;
1472 }
1473
Zhijun He984ff7e2014-03-30 12:40:27 -07001474 CaptureRequest.Builder requestBuilder =
1475 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001476 int[] toneMapModes = mStaticInfo.getAvailableToneMapModesChecked();
1477 for (int mode : toneMapModes) {
Zhijun He984ff7e2014-03-30 12:40:27 -07001478 if (VERBOSE) {
1479 Log.v(TAG, "Testing tonemap mode " + mode);
1480 }
1481
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001482 requestBuilder.set(CaptureRequest.TONEMAP_MODE, mode);
1483 switch (mode) {
1484 case CaptureRequest.TONEMAP_MODE_CONTRAST_CURVE:
1485 TonemapCurve toneCurve = new TonemapCurve(TONEMAP_CURVE_LINEAR,
1486 TONEMAP_CURVE_LINEAR, TONEMAP_CURVE_LINEAR);
1487 requestBuilder.set(CaptureRequest.TONEMAP_CURVE, toneCurve);
1488 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
Zhijun He984ff7e2014-03-30 12:40:27 -07001489
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001490 toneCurve = new TonemapCurve(TONEMAP_CURVE_SRGB,
1491 TONEMAP_CURVE_SRGB, TONEMAP_CURVE_SRGB);
1492 requestBuilder.set(CaptureRequest.TONEMAP_CURVE, toneCurve);
1493 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1494 break;
1495 case CaptureRequest.TONEMAP_MODE_GAMMA_VALUE:
1496 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 1.0f);
1497 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1498 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 2.2f);
1499 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1500 requestBuilder.set(CaptureRequest.TONEMAP_GAMMA, 5.0f);
1501 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1502 break;
1503 case CaptureRequest.TONEMAP_MODE_PRESET_CURVE:
1504 requestBuilder.set(CaptureRequest.TONEMAP_PRESET_CURVE,
1505 CaptureRequest.TONEMAP_PRESET_CURVE_REC709);
1506 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1507 requestBuilder.set(CaptureRequest.TONEMAP_PRESET_CURVE,
1508 CaptureRequest.TONEMAP_PRESET_CURVE_SRGB);
1509 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1510 break;
1511 default:
1512 testToneMapMode(NUM_FRAMES_VERIFIED, requestBuilder);
1513 break;
Zhijun He984ff7e2014-03-30 12:40:27 -07001514 }
1515 }
1516
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001517
Zhijun He984ff7e2014-03-30 12:40:27 -07001518 }
1519
1520 /**
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001521 * Test tonemap mode with speficied request settings
Zhijun He984ff7e2014-03-30 12:40:27 -07001522 *
Zhijun He984ff7e2014-03-30 12:40:27 -07001523 * @param numFramesVerified Number of results to be verified
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001524 * @param requestBuilder the request builder of settings to be tested
Zhijun He984ff7e2014-03-30 12:40:27 -07001525 */
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001526 private void testToneMapMode (int numFramesVerified,
1527 CaptureRequest.Builder requestBuilder) throws Exception {
Zhijun He984ff7e2014-03-30 12:40:27 -07001528 final int MIN_TONEMAP_CURVE_POINTS = 2;
1529 final Float ZERO = new Float(0);
1530 final Float ONE = new Float(1.0f);
1531
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001532 SimpleCaptureCallback listener = new SimpleCaptureCallback();
1533 int tonemapMode = requestBuilder.get(CaptureRequest.TONEMAP_MODE);
1534 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
1535 startPreview(requestBuilder, maxPreviewSz, listener);
1536 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1537
Zhijun He984ff7e2014-03-30 12:40:27 -07001538 int maxCurvePoints = mStaticInfo.getMaxTonemapCurvePointChecked();
1539 for (int i = 0; i < numFramesVerified; i++) {
1540 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1541 mCollector.expectEquals("Capture result tonemap mode should match request", tonemapMode,
Igor Murashkin94399742014-05-19 16:38:37 -07001542 result.get(CaptureResult.TONEMAP_MODE));
Yin-Chia Yehbb247572014-05-27 10:20:54 -07001543 TonemapCurve tc = getValueNotNull(result, CaptureResult.TONEMAP_CURVE);
1544 int pointCount = tc.getPointCount(TonemapCurve.CHANNEL_RED);
1545 float[] mapRed = new float[pointCount * TonemapCurve.POINT_SIZE];
1546 pointCount = tc.getPointCount(TonemapCurve.CHANNEL_GREEN);
1547 float[] mapGreen = new float[pointCount * TonemapCurve.POINT_SIZE];
1548 pointCount = tc.getPointCount(TonemapCurve.CHANNEL_BLUE);
1549 float[] mapBlue = new float[pointCount * TonemapCurve.POINT_SIZE];
1550 tc.copyColorCurve(TonemapCurve.CHANNEL_RED, mapRed, 0);
1551 tc.copyColorCurve(TonemapCurve.CHANNEL_GREEN, mapGreen, 0);
1552 tc.copyColorCurve(TonemapCurve.CHANNEL_BLUE, mapBlue, 0);
Zhijun He984ff7e2014-03-30 12:40:27 -07001553 if (tonemapMode == CaptureResult.TONEMAP_MODE_CONTRAST_CURVE) {
1554 /**
1555 * TODO: need figure out a good way to measure the difference
1556 * between request and result, as they may have different array
1557 * size.
1558 */
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001559 } else if (tonemapMode == CaptureResult.TONEMAP_MODE_GAMMA_VALUE) {
1560 mCollector.expectEquals("Capture result gamma value should match request",
1561 requestBuilder.get(CaptureRequest.TONEMAP_GAMMA),
1562 result.get(CaptureResult.TONEMAP_GAMMA));
1563 } else if (tonemapMode == CaptureResult.TONEMAP_MODE_PRESET_CURVE) {
1564 mCollector.expectEquals("Capture result preset curve should match request",
1565 requestBuilder.get(CaptureRequest.TONEMAP_PRESET_CURVE),
1566 result.get(CaptureResult.TONEMAP_PRESET_CURVE));
Zhijun He984ff7e2014-03-30 12:40:27 -07001567 }
1568
1569 // Tonemap curve result availability and basic sanity check for all modes.
Yin-Chia Yehbb247572014-05-27 10:20:54 -07001570 mCollector.expectValuesInRange("Tonemap curve red values are out of range",
1571 CameraTestUtils.toObject(mapRed), /*min*/ZERO, /*max*/ONE);
1572 mCollector.expectInRange("Tonemap curve red length is out of range",
1573 mapRed.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2);
1574 mCollector.expectValuesInRange("Tonemap curve green values are out of range",
1575 CameraTestUtils.toObject(mapGreen), /*min*/ZERO, /*max*/ONE);
1576 mCollector.expectInRange("Tonemap curve green length is out of range",
1577 mapGreen.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2);
1578 mCollector.expectValuesInRange("Tonemap curve blue values are out of range",
1579 CameraTestUtils.toObject(mapBlue), /*min*/ZERO, /*max*/ONE);
1580 mCollector.expectInRange("Tonemap curve blue length is out of range",
1581 mapBlue.length, MIN_TONEMAP_CURVE_POINTS, maxCurvePoints * 2);
Zhijun He984ff7e2014-03-30 12:40:27 -07001582 }
Yin-Chia Yehb75fb1a2015-05-06 11:29:33 -07001583 stopPreview();
Zhijun He984ff7e2014-03-30 12:40:27 -07001584 }
1585
Zhijun Hed72b9502014-04-27 17:19:23 -07001586 /**
1587 * Test awb mode control.
1588 * <p>
1589 * Test each supported AWB mode, verify the AWB mode in capture result
1590 * matches request. When AWB is locked, the color correction gains and
1591 * transform should remain unchanged.
1592 * </p>
1593 */
1594 private void awbModeAndLockTestByCamera() throws Exception {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001595 int[] awbModes = mStaticInfo.getAwbAvailableModesChecked();
Zhijun Hed72b9502014-04-27 17:19:23 -07001596 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001597 boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
Zhijun Hed72b9502014-04-27 17:19:23 -07001598 CaptureRequest.Builder requestBuilder =
1599 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1600 startPreview(requestBuilder, maxPreviewSize, /*listener*/null);
1601
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001602 for (int mode : awbModes) {
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001603 SimpleCaptureCallback listener;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001604 requestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001605 listener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001606 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001607 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun Hed72b9502014-04-27 17:19:23 -07001608
1609 // Verify AWB mode in capture result.
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001610 verifyCaptureResultForKey(CaptureResult.CONTROL_AWB_MODE, mode, listener,
Zhijun Hed72b9502014-04-27 17:19:23 -07001611 NUM_FRAMES_VERIFIED);
1612
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001613 if (mode == CameraMetadata.CONTROL_AWB_MODE_AUTO && canSetAwbLock) {
Yin-Chia Yeh26024a62014-10-09 10:39:47 -07001614 // Verify color correction transform and gains stay unchanged after a lock.
1615 requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
1616 listener = new SimpleCaptureCallback();
1617 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
1618 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001619
Yin-Chia Yeh26024a62014-10-09 10:39:47 -07001620 if (mStaticInfo.areKeysAvailable(CaptureResult.CONTROL_AWB_STATE)) {
1621 waitForResultValue(listener, CaptureResult.CONTROL_AWB_STATE,
1622 CaptureResult.CONTROL_AWB_STATE_LOCKED, NUM_RESULTS_WAIT_TIMEOUT);
1623 }
1624
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001625 }
Yin-Chia Yeh9c0d9262015-04-03 17:02:13 -07001626 // Don't verify auto mode result if AWB lock is not supported
1627 if (mode != CameraMetadata.CONTROL_AWB_MODE_AUTO || canSetAwbLock) {
1628 verifyAwbCaptureResultUnchanged(listener, NUM_FRAMES_VERIFIED);
1629 }
Zhijun Hed72b9502014-04-27 17:19:23 -07001630 }
1631 }
1632
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001633 private void verifyAwbCaptureResultUnchanged(SimpleCaptureCallback listener,
Zhijun Hed72b9502014-04-27 17:19:23 -07001634 int numFramesVerified) {
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001635 // Skip check if cc gains/transform/mode are not available
1636 if (!mStaticInfo.areKeysAvailable(
1637 CaptureResult.COLOR_CORRECTION_GAINS,
1638 CaptureResult.COLOR_CORRECTION_TRANSFORM,
1639 CaptureResult.COLOR_CORRECTION_MODE)) {
1640 return;
1641 }
1642
Zhijun Hed72b9502014-04-27 17:19:23 -07001643 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001644 RggbChannelVector lockedGains =
1645 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_GAINS);
1646 ColorSpaceTransform lockedTransform =
Zhijun Hed72b9502014-04-27 17:19:23 -07001647 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_TRANSFORM);
1648
1649 for (int i = 0; i < numFramesVerified; i++) {
1650 result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Zhijun He92b56772014-05-31 08:36:31 -07001651 // Color correction mode check is skipped here, as it is checked in colorCorrectionTest.
1652 validateColorCorrectionResult(result, result.get(CaptureResult.COLOR_CORRECTION_MODE));
Zhijun Hed72b9502014-04-27 17:19:23 -07001653
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001654 RggbChannelVector gains = getValueNotNull(result, CaptureResult.COLOR_CORRECTION_GAINS);
1655 ColorSpaceTransform transform =
Zhijun Hed72b9502014-04-27 17:19:23 -07001656 getValueNotNull(result, CaptureResult.COLOR_CORRECTION_TRANSFORM);
1657 mCollector.expectEquals("Color correction gains should remain unchanged after awb lock",
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001658 lockedGains, gains);
Zhijun Hed72b9502014-04-27 17:19:23 -07001659 mCollector.expectEquals("Color correction transform should remain unchanged after"
1660 + " awb lock", lockedTransform, transform);
1661 }
1662 }
1663
1664 /**
1665 * Test AF mode control.
1666 * <p>
1667 * Test all supported AF modes, verify the AF mode in capture result matches
1668 * request. When AF mode is one of the CONTROL_AF_MODE_CONTINUOUS_* mode,
1669 * verify if the AF can converge to PASSIVE_FOCUSED or PASSIVE_UNFOCUSED
1670 * state within certain amount of frames.
1671 * </p>
1672 */
1673 private void afModeTestByCamera() throws Exception {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001674 int[] afModes = mStaticInfo.getAfAvailableModesChecked();
Zhijun Hed72b9502014-04-27 17:19:23 -07001675 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
1676 CaptureRequest.Builder requestBuilder =
1677 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1678 startPreview(requestBuilder, maxPreviewSize, /*listener*/null);
1679
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001680 for (int mode : afModes) {
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001681 SimpleCaptureCallback listener;
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001682 requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001683 listener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001684 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Igor Murashkin6ab7dc52014-07-29 18:38:41 -07001685 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Zhijun Hed72b9502014-04-27 17:19:23 -07001686
1687 // Verify AF mode in capture result.
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001688 verifyCaptureResultForKey(CaptureResult.CONTROL_AF_MODE, mode, listener,
Zhijun Hed72b9502014-04-27 17:19:23 -07001689 NUM_FRAMES_VERIFIED);
1690
Ruben Brunk30033ae2014-09-22 15:29:24 -07001691 // Verify AF can finish a scan for CONTROL_AF_MODE_CONTINUOUS_* modes.
1692 // In LEGACY mode, a transition to one of the continuous AF modes does not necessarily
1693 // result in a passive AF call if the camera has already been focused, and the scene has
1694 // not changed enough to trigger an AF pass. Skip this constraint for LEGACY.
1695 if (mStaticInfo.isHardwareLevelLimitedOrBetter() &&
1696 (mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE ||
1697 mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
Zhijun Hed72b9502014-04-27 17:19:23 -07001698 List<Integer> afStateList = new ArrayList<Integer>();
1699 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED);
1700 afStateList.add(CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED);
1701 waitForAnyResultValue(listener, CaptureResult.CONTROL_AF_STATE, afStateList,
1702 NUM_RESULTS_WAIT_TIMEOUT);
1703 }
1704 }
1705 }
1706
Zhijun He68f3ecf2014-04-29 17:11:32 -07001707 /**
1708 * Test video and optical stabilizations if they are supported by a given camera.
1709 */
1710 private void stabilizationTestByCamera() throws Exception {
1711 // video stabilization test.
Ruben Brunk88470e42014-07-23 15:55:14 -07001712 List<Key<?>> keys = mStaticInfo.getCharacteristics().getKeys();
1713
1714 int[] videoStabModes = (keys.contains(CameraCharacteristics.
1715 CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) ?
1716 mStaticInfo.getAvailableVideoStabilizationModesChecked() : new int[0];
1717 int[] opticalStabModes = (keys.contains(
1718 CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)) ?
1719 mStaticInfo.getAvailableOpticalStabilizationChecked() : new int[0];
1720
Zhijun He68f3ecf2014-04-29 17:11:32 -07001721 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
1722 CaptureRequest.Builder requestBuilder =
1723 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001724 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He68f3ecf2014-04-29 17:11:32 -07001725 startPreview(requestBuilder, maxPreviewSize, listener);
1726
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001727 for (int mode : videoStabModes) {
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001728 listener = new SimpleCaptureCallback();
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001729 requestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, mode);
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001730 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -07001731 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Igor Murashkin9662a562014-07-07 14:30:49 -07001732 verifyCaptureResultForKey(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE, mode,
Zhijun He68f3ecf2014-04-29 17:11:32 -07001733 listener, NUM_FRAMES_VERIFIED);
Zhijun He68f3ecf2014-04-29 17:11:32 -07001734 }
1735
1736 for (int mode : opticalStabModes) {
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001737 listener = new SimpleCaptureCallback();
Igor Murashkin94399742014-05-19 16:38:37 -07001738 requestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE, mode);
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001739 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Ruben Brunk88470e42014-07-23 15:55:14 -07001740 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Igor Murashkin94399742014-05-19 16:38:37 -07001741 verifyCaptureResultForKey(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE, mode,
Zhijun He68f3ecf2014-04-29 17:11:32 -07001742 listener, NUM_FRAMES_VERIFIED);
1743 }
1744
1745 stopPreview();
1746 }
1747
Zhijun He86ece7d2014-05-15 14:13:58 -07001748 private void digitalZoomTestByCamera(Size previewSize) throws Exception {
Zhijun He919306b2014-08-21 20:01:33 -07001749 final int ZOOM_STEPS = 15;
Igor Murashkin9662a562014-07-07 14:30:49 -07001750 final PointF[] TEST_ZOOM_CENTERS;
1751
1752 final int croppingType = mStaticInfo.getScalerCroppingTypeChecked();
1753 if (croppingType ==
1754 CameraCharacteristics.SCALER_CROPPING_TYPE_FREEFORM) {
1755 TEST_ZOOM_CENTERS = new PointF[] {
Zhijun Hedba6dd12014-04-29 18:41:49 -07001756 new PointF(0.5f, 0.5f), // Center point
1757 new PointF(0.25f, 0.25f), // top left corner zoom, minimal zoom: 2x
1758 new PointF(0.75f, 0.25f), // top right corner zoom, minimal zoom: 2x
1759 new PointF(0.25f, 0.75f), // bottom left corner zoom, minimal zoom: 2x
1760 new PointF(0.75f, 0.75f), // bottom right corner zoom, minimal zoom: 2x
Igor Murashkin9662a562014-07-07 14:30:49 -07001761 };
1762
1763 if (VERBOSE) {
1764 Log.v(TAG, "Testing zoom with CROPPING_TYPE = FREEFORM");
1765 }
1766 } else {
1767 // CENTER_ONLY
1768 TEST_ZOOM_CENTERS = new PointF[] {
1769 new PointF(0.5f, 0.5f), // Center point
1770 };
1771
1772 if (VERBOSE) {
1773 Log.v(TAG, "Testing zoom with CROPPING_TYPE = CENTER_ONLY");
1774 }
1775 }
1776
Zhijun Hedba6dd12014-04-29 18:41:49 -07001777 final float maxZoom = mStaticInfo.getAvailableMaxDigitalZoomChecked();
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001778 final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
1779 Rect[] cropRegions = new Rect[ZOOM_STEPS];
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07001780 MeteringRectangle[][] expectRegions = new MeteringRectangle[ZOOM_STEPS][];
Zhijun Hedba6dd12014-04-29 18:41:49 -07001781 CaptureRequest.Builder requestBuilder =
1782 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001783 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He919306b2014-08-21 20:01:33 -07001784
1785 updatePreviewSurface(previewSize);
1786 configurePreviewOutput(requestBuilder);
1787
Zhijun Hedba6dd12014-04-29 18:41:49 -07001788 CaptureRequest[] requests = new CaptureRequest[ZOOM_STEPS];
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001789
1790 // Set algorithm regions to full active region
1791 // TODO: test more different 3A regions
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07001792 final MeteringRectangle[] defaultMeteringRect = new MeteringRectangle[] {
1793 new MeteringRectangle (
Igor Murashkin9662a562014-07-07 14:30:49 -07001794 /*x*/0, /*y*/0, activeArraySize.width(), activeArraySize.height(),
1795 /*meteringWeight*/1)
1796 };
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001797
1798 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07001799 update3aRegion(requestBuilder, algo, defaultMeteringRect);
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001800 }
Zhijun Hedba6dd12014-04-29 18:41:49 -07001801
Igor Murashkin9662a562014-07-07 14:30:49 -07001802 final int CAPTURE_SUBMIT_REPEAT;
1803 {
1804 int maxLatency = mStaticInfo.getSyncMaxLatency();
1805 if (maxLatency == CameraMetadata.SYNC_MAX_LATENCY_UNKNOWN) {
1806 CAPTURE_SUBMIT_REPEAT = NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY + 1;
1807 } else {
1808 CAPTURE_SUBMIT_REPEAT = maxLatency + 1;
1809 }
1810 }
1811
1812 if (VERBOSE) {
1813 Log.v(TAG, "Testing zoom with CAPTURE_SUBMIT_REPEAT = " + CAPTURE_SUBMIT_REPEAT);
1814 }
1815
Zhijun Hedba6dd12014-04-29 18:41:49 -07001816 for (PointF center : TEST_ZOOM_CENTERS) {
Igor Murashkin9662a562014-07-07 14:30:49 -07001817 Rect previousCrop = null;
1818
Zhijun Hedba6dd12014-04-29 18:41:49 -07001819 for (int i = 0; i < ZOOM_STEPS; i++) {
Igor Murashkin9662a562014-07-07 14:30:49 -07001820 /*
1821 * Submit capture request
1822 */
Zhijun Hedba6dd12014-04-29 18:41:49 -07001823 float zoomFactor = (float) (1.0f + (maxZoom - 1.0) * i / ZOOM_STEPS);
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001824 cropRegions[i] = getCropRegionForZoom(zoomFactor, center, maxZoom, activeArraySize);
Zhijun Hedba6dd12014-04-29 18:41:49 -07001825 if (VERBOSE) {
1826 Log.v(TAG, "Testing Zoom for factor " + zoomFactor + " and center " +
Zhijun He86ece7d2014-05-15 14:13:58 -07001827 center + " The cropRegion is " + cropRegions[i] +
1828 " Preview size is " + previewSize);
Zhijun Hedba6dd12014-04-29 18:41:49 -07001829 }
1830 requestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegions[i]);
1831 requests[i] = requestBuilder.build();
Igor Murashkin9662a562014-07-07 14:30:49 -07001832 for (int j = 0; j < CAPTURE_SUBMIT_REPEAT; ++j) {
Zhijun He919306b2014-08-21 20:01:33 -07001833 if (VERBOSE) {
1834 Log.v(TAG, "submit crop region " + cropRegions[i]);
1835 }
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001836 mSession.capture(requests[i], listener, mHandler);
Igor Murashkin9662a562014-07-07 14:30:49 -07001837 }
1838
1839 /*
1840 * Validate capture result
1841 */
1842 waitForNumResults(listener, CAPTURE_SUBMIT_REPEAT - 1); // Drop first few frames
1843 CaptureResult result = listener.getCaptureResultForRequest(
1844 requests[i], NUM_RESULTS_WAIT_TIMEOUT);
1845 Rect cropRegion = getValueNotNull(result, CaptureResult.SCALER_CROP_REGION);
1846
1847 /*
1848 * Validate resulting crop regions
1849 */
1850 if (previousCrop != null) {
1851 Rect currentCrop = cropRegion;
1852 mCollector.expectTrue(String.format(
1853 "Crop region should shrink or stay the same " +
1854 "(previous = %s, current = %s)",
1855 previousCrop, currentCrop),
1856 previousCrop.equals(currentCrop) ||
1857 (previousCrop.width() > currentCrop.width() &&
1858 previousCrop.height() > currentCrop.height()));
1859 }
1860
1861 if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
1862 mCollector.expectRectsAreSimilar(
1863 "Request and result crop region should be similar",
1864 cropRegions[i], cropRegion, CROP_REGION_ERROR_PERCENT_DELTA);
1865 }
1866
1867 if (croppingType == SCALER_CROPPING_TYPE_CENTER_ONLY) {
1868 mCollector.expectRectCentered(
1869 "Result crop region should be centered inside the active array",
1870 new Size(activeArraySize.width(), activeArraySize.height()),
1871 cropRegion, CROP_REGION_ERROR_PERCENT_CENTERED);
1872 }
1873
1874 /*
1875 * Validate resulting metering regions
1876 */
1877
1878 // Use the actual reported crop region to calculate the resulting metering region
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07001879 expectRegions[i] = getExpectedOutputRegion(
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07001880 /*requestRegion*/defaultMeteringRect,
Igor Murashkin9662a562014-07-07 14:30:49 -07001881 /*cropRect*/ cropRegion);
1882
1883 // Verify Output 3A region is intersection of input 3A region and crop region
1884 for (int algo = 0; algo < NUM_ALGORITHMS; algo++) {
1885 validate3aRegion(result, algo, expectRegions[i]);
1886 }
1887
1888 previousCrop = cropRegion;
Zhijun Hedba6dd12014-04-29 18:41:49 -07001889 }
1890
Igor Murashkin9662a562014-07-07 14:30:49 -07001891 if (maxZoom > 1.0f) {
1892 mCollector.expectTrue(
1893 String.format("Most zoomed-in crop region should be smaller" +
1894 "than active array w/h" +
1895 "(last crop = %s, active array = %s)",
1896 previousCrop, activeArraySize),
1897 (previousCrop.width() < activeArraySize.width() &&
1898 previousCrop.height() < activeArraySize.height()));
Zhijun Hedba6dd12014-04-29 18:41:49 -07001899 }
1900 }
Zhijun Hedba6dd12014-04-29 18:41:49 -07001901 }
1902
Zhijun He86ece7d2014-05-15 14:13:58 -07001903 private void digitalZoomPreviewCombinationTestByCamera() throws Exception {
Zhijun He919306b2014-08-21 20:01:33 -07001904 final double ASPECT_RATIO_THRESHOLD = 0.001;
1905 List<Double> aspectRatiosTested = new ArrayList<Double>();
1906 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
1907 aspectRatiosTested.add((double)(maxPreviewSize.getWidth()) / maxPreviewSize.getHeight());
1908
Zhijun He86ece7d2014-05-15 14:13:58 -07001909 for (Size size : mOrderedPreviewSizes) {
Zhijun He919306b2014-08-21 20:01:33 -07001910 // Max preview size was already tested in testDigitalZoom test. skip it.
1911 if (size.equals(maxPreviewSize)) {
1912 continue;
1913 }
1914
1915 // Only test the largest size for each aspect ratio.
1916 double aspectRatio = (double)(size.getWidth()) / size.getHeight();
1917 if (isAspectRatioContained(aspectRatiosTested, aspectRatio, ASPECT_RATIO_THRESHOLD)) {
1918 continue;
1919 }
1920
Zhijun He86ece7d2014-05-15 14:13:58 -07001921 if (VERBOSE) {
1922 Log.v(TAG, "Test preview size " + size.toString() + " digital zoom");
1923 }
1924
Zhijun He919306b2014-08-21 20:01:33 -07001925 aspectRatiosTested.add(aspectRatio);
Zhijun He86ece7d2014-05-15 14:13:58 -07001926 digitalZoomTestByCamera(size);
1927 }
1928 }
1929
Zhijun He919306b2014-08-21 20:01:33 -07001930 private static boolean isAspectRatioContained(List<Double> aspectRatioList,
1931 double aspectRatio, double delta) {
1932 for (Double ratio : aspectRatioList) {
1933 if (Math.abs(ratio - aspectRatio) < delta) {
1934 return true;
1935 }
1936 }
1937
1938 return false;
1939 }
1940
Zhijun He496c0c72014-04-30 17:52:17 -07001941 private void sceneModeTestByCamera() throws Exception {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001942 int[] sceneModes = mStaticInfo.getAvailableSceneModesChecked();
Zhijun He496c0c72014-04-30 17:52:17 -07001943 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
1944 CaptureRequest.Builder requestBuilder =
1945 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001946 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He496c0c72014-04-30 17:52:17 -07001947 requestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_USE_SCENE_MODE);
1948 startPreview(requestBuilder, maxPreviewSize, listener);
1949
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001950 for(int mode : sceneModes) {
1951 requestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001952 listener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001953 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Ruben Brunk33bc28f2014-07-29 10:33:26 -07001954 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1955
Zhijun He496c0c72014-04-30 17:52:17 -07001956 verifyCaptureResultForKey(CaptureResult.CONTROL_SCENE_MODE,
Zhijun He92b56772014-05-31 08:36:31 -07001957 mode, listener, NUM_FRAMES_VERIFIED);
Zhijun He496c0c72014-04-30 17:52:17 -07001958 // This also serves as purpose of showing preview for NUM_FRAMES_VERIFIED
1959 verifyCaptureResultForKey(CaptureResult.CONTROL_MODE,
1960 CaptureRequest.CONTROL_MODE_USE_SCENE_MODE, listener, NUM_FRAMES_VERIFIED);
1961 }
1962 }
1963
1964 private void effectModeTestByCamera() throws Exception {
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001965 int[] effectModes = mStaticInfo.getAvailableEffectModesChecked();
Zhijun He496c0c72014-04-30 17:52:17 -07001966 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
1967 CaptureRequest.Builder requestBuilder =
1968 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1969 requestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001970 SimpleCaptureCallback listener = new SimpleCaptureCallback();
Zhijun He496c0c72014-04-30 17:52:17 -07001971 startPreview(requestBuilder, maxPreviewSize, listener);
1972
Eino-Ville Talvala46bb9762014-05-25 21:33:49 -07001973 for(int mode : effectModes) {
1974 requestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, mode);
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07001975 listener = new SimpleCaptureCallback();
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07001976 mSession.setRepeatingRequest(requestBuilder.build(), listener, mHandler);
Ruben Brunk33bc28f2014-07-29 10:33:26 -07001977 waitForSettingsApplied(listener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1978
Zhijun He92b56772014-05-31 08:36:31 -07001979 verifyCaptureResultForKey(CaptureResult.CONTROL_EFFECT_MODE,
1980 mode, listener, NUM_FRAMES_VERIFIED);
Zhijun He496c0c72014-04-30 17:52:17 -07001981 // This also serves as purpose of showing preview for NUM_FRAMES_VERIFIED
1982 verifyCaptureResultForKey(CaptureResult.CONTROL_MODE,
1983 CaptureRequest.CONTROL_MODE_AUTO, listener, NUM_FRAMES_VERIFIED);
1984 }
1985 }
1986
Zhijun He28f2b3e2014-02-26 14:15:18 -08001987 //----------------------------------------------------------------
1988 //---------Below are common functions for all tests.--------------
1989 //----------------------------------------------------------------
1990
1991 /**
1992 * Enable exposure manual control and change exposure and sensitivity and
1993 * clamp the value into the supported range.
1994 */
1995 private void changeExposure(CaptureRequest.Builder requestBuilder,
1996 long expTime, int sensitivity) {
Zhijun Hedba6dd12014-04-29 18:41:49 -07001997 // Check if the max analog sensitivity is available and no larger than max sensitivity.
1998 // The max analog sensitivity is not actually used here. This is only an extra sanity check.
1999 mStaticInfo.getMaxAnalogSensitivityChecked();
2000
Zhijun He28f2b3e2014-02-26 14:15:18 -08002001 expTime = mStaticInfo.getExposureClampToRange(expTime);
2002 sensitivity = mStaticInfo.getSensitivityClampToRange(sensitivity);
2003
2004 requestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF);
2005 requestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, expTime);
2006 requestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, sensitivity);
2007 }
Zhijun He5f4d0082014-03-19 23:02:03 -07002008 /**
2009 * Enable exposure manual control and change exposure time and
2010 * clamp the value into the supported range.
2011 *
2012 * <p>The sensitivity is set to default value.</p>
2013 */
2014 private void changeExposure(CaptureRequest.Builder requestBuilder, long expTime) {
2015 changeExposure(requestBuilder, expTime, DEFAULT_SENSITIVITY);
2016 }
2017
2018 /**
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002019 * Get the exposure time array that contains multiple exposure time steps in
2020 * the exposure time range.
2021 */
2022 private long[] getExposureTimeTestValues() {
2023 long[] testValues = new long[DEFAULT_NUM_EXPOSURE_TIME_STEPS + 1];
2024 long maxExpTime = mStaticInfo.getExposureMaximumOrDefault(DEFAULT_EXP_TIME_NS);
Yin-Chia Yehd0edc5c2015-08-24 12:15:31 -07002025 long minExpTime = mStaticInfo.getExposureMinimumOrDefault(DEFAULT_EXP_TIME_NS);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002026
Yin-Chia Yehd0edc5c2015-08-24 12:15:31 -07002027 long range = maxExpTime - minExpTime;
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002028 double stepSize = range / (double)DEFAULT_NUM_EXPOSURE_TIME_STEPS;
2029 for (int i = 0; i < testValues.length; i++) {
Yin-Chia Yehd0edc5c2015-08-24 12:15:31 -07002030 testValues[i] = maxExpTime - (long)(stepSize * i);
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002031 testValues[i] = mStaticInfo.getExposureClampToRange(testValues[i]);
2032 }
2033
2034 return testValues;
2035 }
2036
2037 /**
Zhijun Hef2d26f12014-04-14 10:36:55 -07002038 * Generate test focus distances in range of [0, minFocusDistance] in increasing order.
2039 */
2040 private float[] getFocusDistanceTestValuesInOrder() {
2041 float[] testValues = new float[NUM_TEST_FOCUS_DISTANCES + 1];
2042 float minValue = 0;
2043 float maxValue = mStaticInfo.getMinimumFocusDistanceChecked();
2044
2045 float range = maxValue - minValue;
2046 float stepSize = range / NUM_TEST_FOCUS_DISTANCES;
2047 for (int i = 0; i < testValues.length; i++) {
2048 testValues[i] = minValue + stepSize * i;
2049 }
2050
2051 return testValues;
2052 }
2053
2054 /**
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002055 * Get the sensitivity array that contains multiple sensitivity steps in the
2056 * sensitivity range.
2057 * <p>
2058 * Sensitivity number of test values is determined by
2059 * {@value #DEFAULT_SENSITIVITY_STEP_SIZE} and sensitivity range, and
2060 * bounded by {@value #DEFAULT_NUM_SENSITIVITY_STEPS}.
2061 * </p>
2062 */
2063 private int[] getSensitivityTestValues() {
2064 int maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault(
2065 DEFAULT_SENSITIVITY);
2066 int minSensitivity = mStaticInfo.getSensitivityMinimumOrDefault(
2067 DEFAULT_SENSITIVITY);
2068
2069 int range = maxSensitivity - minSensitivity;
2070 int stepSize = DEFAULT_SENSITIVITY_STEP_SIZE;
2071 int numSteps = range / stepSize;
2072 // Bound the test steps to avoid supper long test.
2073 if (numSteps > DEFAULT_NUM_SENSITIVITY_STEPS) {
2074 numSteps = DEFAULT_NUM_SENSITIVITY_STEPS;
2075 stepSize = range / numSteps;
2076 }
2077 int[] testValues = new int[numSteps + 1];
2078 for (int i = 0; i < testValues.length; i++) {
Yin-Chia Yehd0edc5c2015-08-24 12:15:31 -07002079 testValues[i] = maxSensitivity - stepSize * i;
Zhijun He8c8fb1e2014-03-20 14:57:48 -07002080 testValues[i] = mStaticInfo.getSensitivityClampToRange(testValues[i]);
2081 }
2082
2083 return testValues;
2084 }
2085
2086 /**
2087 * Validate the AE manual control exposure time.
2088 *
2089 * <p>Exposure should be close enough, and only round down if they are not equal.</p>
2090 *
2091 * @param request Request exposure time
2092 * @param result Result exposure time
2093 */
2094 private void validateExposureTime(long request, long result) {
2095 long expTimeDelta = request - result;
2096 // First, round down not up, second, need close enough.
2097 mCollector.expectTrue("Exposture time is invalid for AE manaul control test, request: "
2098 + request + " result: " + result,
2099 expTimeDelta < EXPOSURE_TIME_ERROR_MARGIN_NS && expTimeDelta >= 0);
2100 }
2101
2102 /**
2103 * Validate AE manual control sensitivity.
2104 *
2105 * @param request Request sensitivity
2106 * @param result Result sensitivity
2107 */
2108 private void validateSensitivity(int request, int result) {
2109 int sensitivityDelta = request - result;
2110 // First, round down not up, second, need close enough.
2111 mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: "
2112 + request + " result: " + result,
2113 sensitivityDelta < SENSITIVITY_ERROR_MARGIN && sensitivityDelta >= 0);
2114 }
2115
Zhijun He984ff7e2014-03-30 12:40:27 -07002116 /**
2117 * Validate frame duration for a given capture.
2118 *
2119 * <p>Frame duration should be longer than exposure time.</p>
2120 *
2121 * @param result The capture result for a given capture
2122 */
2123 private void validateFrameDurationForCapture(CaptureResult result) {
2124 long expTime = getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME);
2125 long frameDuration = getValueNotNull(result, CaptureResult.SENSOR_FRAME_DURATION);
2126 if (VERBOSE) {
2127 Log.v(TAG, "frame duration: " + frameDuration + " Exposure time: " + expTime);
2128 }
2129
2130 mCollector.expectTrue(String.format("Frame duration (%d) should be longer than exposure"
2131 + " time (%d) for a given capture", frameDuration, expTime),
Zhijun Hef2d26f12014-04-14 10:36:55 -07002132 frameDuration >= expTime);
Zhijun He98dc8f92014-05-13 17:29:01 -07002133
2134 validatePipelineDepth(result);
Zhijun He984ff7e2014-03-30 12:40:27 -07002135 }
2136
Zhijun He99211e42014-04-17 19:09:36 -07002137 /**
2138 * Basic verification for the control mode capture result.
2139 *
2140 * @param key The capture result key to be verified against
2141 * @param requestMode The request mode for this result
2142 * @param listener The capture listener to get capture results
2143 * @param numFramesVerified The number of capture results to be verified
2144 */
Igor Murashkin94399742014-05-19 16:38:37 -07002145 private <T> void verifyCaptureResultForKey(CaptureResult.Key<T> key, T requestMode,
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07002146 SimpleCaptureCallback listener, int numFramesVerified) {
Zhijun He99211e42014-04-17 19:09:36 -07002147 for (int i = 0; i < numFramesVerified; i++) {
2148 CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Zhijun He98dc8f92014-05-13 17:29:01 -07002149 validatePipelineDepth(result);
Zhijun He99211e42014-04-17 19:09:36 -07002150 T resultMode = getValueNotNull(result, key);
Zhijun Hed72b9502014-04-27 17:19:23 -07002151 if (VERBOSE) {
2152 Log.v(TAG, "Expect value: " + requestMode.toString() + " result value: "
2153 + resultMode.toString());
2154 }
Zhijun He99211e42014-04-17 19:09:36 -07002155 mCollector.expectEquals("Key " + key.getName() + " result should match request",
2156 requestMode, resultMode);
2157 }
2158 }
2159
2160 /**
2161 * Verify if the fps is slow down for given input request with certain
2162 * controls inside.
2163 * <p>
2164 * This method selects a max preview size for each fps range, and then
2165 * configure the preview stream. Preview is started with the max preview
2166 * size, and then verify if the result frame duration is in the frame
2167 * duration range.
2168 * </p>
2169 *
2170 * @param requestBuilder The request builder that contains post-processing
2171 * controls that could impact the output frame rate, such as
2172 * {@link CaptureRequest.NOISE_REDUCTION_MODE}. The value of
2173 * these controls must be set to some values such that the frame
2174 * rate is not slow down.
2175 * @param numFramesVerified The number of frames to be verified
2176 */
2177 private void verifyFpsNotSlowDown(CaptureRequest.Builder requestBuilder,
2178 int numFramesVerified) throws Exception {
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002179 boolean frameDurationAvailable = true;
2180 // Allow a few frames for AE to settle on target FPS range
2181 final int NUM_FRAME_TO_SKIP = 6;
2182 float frameDurationErrorMargin = FRAME_DURATION_ERROR_MARGIN;
2183 if (!mStaticInfo.areKeysAvailable(CaptureResult.SENSOR_FRAME_DURATION)) {
2184 frameDurationAvailable = false;
2185 // Allow a larger error margin (1.5%) for timestamps
2186 frameDurationErrorMargin = 0.015f;
2187 }
2188
Igor Murashkina6e6d532014-05-27 18:31:34 -07002189 Range<Integer>[] fpsRanges = mStaticInfo.getAeAvailableTargetFpsRangesChecked();
Zhijun He45942de2014-05-13 12:48:27 -07002190 boolean antiBandingOffIsSupported = mStaticInfo.isAntiBandingOffModeSupported();
Igor Murashkina6e6d532014-05-27 18:31:34 -07002191 Range<Integer> fpsRange;
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07002192 SimpleCaptureCallback resultListener;
Zhijun He99211e42014-04-17 19:09:36 -07002193
Igor Murashkina6e6d532014-05-27 18:31:34 -07002194 for (int i = 0; i < fpsRanges.length; i += 1) {
2195 fpsRange = fpsRanges[i];
Zhijun He99211e42014-04-17 19:09:36 -07002196 Size previewSz = getMaxPreviewSizeForFpsRange(fpsRange);
2197 // If unable to find a preview size, then log the failure, and skip this run.
Yin-Chia Yeh47be9f82014-09-22 12:43:55 -07002198 if (previewSz == null) {
2199 if (mStaticInfo.isCapabilitySupported(
Yin-Chia Yeha7954432014-09-21 14:58:00 -07002200 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
Yin-Chia Yeh47be9f82014-09-22 12:43:55 -07002201 mCollector.addMessage(String.format(
2202 "Unable to find a preview size supporting given fps range %s",
2203 fpsRange));
2204 }
Zhijun He99211e42014-04-17 19:09:36 -07002205 continue;
2206 }
2207
2208 if (VERBOSE) {
Igor Murashkina6e6d532014-05-27 18:31:34 -07002209 Log.v(TAG, String.format("Test fps range %s for preview size %s",
2210 fpsRange, previewSz.toString()));
Zhijun He99211e42014-04-17 19:09:36 -07002211 }
2212 requestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
Zhijun He45942de2014-05-13 12:48:27 -07002213 // Turn off auto antibanding to avoid exposure time and frame duration interference
2214 // from antibanding algorithm.
2215 if (antiBandingOffIsSupported) {
2216 requestBuilder.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
2217 CaptureRequest.CONTROL_AE_ANTIBANDING_MODE_OFF);
2218 } else {
2219 // The device doesn't implement the OFF mode, test continues. It need make sure
2220 // that the antibanding algorithm doesn't slow down the fps.
2221 Log.i(TAG, "OFF antibanding mode is not supported, the camera device output must" +
2222 " not slow down the frame rate regardless of its current antibanding" +
2223 " mode");
2224 }
2225
Eino-Ville Talvalac0dd0222014-09-04 15:07:58 -07002226 resultListener = new SimpleCaptureCallback();
Zhijun He99211e42014-04-17 19:09:36 -07002227 startPreview(requestBuilder, previewSz, resultListener);
Yin-Chia Yeh15e63b32014-11-24 15:16:49 -08002228 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002229 // Wait several more frames for AE to settle on target FPS range
2230 waitForNumResults(resultListener, NUM_FRAME_TO_SKIP);
Yin-Chia Yeh15e63b32014-11-24 15:16:49 -08002231
2232 long[] frameDurationRange = new long[]{
2233 (long) (1e9 / fpsRange.getUpper()), (long) (1e9 / fpsRange.getLower())};
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002234 long captureTime = 0, prevCaptureTime = 0;
Zhijun He99211e42014-04-17 19:09:36 -07002235 for (int j = 0; j < numFramesVerified; j++) {
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002236 long frameDuration = frameDurationRange[0];
Zhijun He99211e42014-04-17 19:09:36 -07002237 CaptureResult result =
2238 resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
Zhijun He98dc8f92014-05-13 17:29:01 -07002239 validatePipelineDepth(result);
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002240 if (frameDurationAvailable) {
2241 frameDuration = getValueNotNull(result, CaptureResult.SENSOR_FRAME_DURATION);
2242 } else {
2243 // if frame duration is not available, check timestamp instead
2244 captureTime = getValueNotNull(result, CaptureResult.SENSOR_TIMESTAMP);
2245 if (j > 0) {
2246 frameDuration = captureTime - prevCaptureTime;
2247 }
2248 prevCaptureTime = captureTime;
2249 }
Zhijun He99211e42014-04-17 19:09:36 -07002250 mCollector.expectInRange(
Yin-Chia Yeh15e63b32014-11-24 15:16:49 -08002251 "Frame duration must be in the range of " +
2252 Arrays.toString(frameDurationRange),
Zhijun He99211e42014-04-17 19:09:36 -07002253 frameDuration,
Yin-Chia Yehc8dd8032015-03-25 11:45:48 -07002254 (long) (frameDurationRange[0] * (1 - frameDurationErrorMargin)),
2255 (long) (frameDurationRange[1] * (1 + frameDurationErrorMargin)));
Zhijun He99211e42014-04-17 19:09:36 -07002256 }
2257 }
2258
Eino-Ville Talvalab80c6612014-07-06 17:58:46 -07002259 mSession.stopRepeating();
Zhijun He99211e42014-04-17 19:09:36 -07002260 }
Zhijun He7e80fe92014-04-24 15:46:41 -07002261
2262 /**
Zhijun He98dc8f92014-05-13 17:29:01 -07002263 * Validate the pipeline depth result.
2264 *
2265 * @param result The capture result to get pipeline depth data
2266 */
2267 private void validatePipelineDepth(CaptureResult result) {
2268 final byte MIN_PIPELINE_DEPTH = 1;
2269 byte maxPipelineDepth = mStaticInfo.getPipelineMaxDepthChecked();
2270 Byte pipelineDepth = getValueNotNull(result, CaptureResult.REQUEST_PIPELINE_DEPTH);
2271 mCollector.expectInRange(String.format("Pipeline depth must be in the range of [%d, %d]",
2272 MIN_PIPELINE_DEPTH, maxPipelineDepth), pipelineDepth, MIN_PIPELINE_DEPTH,
2273 maxPipelineDepth);
2274 }
2275
2276 /**
Zhijun He7e80fe92014-04-24 15:46:41 -07002277 * Calculate the anti-flickering corrected exposure time.
2278 * <p>
2279 * If the input exposure time is very short (shorter than flickering
2280 * boundary), which indicate the scene is bright and very likely at outdoor
2281 * environment, skip the correction, as it doesn't make much sense by doing so.
2282 * </p>
2283 * <p>
2284 * For long exposure time (larger than the flickering boundary), find the
2285 * exposure time that is closest to the flickering boundary.
2286 * </p>
2287 *
2288 * @param flickeringMode The flickering mode
2289 * @param exposureTime The input exposureTime to be corrected
2290 * @return anti-flickering corrected exposure time
2291 */
2292 private long getAntiFlickeringExposureTime(int flickeringMode, long exposureTime) {
2293 if (flickeringMode != ANTI_FLICKERING_50HZ && flickeringMode != ANTI_FLICKERING_60HZ) {
2294 throw new IllegalArgumentException("Input anti-flickering mode must be 50 or 60Hz");
2295 }
2296 long flickeringBoundary = EXPOSURE_TIME_BOUNDARY_50HZ_NS;
2297 if (flickeringMode == ANTI_FLICKERING_60HZ) {
2298 flickeringBoundary = EXPOSURE_TIME_BOUNDARY_60HZ_NS;
2299 }
2300
2301 if (exposureTime <= flickeringBoundary) {
2302 return exposureTime;
2303 }
2304
2305 // Find the closest anti-flickering corrected exposure time
2306 long correctedExpTime = exposureTime + (flickeringBoundary / 2);
2307 correctedExpTime = correctedExpTime - (correctedExpTime % flickeringBoundary);
2308 return correctedExpTime;
2309 }
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002310
2311 /**
2312 * Update one 3A region in capture request builder if that region is supported. Do nothing
2313 * if the specified 3A region is not supported by camera device.
2314 * @param requestBuilder The request to be updated
2315 * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2)
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07002316 * @param regions The 3A regions to be set
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002317 */
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07002318 private void update3aRegion(
2319 CaptureRequest.Builder requestBuilder, int algoIdx, MeteringRectangle[] regions)
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002320 {
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002321 int maxRegions;
2322 CaptureRequest.Key<MeteringRectangle[]> key;
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002323
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07002324 if (regions == null || regions.length == 0) {
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002325 throw new IllegalArgumentException("Invalid input 3A region!");
2326 }
2327
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002328 switch (algoIdx) {
2329 case INDEX_ALGORITHM_AE:
2330 maxRegions = mStaticInfo.getAeMaxRegionsChecked();
2331 key = CaptureRequest.CONTROL_AE_REGIONS;
2332 break;
2333 case INDEX_ALGORITHM_AWB:
2334 maxRegions = mStaticInfo.getAwbMaxRegionsChecked();
2335 key = CaptureRequest.CONTROL_AWB_REGIONS;
2336 break;
2337 case INDEX_ALGORITHM_AF:
2338 maxRegions = mStaticInfo.getAfMaxRegionsChecked();
2339 key = CaptureRequest.CONTROL_AF_REGIONS;
2340 break;
2341 default:
2342 throw new IllegalArgumentException("Unknown 3A Algorithm!");
2343 }
2344
2345 if (maxRegions >= regions.length) {
2346 requestBuilder.set(key, regions);
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002347 }
2348 }
2349
2350 /**
2351 * Validate one 3A region in capture result equals to expected region if that region is
2352 * supported. Do nothing if the specified 3A region is not supported by camera device.
2353 * @param result The capture result to be validated
2354 * @param algoIdx The index to the algorithm. (AE: 0, AWB: 1, AF: 2)
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002355 * @param expectRegions The 3A regions expected in capture result
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002356 */
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07002357 private void validate3aRegion(
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002358 CaptureResult result, int algoIdx, MeteringRectangle[] expectRegions)
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002359 {
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002360 int maxRegions;
2361 CaptureResult.Key<MeteringRectangle[]> key;
Yin-Chia Yeh1cd3c6b2014-05-19 10:16:54 -07002362 MeteringRectangle[] actualRegion;
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002363
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002364 switch (algoIdx) {
2365 case INDEX_ALGORITHM_AE:
2366 maxRegions = mStaticInfo.getAeMaxRegionsChecked();
2367 key = CaptureResult.CONTROL_AE_REGIONS;
2368 break;
2369 case INDEX_ALGORITHM_AWB:
2370 maxRegions = mStaticInfo.getAwbMaxRegionsChecked();
2371 key = CaptureResult.CONTROL_AWB_REGIONS;
2372 break;
2373 case INDEX_ALGORITHM_AF:
2374 maxRegions = mStaticInfo.getAfMaxRegionsChecked();
2375 key = CaptureResult.CONTROL_AF_REGIONS;
2376 break;
2377 default:
2378 throw new IllegalArgumentException("Unknown 3A Algorithm!");
2379 }
2380
2381 if (maxRegions > 0)
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002382 {
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002383 actualRegion = getValueNotNull(result, key);
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002384 mCollector.expectEquals(
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002385 "Expected 3A regions: " + Arrays.toString(expectRegions) +
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002386 " does not match actual one: " + Arrays.toString(actualRegion),
Yin-Chia Yeh53b5f712014-06-04 15:57:16 -07002387 expectRegions, actualRegion);
Yin-Chia Yehe9c7ae72014-05-15 14:06:27 -07002388 }
2389 }
Zhijun He28f2b3e2014-02-26 14:15:18 -08002390}