Home | History | Annotate | Download | only in impl
      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;
     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;
     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      */
     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);
     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
    173     public void prepare(int maxCount, Surface surface) throws CameraAccessException {
    174         mSessionImpl.prepare(maxCount, surface);
    175     }
    176 
    177     @Override
    178     public void tearDown(Surface surface) throws CameraAccessException {
    179         mSessionImpl.tearDown(surface);
    180     }
    181 
    182     @Override
    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 
    260     @Override
    261     public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs)
    262             throws CameraAccessException {
    263         mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
    264     }
    265 
    266     private class WrapperCallback extends StateCallback {
    267         private final StateCallback mCallback;
    268 
    269         public WrapperCallback(StateCallback callback) {
    270             mCallback = callback;
    271         }
    272 
    273         @Override
    274         public void onConfigured(CameraCaptureSession session) {
    275             mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
    276         }
    277 
    278         @Override
    279         public void onConfigureFailed(CameraCaptureSession session) {
    280             mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
    281         }
    282 
    283         @Override
    284         public void onReady(CameraCaptureSession session) {
    285             mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
    286         }
    287 
    288         @Override
    289         public void onActive(CameraCaptureSession session) {
    290             mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
    291         }
    292 
    293         @Override
    294         public void onClosed(CameraCaptureSession session) {
    295             mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
    296         }
    297 
    298         @Override
    299         public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
    300             mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,
    301                     surface);
    302         }
    303 
    304 
    305     }
    306 }
    307