blob: ed9aa02540f1d1f8c685bf0c807fbb21ec598d18 [file] [log] [blame]
Puneet Lall512001d2014-08-13 18:53:53 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
Puneet Lall0ad7ab02014-09-05 10:38:39 -07004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
Puneet Lall512001d2014-08-13 18:53:53 -07006 *
Puneet Lall0ad7ab02014-09-05 10:38:39 -07007 * http://www.apache.org/licenses/LICENSE-2.0
Puneet Lall512001d2014-08-13 18:53:53 -07008 *
Puneet Lall0ad7ab02014-09-05 10:38:39 -07009 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
Puneet Lall512001d2014-08-13 18:53:53 -070013 */
14
15package com.android.camera.one.v2;
16
17import android.annotation.TargetApi;
18import android.content.Context;
19import android.graphics.ImageFormat;
Puneet Lall512001d2014-08-13 18:53:53 -070020import android.graphics.Rect;
21import android.hardware.camera2.CameraAccessException;
22import android.hardware.camera2.CameraCaptureSession;
23import android.hardware.camera2.CameraCharacteristics;
24import android.hardware.camera2.CameraDevice;
25import android.hardware.camera2.CameraMetadata;
26import android.hardware.camera2.CaptureRequest;
27import android.hardware.camera2.CaptureResult;
Puneet Lall580f4512014-08-27 19:27:50 -070028import android.hardware.camera2.CaptureResult.Key;
Puneet Lall512001d2014-08-13 18:53:53 -070029import android.hardware.camera2.TotalCaptureResult;
30import android.hardware.camera2.params.MeteringRectangle;
31import android.hardware.camera2.params.StreamConfigurationMap;
32import android.media.CameraProfile;
33import android.media.Image;
34import android.media.ImageReader;
Andy Huibers17d90842014-08-28 15:05:57 -070035import android.media.MediaActionSound;
Puneet Lall512001d2014-08-13 18:53:53 -070036import android.net.Uri;
37import android.os.Build;
38import android.os.Handler;
39import android.os.HandlerThread;
Puneet Lall580f4512014-08-27 19:27:50 -070040import android.os.SystemClock;
Puneet Lall512001d2014-08-13 18:53:53 -070041import android.support.v4.util.Pools;
42import android.view.Surface;
43
44import com.android.camera.CaptureModuleUtil;
45import com.android.camera.app.MediaSaver.OnMediaSavedListener;
46import com.android.camera.debug.Log;
47import com.android.camera.debug.Log.Tag;
48import com.android.camera.exif.ExifInterface;
49import com.android.camera.exif.ExifTag;
50import com.android.camera.exif.Rational;
51import com.android.camera.one.AbstractOneCamera;
52import com.android.camera.one.OneCamera;
53import com.android.camera.one.OneCamera.PhotoCaptureParameters.Flash;
Andy Huibersb8682742014-08-27 15:28:42 -070054import com.android.camera.one.Settings3A;
Puneet Lall512001d2014-08-13 18:53:53 -070055import com.android.camera.one.v2.ImageCaptureManager.ImageCaptureListener;
Puneet Lall580f4512014-08-27 19:27:50 -070056import com.android.camera.one.v2.ImageCaptureManager.MetadataChangeListener;
Puneet Lall512001d2014-08-13 18:53:53 -070057import com.android.camera.session.CaptureSession;
58import com.android.camera.util.CameraUtil;
Puneet Lallc2387dc2014-10-15 18:21:12 -070059import com.android.camera.util.ListenerCombiner;
Puneet Lall512001d2014-08-13 18:53:53 -070060import com.android.camera.util.JpegUtilNative;
61import com.android.camera.util.Size;
62
63import java.nio.ByteBuffer;
Puneet Lall0ad7ab02014-09-05 10:38:39 -070064import java.security.InvalidParameterException;
Puneet Lall512001d2014-08-13 18:53:53 -070065import java.util.ArrayList;
Puneet Lall863a5ab2014-09-05 17:14:41 -070066import java.util.Collections;
67import java.util.HashSet;
Puneet Lall512001d2014-08-13 18:53:53 -070068import java.util.List;
Puneet Lall863a5ab2014-09-05 17:14:41 -070069import java.util.Set;
Puneet Lall512001d2014-08-13 18:53:53 -070070import java.util.concurrent.LinkedBlockingQueue;
71import java.util.concurrent.ThreadPoolExecutor;
72import java.util.concurrent.TimeUnit;
Puneet Lall512001d2014-08-13 18:53:53 -070073
74/**
75 * {@link OneCamera} implementation directly on top of the Camera2 API with zero
76 * shutter lag.<br>
Puneet Lall512001d2014-08-13 18:53:53 -070077 * TODO: Determine what the maximum number of full YUV capture frames is.
78 */
Dianne Hackborn43d66a02014-10-08 09:37:44 -070079@TargetApi(Build.VERSION_CODES.LOLLIPOP)
Puneet Lall512001d2014-08-13 18:53:53 -070080public class OneCameraZslImpl extends AbstractOneCamera {
81 private static final Tag TAG = new Tag("OneCameraZslImpl2");
82
83 /** Default JPEG encoding quality. */
Puneet Lall0ad7ab02014-09-05 10:38:39 -070084 private static final int JPEG_QUALITY =
85 CameraProfile.getJpegEncodingQualityParameter(CameraProfile.QUALITY_HIGH);
Puneet Lall512001d2014-08-13 18:53:53 -070086 /**
Puneet Lall0ad7ab02014-09-05 10:38:39 -070087 * The maximum number of images to store in the full-size ZSL ring buffer.
Puneet Lall512001d2014-08-13 18:53:53 -070088 * <br>
89 * TODO: Determine this number dynamically based on available memory and the
90 * size of frames.
91 */
Puneet Lall9cd94d72014-10-14 14:05:11 -070092 private static final int MAX_CAPTURE_IMAGES = 10;
Puneet Lall512001d2014-08-13 18:53:53 -070093 /**
94 * True if zero-shutter-lag images should be captured. Some devices produce
95 * lower-quality images for the high-frequency stream, so we may wish to
96 * disable ZSL in that case.
97 */
98 private static final boolean ZSL_ENABLED = true;
99
100 /**
Puneet Lall580f4512014-08-27 19:27:50 -0700101 * Tags which may be used in CaptureRequests.
102 */
103 private static enum RequestTag {
104 /**
105 * Indicates that the request was explicitly sent for a single
106 * high-quality still capture. Unlike other requests, such as the
107 * repeating (ZSL) stream and AF/AE triggers, requests with this tag
108 * should always be saved.
109 */
110 EXPLICIT_CAPTURE
Puneet Lall182ba6f2014-08-28 16:44:08 -0700111 }
Puneet Lall580f4512014-08-27 19:27:50 -0700112
113 /**
Puneet Lall512001d2014-08-13 18:53:53 -0700114 * Set to ImageFormat.JPEG to use the hardware encoder, or
115 * ImageFormat.YUV_420_888 to use the software encoder. No other image
116 * formats are supported.
117 */
118 private static final int sCaptureImageFormat = ImageFormat.YUV_420_888;
Puneet Lall580f4512014-08-27 19:27:50 -0700119 /**
Puneet Lall182ba6f2014-08-28 16:44:08 -0700120 * Token for callbacks posted to {@link #mCameraHandler} to resume
121 * continuous AF.
Puneet Lall580f4512014-08-27 19:27:50 -0700122 */
123 private static final String FOCUS_RESUME_CALLBACK_TOKEN = "RESUME_CONTINUOUS_AF";
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700124
Puneet Lall512001d2014-08-13 18:53:53 -0700125 /** Zero weight 3A region, to reset regions per API. */
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700126 /*package*/ MeteringRectangle[] ZERO_WEIGHT_3A_REGION = AutoFocusHelper.getZeroWeightRegion();
Puneet Lall512001d2014-08-13 18:53:53 -0700127
Puneet Lall580f4512014-08-27 19:27:50 -0700128 /**
129 * Thread on which high-priority camera operations, such as grabbing preview
130 * frames for the viewfinder, are running.
131 */
Puneet Lall512001d2014-08-13 18:53:53 -0700132 private final HandlerThread mCameraThread;
133 /** Handler of the {@link #mCameraThread}. */
134 private final Handler mCameraHandler;
135
Puneet Lall580f4512014-08-27 19:27:50 -0700136 /** Thread on which low-priority camera listeners are running. */
137 private final HandlerThread mCameraListenerThread;
138 private final Handler mCameraListenerHandler;
139
Puneet Lall512001d2014-08-13 18:53:53 -0700140 /** The characteristics of this camera. */
141 private final CameraCharacteristics mCharacteristics;
142 /** The underlying Camera2 API camera device. */
143 private final CameraDevice mDevice;
144
145 /**
146 * The aspect ratio (width/height) of the full resolution for this camera.
147 * Usually the native aspect ratio of this camera.
148 */
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700149 private final float mFullSizeAspectRatio;
Puneet Lall512001d2014-08-13 18:53:53 -0700150 /** The Camera2 API capture session currently active. */
151 private CameraCaptureSession mCaptureSession;
152 /** The surface onto which to render the preview. */
153 private Surface mPreviewSurface;
154 /** Whether closing of this device has been requested. */
155 private volatile boolean mIsClosed = false;
156 /** A callback that is called when the device is fully closed. */
157 private CloseCallback mCloseCallback = null;
158
159 /** Receives the normal captured images. */
160 private final ImageReader mCaptureImageReader;
161
162 /**
163 * Maintains a buffer of images and their associated {@link CaptureResult}s.
164 */
165 private ImageCaptureManager mCaptureManager;
166
167 /**
Puneet Lall863a5ab2014-09-05 17:14:41 -0700168 * The sensor timestamps (which may not be relative to the system time) of
169 * the most recently captured images.
Puneet Lall512001d2014-08-13 18:53:53 -0700170 */
Puneet Lall863a5ab2014-09-05 17:14:41 -0700171 private final Set<Long> mCapturedImageTimestamps = Collections.synchronizedSet(
172 new HashSet<Long>());
Puneet Lall512001d2014-08-13 18:53:53 -0700173
174 /** Thread pool for performing slow jpeg encoding and saving tasks. */
175 private final ThreadPoolExecutor mImageSaverThreadPool;
176
177 /** Pool of native byte buffers on which to store jpeg-encoded images. */
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700178 private final Pools.SynchronizedPool<ByteBuffer> mJpegByteBufferPool =
179 new Pools.SynchronizedPool<ByteBuffer>(64);
Puneet Lall512001d2014-08-13 18:53:53 -0700180
181 /** Current zoom value. 1.0 is no zoom. */
182 private float mZoomValue = 1f;
183 /** Current crop region: set from mZoomValue. */
184 private Rect mCropRegion;
185 /** Current AE, AF, and AWB regions */
Andy Huibersb8682742014-08-27 15:28:42 -0700186 private MeteringRectangle[] mAFRegions = ZERO_WEIGHT_3A_REGION;
187 private MeteringRectangle[] mAERegions = ZERO_WEIGHT_3A_REGION;
Puneet Lall512001d2014-08-13 18:53:53 -0700188
Andy Huibers17d90842014-08-28 15:05:57 -0700189 private MediaActionSound mMediaActionSound = new MediaActionSound();
190
Puneet Lall512001d2014-08-13 18:53:53 -0700191 /**
Puneet Lall142b5bf2014-09-03 14:58:51 -0700192 * Ready state (typically displayed by the UI shutter-button) depends on two
193 * things:<br>
Puneet Lall182ba6f2014-08-28 16:44:08 -0700194 * <ol>
195 * <li>{@link #mCaptureManager} must be ready.</li>
196 * <li>We must not be in the process of capturing a single, high-quality,
197 * image.</li>
198 * </ol>
Puneet Lallc2387dc2014-10-15 18:21:12 -0700199 * See {@link ListenerCombiner} and {@link #mReadyStateManager} for
Puneet Lall142b5bf2014-09-03 14:58:51 -0700200 * details of how this is managed.
Puneet Lall182ba6f2014-08-28 16:44:08 -0700201 */
Puneet Lall68c25ac2014-08-28 18:36:33 -0700202 private static enum ReadyStateRequirement {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700203 CAPTURE_MANAGER_READY, CAPTURE_NOT_IN_PROGRESS
Puneet Lall68c25ac2014-08-28 18:36:33 -0700204 }
205
206 /**
207 * Handles the thread-safe logic of dispatching whenever the logical AND of
208 * these constraints changes.
209 */
Puneet Lallc2387dc2014-10-15 18:21:12 -0700210 private final ListenerCombiner<ReadyStateRequirement>
211 mReadyStateManager = new ListenerCombiner<ReadyStateRequirement>(
212 ReadyStateRequirement.class, new ListenerCombiner.StateChangeListener() {
Puneet Lall142b5bf2014-09-03 14:58:51 -0700213 @Override
Puneet Lallc2387dc2014-10-15 18:21:12 -0700214 public void onStateChange(boolean state) {
Puneet Lall142b5bf2014-09-03 14:58:51 -0700215 broadcastReadyState(state);
216 }
217 });
Puneet Lall182ba6f2014-08-28 16:44:08 -0700218
219 /**
Puneet Lall580f4512014-08-27 19:27:50 -0700220 * An {@link ImageCaptureListener} which will compress and save an image to
221 * disk.
222 */
223 private class ImageCaptureTask implements ImageCaptureListener {
224 private final PhotoCaptureParameters mParams;
225 private final CaptureSession mSession;
226
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700227 public ImageCaptureTask(PhotoCaptureParameters parameters, CaptureSession session) {
Puneet Lall580f4512014-08-27 19:27:50 -0700228 mParams = parameters;
229 mSession = session;
230 }
231
232 @Override
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700233 public void onImageCaptured(Image image, TotalCaptureResult captureResult) {
Puneet Lall580f4512014-08-27 19:27:50 -0700234 long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
235
Puneet Lall863a5ab2014-09-05 17:14:41 -0700236 // We should only capture the image if it hasn't been captured
237 // before. Synchronization is necessary since
238 // mCapturedImageTimestamps is read & modified elsewhere.
239 synchronized (mCapturedImageTimestamps) {
240 if (!mCapturedImageTimestamps.contains(timestamp)) {
241 mCapturedImageTimestamps.add(timestamp);
Puneet Lall580f4512014-08-27 19:27:50 -0700242 } else {
243 // There was a more recent (or identical) image which has
244 // begun being saved, so abort.
245 return;
246 }
Puneet Lall863a5ab2014-09-05 17:14:41 -0700247
248 // Clear out old timestamps from the set.
249 // We must keep old timestamps in the set a little longer (a
250 // factor of 2 seems adequate) to ensure they are cleared out of
251 // the ring buffer before their timestamp is removed from the
252 // set.
253 long maxTimestamps = MAX_CAPTURE_IMAGES * 2;
254 if (mCapturedImageTimestamps.size() > maxTimestamps) {
255 ArrayList<Long> timestamps = new ArrayList<Long>(mCapturedImageTimestamps);
256 Collections.sort(timestamps);
257 for (int i = 0; i < timestamps.size()
258 && mCapturedImageTimestamps.size() > maxTimestamps; i++) {
259 mCapturedImageTimestamps.remove(timestamps.get(i));
260 }
261 }
Puneet Lall580f4512014-08-27 19:27:50 -0700262 }
263
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700264 mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, true);
Puneet Lall182ba6f2014-08-28 16:44:08 -0700265
Puneet Lall580f4512014-08-27 19:27:50 -0700266 mSession.startEmpty();
267 savePicture(image, mParams, mSession);
268 mParams.callback.onPictureTaken(mSession);
269 Log.v(TAG, "Image saved. Frame number = " + captureResult.getFrameNumber());
270 }
271 }
272
273 /**
Puneet Lall512001d2014-08-13 18:53:53 -0700274 * Instantiates a new camera based on Camera 2 API.
275 *
276 * @param device The underlying Camera 2 device.
277 * @param characteristics The device's characteristics.
278 * @param pictureSize the size of the final image to be taken.
279 */
280 OneCameraZslImpl(CameraDevice device, CameraCharacteristics characteristics, Size pictureSize) {
Puneet Lall580f4512014-08-27 19:27:50 -0700281 Log.v(TAG, "Creating new OneCameraZslImpl");
282
Puneet Lall512001d2014-08-13 18:53:53 -0700283 mDevice = device;
284 mCharacteristics = characteristics;
285 mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
286
287 mCameraThread = new HandlerThread("OneCamera2");
288 // If this thread stalls, it will delay viewfinder frames.
289 mCameraThread.setPriority(Thread.MAX_PRIORITY);
290 mCameraThread.start();
291 mCameraHandler = new Handler(mCameraThread.getLooper());
292
Puneet Lall580f4512014-08-27 19:27:50 -0700293 mCameraListenerThread = new HandlerThread("OneCamera2-Listener");
294 mCameraListenerThread.start();
295 mCameraListenerHandler = new Handler(mCameraListenerThread.getLooper());
Puneet Lall512001d2014-08-13 18:53:53 -0700296
297 // TODO: Encoding on multiple cores results in preview jank due to
298 // excessive GC.
299 int numEncodingCores = CameraUtil.getNumCpuCores();
Puneet Lall512001d2014-08-13 18:53:53 -0700300 mImageSaverThreadPool = new ThreadPoolExecutor(numEncodingCores, numEncodingCores, 10,
301 TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
302
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700303 mCaptureManager =
304 new ImageCaptureManager(MAX_CAPTURE_IMAGES, mCameraListenerHandler,
305 mImageSaverThreadPool);
Puneet Lall580f4512014-08-27 19:27:50 -0700306 mCaptureManager.setCaptureReadyListener(new ImageCaptureManager.CaptureReadyListener() {
Puneet Lall512001d2014-08-13 18:53:53 -0700307 @Override
308 public void onReadyStateChange(boolean capturePossible) {
Puneet Lall68c25ac2014-08-28 18:36:33 -0700309 mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_MANAGER_READY,
Puneet Lall182ba6f2014-08-28 16:44:08 -0700310 capturePossible);
Puneet Lall512001d2014-08-13 18:53:53 -0700311 }
312 });
Puneet Lall182ba6f2014-08-28 16:44:08 -0700313
Puneet Lall580f4512014-08-27 19:27:50 -0700314 // Listen for changes to auto focus state and dispatch to
315 // mFocusStateListener.
316 mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AF_STATE,
317 new ImageCaptureManager.MetadataChangeListener() {
318 @Override
319 public void onImageMetadataChange(Key<?> key, Object oldValue, Object newValue,
320 CaptureResult result) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700321 FocusStateListener listener = mFocusStateListener;
322 if (listener != null) {
323 listener.onFocusStatusUpdate(
324 AutoFocusHelper.stateFromCamera2State(
Andy Huibers4a748622014-09-08 14:17:16 -0700325 result.get(CaptureResult.CONTROL_AF_STATE)),
Andy Huibersca3c5642014-09-06 20:44:25 -0700326 result.getFrameNumber());
Andy Huibers4a748622014-09-08 14:17:16 -0700327 }
Puneet Lall580f4512014-08-27 19:27:50 -0700328 }
329 });
330
331 // Allocate the image reader to store all images received from the
332 // camera.
Puneet Lall80f44442014-09-03 10:43:35 -0700333 if (pictureSize == null) {
Puneet Lall4d6d6762014-09-03 13:22:01 -0700334 // TODO The default should be selected by the caller, and
335 // pictureSize should never be null.
336 pictureSize = getDefaultPictureSize();
Puneet Lall80f44442014-09-03 10:43:35 -0700337 }
Puneet Lall580f4512014-08-27 19:27:50 -0700338 mCaptureImageReader = ImageReader.newInstance(pictureSize.getWidth(),
339 pictureSize.getHeight(),
340 sCaptureImageFormat, MAX_CAPTURE_IMAGES);
Puneet Lall512001d2014-08-13 18:53:53 -0700341
342 mCaptureImageReader.setOnImageAvailableListener(mCaptureManager, mCameraHandler);
Andy Huibers17d90842014-08-28 15:05:57 -0700343 mMediaActionSound.load(MediaActionSound.SHUTTER_CLICK);
Puneet Lall512001d2014-08-13 18:53:53 -0700344 }
345
346 /**
Puneet Lall4d6d6762014-09-03 13:22:01 -0700347 * @return The largest supported picture size.
348 */
349 public Size getDefaultPictureSize() {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700350 StreamConfigurationMap configs =
351 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Puneet Lall4d6d6762014-09-03 13:22:01 -0700352 android.util.Size[] supportedSizes = configs.getOutputSizes(sCaptureImageFormat);
353
354 // Find the largest supported size.
355 android.util.Size largestSupportedSize = supportedSizes[0];
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700356 long largestSupportedSizePixels =
357 largestSupportedSize.getWidth() * largestSupportedSize.getHeight();
Puneet Lall4d6d6762014-09-03 13:22:01 -0700358 for (int i = 0; i < supportedSizes.length; i++) {
359 long numPixels = supportedSizes[i].getWidth() * supportedSizes[i].getHeight();
360 if (numPixels > largestSupportedSizePixels) {
361 largestSupportedSize = supportedSizes[i];
362 largestSupportedSizePixels = numPixels;
363 }
364 }
365
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700366 return new Size(largestSupportedSize.getWidth(), largestSupportedSize.getHeight());
Puneet Lall4d6d6762014-09-03 13:22:01 -0700367 }
368
Andy Huibers17d90842014-08-28 15:05:57 -0700369 private void onShutterInvokeUI(final PhotoCaptureParameters params) {
370 // Tell CaptureModule shutter has occurred so it can flash the screen.
371 params.callback.onQuickExpose();
372 // Play shutter click sound.
373 mMediaActionSound.play(MediaActionSound.SHUTTER_CLICK);
374 }
375
Puneet Lall4d6d6762014-09-03 13:22:01 -0700376 /**
Puneet Lall512001d2014-08-13 18:53:53 -0700377 * Take a picture.
378 */
379 @Override
380 public void takePicture(final PhotoCaptureParameters params, final CaptureSession session) {
381 params.checkSanity();
Puneet Lall512001d2014-08-13 18:53:53 -0700382
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700383 mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, false);
Puneet Lall182ba6f2014-08-28 16:44:08 -0700384
Puneet Lall512001d2014-08-13 18:53:53 -0700385 boolean useZSL = ZSL_ENABLED;
386
Puneet Lall580f4512014-08-27 19:27:50 -0700387 // We will only capture images from the zsl ring-buffer which satisfy
388 // this constraint.
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700389 ArrayList<ImageCaptureManager.CapturedImageConstraint> zslConstraints =
390 new ArrayList<ImageCaptureManager.CapturedImageConstraint>();
Puneet Lall580f4512014-08-27 19:27:50 -0700391 zslConstraints.add(new ImageCaptureManager.CapturedImageConstraint() {
392 @Override
393 public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
Puneet Lall580f4512014-08-27 19:27:50 -0700394 Long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
395 Integer lensState = captureResult.get(CaptureResult.LENS_STATE);
396 Integer flashState = captureResult.get(CaptureResult.FLASH_STATE);
397 Integer flashMode = captureResult.get(CaptureResult.FLASH_MODE);
398 Integer aeState = captureResult.get(CaptureResult.CONTROL_AE_STATE);
399 Integer afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
400 Integer awbState = captureResult.get(CaptureResult.CONTROL_AWB_STATE);
401
Puneet Lallbbd65162014-09-05 15:44:24 -0700402 if (lensState == null) {
403 lensState = CaptureResult.LENS_STATE_STATIONARY;
404 }
405 if (flashState == null) {
406 flashState = CaptureResult.FLASH_STATE_UNAVAILABLE;
407 }
408 if (flashMode == null) {
409 flashMode = CaptureResult.FLASH_MODE_OFF;
410 }
411 if (aeState == null) {
412 aeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
413 }
414 if (afState == null) {
415 afState = CaptureResult.CONTROL_AF_STATE_INACTIVE;
416 }
417 if (awbState == null) {
418 awbState = CaptureResult.CONTROL_AWB_STATE_INACTIVE;
419 }
420
Puneet Lall863a5ab2014-09-05 17:14:41 -0700421 synchronized (mCapturedImageTimestamps) {
422 if (mCapturedImageTimestamps.contains(timestamp)) {
423 // Don't save frames which we've already saved.
424 return false;
425 }
Puneet Lall580f4512014-08-27 19:27:50 -0700426 }
427
428 if (lensState == CaptureResult.LENS_STATE_MOVING) {
429 // If we know the lens was moving, don't use this image.
430 return false;
431 }
432
433 if (aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING
434 || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
435 return false;
436 }
437 switch (params.flashMode) {
438 case OFF:
439 break;
440 case ON:
441 if (flashState != CaptureResult.FLASH_STATE_FIRED
442 || flashMode != CaptureResult.FLASH_MODE_SINGLE) {
443 return false;
444 }
445 break;
446 case AUTO:
447 if (aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
448 && flashState != CaptureResult.FLASH_STATE_FIRED) {
449 return false;
450 }
451 break;
452 }
453
454 if (afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN
455 || afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN) {
456 return false;
457 }
458
459 if (awbState == CaptureResult.CONTROL_AWB_STATE_SEARCHING) {
460 return false;
461 }
462
463 return true;
464 }
465 });
Puneet Lall580f4512014-08-27 19:27:50 -0700466 // This constraint lets us capture images which have been explicitly
467 // requested. See {@link RequestTag.EXPLICIT_CAPTURE}.
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700468 ArrayList<ImageCaptureManager.CapturedImageConstraint> singleCaptureConstraint =
469 new ArrayList<ImageCaptureManager.CapturedImageConstraint>();
Puneet Lall580f4512014-08-27 19:27:50 -0700470 singleCaptureConstraint.add(new ImageCaptureManager.CapturedImageConstraint() {
471 @Override
472 public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
473 Object tag = captureResult.getRequest().getTag();
474 return tag == RequestTag.EXPLICIT_CAPTURE;
475 }
476 });
Puneet Lall512001d2014-08-13 18:53:53 -0700477
478 // If we can use ZSL, try to save a previously-captured frame, if an
479 // acceptable one exists in the buffer.
Puneet Lall580f4512014-08-27 19:27:50 -0700480 if (useZSL) {
481 boolean capturedPreviousFrame = mCaptureManager.tryCaptureExistingImage(
482 new ImageCaptureTask(params, session), zslConstraints);
Puneet Lall512001d2014-08-13 18:53:53 -0700483 if (capturedPreviousFrame) {
484 Log.v(TAG, "Saving previous frame");
Andy Huibers17d90842014-08-28 15:05:57 -0700485 onShutterInvokeUI(params);
Puneet Lall512001d2014-08-13 18:53:53 -0700486 } else {
Puneet Lall580f4512014-08-27 19:27:50 -0700487 Log.v(TAG, "No good image Available. Capturing next available good image.");
Puneet Lall512001d2014-08-13 18:53:53 -0700488 // If there was no good frame available in the ring buffer
489 // already, capture the next good image.
Puneet Lall580f4512014-08-27 19:27:50 -0700490 // TODO Disable the shutter button until this image is captured.
Puneet Lall512001d2014-08-13 18:53:53 -0700491
Puneet Lall580f4512014-08-27 19:27:50 -0700492 if (params.flashMode == Flash.ON || params.flashMode == Flash.AUTO) {
493 // We must issue a request for a single capture using the
494 // flash, including an AE precapture trigger.
Puneet Lall512001d2014-08-13 18:53:53 -0700495
Puneet Lall580f4512014-08-27 19:27:50 -0700496 // The following sets up a sequence of events which will
497 // occur in reverse order to the associated method
498 // calls:
499 // 1. Send a request to trigger the Auto Exposure Precapture
500 // 2. Wait for the AE_STATE to leave the PRECAPTURE state,
501 // and then send a request for a single image, with the
502 // appropriate flash settings.
503 // 3. Capture the next appropriate image, which should be
504 // the one we requested in (2).
Puneet Lall512001d2014-08-13 18:53:53 -0700505
Puneet Lall580f4512014-08-27 19:27:50 -0700506 mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
507 singleCaptureConstraint);
508
509 mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AE_STATE,
510 new MetadataChangeListener() {
511 @Override
512 public void onImageMetadataChange(Key<?> key, Object oldValue,
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700513 Object newValue,
514 CaptureResult result) {
Puneet Lall580f4512014-08-27 19:27:50 -0700515 Log.v(TAG, "AE State Changed");
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700516 if (oldValue.equals(Integer.valueOf(
517 CaptureResult.CONTROL_AE_STATE_PRECAPTURE))) {
Puneet Lall580f4512014-08-27 19:27:50 -0700518 mCaptureManager.removeMetadataChangeListener(key, this);
519 sendSingleRequest(params);
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700520 // TODO: Delay this until
521 // onCaptureStarted().
Andy Huibers17d90842014-08-28 15:05:57 -0700522 onShutterInvokeUI(params);
Puneet Lall580f4512014-08-27 19:27:50 -0700523 }
524 }
525 });
526
527 sendAutoExposureTriggerRequest(params.flashMode);
528 } else {
529 // We may get here if, for example, the auto focus is in the
530 // middle of a scan.
531 // If the flash is off, we should just wait for the next
532 // image that arrives. This will have minimal delay since we
533 // do not need to send a new capture request.
534 mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
535 zslConstraints);
536 }
Puneet Lall512001d2014-08-13 18:53:53 -0700537 }
Puneet Lall580f4512014-08-27 19:27:50 -0700538 } else {
539 // TODO If we can't save a previous frame, create a new capture
540 // request to do what we need (e.g. flash) and call
541 // captureNextImage().
542 throw new UnsupportedOperationException("Non-ZSL capture not yet supported");
Puneet Lall512001d2014-08-13 18:53:53 -0700543 }
544 }
545
546 @Override
547 public void startPreview(Surface previewSurface, CaptureReadyCallback listener) {
548 mPreviewSurface = previewSurface;
549 setupAsync(mPreviewSurface, listener);
550 }
551
552 @Override
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700553 public void setViewfinderSize(int width, int height) {
Puneet Lall512001d2014-08-13 18:53:53 -0700554 throw new RuntimeException("Not implemented yet.");
555 }
556
557 @Override
558 public boolean isFlashSupported(boolean enhanced) {
559 throw new RuntimeException("Not implemented yet.");
560 }
561
562 @Override
563 public boolean isSupportingEnhancedMode() {
564 throw new RuntimeException("Not implemented yet.");
565 }
566
567 @Override
568 public void close(CloseCallback closeCallback) {
569 if (mIsClosed) {
570 Log.w(TAG, "Camera is already closed.");
571 return;
572 }
573 try {
Puneet Lall9cd94d72014-10-14 14:05:11 -0700574 mCaptureSession.stopRepeating();
Puneet Lall512001d2014-08-13 18:53:53 -0700575 } catch (CameraAccessException e) {
576 Log.e(TAG, "Could not abort captures in progress.");
577 }
578 mIsClosed = true;
579 mCloseCallback = closeCallback;
580 mCameraThread.quitSafely();
581 mDevice.close();
582 mCaptureManager.close();
Puneet Lall9cd94d72014-10-14 14:05:11 -0700583 mCaptureImageReader.close();
Puneet Lall512001d2014-08-13 18:53:53 -0700584 }
585
586 @Override
Sascha Haeberlingc6da1a12014-11-06 09:50:51 -0800587 public Size[] getSupportedPreviewSizes() {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700588 StreamConfigurationMap config =
589 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Puneet Lall512001d2014-08-13 18:53:53 -0700590 return Size.convert(config.getOutputSizes(sCaptureImageFormat));
591 }
592
593 @Override
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700594 public float getFullSizeAspectRatio() {
Puneet Lall512001d2014-08-13 18:53:53 -0700595 return mFullSizeAspectRatio;
596 }
597
598 @Override
599 public boolean isFrontFacing() {
600 return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
601 == CameraMetadata.LENS_FACING_FRONT;
602 }
603
604 @Override
605 public boolean isBackFacing() {
606 return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
607 == CameraMetadata.LENS_FACING_BACK;
608 }
609
610 private void savePicture(Image image, final PhotoCaptureParameters captureParams,
611 CaptureSession session) {
612 int heading = captureParams.heading;
613
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700614 int degrees = (captureParams.orientation + 270) % 360;
Puneet Lall512001d2014-08-13 18:53:53 -0700615 ExifInterface exif = null;
616
617 exif = new ExifInterface();
618 // TODO: Add more exif tags here.
619
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700620 Size size = getImageSizeForOrientation(image.getWidth(), image.getHeight(),
621 degrees);
Puneet Lall512001d2014-08-13 18:53:53 -0700622
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700623 exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_X_DIMENSION, size.getWidth()));
624 exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_Y_DIMENSION, size.getHeight()));
625
626 exif.setTag(
627 exif.buildTag(ExifInterface.TAG_ORIENTATION, ExifInterface.Orientation.TOP_LEFT));
Puneet Lall512001d2014-08-13 18:53:53 -0700628
629 // Set GPS heading direction based on sensor, if location is on.
630 if (heading >= 0) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700631 ExifTag directionRefTag = exif.buildTag(ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
Puneet Lall512001d2014-08-13 18:53:53 -0700632 ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700633 ExifTag directionTag =
634 exif.buildTag(ExifInterface.TAG_GPS_IMG_DIRECTION, new Rational(heading, 1));
Puneet Lall512001d2014-08-13 18:53:53 -0700635 exif.setTag(directionRefTag);
636 exif.setTag(directionTag);
637 }
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700638 // TODO Find out why this is off by -90 degrees.
639 session.saveAndFinish(acquireJpegBytes(image, degrees),
640 size.getWidth(), size.getHeight(), 0, exif, new OnMediaSavedListener() {
641 @Override
Puneet Lall512001d2014-08-13 18:53:53 -0700642 public void onMediaSaved(Uri uri) {
643 captureParams.callback.onPictureSaved(uri);
644 }
645 });
646 }
647
648 /**
649 * Asynchronously sets up the capture session.
650 *
651 * @param previewSurface the surface onto which the preview should be
652 * rendered.
653 * @param listener called when setup is completed.
654 */
655 private void setupAsync(final Surface previewSurface, final CaptureReadyCallback listener) {
656 mCameraHandler.post(new Runnable() {
657 @Override
658 public void run() {
659 setup(previewSurface, listener);
660 }
661 });
662 }
663
664 /**
665 * Configures and attempts to create a capture session.
666 *
667 * @param previewSurface the surface onto which the preview should be
668 * rendered.
669 * @param listener called when the setup is completed.
670 */
671 private void setup(Surface previewSurface, final CaptureReadyCallback listener) {
672 try {
673 if (mCaptureSession != null) {
674 mCaptureSession.abortCaptures();
675 mCaptureSession = null;
676 }
677 List<Surface> outputSurfaces = new ArrayList<Surface>(2);
678 outputSurfaces.add(previewSurface);
679 outputSurfaces.add(mCaptureImageReader.getSurface());
680
Alan Newbergerf5c62532014-09-08 11:26:27 -0700681 mDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
Puneet Lall512001d2014-08-13 18:53:53 -0700682 @Override
683 public void onConfigureFailed(CameraCaptureSession session) {
684 listener.onSetupFailed();
685 }
686
687 @Override
688 public void onConfigured(CameraCaptureSession session) {
689 mCaptureSession = session;
Andy Huibersb8682742014-08-27 15:28:42 -0700690 mAFRegions = ZERO_WEIGHT_3A_REGION;
691 mAERegions = ZERO_WEIGHT_3A_REGION;
Puneet Lall580f4512014-08-27 19:27:50 -0700692 mZoomValue = 1f;
693 mCropRegion = cropRegionForZoom(mZoomValue);
694 boolean success = sendRepeatingCaptureRequest();
695 if (success) {
Puneet Lall142b5bf2014-09-03 14:58:51 -0700696 mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS,
697 true);
698 mReadyStateManager.notifyListeners();
Puneet Lall580f4512014-08-27 19:27:50 -0700699 listener.onReadyForCapture();
700 } else {
701 listener.onSetupFailed();
702 }
Puneet Lall512001d2014-08-13 18:53:53 -0700703 }
704
705 @Override
706 public void onClosed(CameraCaptureSession session) {
707 super.onClosed(session);
708 if (mCloseCallback != null) {
709 mCloseCallback.onCameraClosed();
710 }
711 }
712 }, mCameraHandler);
713 } catch (CameraAccessException ex) {
714 Log.e(TAG, "Could not set up capture session", ex);
715 listener.onSetupFailed();
716 }
717 }
718
Puneet Lall580f4512014-08-27 19:27:50 -0700719 private void addRegionsToCaptureRequestBuilder(CaptureRequest.Builder builder) {
Andy Huibersb8682742014-08-27 15:28:42 -0700720 builder.set(CaptureRequest.CONTROL_AE_REGIONS, mAERegions);
721 builder.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions);
Puneet Lall580f4512014-08-27 19:27:50 -0700722 builder.set(CaptureRequest.SCALER_CROP_REGION, mCropRegion);
723 }
724
725 private void addFlashToCaptureRequestBuilder(CaptureRequest.Builder builder, Flash flashMode) {
726 switch (flashMode) {
727 case ON:
728 builder.set(CaptureRequest.CONTROL_AE_MODE,
729 CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
730 builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
731 break;
732 case OFF:
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700733 builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
Puneet Lall580f4512014-08-27 19:27:50 -0700734 builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
735 break;
736 case AUTO:
737 builder.set(CaptureRequest.CONTROL_AE_MODE,
738 CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
739 break;
740 }
741 }
742
Puneet Lall512001d2014-08-13 18:53:53 -0700743 /**
Puneet Lall580f4512014-08-27 19:27:50 -0700744 * Request a stream of images.
Puneet Lall512001d2014-08-13 18:53:53 -0700745 *
Puneet Lall580f4512014-08-27 19:27:50 -0700746 * @return true if successful, false if there was an error submitting the
747 * capture request.
Puneet Lall512001d2014-08-13 18:53:53 -0700748 */
Puneet Lall580f4512014-08-27 19:27:50 -0700749 private boolean sendRepeatingCaptureRequest() {
750 Log.v(TAG, "sendRepeatingCaptureRequest()");
Puneet Lall512001d2014-08-13 18:53:53 -0700751 try {
Puneet Lall580f4512014-08-27 19:27:50 -0700752 CaptureRequest.Builder builder;
753 if (ZSL_ENABLED) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700754 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
Puneet Lall580f4512014-08-27 19:27:50 -0700755 } else {
756 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
757 }
Puneet Lall512001d2014-08-13 18:53:53 -0700758
759 builder.addTarget(mPreviewSurface);
Puneet Lall580f4512014-08-27 19:27:50 -0700760
761 if (ZSL_ENABLED) {
762 builder.addTarget(mCaptureImageReader.getSurface());
763 }
764
765 builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
766
767 builder.set(CaptureRequest.CONTROL_AF_MODE,
768 CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
769 builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
770
771 builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
772 builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
773
774 addRegionsToCaptureRequestBuilder(builder);
775
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700776 mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager, mCameraHandler);
Puneet Lall580f4512014-08-27 19:27:50 -0700777 return true;
778 } catch (CameraAccessException e) {
779 if (ZSL_ENABLED) {
780 Log.v(TAG, "Could not execute zero-shutter-lag repeating request.", e);
781 } else {
782 Log.v(TAG, "Could not execute preview request.", e);
783 }
784 return false;
785 }
786 }
787
788 /**
789 * Request a single image.
790 *
791 * @return true if successful, false if there was an error submitting the
792 * capture request.
793 */
794 private boolean sendSingleRequest(OneCamera.PhotoCaptureParameters params) {
795 Log.v(TAG, "sendSingleRequest()");
796 try {
797 CaptureRequest.Builder builder;
798 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
799
800 builder.addTarget(mPreviewSurface);
801
802 // Always add this surface for single image capture requests.
Puneet Lall512001d2014-08-13 18:53:53 -0700803 builder.addTarget(mCaptureImageReader.getSurface());
804
Puneet Lall580f4512014-08-27 19:27:50 -0700805 builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
806
807 addFlashToCaptureRequestBuilder(builder, params.flashMode);
808 addRegionsToCaptureRequestBuilder(builder);
809
810 builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
811 builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
812
813 // Tag this as a special request which should be saved.
814 builder.setTag(RequestTag.EXPLICIT_CAPTURE);
815
816 if (sCaptureImageFormat == ImageFormat.JPEG) {
817 builder.set(CaptureRequest.JPEG_QUALITY, (byte) (JPEG_QUALITY));
818 builder.set(CaptureRequest.JPEG_ORIENTATION,
819 CameraUtil.getJpegRotation(params.orientation, mCharacteristics));
820 }
821
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700822 mCaptureSession.capture(builder.build(), mCaptureManager, mCameraHandler);
Puneet Lall580f4512014-08-27 19:27:50 -0700823 return true;
824 } catch (CameraAccessException e) {
825 Log.v(TAG, "Could not execute single still capture request.", e);
826 return false;
827 }
828 }
829
830 private boolean sendAutoExposureTriggerRequest(Flash flashMode) {
831 Log.v(TAG, "sendAutoExposureTriggerRequest()");
832 try {
833 CaptureRequest.Builder builder;
834 if (ZSL_ENABLED) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700835 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
Puneet Lall580f4512014-08-27 19:27:50 -0700836 } else {
837 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
838 }
839
840 builder.addTarget(mPreviewSurface);
841
842 if (ZSL_ENABLED) {
843 builder.addTarget(mCaptureImageReader.getSurface());
844 }
845
846 builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
847
848 builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
849 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
850
851 addRegionsToCaptureRequestBuilder(builder);
852 addFlashToCaptureRequestBuilder(builder, flashMode);
853
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700854 mCaptureSession.capture(builder.build(), mCaptureManager, mCameraHandler);
Puneet Lall580f4512014-08-27 19:27:50 -0700855
856 return true;
857 } catch (CameraAccessException e) {
858 Log.v(TAG, "Could not execute auto exposure trigger request.", e);
859 return false;
860 }
861 }
862
863 /**
864 */
865 private boolean sendAutoFocusTriggerRequest() {
866 Log.v(TAG, "sendAutoFocusTriggerRequest()");
867 try {
868 CaptureRequest.Builder builder;
869 if (ZSL_ENABLED) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700870 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
Puneet Lall580f4512014-08-27 19:27:50 -0700871 } else {
872 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
873 }
874
875 builder.addTarget(mPreviewSurface);
876
877 if (ZSL_ENABLED) {
878 builder.addTarget(mCaptureImageReader.getSurface());
879 }
880
881 builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
882
883 addRegionsToCaptureRequestBuilder(builder);
884
885 builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
886 builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
887
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700888 mCaptureSession.capture(builder.build(), mCaptureManager, mCameraHandler);
Puneet Lall580f4512014-08-27 19:27:50 -0700889
890 return true;
891 } catch (CameraAccessException e) {
892 Log.v(TAG, "Could not execute auto focus trigger request.", e);
893 return false;
894 }
895 }
896
897 /**
898 * Like {@link #sendRepeatingCaptureRequest()}, but with the focus held
899 * constant.
900 *
901 * @return true if successful, false if there was an error submitting the
902 * capture request.
903 */
904 private boolean sendAutoFocusHoldRequest() {
905 Log.v(TAG, "sendAutoFocusHoldRequest()");
906 try {
907 CaptureRequest.Builder builder;
908 if (ZSL_ENABLED) {
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700909 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
Puneet Lall580f4512014-08-27 19:27:50 -0700910 } else {
911 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
912 }
913
914 builder.addTarget(mPreviewSurface);
915
916 if (ZSL_ENABLED) {
917 builder.addTarget(mCaptureImageReader.getSurface());
918 }
919
Puneet Lall512001d2014-08-13 18:53:53 -0700920 builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
921
Puneet Lall580f4512014-08-27 19:27:50 -0700922 builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
923 builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
Puneet Lall512001d2014-08-13 18:53:53 -0700924
Puneet Lall580f4512014-08-27 19:27:50 -0700925 addRegionsToCaptureRequestBuilder(builder);
926 // TODO: This should fire the torch, if appropriate.
Puneet Lall512001d2014-08-13 18:53:53 -0700927
928 mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager, mCameraHandler);
929
Puneet Lall580f4512014-08-27 19:27:50 -0700930 return true;
931 } catch (CameraAccessException e) {
932 Log.v(TAG, "Could not execute auto focus hold request.", e);
933 return false;
Puneet Lall512001d2014-08-13 18:53:53 -0700934 }
935 }
936
937 /**
938 * Calculate the aspect ratio of the full size capture on this device.
939 *
940 * @param characteristics the characteristics of the camera device.
941 * @return The aspect ration, in terms of width/height of the full capture
942 * size.
943 */
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700944 private static float calculateFullSizeAspectRatio(CameraCharacteristics characteristics) {
Puneet Lall512001d2014-08-13 18:53:53 -0700945 Rect activeArraySize =
946 characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Jiawen Chen9cefdd42014-09-09 14:14:39 -0700947 return ((float) activeArraySize.width()) / activeArraySize.height();
Puneet Lall512001d2014-08-13 18:53:53 -0700948 }
949
950 /**
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700951 * @param originalWidth the width of the original image captured from the
952 * camera
953 * @param originalHeight the height of the original image captured from the
954 * camera
955 * @param orientation the rotation to apply, in degrees.
956 * @return The size of the final rotated image
957 */
958 private Size getImageSizeForOrientation(int originalWidth, int originalHeight,
959 int orientation) {
960 if (orientation == 0 || orientation == 180) {
961 return new Size(originalWidth, originalHeight);
962 } else if (orientation == 90 || orientation == 270) {
963 return new Size(originalHeight, originalWidth);
964 } else {
965 throw new InvalidParameterException("Orientation not supported.");
966 }
967 }
968
969 /**
Puneet Lall512001d2014-08-13 18:53:53 -0700970 * Given an image reader, extracts the JPEG image bytes and then closes the
971 * reader.
972 *
Puneet Lall182ba6f2014-08-28 16:44:08 -0700973 * @param img the image from which to extract jpeg bytes or compress to
974 * jpeg.
Puneet Lall863a5ab2014-09-05 17:14:41 -0700975 * @param degrees the angle to rotate the image, in degrees. Rotation is
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700976 * only applied to YUV images.
Puneet Lall512001d2014-08-13 18:53:53 -0700977 * @return The bytes of the JPEG image. Newly allocated.
978 */
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700979 private byte[] acquireJpegBytes(Image img, int degrees) {
Puneet Lall512001d2014-08-13 18:53:53 -0700980 ByteBuffer buffer;
981
982 if (img.getFormat() == ImageFormat.JPEG) {
983 Image.Plane plane0 = img.getPlanes()[0];
984 buffer = plane0.getBuffer();
985
986 byte[] imageBytes = new byte[buffer.remaining()];
987 buffer.get(imageBytes);
988 buffer.rewind();
989 return imageBytes;
990 } else if (img.getFormat() == ImageFormat.YUV_420_888) {
991 buffer = mJpegByteBufferPool.acquire();
992 if (buffer == null) {
993 buffer = ByteBuffer.allocateDirect(img.getWidth() * img.getHeight() * 3);
994 }
995
Puneet Lall0ad7ab02014-09-05 10:38:39 -0700996 int numBytes = JpegUtilNative.compressJpegFromYUV420Image(img, buffer, JPEG_QUALITY,
997 degrees);
Puneet Lall512001d2014-08-13 18:53:53 -0700998
999 if (numBytes < 0) {
1000 throw new RuntimeException("Error compressing jpeg.");
1001 }
1002
1003 buffer.limit(numBytes);
1004
1005 byte[] imageBytes = new byte[buffer.remaining()];
1006 buffer.get(imageBytes);
1007
1008 buffer.clear();
1009 mJpegByteBufferPool.release(buffer);
1010
1011 return imageBytes;
1012 } else {
1013 throw new RuntimeException("Unsupported image format.");
1014 }
1015 }
1016
Puneet Lall580f4512014-08-27 19:27:50 -07001017 private void startAFCycle() {
1018 // Clean up any existing AF cycle's pending callbacks.
1019 mCameraHandler.removeCallbacksAndMessages(FOCUS_RESUME_CALLBACK_TOKEN);
1020
1021 // Send a single CONTROL_AF_TRIGGER_START capture request.
1022 sendAutoFocusTriggerRequest();
1023
1024 // Immediately send a request for a regular preview stream, but with
1025 // CONTROL_AF_MODE_AUTO set so that the focus remains constant after the
1026 // AF cycle completes.
1027 sendAutoFocusHoldRequest();
1028
Andy Huibersb8682742014-08-27 15:28:42 -07001029 // Waits Settings3A.getFocusHoldMillis() milliseconds before sending
1030 // a request for a regular preview stream to resume.
Puneet Lall580f4512014-08-27 19:27:50 -07001031 mCameraHandler.postAtTime(new Runnable() {
Puneet Lall80f44442014-09-03 10:43:35 -07001032 @Override
Puneet Lall580f4512014-08-27 19:27:50 -07001033 public void run() {
Andy Huibersb8682742014-08-27 15:28:42 -07001034 mAERegions = ZERO_WEIGHT_3A_REGION;
1035 mAFRegions = ZERO_WEIGHT_3A_REGION;
Puneet Lall580f4512014-08-27 19:27:50 -07001036 sendRepeatingCaptureRequest();
1037 }
Andy Huibersb8682742014-08-27 15:28:42 -07001038 }, FOCUS_RESUME_CALLBACK_TOKEN,
1039 SystemClock.uptimeMillis() + Settings3A.getFocusHoldMillis());
Puneet Lall512001d2014-08-13 18:53:53 -07001040 }
1041
1042 /**
1043 * @see com.android.camera.one.OneCamera#triggerFocusAndMeterAtPoint(float,
1044 * float)
1045 */
1046 @Override
1047 public void triggerFocusAndMeterAtPoint(float nx, float ny) {
Jiawen Chen09713762014-09-16 17:05:37 -07001048 int sensorOrientation = mCharacteristics.get(
1049 CameraCharacteristics.SENSOR_ORIENTATION);
1050 mAERegions = AutoFocusHelper.aeRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
1051 mAFRegions = AutoFocusHelper.afRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
Puneet Lall512001d2014-08-13 18:53:53 -07001052
Puneet Lall580f4512014-08-27 19:27:50 -07001053 startAFCycle();
Puneet Lall512001d2014-08-13 18:53:53 -07001054 }
1055
1056 @Override
1057 public Size pickPreviewSize(Size pictureSize, Context context) {
Puneet Lall4d6d6762014-09-03 13:22:01 -07001058 if (pictureSize == null) {
1059 // TODO The default should be selected by the caller, and
1060 // pictureSize should never be null.
1061 pictureSize = getDefaultPictureSize();
1062 }
Puneet Lall512001d2014-08-13 18:53:53 -07001063 float pictureAspectRatio = pictureSize.getWidth() / (float) pictureSize.getHeight();
Sascha Haeberlingc6da1a12014-11-06 09:50:51 -08001064 return CaptureModuleUtil.getOptimalPreviewSize(context, getSupportedPreviewSizes(),
Puneet Lall512001d2014-08-13 18:53:53 -07001065 pictureAspectRatio);
1066 }
1067
1068 @Override
1069 public float getMaxZoom() {
1070 return mCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
1071 }
1072
1073 @Override
1074 public void setZoom(float zoom) {
1075 mZoomValue = zoom;
1076 mCropRegion = cropRegionForZoom(zoom);
Puneet Lall580f4512014-08-27 19:27:50 -07001077 sendRepeatingCaptureRequest();
Puneet Lall512001d2014-08-13 18:53:53 -07001078 }
1079
1080 private Rect cropRegionForZoom(float zoom) {
Andy Huibersb8682742014-08-27 15:28:42 -07001081 return AutoFocusHelper.cropRegionForZoom(mCharacteristics, zoom);
Puneet Lall512001d2014-08-13 18:53:53 -07001082 }
1083}