summaryrefslogtreecommitdiffstats
path: root/core/java/android/hardware
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2015-06-30 10:34:48 -0700
committerEino-Ville Talvala <etalvala@google.com>2015-07-10 00:56:18 +0000
commit639fffee624302ec5b175503d7bd8a441340a629 (patch)
tree90de0fdefbe2cbb6b31bbd6365004e540eab208a /core/java/android/hardware
parent171fe6ac0aa5b0d2dd64ac1cdda25cdcb5f183f3 (diff)
downloadframeworks_base-639fffee624302ec5b175503d7bd8a441340a629.zip
frameworks_base-639fffee624302ec5b175503d7bd8a441340a629.tar.gz
frameworks_base-639fffee624302ec5b175503d7bd8a441340a629.tar.bz2
Camera2: Reorganize high-speed recording API slightly
- Split off distinct high speed capture session class from base capture session - Move createHighSpeedRequestList to CameraConstrainedHighSpeedCaptureSession Bug: 21664295 Change-Id: I67d705fdeee1eaa6e5e3e1416771d5d0df642843
Diffstat (limited to 'core/java/android/hardware')
-rw-r--r--core/java/android/hardware/camera2/CameraCaptureSession.java11
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java2
-rw-r--r--core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java131
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java65
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java13
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java25
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionCore.java64
-rw-r--r--core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java58
-rw-r--r--core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java283
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java213
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java15
-rw-r--r--core/java/android/hardware/camera2/utils/SurfaceUtils.java96
12 files changed, 647 insertions, 329 deletions
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 62ebfb3..46cafad 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -482,17 +482,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.
*
* <p>Each reprocessable capture session has an input {@link Surface} where the reprocess
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 547cce4..30aa2d5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -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,
diff --git a/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java b/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java
new file mode 100644
index 0000000..07d2443
--- /dev/null
+++ b/core/java/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.java
@@ -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;
+
+}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 639c8b1..4a71aa0 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -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
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 0aa6447..c8ae5d4 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -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
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6d8cc54..a136d0f 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -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
*/
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionCore.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionCore.java
new file mode 100644
index 0000000..116f0f1
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionCore.java
@@ -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();
+
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 3d261dd..3c19cd2 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -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;
- }
-
}
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
new file mode 100644
index 0000000..d732535
--- /dev/null
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -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);
+ }
+
+
+ }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 83128c3..c594228 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -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);
- }
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 639ad60..8e0eab2 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -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() {
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 064b21a..4b958df 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -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");
+ }
+ }
+ }
+
}