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.hardware.camera2.CameraDevice;
21import android.hardware.camera2.CaptureRequest;
22import android.os.Build.VERSION_CODES;
23import android.util.Range;
24import android.view.Surface;
25
26import com.android.camera.FatalErrorHandler;
27import com.android.camera.async.HandlerFactory;
28import com.android.camera.async.Lifetime;
29import com.android.camera.async.MainThread;
30import com.android.camera.async.Observable;
31import com.android.camera.async.Observables;
32import com.android.camera.async.Updatable;
33import com.android.camera.burst.BurstFacade;
34import com.android.camera.burst.BurstTaker;
35import com.android.camera.burst.BurstTakerImpl;
36import com.android.camera.debug.Log.Tag;
37import com.android.camera.debug.Logger;
38import com.android.camera.debug.Loggers;
39import com.android.camera.one.OneCamera;
40import com.android.camera.one.OneCameraCharacteristics;
41import com.android.camera.one.config.OneCameraFeatureConfig.CaptureSupportLevel;
42import com.android.camera.one.v2.camera2proxy.AndroidImageReaderProxy;
43import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
44import com.android.camera.one.v2.camera2proxy.CameraDeviceProxy;
45import com.android.camera.one.v2.camera2proxy.CameraDeviceRequestBuilderFactory;
46import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
47import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy;
48import com.android.camera.one.v2.commands.CameraCommandExecutor;
49import com.android.camera.one.v2.commands.ZslPreviewCommandFactory;
50import com.android.camera.one.v2.common.BasicCameraFactory;
51import com.android.camera.one.v2.common.SimpleCaptureStream;
52import com.android.camera.one.v2.core.FrameServer;
53import com.android.camera.one.v2.core.FrameServerFactory;
54import com.android.camera.one.v2.core.RequestTemplate;
55import com.android.camera.one.v2.core.ResponseListener;
56import com.android.camera.one.v2.core.ResponseListeners;
57import com.android.camera.one.v2.errorhandling.FramerateJankDetector;
58import com.android.camera.one.v2.errorhandling.RepeatFailureHandlerComponent;
59import com.android.camera.one.v2.imagesaver.ImageSaver;
60import com.android.camera.one.v2.initialization.CameraStarter;
61import com.android.camera.one.v2.initialization.InitializedOneCameraFactory;
62import com.android.camera.one.v2.photo.ZslPictureTakerFactory;
63import com.android.camera.one.v2.sharedimagereader.ZslSharedImageReaderFactory;
64import com.android.camera.stats.UsageStatistics;
65import com.android.camera.util.AndroidContext;
66import com.android.camera.util.ApiHelper;
67import com.android.camera.util.GservicesHelper;
68import com.android.camera.util.Provider;
69import com.android.camera.util.Size;
70import com.google.common.base.Supplier;
71
72import java.util.ArrayList;
73import java.util.Arrays;
74import java.util.List;
75import java.util.concurrent.ExecutorService;
76import java.util.concurrent.Executors;
77
78@TargetApi(VERSION_CODES.LOLLIPOP)
79public class ZslOneCameraFactory implements OneCameraFactory {
80    private static Tag TAG = new Tag("ZslOneCamFactory");
81
82    private final Logger mLogger;
83    private final int mImageFormat;
84    private final int mMaxImageCount;
85    private final int maxRingBufferSize;
86
87    public ZslOneCameraFactory(int imageFormat, int maxImageCount) {
88        mImageFormat = imageFormat;
89        mMaxImageCount = maxImageCount;
90        mLogger = Loggers.tagFactory().create(TAG);
91
92        // Determines the maximum size of the ZSL ring-buffer.
93        // Note that this is *different* from mMaxImageCount.
94        // mMaxImageCount determines the size of the ImageReader used for large
95        // (typically YUV) images to be saved. It is correlated with the total
96        // number of in-progress captures which can simultaneously occur by
97        // buffering captured images.
98        // maxRingBufferSize determines the maximum size of the ring-buffer
99        // (which uses a subset of the capacity of the ImageReader). This is
100        // correlated to the maximum amount of look-back for zero-shutter-lag
101        // photography. If this is greater than mMaxImageCount - 2, then it
102        // places no additional constraints on ring-buffer size. That is,
103        // the ring-buffer will expand to fill the entire capacity of the
104        // ImageReader whenever possible.
105
106        // A value of 1 here is adequate for single-frame ZSL capture, but
107        // *must* be increased to support multi-frame burst capture with
108        // zero-shutter-lag.
109        maxRingBufferSize = 1;
110    }
111
112    /**
113     * Slows down the requested camera frame for Nexus 5 back camera issue. This
114     * hack is for the Back Camera for Nexus 5. Requesting on full YUV frames at
115     * 30 fps causes the video preview to deliver frames out of order, mostly
116     * likely due to the overloading of the ISP, and/or image bandwith. The
117     * short-term solution is to back off the frame rate to unadvertised, valid
118     * frame rate of 28 fps. The long-term solution is to advertise this [7,28]
119     * frame rate range in the HAL and get buy-in from the manufacturer to
120     * support and CTS this feature. Then framerate process can occur in more
121     * integrated manner. The tracking bug for this issue is b/18950682.
122     *
123     * @param requestTemplate Request template that will be applied to the
124     *            current camera device
125     */
126    private void applyNexus5BackCameraFrameRateWorkaround(RequestTemplate requestTemplate) {
127        Range<Integer> frameRateBackOff = new Range<>(7, 28);
128        mLogger.v("Applying Nexus5 specific framerate backoff of " + frameRateBackOff);
129        requestTemplate.setParam(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, frameRateBackOff);
130    }
131
132    @Override
133    public OneCamera createOneCamera(final CameraDeviceProxy device,
134            final OneCameraCharacteristics characteristics,
135            CaptureSupportLevel featureConfig,
136            final MainThread mainThread,
137            Size pictureSize,
138            final ImageSaver.Builder imageSaverBuilder,
139            final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting,
140            final Observable<Integer> exposureSetting,
141            final Observable<Boolean> hdrSceneSetting,
142            final BurstFacade burstFacade,
143            final FatalErrorHandler fatalErrorHandler) {
144        final Lifetime lifetime = new Lifetime();
145
146        final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(
147                new LoggingImageReader(AndroidImageReaderProxy.newInstance(
148                        pictureSize.getWidth(), pictureSize.getHeight(),
149                        mImageFormat, mMaxImageCount), Loggers.tagFactory()));
150
151        lifetime.add(imageReader);
152        lifetime.add(device);
153
154        List<Surface> outputSurfaces = new ArrayList<>();
155        outputSurfaces.add(imageReader.getSurface());
156        if (burstFacade.getInputSurface() != null) {
157            outputSurfaces.add(burstFacade.getInputSurface());
158        }
159
160        /**
161         * Finishes constructing the camera when prerequisites, e.g. the preview
162         * stream and capture session, are ready.
163         */
164        CameraStarter cameraStarter = new CameraStarter() {
165            @Override
166            public CameraControls startCamera(Lifetime cameraLifetime,
167                    CameraCaptureSessionProxy cameraCaptureSession,
168                    Surface previewSurface,
169                    Observable<Float> zoomState,
170                    Updatable<TotalCaptureResultProxy> metadataCallback,
171                    Updatable<Boolean> readyStateCallback) {
172                // Create the FrameServer from the CaptureSession.
173                FrameServerFactory frameServerComponent = new FrameServerFactory(new Lifetime
174                        (cameraLifetime), cameraCaptureSession, new HandlerFactory());
175
176                FrameServer frameServer = frameServerComponent.provideFrameServer();
177                FrameServer ephemeralFrameServer = frameServerComponent
178                        .provideEphemeralFrameServer();
179
180                // Create the shared image reader.
181                ZslSharedImageReaderFactory sharedImageReaderFactory =
182                        new ZslSharedImageReaderFactory(new Lifetime(cameraLifetime),
183                                imageReader, new HandlerFactory(), maxRingBufferSize);
184
185                CameraCommandExecutor cameraCommandExecutor = new CameraCommandExecutor(
186                        Loggers.tagFactory(),
187                        new Provider<ExecutorService>() {
188                            @Override
189                            public ExecutorService get() {
190                                // Use a dynamically-expanding thread pool to
191                                // allow any number of commands to execute
192                                // simultaneously.
193                                return Executors.newCachedThreadPool();
194                            }
195                        });
196
197                // Create the request builder used by all camera operations.
198                // Streams, ResponseListeners, and Parameters added to
199                // this will be applied to *all* requests sent to the camera.
200                RequestTemplate rootTemplate = new RequestTemplate(
201                        new CameraDeviceRequestBuilderFactory(device));
202                rootTemplate.addResponseListener(sharedImageReaderFactory
203                        .provideGlobalResponseListener());
204                rootTemplate.addResponseListener(ResponseListeners
205                        .forFinalMetadata(metadataCallback));
206
207                // Create the request builder for the preview warmup in order to workaround
208                // the face detection failure. This is a work around of the HAL face detection
209                // failure in b/20724126.
210                RequestTemplate previewWarmupTemplate = new RequestTemplate(rootTemplate);
211                previewWarmupTemplate.addStream(new SimpleCaptureStream(previewSurface));
212
213                // Create the request builder for the ZSL stream
214                RequestTemplate zslTemplate = new RequestTemplate(rootTemplate);
215                zslTemplate.addStream(sharedImageReaderFactory.provideZSLStream());
216
217                // Create the request builder that will be used by most camera
218                // operations.
219                RequestTemplate zslAndPreviewTemplate = new RequestTemplate(zslTemplate);
220                zslAndPreviewTemplate.addStream(new SimpleCaptureStream(previewSurface));
221
222                boolean isBackCamera = characteristics.getCameraDirection() ==
223                        OneCamera.Facing.BACK;
224
225                if (isBackCamera && ApiHelper.IS_NEXUS_5) {
226                    applyNexus5BackCameraFrameRateWorkaround(zslTemplate);
227                }
228
229                // Create basic functionality (zoom, AE, AF).
230                BasicCameraFactory basicCameraFactory = new BasicCameraFactory(
231                        new Lifetime(cameraLifetime),
232                        characteristics,
233                        ephemeralFrameServer,
234                        zslAndPreviewTemplate,
235                        cameraCommandExecutor,
236                        new ZslPreviewCommandFactory(ephemeralFrameServer,
237                                previewWarmupTemplate,
238                                zslTemplate),
239                        flashSetting,
240                        exposureSetting,
241                        zoomState,
242                        hdrSceneSetting,
243                        CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
244
245                lifetime.add(cameraCommandExecutor);
246
247                // Create the picture-taker.
248                ZslPictureTakerFactory pictureTakerFactory = ZslPictureTakerFactory.create(
249                        Loggers.tagFactory(),
250                        mainThread,
251                        cameraCommandExecutor,
252                        imageSaverBuilder,
253                        frameServer,
254                        basicCameraFactory.provideMeteredZoomedRequestBuilder(),
255                        sharedImageReaderFactory.provideSharedImageReader(),
256                        sharedImageReaderFactory.provideZSLStream(),
257                        sharedImageReaderFactory.provideMetadataPool(),
258                        flashSetting,
259                        zslAndPreviewTemplate);
260
261                BurstTaker burstTaker = new BurstTakerImpl(cameraCommandExecutor,
262                        frameServer,
263                        basicCameraFactory.provideMeteredZoomedRequestBuilder(),
264                        sharedImageReaderFactory.provideSharedImageReader(),
265                        burstFacade.getInputSurface(),
266                        basicCameraFactory.providePreviewUpdater(),
267                        // ImageReader#acquireLatestImage() requires two images
268                        // as the margin so
269                        // specify that as the maximum number of images that can
270                        // be used by burst.
271                        mMaxImageCount - 2);
272                burstFacade.setBurstTaker(burstTaker);
273
274                if (isBackCamera && ApiHelper.IS_NEXUS_5) {
275                    // Workaround for bug: 19061883
276                    ResponseListener failureDetector = RepeatFailureHandlerComponent.create(
277                            Loggers.tagFactory(),
278                            fatalErrorHandler,
279                            cameraCaptureSession,
280                            cameraCommandExecutor,
281                            basicCameraFactory.providePreviewUpdater(),
282                            UsageStatistics.instance(),
283                            10 /* consecutiveFailureThreshold */).provideResponseListener();
284                    zslTemplate.addResponseListener(failureDetector);
285                }
286
287                if (GservicesHelper.isJankStatisticsEnabled(AndroidContext.instance().get()
288                        .getContentResolver())) {
289                    // Don't add jank detection unless the preview is running.
290                    zslAndPreviewTemplate.addResponseListener(
291                          new FramerateJankDetector(Loggers.tagFactory(),
292                                UsageStatistics.instance()));
293                }
294
295                final Observable<Integer> availableImageCount = sharedImageReaderFactory
296                        .provideAvailableImageCount();
297                final Observable<Boolean> frameServerAvailability = frameServerComponent
298                        .provideReadyState();
299                Observable<Boolean> readyObservable = Observables.transform(
300                        Arrays.asList(availableImageCount, frameServerAvailability),
301                        new Supplier<Boolean>() {
302                            @Override
303                            public Boolean get() {
304                                boolean atLeastOneImageAvailable = availableImageCount.get() >= 1;
305                                boolean frameServerAvailable = frameServerAvailability.get();
306                                return atLeastOneImageAvailable && frameServerAvailable;
307                            }
308                        });
309
310                lifetime.add(Observables.addThreadSafeCallback(readyObservable,
311                        readyStateCallback));
312
313                basicCameraFactory.providePreviewUpdater().run();
314
315                return new CameraControls(
316                        pictureTakerFactory.providePictureTaker(),
317                        basicCameraFactory.provideManualAutoFocus());
318            }
319        };
320
321        float maxZoom = characteristics.getAvailableMaxDigitalZoom();
322        List<Size> supportedPreviewSizes = characteristics.getSupportedPreviewSizes();
323        OneCamera.Facing direction = characteristics.getCameraDirection();
324        return new InitializedOneCameraFactory(lifetime, cameraStarter, device,
325                outputSurfaces, mainThread, new HandlerFactory(), maxZoom,
326                supportedPreviewSizes, characteristics.getLensFocusRange(),
327                direction).provideOneCamera();
328    }
329}
330