Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 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; |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 24 | import android.hardware.camera2.params.OutputConfiguration; |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 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 | */ |
Shuzhen Wang | 9c663d4 | 2016-10-28 23:25:02 -0700 | [diff] [blame] | 61 | CameraConstrainedHighSpeedCaptureSessionImpl(int id, |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 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); |
Shuzhen Wang | 9c663d4 | 2016-10-28 23:25:02 -0700 | [diff] [blame] | 68 | mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback, |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 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 |
Ruben Brunk | 7ed1aaa | 2015-08-13 17:57:14 -0700 | [diff] [blame] | 173 | public void prepare(int maxCount, Surface surface) throws CameraAccessException { |
| 174 | mSessionImpl.prepare(maxCount, surface); |
| 175 | } |
| 176 | |
| 177 | @Override |
Eino-Ville Talvala | 14c09fa | 2015-07-15 16:04:04 -0700 | [diff] [blame] | 178 | public void tearDown(Surface surface) throws CameraAccessException { |
| 179 | mSessionImpl.tearDown(surface); |
| 180 | } |
| 181 | |
| 182 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 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 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 260 | @Override |
Shuzhen Wang | 4bd7abe | 2017-01-11 09:58:58 -0800 | [diff] [blame] | 261 | public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs) |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 262 | throws CameraAccessException { |
Shuzhen Wang | 4bd7abe | 2017-01-11 09:58:58 -0800 | [diff] [blame] | 263 | mSessionImpl.finalizeOutputConfigurations(deferredOutputConfigs); |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 264 | } |
| 265 | |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 266 | private class WrapperCallback extends StateCallback { |
| 267 | private final StateCallback mCallback; |
| 268 | |
| 269 | public WrapperCallback(StateCallback callback) { |
| 270 | mCallback = callback; |
| 271 | } |
| 272 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 273 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 274 | public void onConfigured(CameraCaptureSession session) { |
| 275 | mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 276 | } |
| 277 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 278 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 279 | public void onConfigureFailed(CameraCaptureSession session) { |
| 280 | mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 281 | } |
| 282 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 283 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 284 | public void onReady(CameraCaptureSession session) { |
| 285 | mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 286 | } |
| 287 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 288 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 289 | public void onActive(CameraCaptureSession session) { |
| 290 | mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 291 | } |
| 292 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 293 | @Override |
Shuzhen Wang | 88f1af2 | 2016-09-30 10:29:28 -0700 | [diff] [blame] | 294 | public void onCaptureQueueEmpty(CameraCaptureSession session) { |
| 295 | mCallback.onCaptureQueueEmpty(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 296 | } |
| 297 | |
| 298 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 299 | public void onClosed(CameraCaptureSession session) { |
| 300 | mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this); |
| 301 | } |
| 302 | |
Zhijun He | c8b181e | 2016-05-30 14:54:39 -0700 | [diff] [blame] | 303 | @Override |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 304 | public void onSurfacePrepared(CameraCaptureSession session, Surface surface) { |
| 305 | mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this, |
| 306 | surface); |
| 307 | } |
Eino-Ville Talvala | 639fffe | 2015-06-30 10:34:48 -0700 | [diff] [blame] | 308 | } |
| 309 | } |