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