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