• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.camera.one.v2;
18 
19 import android.annotation.TargetApi;
20 import android.hardware.camera2.CameraDevice;
21 import android.hardware.camera2.CaptureRequest;
22 import android.os.Build.VERSION_CODES;
23 import android.util.Range;
24 import android.view.Surface;
25 
26 import com.android.camera.FatalErrorHandler;
27 import com.android.camera.async.HandlerFactory;
28 import com.android.camera.async.Lifetime;
29 import com.android.camera.async.MainThread;
30 import com.android.camera.async.Observable;
31 import com.android.camera.async.Observables;
32 import com.android.camera.async.Updatable;
33 import com.android.camera.burst.BurstFacade;
34 import com.android.camera.burst.BurstTaker;
35 import com.android.camera.burst.BurstTakerImpl;
36 import com.android.camera.debug.Log.Tag;
37 import com.android.camera.debug.Logger;
38 import com.android.camera.debug.Loggers;
39 import com.android.camera.one.OneCamera;
40 import com.android.camera.one.OneCameraCharacteristics;
41 import com.android.camera.one.config.OneCameraFeatureConfig.CaptureSupportLevel;
42 import com.android.camera.one.v2.camera2proxy.AndroidImageReaderProxy;
43 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
44 import com.android.camera.one.v2.camera2proxy.CameraDeviceProxy;
45 import com.android.camera.one.v2.camera2proxy.CameraDeviceRequestBuilderFactory;
46 import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
47 import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy;
48 import com.android.camera.one.v2.commands.CameraCommandExecutor;
49 import com.android.camera.one.v2.commands.ZslPreviewCommandFactory;
50 import com.android.camera.one.v2.common.BasicCameraFactory;
51 import com.android.camera.one.v2.common.SimpleCaptureStream;
52 import com.android.camera.one.v2.core.FrameServer;
53 import com.android.camera.one.v2.core.FrameServerFactory;
54 import com.android.camera.one.v2.core.RequestTemplate;
55 import com.android.camera.one.v2.core.ResponseListener;
56 import com.android.camera.one.v2.core.ResponseListeners;
57 import com.android.camera.one.v2.errorhandling.FramerateJankDetector;
58 import com.android.camera.one.v2.errorhandling.RepeatFailureHandlerComponent;
59 import com.android.camera.one.v2.imagesaver.ImageSaver;
60 import com.android.camera.one.v2.initialization.CameraStarter;
61 import com.android.camera.one.v2.initialization.InitializedOneCameraFactory;
62 import com.android.camera.one.v2.photo.ZslPictureTakerFactory;
63 import com.android.camera.one.v2.sharedimagereader.ZslSharedImageReaderFactory;
64 import com.android.camera.stats.UsageStatistics;
65 import com.android.camera.util.AndroidContext;
66 import com.android.camera.util.ApiHelper;
67 import com.android.camera.util.GservicesHelper;
68 import com.android.camera.util.Provider;
69 import com.android.camera.util.Size;
70 import com.google.common.base.Supplier;
71 
72 import java.util.ArrayList;
73 import java.util.Arrays;
74 import java.util.List;
75 import java.util.concurrent.ExecutorService;
76 import java.util.concurrent.Executors;
77 
78 @TargetApi(VERSION_CODES.LOLLIPOP)
79 public 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 
ZslOneCameraFactory(int imageFormat, int maxImageCount)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      */
applyNexus5BackCameraFrameRateWorkaround(RequestTemplate requestTemplate)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
createOneCamera(final CameraDeviceProxy device, final OneCameraCharacteristics characteristics, CaptureSupportLevel featureConfig, final MainThread mainThread, Size pictureSize, final ImageSaver.Builder imageSaverBuilder, final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting, final Observable<Integer> exposureSetting, final Observable<Boolean> hdrSceneSetting, final BurstFacade burstFacade, final FatalErrorHandler fatalErrorHandler)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