OneCameraZslImpl.java revision 6281a7942de9e55386c20c6f41bfb656b126a364
1/*
2 * Copyright (C) 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 com.android.camera.one.v2;
18
19import android.annotation.TargetApi;
20import android.content.Context;
21import android.graphics.ImageFormat;
22import android.graphics.Rect;
23import android.hardware.camera2.CameraAccessException;
24import android.hardware.camera2.CameraCaptureSession;
25import android.hardware.camera2.CameraCharacteristics;
26import android.hardware.camera2.CameraDevice;
27import android.hardware.camera2.CameraMetadata;
28import android.hardware.camera2.CaptureRequest;
29import android.hardware.camera2.CaptureResult;
30import android.hardware.camera2.CaptureResult.Key;
31import android.hardware.camera2.TotalCaptureResult;
32import android.hardware.camera2.params.MeteringRectangle;
33import android.hardware.camera2.params.StreamConfigurationMap;
34import android.media.CameraProfile;
35import android.media.Image;
36import android.media.ImageReader;
37import android.media.MediaActionSound;
38import android.net.Uri;
39import android.os.Build;
40import android.os.Handler;
41import android.os.HandlerThread;
42import android.os.SystemClock;
43import android.support.v4.util.Pools;
44import android.view.Surface;
45
46import com.android.camera.CaptureModuleUtil;
47import com.android.camera.app.MediaSaver.OnMediaSavedListener;
48import com.android.camera.debug.Log;
49import com.android.camera.debug.Log.Tag;
50import com.android.camera.exif.ExifInterface;
51import com.android.camera.exif.ExifTag;
52import com.android.camera.exif.Rational;
53import com.android.camera.one.AbstractOneCamera;
54import com.android.camera.one.OneCamera;
55import com.android.camera.one.OneCamera.PhotoCaptureParameters.Flash;
56import com.android.camera.one.Settings3A;
57import com.android.camera.one.v2.ImageCaptureManager.ImageCaptureListener;
58import com.android.camera.one.v2.ImageCaptureManager.MetadataChangeListener;
59import com.android.camera.session.CaptureSession;
60import com.android.camera.util.CameraUtil;
61import com.android.camera.util.ConjunctionListenerMux;
62import com.android.camera.util.JpegUtilNative;
63import com.android.camera.util.Size;
64
65import java.nio.ByteBuffer;
66import java.util.ArrayList;
67import java.util.List;
68import java.util.concurrent.LinkedBlockingQueue;
69import java.util.concurrent.ThreadPoolExecutor;
70import java.util.concurrent.TimeUnit;
71import java.util.concurrent.atomic.AtomicLong;
72
73/**
74 * {@link OneCamera} implementation directly on top of the Camera2 API with zero
75 * shutter lag.<br>
76 * TODO: Determine what the maximum number of full YUV capture frames is.
77 */
78@TargetApi(Build.VERSION_CODES.L)
79public class OneCameraZslImpl extends AbstractOneCamera {
80    private static final Tag TAG = new Tag("OneCameraZslImpl2");
81
82    /** Default JPEG encoding quality. */
83    private static final int JPEG_QUALITY = CameraProfile.getJpegEncodingQualityParameter(
84            CameraProfile.QUALITY_HIGH);
85    /**
86     * The maximum number of images to store in the full-size ZSL ring buffer.
87     * <br>
88     * TODO: Determine this number dynamically based on available memory and the
89     * size of frames.
90     */
91    private static final int MAX_CAPTURE_IMAGES = 10;
92    /**
93     * True if zero-shutter-lag images should be captured. Some devices produce
94     * lower-quality images for the high-frequency stream, so we may wish to
95     * disable ZSL in that case.
96     */
97    private static final boolean ZSL_ENABLED = true;
98
99    /**
100     * Tags which may be used in CaptureRequests.
101     */
102    private static enum RequestTag {
103        /**
104         * Indicates that the request was explicitly sent for a single
105         * high-quality still capture. Unlike other requests, such as the
106         * repeating (ZSL) stream and AF/AE triggers, requests with this tag
107         * should always be saved.
108         */
109        EXPLICIT_CAPTURE
110    }
111
112    /**
113     * Set to ImageFormat.JPEG to use the hardware encoder, or
114     * ImageFormat.YUV_420_888 to use the software encoder. No other image
115     * formats are supported.
116     */
117    private static final int sCaptureImageFormat = ImageFormat.YUV_420_888;
118    /**
119     * Token for callbacks posted to {@link #mCameraHandler} to resume
120     * continuous AF.
121     */
122    private static final String FOCUS_RESUME_CALLBACK_TOKEN = "RESUME_CONTINUOUS_AF";
123    /** Zero weight 3A region, to reset regions per API. */
124    MeteringRectangle[] ZERO_WEIGHT_3A_REGION = AutoFocusHelper.getZeroWeightRegion();
125
126    /**
127     * Thread on which high-priority camera operations, such as grabbing preview
128     * frames for the viewfinder, are running.
129     */
130    private final HandlerThread mCameraThread;
131    /** Handler of the {@link #mCameraThread}. */
132    private final Handler mCameraHandler;
133
134    /** Thread on which low-priority camera listeners are running. */
135    private final HandlerThread mCameraListenerThread;
136    private final Handler mCameraListenerHandler;
137
138    /** The characteristics of this camera. */
139    private final CameraCharacteristics mCharacteristics;
140    /** The underlying Camera2 API camera device. */
141    private final CameraDevice mDevice;
142
143    /**
144     * The aspect ratio (width/height) of the full resolution for this camera.
145     * Usually the native aspect ratio of this camera.
146     */
147    private final double mFullSizeAspectRatio;
148    /** The Camera2 API capture session currently active. */
149    private CameraCaptureSession mCaptureSession;
150    /** The surface onto which to render the preview. */
151    private Surface mPreviewSurface;
152    /** Whether closing of this device has been requested. */
153    private volatile boolean mIsClosed = false;
154    /** A callback that is called when the device is fully closed. */
155    private CloseCallback mCloseCallback = null;
156
157    /** Receives the normal captured images. */
158    private final ImageReader mCaptureImageReader;
159
160    /**
161     * Maintains a buffer of images and their associated {@link CaptureResult}s.
162     */
163    private ImageCaptureManager mCaptureManager;
164
165    /**
166     * The sensor timestamp (which may not be relative to the system time) of
167     * the most recently captured image.
168     */
169    private final AtomicLong mLastCapturedImageTimestamp = new AtomicLong(0);
170
171    /** Thread pool for performing slow jpeg encoding and saving tasks. */
172    private final ThreadPoolExecutor mImageSaverThreadPool;
173
174    /** Pool of native byte buffers on which to store jpeg-encoded images. */
175    private final Pools.SynchronizedPool<ByteBuffer> mJpegByteBufferPool = new
176            Pools.SynchronizedPool<ByteBuffer>(64);
177
178    /** Current zoom value. 1.0 is no zoom. */
179    private float mZoomValue = 1f;
180    /** Current crop region: set from mZoomValue. */
181    private Rect mCropRegion;
182    /** Current AE, AF, and AWB regions */
183    private MeteringRectangle[] mAFRegions = ZERO_WEIGHT_3A_REGION;
184    private MeteringRectangle[] mAERegions = ZERO_WEIGHT_3A_REGION;
185
186    private MediaActionSound mMediaActionSound = new MediaActionSound();
187
188    /**
189     * Ready state (typically displayed by the UI shutter-button) depends on two
190     * things:<br>
191     * <ol>
192     * <li>{@link #mCaptureManager} must be ready.</li>
193     * <li>We must not be in the process of capturing a single, high-quality,
194     * image.</li>
195     * </ol>
196     * See {@link ConjunctionListenerMux} and {@link #mReadyStateManager} for
197     * details of how this is managed.
198     */
199    private static enum ReadyStateRequirement {
200        CAPTURE_MANAGER_READY,
201        CAPTURE_NOT_IN_PROGRESS
202    }
203
204    /**
205     * Handles the thread-safe logic of dispatching whenever the logical AND of
206     * these constraints changes.
207     */
208    private final ConjunctionListenerMux<ReadyStateRequirement>
209            mReadyStateManager = new ConjunctionListenerMux<ReadyStateRequirement>(
210                    ReadyStateRequirement.class, new ConjunctionListenerMux.OutputChangeListener() {
211                            @Override
212                        public void onOutputChange(boolean state) {
213                            broadcastReadyState(state);
214                        }
215                    });
216
217    /**
218     * An {@link ImageCaptureListener} which will compress and save an image to
219     * disk.
220     */
221    private class ImageCaptureTask implements ImageCaptureListener {
222        private final PhotoCaptureParameters mParams;
223        private final CaptureSession mSession;
224
225        public ImageCaptureTask(PhotoCaptureParameters parameters,
226                CaptureSession session) {
227            mParams = parameters;
228            mSession = session;
229        }
230
231        @Override
232        public void onImageCaptured(Image image, TotalCaptureResult
233                captureResult) {
234            long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
235
236            // We should only capture the image if it's more recent than the
237            // latest one. Synchronization is necessary since this method is
238            // called on {@link #mImageSaverThreadPool}.
239            synchronized (mLastCapturedImageTimestamp) {
240                if (timestamp > mLastCapturedImageTimestamp.get()) {
241                    mLastCapturedImageTimestamp.set(timestamp);
242                } else {
243                    // There was a more recent (or identical) image which has
244                    // begun being saved, so abort.
245                    return;
246                }
247            }
248
249            mReadyStateManager.setInput(
250                    ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, true);
251
252            mSession.startEmpty();
253            savePicture(image, mParams, mSession);
254            mParams.callback.onPictureTaken(mSession);
255            Log.v(TAG, "Image saved.  Frame number = " + captureResult.getFrameNumber());
256        }
257    }
258
259    /**
260     * Instantiates a new camera based on Camera 2 API.
261     *
262     * @param device The underlying Camera 2 device.
263     * @param characteristics The device's characteristics.
264     * @param pictureSize the size of the final image to be taken.
265     */
266    OneCameraZslImpl(CameraDevice device, CameraCharacteristics characteristics, Size pictureSize) {
267        Log.v(TAG, "Creating new OneCameraZslImpl");
268
269        mDevice = device;
270        mCharacteristics = characteristics;
271        mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
272
273        mCameraThread = new HandlerThread("OneCamera2");
274        // If this thread stalls, it will delay viewfinder frames.
275        mCameraThread.setPriority(Thread.MAX_PRIORITY);
276        mCameraThread.start();
277        mCameraHandler = new Handler(mCameraThread.getLooper());
278
279        mCameraListenerThread = new HandlerThread("OneCamera2-Listener");
280        mCameraListenerThread.start();
281        mCameraListenerHandler = new Handler(mCameraListenerThread.getLooper());
282
283        // TODO: Encoding on multiple cores results in preview jank due to
284        // excessive GC.
285        int numEncodingCores = CameraUtil.getNumCpuCores();
286        mImageSaverThreadPool = new ThreadPoolExecutor(numEncodingCores, numEncodingCores, 10,
287                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
288
289        mCaptureManager = new ImageCaptureManager(MAX_CAPTURE_IMAGES, mCameraListenerHandler,
290                mImageSaverThreadPool);
291        mCaptureManager.setCaptureReadyListener(new ImageCaptureManager.CaptureReadyListener() {
292                @Override
293            public void onReadyStateChange(boolean capturePossible) {
294                mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_MANAGER_READY,
295                        capturePossible);
296            }
297        });
298
299        // Listen for changes to auto focus state and dispatch to
300        // mFocusStateListener.
301        mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AF_STATE,
302                new ImageCaptureManager.MetadataChangeListener() {
303                @Override
304                    public void onImageMetadataChange(Key<?> key, Object oldValue, Object newValue,
305                            CaptureResult result) {
306                        mFocusStateListener.onFocusStatusUpdate(
307                                AutoFocusHelper.stateFromCamera2State(
308                                        result.get(CaptureResult.CONTROL_AF_STATE)),
309                                result.getFrameNumber());
310                    }
311                });
312
313        // Allocate the image reader to store all images received from the
314        // camera.
315        if (pictureSize == null) {
316            // TODO The default should be selected by the caller, and
317            // pictureSize should never be null.
318            pictureSize = getDefaultPictureSize();
319        }
320        mCaptureImageReader = ImageReader.newInstance(pictureSize.getWidth(),
321                pictureSize.getHeight(),
322                sCaptureImageFormat, MAX_CAPTURE_IMAGES);
323
324        mCaptureImageReader.setOnImageAvailableListener(mCaptureManager, mCameraHandler);
325        mMediaActionSound.load(MediaActionSound.SHUTTER_CLICK);
326    }
327
328    /**
329     * @return The largest supported picture size.
330     */
331    public Size getDefaultPictureSize() {
332        StreamConfigurationMap configs = mCharacteristics.get(
333                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
334        android.util.Size[] supportedSizes = configs.getOutputSizes(sCaptureImageFormat);
335
336        // Find the largest supported size.
337        android.util.Size largestSupportedSize = supportedSizes[0];
338        long largestSupportedSizePixels = largestSupportedSize.getWidth()
339                * largestSupportedSize.getHeight();
340        for (int i = 0; i < supportedSizes.length; i++) {
341            long numPixels = supportedSizes[i].getWidth() * supportedSizes[i].getHeight();
342            if (numPixels > largestSupportedSizePixels) {
343                largestSupportedSize = supportedSizes[i];
344                largestSupportedSizePixels = numPixels;
345            }
346        }
347
348        return new Size(largestSupportedSize.getWidth(),
349                largestSupportedSize.getHeight());
350    }
351
352
353    private void onShutterInvokeUI(final PhotoCaptureParameters params) {
354        // Tell CaptureModule shutter has occurred so it can flash the screen.
355        params.callback.onQuickExpose();
356        // Play shutter click sound.
357        mMediaActionSound.play(MediaActionSound.SHUTTER_CLICK);
358    }
359
360    /**
361     * Take a picture.
362     */
363    @Override
364    public void takePicture(final PhotoCaptureParameters params, final CaptureSession session) {
365        params.checkSanity();
366
367        mReadyStateManager.setInput(
368                ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, false);
369
370        boolean useZSL = ZSL_ENABLED;
371
372        // We will only capture images from the zsl ring-buffer which satisfy
373        // this constraint.
374        ArrayList<ImageCaptureManager.CapturedImageConstraint> zslConstraints = new ArrayList<
375                ImageCaptureManager.CapturedImageConstraint>();
376        zslConstraints.add(new ImageCaptureManager.CapturedImageConstraint() {
377                @Override
378            public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
379                Long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
380                Integer lensState = captureResult.get(CaptureResult.LENS_STATE);
381                Integer flashState = captureResult.get(CaptureResult.FLASH_STATE);
382                Integer flashMode = captureResult.get(CaptureResult.FLASH_MODE);
383                Integer aeState = captureResult.get(CaptureResult.CONTROL_AE_STATE);
384                Integer afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
385                Integer awbState = captureResult.get(CaptureResult.CONTROL_AWB_STATE);
386
387                if (timestamp <= mLastCapturedImageTimestamp.get()) {
388                    // Don't save frames older than the most
389                    // recently-captured frame.
390                    // TODO This technically has a race condition in which
391                    // duplicate frames may be saved, but if a user is
392                    // tapping at >30Hz, duplicate images may be what they
393                    // expect.
394                    return false;
395                }
396
397                if (lensState == CaptureResult.LENS_STATE_MOVING) {
398                    // If we know the lens was moving, don't use this image.
399                    return false;
400                }
401
402                if (aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING
403                        || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
404                    return false;
405                }
406                switch (params.flashMode) {
407                    case OFF:
408                        break;
409                    case ON:
410                        if (flashState != CaptureResult.FLASH_STATE_FIRED
411                                || flashMode != CaptureResult.FLASH_MODE_SINGLE) {
412                            return false;
413                        }
414                        break;
415                    case AUTO:
416                        if (aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
417                                && flashState != CaptureResult.FLASH_STATE_FIRED) {
418                            return false;
419                        }
420                        break;
421                }
422
423                if (afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN
424                        || afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN) {
425                    return false;
426                }
427
428                if (awbState == CaptureResult.CONTROL_AWB_STATE_SEARCHING) {
429                    return false;
430                }
431
432                return true;
433            }
434        });
435        // This constraint lets us capture images which have been explicitly
436        // requested. See {@link RequestTag.EXPLICIT_CAPTURE}.
437        ArrayList<ImageCaptureManager.CapturedImageConstraint> singleCaptureConstraint = new ArrayList<
438                ImageCaptureManager.CapturedImageConstraint>();
439        singleCaptureConstraint.add(new ImageCaptureManager.CapturedImageConstraint() {
440                @Override
441            public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
442                Object tag = captureResult.getRequest().getTag();
443                return tag == RequestTag.EXPLICIT_CAPTURE;
444            }
445        });
446
447        // If we can use ZSL, try to save a previously-captured frame, if an
448        // acceptable one exists in the buffer.
449        if (useZSL) {
450            boolean capturedPreviousFrame = mCaptureManager.tryCaptureExistingImage(
451                    new ImageCaptureTask(params, session), zslConstraints);
452            if (capturedPreviousFrame) {
453                Log.v(TAG, "Saving previous frame");
454                onShutterInvokeUI(params);
455            } else {
456                Log.v(TAG, "No good image Available.  Capturing next available good image.");
457                // If there was no good frame available in the ring buffer
458                // already, capture the next good image.
459                // TODO Disable the shutter button until this image is captured.
460
461                if (params.flashMode == Flash.ON || params.flashMode == Flash.AUTO) {
462                    // We must issue a request for a single capture using the
463                    // flash, including an AE precapture trigger.
464
465                    // The following sets up a sequence of events which will
466                    // occur in reverse order to the associated method
467                    // calls:
468                    // 1. Send a request to trigger the Auto Exposure Precapture
469                    // 2. Wait for the AE_STATE to leave the PRECAPTURE state,
470                    // and then send a request for a single image, with the
471                    // appropriate flash settings.
472                    // 3. Capture the next appropriate image, which should be
473                    // the one we requested in (2).
474
475                    mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
476                            singleCaptureConstraint);
477
478                    mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AE_STATE,
479                            new MetadataChangeListener() {
480                            @Override
481                                public void onImageMetadataChange(Key<?> key, Object oldValue,
482                                        Object newValue, CaptureResult result) {
483                                    Log.v(TAG, "AE State Changed");
484                                    if (oldValue.equals(
485                                            Integer.valueOf(
486                                                    CaptureResult.CONTROL_AE_STATE_PRECAPTURE))) {
487                                        mCaptureManager.removeMetadataChangeListener(key, this);
488                                        sendSingleRequest(params);
489                                        // TODO: Delay this until onCaptureStarted().
490                                        onShutterInvokeUI(params);
491                                    }
492                                }
493                            });
494
495                    sendAutoExposureTriggerRequest(params.flashMode);
496                } else {
497                    // We may get here if, for example, the auto focus is in the
498                    // middle of a scan.
499                    // If the flash is off, we should just wait for the next
500                    // image that arrives. This will have minimal delay since we
501                    // do not need to send a new capture request.
502                    mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
503                            zslConstraints);
504                }
505            }
506        } else {
507            // TODO If we can't save a previous frame, create a new capture
508            // request to do what we need (e.g. flash) and call
509            // captureNextImage().
510            throw new UnsupportedOperationException("Non-ZSL capture not yet supported");
511        }
512    }
513
514    @Override
515    public void startPreview(Surface previewSurface, CaptureReadyCallback listener) {
516        mPreviewSurface = previewSurface;
517        setupAsync(mPreviewSurface, listener);
518    }
519
520    @Override
521    public void setViewFinderSize(int width, int height) {
522        throw new RuntimeException("Not implemented yet.");
523    }
524
525    @Override
526    public boolean isFlashSupported(boolean enhanced) {
527        throw new RuntimeException("Not implemented yet.");
528    }
529
530    @Override
531    public boolean isSupportingEnhancedMode() {
532        throw new RuntimeException("Not implemented yet.");
533    }
534
535    @Override
536    public void close(CloseCallback closeCallback) {
537        if (mIsClosed) {
538            Log.w(TAG, "Camera is already closed.");
539            return;
540        }
541        try {
542            mCaptureSession.abortCaptures();
543        } catch (CameraAccessException e) {
544            Log.e(TAG, "Could not abort captures in progress.");
545        }
546        mIsClosed = true;
547        mCloseCallback = closeCallback;
548        mCameraThread.quitSafely();
549        mDevice.close();
550        mCaptureManager.close();
551    }
552
553    @Override
554    public Size[] getSupportedSizes() {
555        StreamConfigurationMap config = mCharacteristics
556                .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
557        return Size.convert(config.getOutputSizes(sCaptureImageFormat));
558    }
559
560    @Override
561    public double getFullSizeAspectRatio() {
562        return mFullSizeAspectRatio;
563    }
564
565    @Override
566    public boolean isFrontFacing() {
567        return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
568                == CameraMetadata.LENS_FACING_FRONT;
569    }
570
571    @Override
572    public boolean isBackFacing() {
573        return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
574                == CameraMetadata.LENS_FACING_BACK;
575    }
576
577    private void savePicture(Image image, final PhotoCaptureParameters captureParams,
578            CaptureSession session) {
579        int heading = captureParams.heading;
580
581        int width = image.getWidth();
582        int height = image.getHeight();
583        int rotation = 0;
584        ExifInterface exif = null;
585
586        exif = new ExifInterface();
587        // TODO: Add more exif tags here.
588
589        exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_X_DIMENSION, width));
590        exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_Y_DIMENSION, height));
591
592        // TODO: Handle rotation correctly.
593
594        // Set GPS heading direction based on sensor, if location is on.
595        if (heading >= 0) {
596            ExifTag directionRefTag = exif.buildTag(
597                    ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
598                    ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
599            ExifTag directionTag = exif.buildTag(
600                    ExifInterface.TAG_GPS_IMG_DIRECTION,
601                    new Rational(heading, 1));
602            exif.setTag(directionRefTag);
603            exif.setTag(directionTag);
604        }
605
606        session.saveAndFinish(acquireJpegBytes(image), width, height, rotation, exif,
607                new OnMediaSavedListener() {
608                @Override
609                    public void onMediaSaved(Uri uri) {
610                        captureParams.callback.onPictureSaved(uri);
611                    }
612                });
613    }
614
615    /**
616     * Asynchronously sets up the capture session.
617     *
618     * @param previewSurface the surface onto which the preview should be
619     *            rendered.
620     * @param listener called when setup is completed.
621     */
622    private void setupAsync(final Surface previewSurface, final CaptureReadyCallback listener) {
623        mCameraHandler.post(new Runnable() {
624                @Override
625            public void run() {
626                setup(previewSurface, listener);
627            }
628        });
629    }
630
631    /**
632     * Configures and attempts to create a capture session.
633     *
634     * @param previewSurface the surface onto which the preview should be
635     *            rendered.
636     * @param listener called when the setup is completed.
637     */
638    private void setup(Surface previewSurface, final CaptureReadyCallback listener) {
639        try {
640            if (mCaptureSession != null) {
641                mCaptureSession.abortCaptures();
642                mCaptureSession = null;
643            }
644            List<Surface> outputSurfaces = new ArrayList<Surface>(2);
645            outputSurfaces.add(previewSurface);
646            outputSurfaces.add(mCaptureImageReader.getSurface());
647
648            mDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
649                    @Override
650                public void onConfigureFailed(CameraCaptureSession session) {
651                    listener.onSetupFailed();
652                }
653
654                    @Override
655                public void onConfigured(CameraCaptureSession session) {
656                    mCaptureSession = session;
657                    mAFRegions = ZERO_WEIGHT_3A_REGION;
658                    mAERegions = ZERO_WEIGHT_3A_REGION;
659                    mZoomValue = 1f;
660                    mCropRegion = cropRegionForZoom(mZoomValue);
661                    boolean success = sendRepeatingCaptureRequest();
662                    if (success) {
663                        mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS,
664                                true);
665                        mReadyStateManager.notifyListeners();
666                        listener.onReadyForCapture();
667                    } else {
668                        listener.onSetupFailed();
669                    }
670                }
671
672                    @Override
673                public void onClosed(CameraCaptureSession session) {
674                    super.onClosed(session);
675                    if (mCloseCallback != null) {
676                        mCloseCallback.onCameraClosed();
677                    }
678                }
679            }, mCameraHandler);
680        } catch (CameraAccessException ex) {
681            Log.e(TAG, "Could not set up capture session", ex);
682            listener.onSetupFailed();
683        }
684    }
685
686    private void addRegionsToCaptureRequestBuilder(CaptureRequest.Builder builder) {
687        builder.set(CaptureRequest.CONTROL_AE_REGIONS, mAERegions);
688        builder.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions);
689        builder.set(CaptureRequest.SCALER_CROP_REGION, mCropRegion);
690    }
691
692    private void addFlashToCaptureRequestBuilder(CaptureRequest.Builder builder, Flash flashMode) {
693        switch (flashMode) {
694            case ON:
695                builder.set(CaptureRequest.CONTROL_AE_MODE,
696                        CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
697                builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
698                break;
699            case OFF:
700                builder.set(CaptureRequest.CONTROL_AE_MODE,
701                        CaptureRequest.CONTROL_AE_MODE_ON);
702                builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
703                break;
704            case AUTO:
705                builder.set(CaptureRequest.CONTROL_AE_MODE,
706                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
707                break;
708        }
709    }
710
711    /**
712     * Request a stream of images.
713     *
714     * @return true if successful, false if there was an error submitting the
715     *         capture request.
716     */
717    private boolean sendRepeatingCaptureRequest() {
718        Log.v(TAG, "sendRepeatingCaptureRequest()");
719        try {
720            CaptureRequest.Builder builder;
721            if (ZSL_ENABLED) {
722                builder = mDevice.
723                        createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
724            } else {
725                builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
726            }
727
728            builder.addTarget(mPreviewSurface);
729
730            if (ZSL_ENABLED) {
731                builder.addTarget(mCaptureImageReader.getSurface());
732            }
733
734            builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
735
736            builder.set(CaptureRequest.CONTROL_AF_MODE,
737                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
738            builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
739
740            builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
741            builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
742
743            addRegionsToCaptureRequestBuilder(builder);
744
745            mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager,
746                    mCameraHandler);
747            return true;
748        } catch (CameraAccessException e) {
749            if (ZSL_ENABLED) {
750                Log.v(TAG, "Could not execute zero-shutter-lag repeating request.", e);
751            } else {
752                Log.v(TAG, "Could not execute preview request.", e);
753            }
754            return false;
755        }
756    }
757
758    /**
759     * Request a single image.
760     *
761     * @return true if successful, false if there was an error submitting the
762     *         capture request.
763     */
764    private boolean sendSingleRequest(OneCamera.PhotoCaptureParameters params) {
765        Log.v(TAG, "sendSingleRequest()");
766        try {
767            CaptureRequest.Builder builder;
768            builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
769
770            builder.addTarget(mPreviewSurface);
771
772            // Always add this surface for single image capture requests.
773            builder.addTarget(mCaptureImageReader.getSurface());
774
775            builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
776
777            addFlashToCaptureRequestBuilder(builder, params.flashMode);
778            addRegionsToCaptureRequestBuilder(builder);
779
780            builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
781            builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
782
783            // Tag this as a special request which should be saved.
784            builder.setTag(RequestTag.EXPLICIT_CAPTURE);
785
786            if (sCaptureImageFormat == ImageFormat.JPEG) {
787                builder.set(CaptureRequest.JPEG_QUALITY, (byte) (JPEG_QUALITY));
788                builder.set(CaptureRequest.JPEG_ORIENTATION,
789                        CameraUtil.getJpegRotation(params.orientation, mCharacteristics));
790            }
791
792            mCaptureSession.capture(builder.build(), mCaptureManager,
793                    mCameraHandler);
794            return true;
795        } catch (CameraAccessException e) {
796            Log.v(TAG, "Could not execute single still capture request.", e);
797            return false;
798        }
799    }
800
801    private boolean sendAutoExposureTriggerRequest(Flash flashMode) {
802        Log.v(TAG, "sendAutoExposureTriggerRequest()");
803        try {
804            CaptureRequest.Builder builder;
805            if (ZSL_ENABLED) {
806                builder = mDevice.
807                        createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
808            } else {
809                builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
810            }
811
812            builder.addTarget(mPreviewSurface);
813
814            if (ZSL_ENABLED) {
815                builder.addTarget(mCaptureImageReader.getSurface());
816            }
817
818            builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
819
820            builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
821                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
822
823            addRegionsToCaptureRequestBuilder(builder);
824            addFlashToCaptureRequestBuilder(builder, flashMode);
825
826            mCaptureSession.capture(builder.build(), mCaptureManager,
827                    mCameraHandler);
828
829            return true;
830        } catch (CameraAccessException e) {
831            Log.v(TAG, "Could not execute auto exposure trigger request.", e);
832            return false;
833        }
834    }
835
836    /**
837     */
838    private boolean sendAutoFocusTriggerRequest() {
839        Log.v(TAG, "sendAutoFocusTriggerRequest()");
840        try {
841            CaptureRequest.Builder builder;
842            if (ZSL_ENABLED) {
843                builder = mDevice.
844                        createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
845            } else {
846                builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
847            }
848
849            builder.addTarget(mPreviewSurface);
850
851            if (ZSL_ENABLED) {
852                builder.addTarget(mCaptureImageReader.getSurface());
853            }
854
855            builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
856
857            addRegionsToCaptureRequestBuilder(builder);
858
859            builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
860            builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
861
862            mCaptureSession.capture(builder.build(), mCaptureManager,
863                    mCameraHandler);
864
865            return true;
866        } catch (CameraAccessException e) {
867            Log.v(TAG, "Could not execute auto focus trigger request.", e);
868            return false;
869        }
870    }
871
872    /**
873     * Like {@link #sendRepeatingCaptureRequest()}, but with the focus held
874     * constant.
875     *
876     * @return true if successful, false if there was an error submitting the
877     *         capture request.
878     */
879    private boolean sendAutoFocusHoldRequest() {
880        Log.v(TAG, "sendAutoFocusHoldRequest()");
881        try {
882            CaptureRequest.Builder builder;
883            if (ZSL_ENABLED) {
884                builder = mDevice.
885                        createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
886            } else {
887                builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
888            }
889
890            builder.addTarget(mPreviewSurface);
891
892            if (ZSL_ENABLED) {
893                builder.addTarget(mCaptureImageReader.getSurface());
894            }
895
896            builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
897
898            builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
899            builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
900
901            addRegionsToCaptureRequestBuilder(builder);
902            // TODO: This should fire the torch, if appropriate.
903
904            mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager, mCameraHandler);
905
906            return true;
907        } catch (CameraAccessException e) {
908            Log.v(TAG, "Could not execute auto focus hold request.", e);
909            return false;
910        }
911    }
912
913    /**
914     * Calculate the aspect ratio of the full size capture on this device.
915     *
916     * @param characteristics the characteristics of the camera device.
917     * @return The aspect ration, in terms of width/height of the full capture
918     *         size.
919     */
920    private static double calculateFullSizeAspectRatio(CameraCharacteristics characteristics) {
921        Rect activeArraySize =
922                characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
923        return (double) activeArraySize.width() / activeArraySize.height();
924    }
925
926    /**
927     * Given an image reader, extracts the JPEG image bytes and then closes the
928     * reader.
929     *
930     * @param img the image from which to extract jpeg bytes or compress to
931     *            jpeg.
932     * @return The bytes of the JPEG image. Newly allocated.
933     */
934    private byte[] acquireJpegBytes(Image img) {
935        ByteBuffer buffer;
936
937        if (img.getFormat() == ImageFormat.JPEG) {
938            Image.Plane plane0 = img.getPlanes()[0];
939            buffer = plane0.getBuffer();
940
941            byte[] imageBytes = new byte[buffer.remaining()];
942            buffer.get(imageBytes);
943            buffer.rewind();
944            return imageBytes;
945        } else if (img.getFormat() == ImageFormat.YUV_420_888) {
946            buffer = mJpegByteBufferPool.acquire();
947            if (buffer == null) {
948                buffer = ByteBuffer.allocateDirect(img.getWidth() * img.getHeight() * 3);
949            }
950
951            int numBytes = JpegUtilNative.compressJpegFromYUV420Image(img, buffer, JPEG_QUALITY);
952
953            if (numBytes < 0) {
954                throw new RuntimeException("Error compressing jpeg.");
955            }
956
957            buffer.limit(numBytes);
958
959            byte[] imageBytes = new byte[buffer.remaining()];
960            buffer.get(imageBytes);
961
962            buffer.clear();
963            mJpegByteBufferPool.release(buffer);
964
965            return imageBytes;
966        } else {
967            throw new RuntimeException("Unsupported image format.");
968        }
969    }
970
971    private void startAFCycle() {
972        // Clean up any existing AF cycle's pending callbacks.
973        mCameraHandler.removeCallbacksAndMessages(FOCUS_RESUME_CALLBACK_TOKEN);
974
975        // Send a single CONTROL_AF_TRIGGER_START capture request.
976        sendAutoFocusTriggerRequest();
977
978        // Immediately send a request for a regular preview stream, but with
979        // CONTROL_AF_MODE_AUTO set so that the focus remains constant after the
980        // AF cycle completes.
981        sendAutoFocusHoldRequest();
982
983        // Waits Settings3A.getFocusHoldMillis() milliseconds before sending
984        // a request for a regular preview stream to resume.
985        mCameraHandler.postAtTime(new Runnable() {
986                @Override
987            public void run() {
988                mAERegions = ZERO_WEIGHT_3A_REGION;
989                mAFRegions = ZERO_WEIGHT_3A_REGION;
990                sendRepeatingCaptureRequest();
991            }
992        }, FOCUS_RESUME_CALLBACK_TOKEN,
993                SystemClock.uptimeMillis() + Settings3A.getFocusHoldMillis());
994    }
995
996    /**
997     * @see com.android.camera.one.OneCamera#triggerFocusAndMeterAtPoint(float,
998     *      float)
999     */
1000    @Override
1001    public void triggerFocusAndMeterAtPoint(float nx, float ny) {
1002        // xc, yc is center of tap point in sensor coordinate system.
1003        int xc = mCropRegion.left + (int) (mCropRegion.width() * ny);
1004        int yc = mCropRegion.top + (int) (mCropRegion.height() * (1f - nx));
1005
1006        mAERegions = AutoFocusHelper.aeRegionsForSensorCoord(xc, yc, mCropRegion);
1007        mAFRegions = AutoFocusHelper.afRegionsForSensorCoord(xc, yc, mCropRegion);
1008
1009        startAFCycle();
1010    }
1011
1012    @Override
1013    public Size pickPreviewSize(Size pictureSize, Context context) {
1014        if (pictureSize == null) {
1015            // TODO The default should be selected by the caller, and
1016            // pictureSize should never be null.
1017            pictureSize = getDefaultPictureSize();
1018        }
1019        float pictureAspectRatio = pictureSize.getWidth() / (float) pictureSize.getHeight();
1020        return CaptureModuleUtil.getOptimalPreviewSize(context, getSupportedSizes(),
1021                pictureAspectRatio);
1022    }
1023
1024    @Override
1025    public float getMaxZoom() {
1026        return mCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
1027    }
1028
1029    @Override
1030    public void setZoom(float zoom) {
1031        mZoomValue = zoom;
1032        mCropRegion = cropRegionForZoom(zoom);
1033        sendRepeatingCaptureRequest();
1034    }
1035
1036    private Rect cropRegionForZoom(float zoom) {
1037        return AutoFocusHelper.cropRegionForZoom(mCharacteristics, zoom);
1038    }
1039}
1040