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.graphics.ImageFormat;
21import android.hardware.camera2.CameraDevice;
22import android.hardware.camera2.CaptureRequest;
23import android.os.Build;
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.debug.Loggers;
35import com.android.camera.one.OneCamera;
36import com.android.camera.one.OneCameraCharacteristics;
37import com.android.camera.one.config.OneCameraFeatureConfig;
38import com.android.camera.one.v2.camera2proxy.AndroidImageReaderProxy;
39import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
40import com.android.camera.one.v2.camera2proxy.CameraDeviceProxy;
41import com.android.camera.one.v2.camera2proxy.CameraDeviceRequestBuilderFactory;
42import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
43import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy;
44import com.android.camera.one.v2.commands.CameraCommandExecutor;
45import com.android.camera.one.v2.commands.BasicPreviewCommandFactory;
46import com.android.camera.one.v2.common.BasicCameraFactory;
47import com.android.camera.one.v2.common.SimpleCaptureStream;
48import com.android.camera.one.v2.core.FrameServer;
49import com.android.camera.one.v2.core.FrameServerFactory;
50import com.android.camera.one.v2.core.RequestBuilder;
51import com.android.camera.one.v2.core.RequestTemplate;
52import com.android.camera.one.v2.core.ResponseListeners;
53import com.android.camera.one.v2.errorhandling.FramerateJankDetector;
54import com.android.camera.one.v2.imagesaver.ImageSaver;
55import com.android.camera.one.v2.initialization.CameraStarter;
56import com.android.camera.one.v2.initialization.InitializedOneCameraFactory;
57import com.android.camera.one.v2.photo.ImageRotationCalculator;
58import com.android.camera.one.v2.photo.LegacyPictureTakerFactory;
59import com.android.camera.one.v2.photo.PictureTaker;
60import com.android.camera.one.v2.photo.PictureTakerFactory;
61import com.android.camera.one.v2.sharedimagereader.ManagedImageReader;
62import com.android.camera.one.v2.sharedimagereader.SharedImageReaderFactory;
63import com.android.camera.stats.UsageStatistics;
64import com.android.camera.util.AndroidContext;
65import com.android.camera.util.GservicesHelper;
66import com.android.camera.util.Provider;
67import com.android.camera.util.Size;
68import com.google.common.base.Supplier;
69
70import java.util.ArrayList;
71import java.util.Arrays;
72import java.util.List;
73import java.util.concurrent.ExecutorService;
74import java.util.concurrent.Executors;
75
76/**
77 * Creates a camera which takes jpeg images using the hardware encoder with
78 * baseline functionality.
79 */
80@TargetApi(Build.VERSION_CODES.LOLLIPOP)
81public class SimpleOneCameraFactory implements OneCameraFactory {
82    private final int mImageFormat;
83    private final int mMaxImageCount;
84    private final ImageRotationCalculator mImageRotationCalculator;
85
86    /**
87     * @param imageFormat The {@link ImageFormat} to use for full-size images to
88     *            be saved.
89     * @param maxImageCount The size of the image reader to use for full-size
90     *            images.
91     */
92    public SimpleOneCameraFactory(int imageFormat, int maxImageCount,
93            ImageRotationCalculator imageRotationCalculator) {
94        mImageFormat = imageFormat;
95        mMaxImageCount = maxImageCount;
96        mImageRotationCalculator = imageRotationCalculator;
97    }
98
99    @Override
100    public OneCamera createOneCamera(final CameraDeviceProxy device,
101            final OneCameraCharacteristics characteristics,
102            final OneCameraFeatureConfig.CaptureSupportLevel supportLevel,
103            final MainThread mainExecutor,
104            final Size pictureSize,
105            final ImageSaver.Builder imageSaverBuilder,
106            final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting,
107            final Observable<Integer> exposureSetting,
108            final Observable<Boolean> hdrSceneSetting,
109            final BurstFacade burstFacade,
110            final FatalErrorHandler fatalErrorHandler) {
111        final Lifetime lifetime = new Lifetime();
112
113        final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(new LoggingImageReader(
114                AndroidImageReaderProxy.newInstance(
115                        pictureSize.getWidth(), pictureSize.getHeight(),
116                        mImageFormat, mMaxImageCount),
117                Loggers.tagFactory()));
118
119        lifetime.add(imageReader);
120        lifetime.add(device);
121
122        List<Surface> outputSurfaces = new ArrayList<>();
123        outputSurfaces.add(imageReader.getSurface());
124
125        /**
126         * Finishes constructing the camera when prerequisites, e.g. the preview
127         * stream and capture session, are ready.
128         */
129        CameraStarter cameraStarter = new CameraStarter() {
130            @Override
131            public CameraStarter.CameraControls startCamera(Lifetime cameraLifetime,
132                    CameraCaptureSessionProxy cameraCaptureSession,
133                    Surface previewSurface,
134                    Observable<Float> zoomState,
135                    Updatable<TotalCaptureResultProxy> metadataCallback,
136                    Updatable<Boolean> readyState) {
137                // Create the FrameServer from the CaptureSession.
138                FrameServerFactory frameServerComponent = new FrameServerFactory(
139                        new Lifetime(cameraLifetime), cameraCaptureSession, new HandlerFactory());
140
141                CameraCommandExecutor cameraCommandExecutor = new CameraCommandExecutor(
142                        Loggers.tagFactory(),
143                        new Provider<ExecutorService>() {
144                            @Override
145                            public ExecutorService get() {
146                                // Use a dynamically-expanding thread pool to
147                                // allow any number of commands to execute
148                                // simultaneously.
149                                return Executors.newCachedThreadPool();
150                            }
151                        });
152
153                // Create the shared image reader.
154                SharedImageReaderFactory sharedImageReaderFactory =
155                        new SharedImageReaderFactory(new Lifetime(cameraLifetime), imageReader,
156                                new HandlerFactory());
157                Updatable<Long> globalTimestampCallback =
158                        sharedImageReaderFactory.provideGlobalTimestampQueue();
159                ManagedImageReader managedImageReader =
160                        sharedImageReaderFactory.provideSharedImageReader();
161
162                // Create the request builder used by all camera operations.
163                // Streams, ResponseListeners, and Parameters added to
164                // this will be applied to *all* requests sent to the camera.
165                RequestTemplate rootBuilder = new RequestTemplate
166                        (new CameraDeviceRequestBuilderFactory(device));
167                // The shared image reader must be wired to receive every
168                // timestamp for every image (including the preview).
169                rootBuilder.addResponseListener(
170                        ResponseListeners.forTimestamps(globalTimestampCallback));
171                rootBuilder.addStream(new SimpleCaptureStream(previewSurface));
172                rootBuilder.addResponseListener(ResponseListeners.forFinalMetadata(
173                        metadataCallback));
174
175                FrameServer ephemeralFrameServer =
176                      frameServerComponent.provideEphemeralFrameServer();
177
178                // Create basic functionality (zoom, AE, AF).
179                BasicCameraFactory basicCameraFactory = new BasicCameraFactory(new Lifetime
180                        (cameraLifetime),
181                        characteristics,
182                        ephemeralFrameServer,
183                        rootBuilder,
184                        cameraCommandExecutor,
185                        new BasicPreviewCommandFactory(ephemeralFrameServer),
186                        flashSetting,
187                        exposureSetting,
188                        zoomState,
189                        hdrSceneSetting,
190                        CameraDevice.TEMPLATE_PREVIEW);
191
192                // Register the dynamic updater via orientation supplier
193                rootBuilder.setParam(CaptureRequest.JPEG_ORIENTATION,
194                        mImageRotationCalculator.getSupplier());
195
196                if (GservicesHelper.isJankStatisticsEnabled(AndroidContext.instance().get()
197                      .getContentResolver())) {
198                    rootBuilder.addResponseListener(
199                          new FramerateJankDetector(Loggers.tagFactory(),
200                                UsageStatistics.instance()));
201                }
202
203                RequestBuilder.Factory meteredZoomedRequestBuilder =
204                        basicCameraFactory.provideMeteredZoomedRequestBuilder();
205
206                // Create the picture-taker.
207                PictureTaker pictureTaker;
208                if (supportLevel == OneCameraFeatureConfig.CaptureSupportLevel.LEGACY_JPEG) {
209                    pictureTaker = new LegacyPictureTakerFactory(imageSaverBuilder,
210                            cameraCommandExecutor, mainExecutor,
211                            frameServerComponent.provideFrameServer(),
212                            meteredZoomedRequestBuilder, managedImageReader).providePictureTaker();
213                } else {
214                    pictureTaker = PictureTakerFactory.create(Loggers.tagFactory(), mainExecutor,
215                            cameraCommandExecutor, imageSaverBuilder,
216                            frameServerComponent.provideFrameServer(),
217                            meteredZoomedRequestBuilder, managedImageReader, flashSetting)
218                            .providePictureTaker();
219                }
220
221                // Wire-together ready-state.
222                final Observable<Integer> availableImageCount = sharedImageReaderFactory
223                        .provideAvailableImageCount();
224                final Observable<Boolean> frameServerAvailability = frameServerComponent
225                        .provideReadyState();
226                Observable<Boolean> ready = Observables.transform(
227                        Arrays.asList(availableImageCount, frameServerAvailability),
228                        new Supplier<Boolean>() {
229                            @Override
230                            public Boolean get() {
231                                boolean atLeastOneImageAvailable = availableImageCount.get() >= 1;
232                                boolean frameServerAvailable = frameServerAvailability.get();
233                                return atLeastOneImageAvailable && frameServerAvailable;
234                            }
235                        });
236
237                lifetime.add(Observables.addThreadSafeCallback(ready, readyState));
238
239                basicCameraFactory.providePreviewUpdater().run();
240
241                return new CameraStarter.CameraControls(
242                        pictureTaker,
243                        basicCameraFactory.provideManualAutoFocus());
244            }
245        };
246
247        float maxZoom = characteristics.getAvailableMaxDigitalZoom();
248        List<Size> supportedPreviewSizes = characteristics.getSupportedPreviewSizes();
249        OneCamera.Facing direction = characteristics.getCameraDirection();
250
251        return new InitializedOneCameraFactory(lifetime, cameraStarter, device, outputSurfaces,
252                mainExecutor, new HandlerFactory(), maxZoom, supportedPreviewSizes,
253                characteristics.getLensFocusRange(), direction)
254                .provideOneCamera();
255    }
256}
257