1 /* 2 * Copyright (C) 2015 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 package android.hardware.camera2.impl; 17 18 import android.hardware.camera2.CameraAccessException; 19 import android.hardware.camera2.CameraCaptureSession; 20 import android.hardware.camera2.CameraCharacteristics; 21 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession; 22 import android.hardware.camera2.CameraDevice; 23 import android.hardware.camera2.CaptureRequest; 24 import android.hardware.camera2.params.OutputConfiguration; 25 import android.hardware.camera2.params.StreamConfigurationMap; 26 import android.hardware.camera2.utils.SurfaceUtils; 27 import android.os.Handler; 28 import android.util.Range; 29 import android.view.Surface; 30 31 import java.util.ArrayList; 32 import java.util.Collection; 33 import java.util.Collections; 34 import java.util.Iterator; 35 import java.util.List; 36 37 import static com.android.internal.util.Preconditions.*; 38 39 /** 40 * Standard implementation of CameraConstrainedHighSpeedCaptureSession. 41 * 42 * <p> 43 * Mostly just forwards calls to an instance of CameraCaptureSessionImpl, 44 * but implements the few necessary behavior changes and additional methods required 45 * for the constrained high speed speed mode. 46 * </p> 47 */ 48 49 public class CameraConstrainedHighSpeedCaptureSessionImpl 50 extends CameraConstrainedHighSpeedCaptureSession implements CameraCaptureSessionCore { 51 private final CameraCharacteristics mCharacteristics; 52 private final CameraCaptureSessionImpl mSessionImpl; 53 54 /** 55 * Create a new CameraCaptureSession. 56 * 57 * <p>The camera device must already be in the {@code IDLE} state when this is invoked. 58 * There must be no pending actions 59 * (e.g. no pending captures, no repeating requests, no flush).</p> 60 */ 61 CameraConstrainedHighSpeedCaptureSessionImpl(int id, List<Surface> outputs, 62 CameraCaptureSession.StateCallback callback, Handler stateHandler, 63 android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, 64 Handler deviceStateHandler, boolean configureSuccess, 65 CameraCharacteristics characteristics) { 66 mCharacteristics = characteristics; 67 CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback); 68 mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, outputs, wrapperCallback, 69 stateHandler, deviceImpl, deviceStateHandler, configureSuccess); 70 } 71 72 @Override 73 public List<CaptureRequest> createHighSpeedRequestList(CaptureRequest request) 74 throws CameraAccessException { 75 if (request == null) { 76 throw new IllegalArgumentException("Input capture request must not be null"); 77 } 78 Collection<Surface> outputSurfaces = request.getTargets(); 79 Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE); 80 81 StreamConfigurationMap config = 82 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 83 SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config); 84 85 // Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize 86 // the preview frame rate, should use maxBatch size for that high speed stream 87 // configuration. We choose the former for now. 88 int requestListSize = fpsRange.getUpper() / 30; 89 List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); 90 91 // Prepare the Request builders: need carry over the request controls. 92 // First, create a request builder that will only include preview or recording target. 93 CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy()); 94 // Note that after this step, the requestMetadata is mutated (swapped) and can not be used 95 // for next request builder creation. 96 CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder( 97 requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); 98 99 // Overwrite the capture intent to make sure a good value is set. 100 Iterator<Surface> iterator = outputSurfaces.iterator(); 101 Surface firstSurface = iterator.next(); 102 Surface secondSurface = null; 103 if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(firstSurface)) { 104 singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, 105 CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW); 106 } else { 107 // Video only, or preview + video 108 singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, 109 CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); 110 } 111 singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true); 112 113 // Second, Create a request builder that will include both preview and recording targets. 114 CaptureRequest.Builder doubleTargetRequestBuilder = null; 115 if (outputSurfaces.size() == 2) { 116 // Have to create a new copy, the original one was mutated after a new 117 // CaptureRequest.Builder creation. 118 requestMetadata = new CameraMetadataNative(request.getNativeCopy()); 119 doubleTargetRequestBuilder = new CaptureRequest.Builder( 120 requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); 121 doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, 122 CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD); 123 doubleTargetRequestBuilder.addTarget(firstSurface); 124 secondSurface = iterator.next(); 125 doubleTargetRequestBuilder.addTarget(secondSurface); 126 doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true); 127 // Make sure singleTargetRequestBuilder contains only recording surface for 128 // preview + recording case. 129 Surface recordingSurface = firstSurface; 130 if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) { 131 recordingSurface = secondSurface; 132 } 133 singleTargetRequestBuilder.addTarget(recordingSurface); 134 } else { 135 // Single output case: either recording or preview. 136 singleTargetRequestBuilder.addTarget(firstSurface); 137 } 138 139 // Generate the final request list. 140 for (int i = 0; i < requestListSize; i++) { 141 if (i == 0 && doubleTargetRequestBuilder != null) { 142 // First request should be recording + preview request 143 requestList.add(doubleTargetRequestBuilder.build()); 144 } else { 145 requestList.add(singleTargetRequestBuilder.build()); 146 } 147 } 148 149 return Collections.unmodifiableList(requestList); 150 } 151 152 private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) { 153 checkCollectionNotEmpty(requestList, "High speed request list"); 154 for (CaptureRequest request : requestList) { 155 if (!request.isPartOfCRequestList()) { 156 return false; 157 } 158 } 159 return true; 160 } 161 162 @Override 163 public CameraDevice getDevice() { 164 return mSessionImpl.getDevice(); 165 } 166 167 @Override 168 public void prepare(Surface surface) throws CameraAccessException { 169 mSessionImpl.prepare(surface); 170 } 171 172 @Override 173 public void prepare(int maxCount, Surface surface) throws CameraAccessException { 174 mSessionImpl.prepare(maxCount, surface); 175 } 176 177 @Override 178 public void tearDown(Surface surface) throws CameraAccessException { 179 mSessionImpl.tearDown(surface); 180 } 181 182 @Override 183 public int capture(CaptureRequest request, CaptureCallback listener, Handler handler) 184 throws CameraAccessException { 185 throw new UnsupportedOperationException("Constrained high speed session doesn't support" 186 + " this method"); 187 } 188 189 @Override 190 public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener, 191 Handler handler) throws CameraAccessException { 192 if (!isConstrainedHighSpeedRequestList(requests)) { 193 throw new IllegalArgumentException( 194 "Only request lists created by createHighSpeedRequestList() can be submitted to " + 195 "a constrained high speed capture session"); 196 } 197 return mSessionImpl.captureBurst(requests, listener, handler); 198 } 199 200 @Override 201 public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener, 202 Handler handler) throws CameraAccessException { 203 throw new UnsupportedOperationException("Constrained high speed session doesn't support" 204 + " this method"); 205 } 206 207 @Override 208 public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener, 209 Handler handler) throws CameraAccessException { 210 if (!isConstrainedHighSpeedRequestList(requests)) { 211 throw new IllegalArgumentException( 212 "Only request lists created by createHighSpeedRequestList() can be submitted to " + 213 "a constrained high speed capture session"); 214 } 215 return mSessionImpl.setRepeatingBurst(requests, listener, handler); 216 } 217 218 @Override 219 public void stopRepeating() throws CameraAccessException { 220 mSessionImpl.stopRepeating(); 221 } 222 223 @Override 224 public void abortCaptures() throws CameraAccessException { 225 mSessionImpl.abortCaptures(); 226 } 227 228 @Override 229 public Surface getInputSurface() { 230 return null; 231 } 232 233 @Override 234 public void close() { 235 mSessionImpl.close(); 236 } 237 238 @Override 239 public boolean isReprocessable() { 240 return false; 241 } 242 243 // Implementation of CameraCaptureSessionCore methods 244 245 @Override 246 public void replaceSessionClose() { 247 mSessionImpl.replaceSessionClose(); 248 } 249 250 @Override 251 public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() { 252 return mSessionImpl.getDeviceStateCallback(); 253 } 254 255 @Override 256 public boolean isAborting() { 257 return mSessionImpl.isAborting(); 258 } 259 260 @Override 261 public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs) 262 throws CameraAccessException { 263 mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs); 264 } 265 266 private class WrapperCallback extends StateCallback { 267 private final StateCallback mCallback; 268 269 public WrapperCallback(StateCallback callback) { 270 mCallback = callback; 271 } 272 273 @Override 274 public void onConfigured(CameraCaptureSession session) { 275 mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this); 276 } 277 278 @Override 279 public void onConfigureFailed(CameraCaptureSession session) { 280 mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this); 281 } 282 283 @Override 284 public void onReady(CameraCaptureSession session) { 285 mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this); 286 } 287 288 @Override 289 public void onActive(CameraCaptureSession session) { 290 mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this); 291 } 292 293 @Override 294 public void onClosed(CameraCaptureSession session) { 295 mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this); 296 } 297 298 @Override 299 public void onSurfacePrepared(CameraCaptureSession session, Surface surface) { 300 mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this, 301 surface); 302 } 303 304 305 } 306 } 307