2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package android.hardware.camera2.impl;
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;
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;
37 import static com.android.internal.util.Preconditions.*;
40 * Standard implementation of CameraConstrainedHighSpeedCaptureSession.
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.
49 public class CameraConstrainedHighSpeedCaptureSessionImpl
50 extends CameraConstrainedHighSpeedCaptureSession implements CameraCaptureSessionCore {
51 private final CameraCharacteristics mCharacteristics;
52 private final CameraCaptureSessionImpl mSessionImpl;
55 * Create a new CameraCaptureSession.
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>
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);
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");
78 Collection<Surface> outputSurfaces = request.getTargets();
79 Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
81 StreamConfigurationMap config =
82 mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
83 SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config);
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>();
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);
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);
107 // Video only, or preview + video
108 singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
109 CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
111 singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
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;
133 singleTargetRequestBuilder.addTarget(recordingSurface);
135 // Single output case: either recording or preview.
136 singleTargetRequestBuilder.addTarget(firstSurface);
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());
145 requestList.add(singleTargetRequestBuilder.build());
149 return Collections.unmodifiableList(requestList);
152 private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) {
153 checkCollectionNotEmpty(requestList, "High speed request list");
154 for (CaptureRequest request : requestList) {
155 if (!request.isPartOfCRequestList()) {
163 public CameraDevice getDevice() {
164 return mSessionImpl.getDevice();
168 public void prepare(Surface surface) throws CameraAccessException {
169 mSessionImpl.prepare(surface);
173 public void prepare(int maxCount, Surface surface) throws CameraAccessException {
174 mSessionImpl.prepare(maxCount, surface);
178 public void tearDown(Surface surface) throws CameraAccessException {
179 mSessionImpl.tearDown(surface);
183 public int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
184 throws CameraAccessException {
185 throw new UnsupportedOperationException("Constrained high speed session doesn't support"
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");
197 return mSessionImpl.captureBurst(requests, listener, handler);
201 public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener,
202 Handler handler) throws CameraAccessException {
203 throw new UnsupportedOperationException("Constrained high speed session doesn't support"
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");
215 return mSessionImpl.setRepeatingBurst(requests, listener, handler);
219 public void stopRepeating() throws CameraAccessException {
220 mSessionImpl.stopRepeating();
224 public void abortCaptures() throws CameraAccessException {
225 mSessionImpl.abortCaptures();
229 public Surface getInputSurface() {
234 public void close() {
235 mSessionImpl.close();
239 public boolean isReprocessable() {
243 // Implementation of CameraCaptureSessionCore methods
246 public void replaceSessionClose() {
247 mSessionImpl.replaceSessionClose();
251 public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
252 return mSessionImpl.getDeviceStateCallback();
256 public boolean isAborting() {
257 return mSessionImpl.isAborting();
261 public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs)
262 throws CameraAccessException {
263 mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
266 private class WrapperCallback extends StateCallback {
267 private final StateCallback mCallback;
269 public WrapperCallback(StateCallback callback) {
270 mCallback = callback;
274 public void onConfigured(CameraCaptureSession session) {
275 mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
279 public void onConfigureFailed(CameraCaptureSession session) {
280 mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
284 public void onReady(CameraCaptureSession session) {
285 mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
289 public void onActive(CameraCaptureSession session) {
290 mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
294 public void onClosed(CameraCaptureSession session) {
295 mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
299 public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
300 mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,