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