am a2cd9c56: Merge "Camera2: Reorganize high-speed recording API slightly" into mnc-dev

* commit 'a2cd9c56f8648b5a4faee14d9dd0c4151730f78c':
  Camera2: Reorganize high-speed recording API slightly
This commit is contained in:
Eino-Ville Talvala
2015-07-10 16:59:57 +00:00
committed by Android Git Automerger
14 changed files with 657 additions and 333 deletions

View File

@@ -13178,7 +13178,6 @@ package android.hardware.camera2 {
method public abstract void close();
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isConstrainedHighSpeed();
method public abstract boolean isReprocessable();
method public abstract void prepare(android.view.Surface) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
@@ -13296,12 +13295,16 @@ package android.hardware.camera2 {
method public final int hashCode();
}
public abstract class CameraConstrainedHighSpeedCaptureSession extends android.hardware.camera2.CameraCaptureSession {
ctor public CameraConstrainedHighSpeedCaptureSession();
method public abstract java.util.List<android.hardware.camera2.CaptureRequest> createHighSpeedRequestList(android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
}
public abstract class CameraDevice implements java.lang.AutoCloseable {
method public abstract void close();
method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.util.List<android.hardware.camera2.CaptureRequest> createConstrainedHighSpeedRequestList(android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();

View File

@@ -13518,7 +13518,6 @@ package android.hardware.camera2 {
method public abstract void close();
method public abstract android.hardware.camera2.CameraDevice getDevice();
method public abstract android.view.Surface getInputSurface();
method public abstract boolean isConstrainedHighSpeed();
method public abstract boolean isReprocessable();
method public abstract void prepare(android.view.Surface) throws android.hardware.camera2.CameraAccessException;
method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
@@ -13636,12 +13635,16 @@ package android.hardware.camera2 {
method public final int hashCode();
}
public abstract class CameraConstrainedHighSpeedCaptureSession extends android.hardware.camera2.CameraCaptureSession {
ctor public CameraConstrainedHighSpeedCaptureSession();
method public abstract java.util.List<android.hardware.camera2.CaptureRequest> createHighSpeedRequestList(android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
}
public abstract class CameraDevice implements java.lang.AutoCloseable {
method public abstract void close();
method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract void createConstrainedHighSpeedCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.util.List<android.hardware.camera2.CaptureRequest> createConstrainedHighSpeedRequestList(android.hardware.camera2.CaptureRequest) throws android.hardware.camera2.CameraAccessException;
method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
method public abstract void createReprocessableCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
method public abstract java.lang.String getId();

View File

@@ -481,17 +481,6 @@ public abstract class CameraCaptureSession implements AutoCloseable {
*/
public abstract boolean isReprocessable();
/**
* Return if this capture session is constrained high speed session that is created by
* {@link CameraDevice#createConstrainedHighSpeedCaptureSession}.
*
* @return {@code true} if this session is constrained high speed capture session,
* {@code false} otherwise.
*
* @see CameraDevice#createConstrainedHighSpeedCaptureSession
*/
public abstract boolean isConstrainedHighSpeed();
/**
* Get the input Surface associated with a reprocessable capture session.
*

View File

@@ -664,7 +664,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* the max possible number of frames the camera device will group together for this high
* speed stream configuration. This max batch size will be used to generate a high speed
* recording request list by
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList }.
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.
* The max batch size for each configuration will satisfy below conditions:</p>
* <ul>
* <li>Each max batch size will be a divisor of its corresponding fps_max / 30. For example,

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2;
import android.annotation.NonNull;
import android.hardware.camera2.params.StreamConfigurationMap;
import java.util.List;
/**
* A constrained high speed capture session for a {@link CameraDevice}, used for capturing high
* speed images from the {@link CameraDevice} for high speed video recording use case.
* <p>
* A CameraHighSpeedCaptureSession is created by providing a set of target output surfaces to
* {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, Once created, the session is
* active until a new session is created by the camera device, or the camera device is closed.
* </p>
* <p>
* An active high speed capture session is a specialized capture session that is only targeted at
* high speed video recording (>=120fps) use case if the camera device supports high speed video
* capability (i.e., {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} contains
* {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO}). It only
* accepts request lists created via {@link #createHighSpeedRequestList}, and the request list can
* only be submitted to this session via {@link CameraCaptureSession#captureBurst captureBurst}, or
* {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}. See
* {@link CameraDevice#createConstrainedHighSpeedCaptureSession} for more details of the
* limitations.
* </p>
* <p>
* Creating a session is an expensive operation and can take several hundred milliseconds, since it
* requires configuring the camera device's internal pipelines and allocating memory buffers for
* sending images to the desired targets. Therefore the setup is done asynchronously, and
* {@link CameraDevice#createConstrainedHighSpeedCaptureSession} will send the ready-to-use
* CameraCaptureSession to the provided listener's
* {@link CameraCaptureSession.StateCallback#onConfigured} callback. If configuration cannot be
* completed, then the {@link CameraCaptureSession.StateCallback#onConfigureFailed} is called, and
* the session will not become active.
* </p>
* <!--
* <p>
* Any capture requests (repeating or non-repeating) submitted before the session is ready will be
* queued up and will begin capture once the session becomes ready. In case the session cannot be
* configured and {@link CameraCaptureSession.StateCallback#onConfigureFailed onConfigureFailed} is
* called, all queued capture requests are discarded. </p>
* -->
* <p>
* If a new session is created by the camera device, then the previous session is closed, and its
* associated {@link CameraCaptureSession.StateCallback#onClosed onClosed} callback will be
* invoked. All of the session methods will throw an IllegalStateException if called once the
* session is closed.
* </p>
* <p>
* A closed session clears any repeating requests (as if {@link #stopRepeating} had been called),
* but will still complete all of its in-progress capture requests as normal, before a newly created
* session takes over and reconfigures the camera device.
* </p>
*/
public abstract class CameraConstrainedHighSpeedCaptureSession extends CameraCaptureSession {
/**
* <p>Create a unmodifiable list of requests that is suitable for constrained high speed capture
* session streaming.</p>
*
* <p>High speed video streaming creates significant performance pressure on the camera device,
* so to achieve efficient high speed streaming, the camera device may have to aggregate
* multiple frames together. This means requests must be sent in batched groups, with all
* requests sharing the same settings. This method takes the list of output target
* Surfaces (subject to the output Surface requirements specified by the constrained high speed
* session) and a {@link CaptureRequest request}, and generates a request list that has the same
* controls for each request. The input {@link CaptureRequest request} must contain the target
* output Surfaces and target high speed FPS range that is one of the
* {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor} for the Surface size.</p>
*
* <p>If both preview and recording Surfaces are specified in the {@code request}, the
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE target FPS range} in the input
* {@link CaptureRequest request} must be a fixed frame rate FPS range, where the
* {@link android.util.Range#getLower minimal FPS} ==
* {@link android.util.Range#getUpper() maximum FPS}. The created request list will contain
* a interleaved request pattern such that the preview output FPS is at least 30fps, the
* recording output FPS is {@link android.util.Range#getUpper() maximum FPS} of the requested
* FPS range. The application can submit this request list directly to an active high speed
* capture session to achieve high speed video recording. When only preview or recording
* Surface is specified, this method will return a list of request that have the same controls
* and output targets for all requests.</p>
*
* <p>Submitting a request list created by this method to a normal capture session will result
* in an {@link IllegalArgumentException} if the high speed
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} is not supported by
* {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}.</p>
*
* @param request The high speed capture request that will be used to generate the high speed
* request list.
* @return A unmodifiable CaptureRequest list that is suitable for constrained high speed
* capture.
*
* @throws IllegalArgumentException if the set of output Surfaces in the request do not meet the
* high speed video capability requirements, or the camera
* device doesn't support high speed video capability, or the
* request doesn't meet the high speed video capability
* requirements, or the request doesn't contain the required
* controls for high speed capture.
* @throws CameraAccessException if the camera device is no longer connected or has
* encountered a fatal error
* @throws IllegalStateException if the camera device has been closed
*
* @see CameraDevice#createConstrainedHighSpeedCaptureSession
* @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
* @see android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoSizes
* @see android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRangesFor
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
*/
@NonNull
public abstract List<CaptureRequest> createHighSpeedRequestList(
@NonNull CaptureRequest request) throws CameraAccessException;
}

View File

@@ -613,8 +613,9 @@ public abstract class CameraDevice implements AutoCloseable {
* When multiple Surfaces are configured, their size must be same.</li>
*
* <li>An active high speed capture session only accepts request lists created via
* {@link #createConstrainedHighSpeedRequestList}, and the request list can only be submitted
* to this session via {@link CameraCaptureSession#captureBurst captureBurst}, or
* {@link CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}, and the
* request list can only be submitted to this session via
* {@link CameraCaptureSession#captureBurst captureBurst}, or
* {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</li>
*
* <li>The FPS ranges being requested to this session must be selected from
@@ -661,71 +662,13 @@ public abstract class CameraDevice implements AutoCloseable {
* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
* @see CameraCaptureSession#captureBurst
* @see CameraCaptureSession#setRepeatingBurst
* @see #createConstrainedHighSpeedRequestList
* @see CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList
*/
public abstract void createConstrainedHighSpeedCaptureSession(@NonNull List<Surface> outputs,
@NonNull CameraCaptureSession.StateCallback callback,
@Nullable Handler handler)
throws CameraAccessException;
/**
* <p>Create a unmodifiable list of requests that is suitable for constrained high speed capture
* session streaming.</p>
*
* <p>High speed video streaming creates significant performance pressue on the camera device,
* so to achieve efficient high speed streaming, the camera device may have to aggregate
* multiple frames together. This means requests must be sent in batched groups, with all
* requests sharing the same settings. This method takes the list of output target
* Surfaces (subject to the output Surface requirements specified by the contrained high speed
* session) and a {@link CaptureRequest request}, and generates a request list that has the same
* controls for each request. The input {@link CaptureRequest request} must contain the target
* output Surfaces and target high speed FPS range that is one of the
* {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor} for the Surface size.</p>
*
* <p>If both preview and recording Surfaces are specified in the {@code request}, the
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE target FPS range} in the input
* {@link CaptureRequest request} must be a fixed framerate FPS range, where the
* {@link android.util.Range#getLower minimal FPS} ==
* {@link android.util.Range#getUpper() maximum FPS}. The created request list will contain
* a interleaved request pattern such that the preview output FPS is at least 30fps, the
* recording output FPS is {@link android.util.Range#getUpper() maximum FPS} of the requested
* FPS range. The application can submit this request list directly to an active high speed
* capture session to achieve high speed video recording. When only preview or recording
* Surface is specified, this method will return a list of request that have the same controls
* and output targets for all requests.</p>
*
* <p>Submitting a request list created by this method to a normal capture session will result
* in an {@link IllegalArgumentException} if the high speed
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} is not supported by
* {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES}.</p>
*
* @param request The high speed capture request that will be used to generate the high speed
* request list.
* @return A unmodifiable CaptureRequest list that is suitable for constrained high speed
* capture.
*
* @throws IllegalArgumentException if the set of output Surfaces in the request do not meet the
* high speed video capability requirements, or the camera
* device doesn't support high speed video capability, or the
* request doesn't meet the high speed video capability
* requirements, or the request doesn't contain the required
* controls for high speed capture.
* @throws CameraAccessException if the camera device is no longer connected or has
* encountered a fatal error
* @throws IllegalStateException if the camera device has been closed
*
* @see #createConstrainedHighSpeedCaptureSession
* @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
* @see StreamConfigurationMap#getHighSpeedVideoSizes
* @see StreamConfigurationMap#getHighSpeedVideoFpsRangesFor
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
*/
@NonNull
public abstract List<CaptureRequest> createConstrainedHighSpeedRequestList(
@NonNull CaptureRequest request)throws CameraAccessException;
/**
* <p>Create a {@link CaptureRequest.Builder} for new capture requests,
* initialized with template for a target use case. The settings are chosen

View File

@@ -655,8 +655,8 @@ public abstract class CameraMetadata<TKey> {
* <p>The device supports constrained high speed video recording (frame rate &gt;=120fps)
* use case. The camera device will support high speed capture session created by
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }, which
* only accepts high speed request list created by
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList }.</p>
* only accepts high speed request lists created by
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }.</p>
* <p>A camera device can still support high speed video streaming by advertising the high speed
* FPS ranges in {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges}. For this case, all normal
* capture request per frame control and synchronization requirements will apply to
@@ -717,9 +717,9 @@ public abstract class CameraMetadata<TKey> {
* <li>The FPS ranges are selected from
* {@link android.hardware.camera2.params.StreamConfigurationMap#getHighSpeedVideoFpsRanges }.</li>
* </ul>
* <p>When above conditions are NOT satistied, the
* <p>When above conditions are NOT satistied,
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }
* and {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList } will fail.</p>
* will fail.</p>
* <p>Switching to a FPS range that has different maximum FPS may trigger some camera device
* reconfigurations, which may introduce extra latency. It is recommended that
* the application avoids unnecessary maximum target FPS changes as much as possible
@@ -1813,9 +1813,8 @@ public abstract class CameraMetadata<TKey> {
public static final int CONTROL_SCENE_MODE_BARCODE = 16;
/**
* <p>This is deprecated, please use
* {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }
* and {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedRequestList }
* <p>This is deprecated, please use {@link android.hardware.camera2.CameraDevice#createConstrainedHighSpeedCaptureSession }
* and {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList }
* for high speed video recording.</p>
* <p>Optimized for high speed video recording (frame rate &gt;=60fps) use case.</p>
* <p>The supported high speed video sizes and fps ranges are specified in

View File

@@ -184,7 +184,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
private final CameraMetadataNative mSettings;
private boolean mIsReprocess;
// If this request is part of constrained high speed request list that was created by
// {@link CameraDevice#createConstrainedHighSpeedRequestList}.
// {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
private boolean mIsPartOfCHSRequestList = false;
// Each reprocess request must be tied to a reprocessable session ID.
// Valid only for reprocess requests (mIsReprocess == true).
@@ -340,14 +340,14 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Determine if this request is part of a constrained high speed request list that was
* created by {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high
* speed request list contains some constrained high speed capture requests with certain
* interleaved pattern that is suitable for high speed preview/video streaming. An active
* constrained high speed capture session only accepts constrained high speed request lists.
* This method can be used to do the sanity check when a constrained high speed capture session
* receives a request list via {@link CameraCaptureSession#setRepeatingBurst} or
* {@link CameraCaptureSession#captureBurst}.
* </p>
* created by
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
* A constrained high speed request list contains some constrained high speed capture requests
* with certain interleaved pattern that is suitable for high speed preview/video streaming. An
* active constrained high speed capture session only accepts constrained high speed request
* lists. This method can be used to do the sanity check when a constrained high speed capture
* session receives a request list via {@link CameraCaptureSession#setRepeatingBurst} or
* {@link CameraCaptureSession#captureBurst}. </p>
*
*
* @return {@code true} if this request is part of a constrained high speed request list,
@@ -595,9 +595,10 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>Mark this request as part of a constrained high speed request list created by
* {@link CameraDevice#createConstrainedHighSpeedRequestList}. A constrained high speed
* request list contains some constrained high speed capture requests with certain
* interleaved pattern that is suitable for high speed preview/video streaming.</p>
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
* A constrained high speed request list contains some constrained high speed capture
* requests with certain interleaved pattern that is suitable for high speed preview/video
* streaming.</p>
*
* @hide
*/

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.impl;
/**
* Internal interface for CameraDeviceImpl to CameraCaptureSessionImpl(s) communication
*/
public interface CameraCaptureSessionCore {
/**
* Replace this session with another session.
*
* <p>This is an optimization to avoid unconfiguring and then immediately having to
* reconfigure again.</p>
*
* <p>The semantics are identical to {@link #close}, except that unconfiguring will be skipped.
* </p>
*
* <p>After this call completes, the session will not call any further methods on the camera
* device.</p>
*
* @see CameraCaptureSession#close
*/
void replaceSessionClose();
/**
*
* Create an internal state callback, to be invoked on the mDeviceHandler
*
* <p>It has a few behaviors:
* <ul>
* <li>Convert device state changes into session state changes.
* <li>Keep track of async tasks that the session began (idle, abort).
* </ul>
* </p>
* */
CameraDeviceImpl.StateCallbackKK getDeviceStateCallback();
/**
* Whether currently in mid-abort.
*
* <p>This is used by the implementation to set the capture failure
* reason, in lieu of more accurate error codes from the camera service.
* Unsynchronized to avoid deadlocks between simultaneous session->device,
* device->session calls.</p>
*
*/
boolean isAborting();
}

View File

@@ -36,7 +36,8 @@ import java.util.List;
import static android.hardware.camera2.impl.CameraDeviceImpl.checkHandler;
import static com.android.internal.util.Preconditions.*;
public class CameraCaptureSessionImpl extends CameraCaptureSession {
public class CameraCaptureSessionImpl extends CameraCaptureSession
implements CameraCaptureSessionCore {
private static final String TAG = "CameraCaptureSession";
private static final boolean DEBUG = false;
@@ -60,7 +61,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
private final android.hardware.camera2.impl.CameraDeviceImpl mDeviceImpl;
/** Internal handler; used for all incoming events to preserve total order */
private final Handler mDeviceHandler;
private final boolean mIsConstrainedHighSpeedSession;
/** Drain Sequence IDs which have been queued but not yet finished with aborted/completed */
private final TaskDrainer<Integer> mSequenceDrainer;
@@ -89,14 +89,13 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs,
CameraCaptureSession.StateCallback callback, Handler stateHandler,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess, boolean isConstrainedHighSpeed) {
Handler deviceStateHandler, boolean configureSuccess) {
if (outputs == null || outputs.isEmpty()) {
throw new IllegalArgumentException("outputs must be a non-null, non-empty list");
} else if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
mIsConstrainedHighSpeedSession = isConstrainedHighSpeed;
mId = id;
mIdString = String.format("Session %d: ", mId);
@@ -136,30 +135,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
}
private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) {
checkCollectionNotEmpty(requestList, "High speed request list");
for (CaptureRequest request : requestList) {
if (!request.isPartOfCRequestList()) {
return false;
}
}
return true;
}
/**
* If the session is constrained high speed session, it only accept constrained high speed
* request list.
*/
private void checkConstrainedHighSpeedRequestSanity(List<CaptureRequest> requestList) {
if (mIsConstrainedHighSpeedSession) {
if (!isConstrainedHighSpeedRequestList(requestList)) {
throw new IllegalArgumentException("It is only allowed to submit a constrained "
+ "high speed request list to a constrained high speed session!!!");
}
}
}
@Override
public CameraDevice getDevice() {
return mDeviceImpl;
@@ -181,10 +156,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
} else if (request.isReprocess() && request.getReprocessableSessionId() != mId) {
throw new IllegalArgumentException("capture request was created for another session");
}
if (mIsConstrainedHighSpeedSession) {
throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ " this method");
}
checkNotClosed();
@@ -208,8 +179,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
throw new IllegalArgumentException("Requests must have at least one element");
}
checkConstrainedHighSpeedRequestSanity(requests);
for (CaptureRequest request : requests) {
if (request.isReprocess()) {
if (!isReprocessable()) {
@@ -244,10 +213,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
} else if (request.isReprocess()) {
throw new IllegalArgumentException("repeating reprocess requests are not supported");
}
if (mIsConstrainedHighSpeedSession) {
throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ " this method");
}
checkNotClosed();
@@ -271,8 +236,6 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
throw new IllegalArgumentException("requests must have at least one element");
}
checkConstrainedHighSpeedRequestSanity(requests);
for (CaptureRequest r : requests) {
if (r.isReprocess()) {
throw new IllegalArgumentException("repeating reprocess burst requests are not " +
@@ -349,7 +312,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
*
* @see CameraCaptureSession#close
*/
synchronized void replaceSessionClose() {
@Override
public synchronized void replaceSessionClose() {
/*
* In order for creating new sessions to be fast, the new session should be created
* before the old session is closed.
@@ -431,9 +395,9 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* Unsynchronized to avoid deadlocks between simultaneous session->device,
* device->session calls.</p>
*
* <p>Package-private.</p>
*/
boolean isAborting() {
@Override
public boolean isAborting() {
return mAborting;
}
@@ -521,7 +485,8 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
* </ul>
* </p>
* */
CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
@Override
public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
final CameraCaptureSession session = this;
return new CameraDeviceImpl.StateCallbackKK() {
@@ -759,9 +724,4 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession {
}
}
@Override
public boolean isConstrainedHighSpeed() {
return mIsConstrainedHighSpeedSession;
}
}

View File

@@ -0,0 +1,283 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.camera2.impl;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.SurfaceUtils;
import android.os.Handler;
import android.util.Range;
import android.view.Surface;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static com.android.internal.util.Preconditions.*;
/**
* Standard implementation of CameraConstrainedHighSpeedCaptureSession.
*
* <p>
* Mostly just forwards calls to an instance of CameraCaptureSessionImpl,
* but implements the few necessary behavior changes and additional methods required
* for the constrained high speed speed mode.
* </p>
*/
public class CameraConstrainedHighSpeedCaptureSessionImpl
extends CameraConstrainedHighSpeedCaptureSession implements CameraCaptureSessionCore {
private final CameraCharacteristics mCharacteristics;
private final CameraCaptureSessionImpl mSessionImpl;
/**
* Create a new CameraCaptureSession.
*
* <p>The camera device must already be in the {@code IDLE} state when this is invoked.
* There must be no pending actions
* (e.g. no pending captures, no repeating requests, no flush).</p>
*/
CameraConstrainedHighSpeedCaptureSessionImpl(int id, List<Surface> outputs,
CameraCaptureSession.StateCallback callback, Handler stateHandler,
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
Handler deviceStateHandler, boolean configureSuccess,
CameraCharacteristics characteristics) {
mCharacteristics = characteristics;
CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, outputs, wrapperCallback,
stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
}
@Override
public List<CaptureRequest> createHighSpeedRequestList(CaptureRequest request)
throws CameraAccessException {
if (request == null) {
throw new IllegalArgumentException("Input capture request must not be null");
}
Collection<Surface> outputSurfaces = request.getTargets();
Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
StreamConfigurationMap config =
mCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange, config);
// Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
// the preview frame rate, should use maxBatch size for that high speed stream
// configuration. We choose the former for now.
int requestListSize = fpsRange.getUpper() / 30;
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
// Prepare the Request builders: need carry over the request controls.
// First, create a request builder that will only include preview or recording target.
CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy());
// Note that after this step, the requestMetadata is mutated (swapped) and can not be used
// for next request builder creation.
CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder(
requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
// Overwrite the capture intent to make sure a good value is set.
Iterator<Surface> iterator = outputSurfaces.iterator();
Surface firstSurface = iterator.next();
Surface secondSurface = null;
if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(firstSurface)) {
singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
} else {
// Video only, or preview + video
singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
}
singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
// Second, Create a request builder that will include both preview and recording targets.
CaptureRequest.Builder doubleTargetRequestBuilder = null;
if (outputSurfaces.size() == 2) {
// Have to create a new copy, the original one was mutated after a new
// CaptureRequest.Builder creation.
requestMetadata = new CameraMetadataNative(request.getNativeCopy());
doubleTargetRequestBuilder = new CaptureRequest.Builder(
requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
doubleTargetRequestBuilder.addTarget(firstSurface);
secondSurface = iterator.next();
doubleTargetRequestBuilder.addTarget(secondSurface);
doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
// Make sure singleTargetRequestBuilder contains only recording surface for
// preview + recording case.
Surface recordingSurface = firstSurface;
if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) {
recordingSurface = secondSurface;
}
singleTargetRequestBuilder.addTarget(recordingSurface);
} else {
// Single output case: either recording or preview.
singleTargetRequestBuilder.addTarget(firstSurface);
}
// Generate the final request list.
for (int i = 0; i < requestListSize; i++) {
if (i == 0 && doubleTargetRequestBuilder != null) {
// First request should be recording + preview request
requestList.add(doubleTargetRequestBuilder.build());
} else {
requestList.add(singleTargetRequestBuilder.build());
}
}
return Collections.unmodifiableList(requestList);
}
private boolean isConstrainedHighSpeedRequestList(List<CaptureRequest> requestList) {
checkCollectionNotEmpty(requestList, "High speed request list");
for (CaptureRequest request : requestList) {
if (!request.isPartOfCRequestList()) {
return false;
}
}
return true;
}
@Override
public CameraDevice getDevice() {
return mSessionImpl.getDevice();
}
@Override
public void prepare(Surface surface) throws CameraAccessException {
mSessionImpl.prepare(surface);
}
@Override
public int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
throws CameraAccessException {
throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ " this method");
}
@Override
public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener,
Handler handler) throws CameraAccessException {
if (!isConstrainedHighSpeedRequestList(requests)) {
throw new IllegalArgumentException(
"Only request lists created by createHighSpeedRequestList() can be submitted to " +
"a constrained high speed capture session");
}
return mSessionImpl.captureBurst(requests, listener, handler);
}
@Override
public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener,
Handler handler) throws CameraAccessException {
throw new UnsupportedOperationException("Constrained high speed session doesn't support"
+ " this method");
}
@Override
public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener,
Handler handler) throws CameraAccessException {
if (!isConstrainedHighSpeedRequestList(requests)) {
throw new IllegalArgumentException(
"Only request lists created by createHighSpeedRequestList() can be submitted to " +
"a constrained high speed capture session");
}
return mSessionImpl.setRepeatingBurst(requests, listener, handler);
}
@Override
public void stopRepeating() throws CameraAccessException {
mSessionImpl.stopRepeating();
}
@Override
public void abortCaptures() throws CameraAccessException {
mSessionImpl.abortCaptures();
}
@Override
public Surface getInputSurface() {
return null;
}
@Override
public void close() {
mSessionImpl.close();
}
@Override
public boolean isReprocessable() {
return false;
}
// Implementation of CameraCaptureSessionCore methods
@Override
public void replaceSessionClose() {
mSessionImpl.replaceSessionClose();
}
@Override
public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() {
return mSessionImpl.getDeviceStateCallback();
}
@Override
public boolean isAborting() {
return mSessionImpl.isAborting();
}
private class WrapperCallback extends StateCallback {
private final StateCallback mCallback;
public WrapperCallback(StateCallback callback) {
mCallback = callback;
}
public void onConfigured(CameraCaptureSession session) {
mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
public void onConfigureFailed(CameraCaptureSession session) {
mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
public void onReady(CameraCaptureSession session) {
mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
public void onActive(CameraCaptureSession session) {
mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
public void onClosed(CameraCaptureSession session) {
mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
}
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,
surface);
}
}
}

View File

@@ -113,7 +113,7 @@ public class CameraDeviceImpl extends CameraDevice {
*/
private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
private CameraCaptureSessionImpl mCurrentSession;
private CameraCaptureSessionCore mCurrentSession;
private int mNextSessionId = 0;
// Runnables for all state transitions, except error, which needs the
@@ -510,6 +510,26 @@ public class CameraDeviceImpl extends CameraDevice {
/*isConstrainedHighSpeed*/false);
}
@Override
public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException {
if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
throw new IllegalArgumentException(
"Output surface list must not be null and the size must be no more than 2");
}
StreamConfigurationMap config =
getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
SurfaceUtils.checkConstrainedHighSpeedSurfaces(outputs, /*fpsRange*/null, config);
List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
createCaptureSessionInternal(null, outConfigurations, callback, handler,
/*isConstrainedHighSpeed*/true);
}
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List<OutputConfiguration> outputConfigurations,
CameraCaptureSession.StateCallback callback, Handler handler,
@@ -565,10 +585,16 @@ public class CameraDeviceImpl extends CameraDevice {
outSurfaces.add(config.getSurface());
}
// Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
CameraCaptureSessionImpl newSession =
new CameraCaptureSessionImpl(mNextSessionId++, input,
outSurfaces, callback, handler, this, mDeviceHandler,
configureSuccess, isConstrainedHighSpeed);
CameraCaptureSessionCore newSession = null;
if (isConstrainedHighSpeed) {
newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
outSurfaces, callback, handler, this, mDeviceHandler, configureSuccess,
mCharacteristics);
} else {
newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
outSurfaces, callback, handler, this, mDeviceHandler,
configureSuccess);
}
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
@@ -1933,181 +1959,4 @@ public class CameraDeviceImpl extends CameraDevice {
return mCharacteristics;
}
/**
* A high speed output surface can only be preview or hardware encoder surface.
*
* @param surface The high speed output surface to be checked.
*/
private void checkHighSpeedSurfaceFormat(Surface surface) {
// TODO: remove this override since the default format should be
// ImageFormat.PRIVATE. b/9487482
final int HAL_FORMAT_RGB_START = 1; // HAL_PIXEL_FORMAT_RGBA_8888 from graphics.h
final int HAL_FORMAT_RGB_END = 5; // HAL_PIXEL_FORMAT_BGRA_8888 from graphics.h
int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
if (surfaceFormat >= HAL_FORMAT_RGB_START &&
surfaceFormat <= HAL_FORMAT_RGB_END) {
surfaceFormat = ImageFormat.PRIVATE;
}
if (surfaceFormat != ImageFormat.PRIVATE) {
throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not"
+ " for preview or hardware video encoding!");
}
}
private void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces,
Range<Integer> fpsRange) {
if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) {
throw new IllegalArgumentException("Output target surface list must not be null and"
+ " the size must be 1 or 2");
}
StreamConfigurationMap config =
getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
List<Size> highSpeedSizes = null;
if (fpsRange == null) {
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
} else {
// Check the FPS range first if provided
Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges();
if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) {
throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the"
+ " request is not a supported high speed fps range " +
Arrays.toString(highSpeedFpsRanges));
}
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange));
}
for (Surface surface : surfaces) {
checkHighSpeedSurfaceFormat(surface);
// Surface size must be supported high speed sizes.
Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
if (!highSpeedSizes.contains(surfaceSize)) {
throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is"
+ " not part of the high speed supported size list " +
Arrays.toString(highSpeedSizes.toArray()));
}
// Each output surface must be either preview surface or recording surface.
if (!SurfaceUtils.isSurfaceForPreview(surface) &&
!SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface is neither preview nor "
+ "hardware video encoding surface");
}
if (SurfaceUtils.isSurfaceForPreview(surface) &&
SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface can not be both preview"
+ " and hardware video encoding surface");
}
}
// For 2 output surface case, they shouldn't be same type.
if (surfaces.size() == 2) {
// Up to here, each surface can only be either preview or recording.
Iterator<Surface> iterator = surfaces.iterator();
boolean isFirstSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
boolean isSecondSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
if (isFirstSurfacePreview == isSecondSurfacePreview) {
throw new IllegalArgumentException("The 2 output surfaces must have different"
+ " type");
}
}
}
@Override
public void createConstrainedHighSpeedCaptureSession(List<Surface> outputs,
android.hardware.camera2.CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException {
if (outputs == null || outputs.size() == 0 || outputs.size() > 2) {
throw new IllegalArgumentException(
"Output surface list must not be null and the size must be no more than 2");
}
checkConstrainedHighSpeedSurfaces(outputs, /*fpsRange*/null);
List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
for (Surface surface : outputs) {
outConfigurations.add(new OutputConfiguration(surface));
}
createCaptureSessionInternal(null, outConfigurations, callback, handler,
/*isConstrainedHighSpeed*/true);
}
@Override
public List<CaptureRequest> createConstrainedHighSpeedRequestList(CaptureRequest request)
throws CameraAccessException {
if (request == null) {
throw new IllegalArgumentException("Input capture request must not be null");
}
Collection<Surface> outputSurfaces = request.getTargets();
Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
checkConstrainedHighSpeedSurfaces(outputSurfaces, fpsRange);
// Request list size: to limit the preview to 30fps, need use maxFps/30; to maximize
// the preview frame rate, should use maxBatch size for that high speed stream
// configuration. We choose the former for now.
int requestListSize = fpsRange.getUpper() / 30;
List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
// Prepare the Request builders: need carry over the request controls.
// First, create a request builder that will only include preview or recording target.
CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy());
// Note that after this step, the requestMetadata is mutated (swapped) and can not be used
// for next request builder creation.
CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder(
requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
// Overwrite the capture intent to make sure a good value is set.
Iterator<Surface> iterator = outputSurfaces.iterator();
Surface firstSurface = iterator.next();
Surface secondSurface = null;
if (outputSurfaces.size() == 1 && SurfaceUtils.isSurfaceForHwVideoEncoder(firstSurface)) {
singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
} else {
// Video only, or preview + video
singleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
}
singleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
// Second, Create a request builder that will include both preview and recording targets.
CaptureRequest.Builder doubleTargetRequestBuilder = null;
if (outputSurfaces.size() == 2) {
// Have to create a new copy, the original one was mutated after a new
// CaptureRequest.Builder creation.
requestMetadata = new CameraMetadataNative(request.getNativeCopy());
doubleTargetRequestBuilder = new CaptureRequest.Builder(
requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT,
CaptureRequest.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
doubleTargetRequestBuilder.addTarget(firstSurface);
secondSurface = iterator.next();
doubleTargetRequestBuilder.addTarget(secondSurface);
doubleTargetRequestBuilder.setPartOfCHSRequestList(/*partOfCHSList*/true);
// Make sure singleTargetRequestBuilder contains only recording surface for
// preview + recording case.
Surface recordingSurface = firstSurface;
if (!SurfaceUtils.isSurfaceForHwVideoEncoder(recordingSurface)) {
recordingSurface = secondSurface;
}
singleTargetRequestBuilder.addTarget(recordingSurface);
} else {
// Single output case: either recording or preview.
singleTargetRequestBuilder.addTarget(firstSurface);
}
// Generate the final request list.
for (int i = 0; i < requestListSize; i++) {
if (i == 0 && doubleTargetRequestBuilder != null) {
// First request should be recording + preview request
requestList.add(doubleTargetRequestBuilder.build());
} else {
requestList.add(singleTargetRequestBuilder.build());
}
}
return Collections.unmodifiableList(requestList);
}
}

View File

@@ -495,7 +495,8 @@ public final class StreamConfigurationMap {
* <p>
* To enable high speed video recording, application must create a constrained create high speed
* capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
* a CaptureRequest list created by {@link CameraDevice#createConstrainedHighSpeedRequestList}
* a CaptureRequest list created by
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
* to this session. The application must select the video size from this method and
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
* {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
@@ -506,14 +507,15 @@ public final class StreamConfigurationMap {
* the same size). Otherwise, the high speed session creation will fail. Once the size is
* selected, application can get the supported FPS ranges by
* {@link #getHighSpeedVideoFpsRangesFor}, and use these FPS ranges to setup the recording
* request lists via {@link CameraDevice#createConstrainedHighSpeedRequestList}.
* request lists via
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
* </p>
*
* @return an array of supported high speed video recording sizes
* @see #getHighSpeedVideoFpsRangesFor(Size)
* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
* @see CameraDevice#createConstrainedHighSpeedCaptureSession
* @see CameraDevice#createConstrainedHighSpeedRequestList
* @see android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList
*/
public Size[] getHighSpeedVideoSizes() {
Set<Size> keySet = mHighSpeedVideoSizeMap.keySet();
@@ -571,7 +573,8 @@ public final class StreamConfigurationMap {
* <p>
* To enable high speed video recording, application must create a constrained create high speed
* capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
* a CaptureRequest list created by {@link CameraDevice#createConstrainedHighSpeedRequestList}
* a CaptureRequest list created by
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}
* to this session. The application must select the video size from this method and
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
* {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
@@ -583,7 +586,7 @@ public final class StreamConfigurationMap {
* recording streams must have the same size). Otherwise, the high speed session creation will
* fail. Once the high speed capture session is created, the application can set the FPS range
* in the recording request lists via
* {@link CameraDevice#createConstrainedHighSpeedRequestList}.
* {@link android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList}.
* </p>
* <p>
* The FPS ranges reported by this method will have below characteristics:
@@ -601,7 +604,7 @@ public final class StreamConfigurationMap {
* @see #getHighSpeedVideoSizesFor
* @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
* @see CameraDevice#createConstrainedHighSpeedCaptureSession
* @see CameraDevice#createConstrainedHighSpeedRequestList
* @see CameraDevice#createHighSpeedRequestList
*/
@SuppressWarnings("unchecked")
public Range<Integer>[] getHighSpeedVideoFpsRanges() {

View File

@@ -19,9 +19,16 @@ package android.hardware.camera2.utils;
import android.graphics.ImageFormat;
import android.hardware.camera2.legacy.LegacyCameraDevice;
import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.util.Range;
import android.util.Size;
import android.view.Surface;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Various Surface utilities.
*/
@@ -105,4 +112,93 @@ public class SurfaceUtils {
return LegacyCameraDevice.isFlexibleConsumer(output);
}
/**
* A high speed output surface can only be preview or hardware encoder surface.
*
* @param surface The high speed output surface to be checked.
*/
private static void checkHighSpeedSurfaceFormat(Surface surface) {
// TODO: remove this override since the default format should be
// ImageFormat.PRIVATE. b/9487482
final int HAL_FORMAT_RGB_START = 1; // HAL_PIXEL_FORMAT_RGBA_8888 from graphics.h
final int HAL_FORMAT_RGB_END = 5; // HAL_PIXEL_FORMAT_BGRA_8888 from graphics.h
int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
if (surfaceFormat >= HAL_FORMAT_RGB_START &&
surfaceFormat <= HAL_FORMAT_RGB_END) {
surfaceFormat = ImageFormat.PRIVATE;
}
if (surfaceFormat != ImageFormat.PRIVATE) {
throw new IllegalArgumentException("Surface format(" + surfaceFormat + ") is not"
+ " for preview or hardware video encoding!");
}
}
/**
* Verify that that the surfaces are valid for high-speed recording mode,
* and that the FPS range is supported
*
* @param surfaces the surfaces to verify as valid in terms of size and format
* @param fpsRange the target high-speed FPS range to validate
* @param config The stream configuration map for the device in question
*/
public static void checkConstrainedHighSpeedSurfaces(Collection<Surface> surfaces,
Range<Integer> fpsRange, StreamConfigurationMap config) {
if (surfaces == null || surfaces.size() == 0 || surfaces.size() > 2) {
throw new IllegalArgumentException("Output target surface list must not be null and"
+ " the size must be 1 or 2");
}
List<Size> highSpeedSizes = null;
if (fpsRange == null) {
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
} else {
// Check the FPS range first if provided
Range<Integer>[] highSpeedFpsRanges = config.getHighSpeedVideoFpsRanges();
if(!Arrays.asList(highSpeedFpsRanges).contains(fpsRange)) {
throw new IllegalArgumentException("Fps range " + fpsRange.toString() + " in the"
+ " request is not a supported high speed fps range " +
Arrays.toString(highSpeedFpsRanges));
}
highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizesFor(fpsRange));
}
for (Surface surface : surfaces) {
checkHighSpeedSurfaceFormat(surface);
// Surface size must be supported high speed sizes.
Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
if (!highSpeedSizes.contains(surfaceSize)) {
throw new IllegalArgumentException("Surface size " + surfaceSize.toString() + " is"
+ " not part of the high speed supported size list " +
Arrays.toString(highSpeedSizes.toArray()));
}
// Each output surface must be either preview surface or recording surface.
if (!SurfaceUtils.isSurfaceForPreview(surface) &&
!SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface is neither preview nor "
+ "hardware video encoding surface");
}
if (SurfaceUtils.isSurfaceForPreview(surface) &&
SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) {
throw new IllegalArgumentException("This output surface can not be both preview"
+ " and hardware video encoding surface");
}
}
// For 2 output surface case, they shouldn't be same type.
if (surfaces.size() == 2) {
// Up to here, each surface can only be either preview or recording.
Iterator<Surface> iterator = surfaces.iterator();
boolean isFirstSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
boolean isSecondSurfacePreview =
SurfaceUtils.isSurfaceForPreview(iterator.next());
if (isFirstSurfacePreview == isSecondSurfacePreview) {
throw new IllegalArgumentException("The 2 output surfaces must have different"
+ " type");
}
}
}
}