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