summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorShuzhen Wang <shuzhenwang@google.com>2018-11-07 22:54:02 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2018-11-07 22:54:02 +0000
commit89d277a982472074fd7184f21c37f4d994b9b57a (patch)
treed02b7773bfe3f72a891fcd7e6355479927b1f90f /core/java/android
parent7c62638354e5c2d228194af7fb1110babd991b63 (diff)
parent2776ca3f4e877709e0e313e25d2d9f86cbd89b8b (diff)
Merge "Camera: Add support for recommended stream configurations"
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java148
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java260
-rw-r--r--core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java84
-rw-r--r--core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java102
-rw-r--r--core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java509
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfiguration.java10
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java79
7 files changed, 1172 insertions, 20 deletions
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 33cc7a84b335..444ca87a68ef 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -22,12 +22,14 @@ import android.annotation.UnsupportedAppUsage;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.impl.PublicKey;
import android.hardware.camera2.impl.SyntheticKey;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.ArrayUtils;
import android.hardware.camera2.utils.TypeReference;
import android.util.Rational;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -193,6 +195,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
private List<CaptureRequest.Key<?>> mAvailableSessionKeys;
private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys;
private List<CaptureResult.Key<?>> mAvailableResultKeys;
+ private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations;
/**
* Takes ownership of the passed-in properties object
@@ -313,6 +316,103 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
}
/**
+ * <p>Retrieve camera device recommended stream configuration map
+ * {@link RecommendedStreamConfigurationMap} for a given use case.</p>
+ *
+ * <p>The stream configurations advertised here are efficient in terms of power and performance
+ * for common use cases like preview, video, snapshot, etc. The recommended maps are usually
+ * only small subsets of the exhaustive list provided in
+ * {@link #SCALER_STREAM_CONFIGURATION_MAP} and suggested for a particular use case by the
+ * camera device implementation. For further information about the expected configurations in
+ * various scenarios please refer to:
+ * <ul>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_PREVIEW}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_RECORD}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_VIDEO_SNAPSHOT}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li>
+ * </ul>
+ * </p>
+ *
+ * <p>For example on how this can be used by camera clients to find out the maximum recommended
+ * preview and snapshot resolution, consider the following pseudo-code:
+ * </p>
+ * <pre><code>
+ * public static Size getMaxSize(Size... sizes) {
+ * if (sizes == null || sizes.length == 0) {
+ * throw new IllegalArgumentException("sizes was empty");
+ * }
+ *
+ * Size sz = sizes[0];
+ * for (Size size : sizes) {
+ * if (size.getWidth() * size.getHeight() &gt; sz.getWidth() * sz.getHeight()) {
+ * sz = size;
+ * }
+ * }
+ *
+ * return sz;
+ * }
+ *
+ * CameraCharacteristics characteristics =
+ * cameraManager.getCameraCharacteristics(cameraId);
+ * RecommendedStreamConfigurationMap previewConfig =
+ * characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+ * RecommendedStreamConfigurationMap snapshotConfig =
+ * characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_SNAPSHOT);
+ *
+ * if ((previewConfig != null) &amp;&amp; (snapshotConfig != null)) {
+ *
+ * Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes(
+ * ImageFormat.JPEG);
+ * Size[] snapshotSizes = new Size[snapshotSizeSet.size()];
+ * snapshotSizes = snapshotSizeSet.toArray(snapshotSizes);
+ * Size suggestedMaxJpegSize = getMaxSize(snapshotSizes);
+ *
+ * Set<Size> previewSizeSet = snapshotConfig.getOutputSizes(
+ * ImageFormat.PRIVATE);
+ * Size[] previewSizes = new Size[previewSizeSet.size()];
+ * previewSizes = previewSizeSet.toArray(previewSizes);
+ * Size suggestedMaxPreviewSize = getMaxSize(previewSizes);
+ * }
+ *
+ * </code></pre>
+ *
+ * <p>Similar logic can be used for other use cases as well.</p>
+ *
+ * <p>Support for recommended stream configurations is optional. In case there a no
+ * suggested configurations for the particular use case, please refer to
+ * {@link #SCALER_STREAM_CONFIGURATION_MAP} for the exhaustive available list.</p>
+ *
+ * @param usecase Use case id.
+ *
+ * @throws IllegalArgumentException In case the use case argument is invalid.
+ * @return Valid {@link RecommendedStreamConfigurationMap} or null in case the camera device
+ * doesn't have any recommendation for this use case or the recommended configurations
+ * are invalid.
+ */
+ public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
+ @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
+ if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
+ (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
+ ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
+ (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
+ if (mRecommendedConfigurations == null) {
+ mRecommendedConfigurations = mProperties.getRecommendedStreamConfigurations();
+ if (mRecommendedConfigurations == null) {
+ return null;
+ }
+ }
+
+ return mRecommendedConfigurations.get(usecase);
+ }
+
+ throw new IllegalArgumentException(String.format("Invalid use case: %d", usecase));
+ }
+
+ /**
* <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the
* camera device can pass as part of the capture session initialization.</p>
*
@@ -329,7 +429,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* but clients should be aware and expect delays during their application.
* An example usage scenario could look like this:</p>
* <ul>
- * <li>The camera client starts by quering the session parameter key list via
+ * <li>The camera client starts by querying the session parameter key list via
* {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</li>
* <li>Before triggering the capture session create sequence, a capture request
* must be built via {@link CameraDevice#createCaptureRequest } using an
@@ -2478,6 +2578,37 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<Integer>("android.scaler.croppingType", int.class);
/**
+ * <p>Recommended stream configurations for common client use cases.</p>
+ * <p>Optional subset of the android.scaler.availableStreamConfigurations that contains
+ * similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.scaler.availableRecommendedStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+ /**
+ * <p>Recommended mappings of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ * <p>This is a recommended subset of the complete list of mappings found in
+ * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well.
+ * The list however doesn't need to contain all available and supported mappings. Instead of
+ * this developers must list only recommended and efficient entries.
+ * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream
+ * configuration see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP =
+ new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class);
+
+ /**
* <p>The area of the image sensor which corresponds to active pixels after any geometric
* distortion correction has been applied.</p>
* <p>This is the rectangle representing the size of the active region of the sensor (i.e.
@@ -3518,6 +3649,21 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
/**
+ * <p>Recommended depth stream configurations for common client use cases.</p>
+ * <p>Optional subset of the android.depth.availableDepthStreamConfigurations that
+ * contains similar tuples listed as
+ * (i.e. width, height, format, output/input stream, usecase bit field).
+ * Camera devices will be able to suggest particular depth stream configurations which are
+ * power and performance efficient for specific use cases. For more information about
+ * retrieving the suggestions see
+ * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @hide
+ */
+ public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS =
+ new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
+
+ /**
* <p>String containing the ids of the underlying physical cameras.</p>
* <p>For a logical camera, this is concatenation of all underlying physical camera ids.
* The null terminator for physical camera id must be preserved so that the whole string
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0610d7a3746b..f81bd1377a7a 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -21,6 +21,7 @@ import android.graphics.ImageFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.marshal.MarshalQueryable;
@@ -38,6 +39,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryablePair;
import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable;
import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive;
import android.hardware.camera2.marshal.impl.MarshalQueryableRange;
+import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration;
import android.hardware.camera2.marshal.impl.MarshalQueryableRect;
import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap;
import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector;
@@ -50,6 +52,8 @@ import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
import android.hardware.camera2.params.OisSample;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.params.RecommendedStreamConfigurationMap;
import android.hardware.camera2.params.ReprocessFormatsMap;
import android.hardware.camera2.params.StreamConfiguration;
import android.hardware.camera2.params.StreamConfigurationDuration;
@@ -911,6 +915,252 @@ public class CameraMetadataNative implements Parcelable {
return true;
}
+ private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations,
+ StreamConfigurationMap fullMap, boolean isDepth,
+ ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList,
+ ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList,
+ ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList,
+ boolean[] /*out*/supportsPrivate) {
+
+ streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ streamConfigList.add(new ArrayList<StreamConfiguration> ());
+ streamDurationList.add(new ArrayList<StreamConfigurationDuration> ());
+ streamStallList.add(new ArrayList<StreamConfigurationDuration> ());
+ }
+
+ for (RecommendedStreamConfiguration c : configurations) {
+ int width = c.getWidth();
+ int height = c.getHeight();
+ int internalFormat = c.getFormat();
+ int publicFormat =
+ (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) :
+ StreamConfigurationMap.imageFormatToPublic(internalFormat);
+ Size sz = new Size(width, height);
+ int usecaseBitmap = c.getUsecaseBitmap();
+
+ if (!c.isInput()) {
+ StreamConfigurationDuration minDurationConfiguration = null;
+ StreamConfigurationDuration stallDurationConfiguration = null;
+
+ StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat,
+ width, height, /*input*/ false);
+
+ long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz);
+ if (minFrameDuration > 0) {
+ minDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+ width, height, minFrameDuration);
+ }
+
+ long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz);
+ if (stallDuration > 0) {
+ stallDurationConfiguration = new StreamConfigurationDuration(internalFormat,
+ width, height, stallDuration);
+ }
+
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ if ((usecaseBitmap & (1 << i)) != 0) {
+ ArrayList<StreamConfiguration> sc = streamConfigList.get(i);
+ sc.add(streamConfiguration);
+
+ if (minFrameDuration > 0) {
+ ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i);
+ scd.add(minDurationConfiguration);
+ }
+
+ if (stallDuration > 0) {
+ ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i);
+ scs.add(stallDurationConfiguration);
+ }
+
+ if ((supportsPrivate != null) && !supportsPrivate[i] &&
+ (publicFormat == ImageFormat.PRIVATE)) {
+ supportsPrivate[i] = true;
+ }
+ }
+ }
+ } else {
+ if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) {
+ throw new IllegalArgumentException("Recommended input stream configurations " +
+ "should only be advertised in the ZSL use case!");
+ }
+
+ ArrayList<StreamConfiguration> sc = streamConfigList.get(
+ RecommendedStreamConfigurationMap.USECASE_ZSL);
+ sc.add(new StreamConfiguration(internalFormat,
+ width, height, /*input*/ true));
+ }
+ }
+ }
+
+ private class StreamConfigurationData {
+ StreamConfiguration [] streamConfigurationArray = null;
+ StreamConfigurationDuration [] minDurationArray = null;
+ StreamConfigurationDuration [] stallDurationArray = null;
+ }
+
+ public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc,
+ ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs,
+ StreamConfigurationData /*out*/scData) {
+ if ((scData == null) || (sc == null)) {
+ return;
+ }
+
+ scData.streamConfigurationArray = new StreamConfiguration[sc.size()];
+ scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray);
+
+ if ((scd != null) && !scd.isEmpty()) {
+ scData.minDurationArray = new StreamConfigurationDuration[scd.size()];
+ scData.minDurationArray = scd.toArray(scData.minDurationArray);
+ } else {
+ scData.minDurationArray = new StreamConfigurationDuration[0];
+ }
+
+ if ((scs != null) && !scs.isEmpty()) {
+ scData.stallDurationArray = new StreamConfigurationDuration[scs.size()];
+ scData.stallDurationArray = scs.toArray(scData.stallDurationArray);
+ } else {
+ scData.stallDurationArray = new StreamConfigurationDuration[0];
+ }
+ }
+
+ /**
+ * Retrieve the list of recommended stream configurations.
+ *
+ * @return A list of recommended stream configuration maps for each common use case or null
+ * in case the recommended stream configurations are invalid or incomplete.
+ * @hide
+ */
+ public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() {
+ RecommendedStreamConfiguration[] configurations = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS);
+ RecommendedStreamConfiguration[] depthConfigurations = getBase(
+ CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS);
+ if ((configurations == null) && (depthConfigurations == null)) {
+ return null;
+ }
+
+ StreamConfigurationMap fullMap = getStreamConfigurationMap();
+ ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations =
+ new ArrayList<RecommendedStreamConfigurationMap> ();
+
+ ArrayList<ArrayList<StreamConfiguration>> streamConfigList =
+ new ArrayList<ArrayList<StreamConfiguration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ boolean[] supportsPrivate =
+ new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT];
+ try {
+ if (configurations != null) {
+ parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false,
+ streamConfigList, streamDurationList, streamStallList, supportsPrivate);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed parsing the recommended stream configurations!");
+ return null;
+ }
+
+ ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList =
+ new ArrayList<ArrayList<StreamConfiguration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList =
+ new ArrayList<ArrayList<StreamConfigurationDuration>>();
+ if (depthConfigurations != null) {
+ try {
+ parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true,
+ depthStreamConfigList, depthStreamDurationList, depthStreamStallList,
+ /*supportsPrivate*/ null);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed parsing the recommended depth stream configurations!");
+ return null;
+ }
+ }
+
+ ReprocessFormatsMap inputOutputFormatsMap = getBase(
+ CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP);
+ HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
+ CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+ boolean listHighResolution = isBurstSupported();
+ recommendedConfigurations.ensureCapacity(
+ RecommendedStreamConfigurationMap.MAX_USECASE_COUNT);
+ for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) {
+ StreamConfigurationData scData = new StreamConfigurationData();
+ if (configurations != null) {
+ initializeStreamConfigurationData(streamConfigList.get(i),
+ streamDurationList.get(i), streamStallList.get(i), scData);
+ }
+
+ StreamConfigurationData depthScData = new StreamConfigurationData();
+ if (depthConfigurations != null) {
+ initializeStreamConfigurationData(depthStreamConfigList.get(i),
+ depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
+ }
+
+ if ((scData.streamConfigurationArray == null) &&
+ (depthScData.streamConfigurationArray == null)) {
+ recommendedConfigurations.add(null);
+ continue;
+ }
+
+ StreamConfigurationMap map = null;
+ switch (i) {
+ case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
+ case RecommendedStreamConfigurationMap.USECASE_RAW:
+ case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ /*depthconfiguration*/ null, /*depthminduration*/ null,
+ /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null,
+ /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+ break;
+ case RecommendedStreamConfigurationMap.USECASE_RECORD:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ /*depthconfiguration*/ null, /*depthminduration*/ null,
+ /*depthstallduration*/ null, highSpeedVideoConfigurations,
+ /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
+ break;
+ case RecommendedStreamConfigurationMap.USECASE_ZSL:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ depthScData.streamConfigurationArray, depthScData.minDurationArray,
+ depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+ inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
+ break;
+ default:
+ map = new StreamConfigurationMap(scData.streamConfigurationArray,
+ scData.minDurationArray, scData.stallDurationArray,
+ depthScData.streamConfigurationArray, depthScData.minDurationArray,
+ depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+ /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
+ }
+
+ recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i,
+ supportsPrivate[i]));
+ }
+
+ return recommendedConfigurations;
+ }
+
+ private boolean isBurstSupported() {
+ boolean ret = false;
+
+ int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ for (int capability : capabilities) {
+ if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
+ ret = true;
+ break;
+ }
+ }
+
+ return ret;
+ }
+
private StreamConfigurationMap getStreamConfigurationMap() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
@@ -928,14 +1178,7 @@ public class CameraMetadataNative implements Parcelable {
CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
ReprocessFormatsMap inputOutputFormatsMap = getBase(
CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
- int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
- boolean listHighResolution = false;
- for (int capability : capabilities) {
- if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
- listHighResolution = true;
- break;
- }
- }
+ boolean listHighResolution = isBurstSupported();
return new StreamConfigurationMap(
configurations, minFrameDurations, stallDurations,
depthConfigurations, depthMinFrameDurations, depthStallDurations,
@@ -1399,6 +1642,7 @@ public class CameraMetadataNative implements Parcelable {
new MarshalQueryableRggbChannelVector(),
new MarshalQueryableBlackLevelPattern(),
new MarshalQueryableHighSpeedVideoConfiguration(),
+ new MarshalQueryableRecommendedStreamConfiguration(),
// generic parcelable marshaler (MUST BE LAST since it has lowest priority)
new MarshalQueryableParcelable(),
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
new file mode 100644
index 000000000000..22a76b7346e8
--- /dev/null
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 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.marshal.impl;
+
+import android.hardware.camera2.marshal.Marshaler;
+import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RecommendedStreamConfiguration;
+import android.hardware.camera2.utils.TypeReference;
+
+import static android.hardware.camera2.impl.CameraMetadataNative.*;
+import static android.hardware.camera2.marshal.MarshalHelpers.*;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Marshaler for {@code android.scaler.availableRecommendedStreamConfigurations} custom class
+ * {@link RecommendedStreamConfiguration}
+ *
+ * <p>Data is stored as {@code (width, height, format, input, usecaseBitmap)} tuples (int32).</p>
+ */
+public class MarshalQueryableRecommendedStreamConfiguration
+ implements MarshalQueryable<RecommendedStreamConfiguration> {
+ private static final int SIZE = SIZEOF_INT32 * 5;
+
+ private class MarshalerRecommendedStreamConfiguration
+ extends Marshaler<RecommendedStreamConfiguration> {
+ protected MarshalerRecommendedStreamConfiguration(
+ TypeReference<RecommendedStreamConfiguration> typeReference, int nativeType) {
+ super(MarshalQueryableRecommendedStreamConfiguration.this, typeReference, nativeType);
+ }
+
+ @Override
+ public void marshal(RecommendedStreamConfiguration value, ByteBuffer buffer) {
+ buffer.putInt(value.getWidth());
+ buffer.putInt(value.getHeight());
+ buffer.putInt(value.getFormat());
+ buffer.putInt(value.isInput() ? 1 : 0);
+ buffer.putInt(value.getUsecaseBitmap());
+ }
+
+ @Override
+ public RecommendedStreamConfiguration unmarshal(ByteBuffer buffer) {
+ int width = buffer.getInt();
+ int height = buffer.getInt();
+ int format = buffer.getInt();
+ boolean input = buffer.getInt() != 0;
+ int usecaseBitmap = buffer.getInt();
+
+ return new RecommendedStreamConfiguration(format, width, height, input, usecaseBitmap);
+ }
+
+ @Override
+ public int getNativeSize() {
+ return SIZE;
+ }
+
+ }
+
+ @Override
+ public Marshaler<RecommendedStreamConfiguration> createMarshaler(
+ TypeReference<RecommendedStreamConfiguration> managedType, int nativeType) {
+ return new MarshalerRecommendedStreamConfiguration(managedType, nativeType);
+ }
+
+ @Override
+ public boolean isTypeMappingSupported(TypeReference<RecommendedStreamConfiguration> managedType,
+ int nativeType) {
+ return nativeType ==
+ TYPE_INT32 && managedType.getType().equals(RecommendedStreamConfiguration.class);
+ }
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
new file mode 100644
index 000000000000..5dd0517ae47e
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 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.params;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session}
+ * with {@link CameraDevice#createCaptureSession}.
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ *
+ * @hide
+ */
+public final class RecommendedStreamConfiguration extends StreamConfiguration{
+
+ /**
+ * Create a new {@link RecommendedStreamConfiguration}.
+ *
+ * @param format image format
+ * @param width image width, in pixels (positive)
+ * @param height image height, in pixels (positive)
+ * @param input true if this is an input configuration, false for output configurations
+ * @param usecaseBitmap Use case bitmap
+ *
+ * @throws IllegalArgumentException
+ * if width/height were not positive
+ * or if the format was not user-defined in ImageFormat/PixelFormat
+ * (IMPL_DEFINED is ok)
+ *
+ * @hide
+ */
+ public RecommendedStreamConfiguration(
+ final int format, final int width, final int height, final boolean input, final int
+ usecaseBitmap) {
+ super(format, width, height, input);
+ mUsecaseBitmap = usecaseBitmap;
+ }
+
+ /**
+ * Return usecase bitmap.
+ *
+ * @return usecase bitmap
+ */
+ public int getUsecaseBitmap() {
+ return mUsecaseBitmap;
+ }
+
+ /**
+ * Check if this {@link RecommendedStreamConfiguration} is equal to another
+ * {@link RecommendedStreamConfiguration}.
+ *
+ * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
+ *
+ * @return {@code true} if the objects were equal, {@code false} otherwise
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof RecommendedStreamConfiguration) {
+ final RecommendedStreamConfiguration other = (RecommendedStreamConfiguration) obj;
+ return mFormat == other.mFormat &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight &&
+ mUsecaseBitmap == other.mUsecaseBitmap &&
+ mInput == other.mInput;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0, mUsecaseBitmap);
+ }
+
+ private final int mUsecaseBitmap;
+}
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
new file mode 100644
index 000000000000..59e4a3366995
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2018 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.params;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.ImageFormat;
+import android.graphics.PixelFormat;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
+import android.util.ArraySet;
+import android.util.Range;
+import android.util.Size;
+import android.view.Surface;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Immutable class to store the recommended stream configurations to set up
+ * {@link android.view.Surface Surfaces} for creating a
+ * {@link android.hardware.camera2.CameraCaptureSession capture session} with
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
+ *
+ * <p>The recommended list does not replace or deprecate the exhaustive complete list found in
+ * {@link StreamConfigurationMap}. It is a suggestion about available power and performance
+ * efficient stream configurations for a specific use case. Per definition it is only a subset
+ * of {@link StreamConfigurationMap} and can be considered by developers for optimization
+ * purposes.</p>
+ *
+ * <p>This also duplicates the minimum frame durations and stall durations from the
+ * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate
+ * effective frame rate when submitting multiple captures.
+ * </p>
+ *
+ * <p>An instance of this object is available by invoking
+ * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective
+ * usecase id. For more information about supported use case constants see
+ * {@link #USECASE_PREVIEW}.</p>
+ *
+ * <pre><code>{@code
+ * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
+ * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap(
+ * RecommendedStreamConfigurationMap.USECASE_PREVIEW);
+ * }</code></pre>
+ *
+ * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
+ * @see CameraDevice#createCaptureSession
+ */
+public final class RecommendedStreamConfigurationMap {
+
+ private static final String TAG = "RecommendedStreamConfigurationMap";
+ private int mUsecase;
+ private boolean mSupportsPrivate;
+ private StreamConfigurationMap mRecommendedMap;
+
+ /** @hide */
+ public static final int MAX_USECASE_COUNT = 32;
+
+ /**
+ * The recommended stream configuration map for use case preview must contain a subset of
+ * efficient, non-stalling configurations that must include both
+ * {@link android.graphics.ImageFormat#PRIVATE} and
+ * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the
+ * camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_PREVIEW = 0x0;
+
+ /**
+ * The recommended stream configuration map for recording must contain a subset of efficient
+ * video configurations that include {@link android.graphics.ImageFormat#PRIVATE}
+ * output format for at least all supported {@link android.media.CamcorderProfile profiles}.
+ * High speed configurations if supported will be available as well. Even if available for the
+ * camera device, input configurations will be absent.
+ */
+ public static final int USECASE_RECORD = 0x1;
+
+ /**
+ * The recommended stream configuration map for use case video snapshot must only contain a
+ * subset of efficient liveshot configurations that include
+ * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least
+ * the maximum resolution of usecase record and will not cause any preview glitches. Even
+ * if available for the camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_VIDEO_SNAPSHOT = 0x2;
+
+ /**
+ * The recommended stream configuration map for use case snapshot must contain a subset of
+ * efficient still capture configurations that must include
+ * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with
+ * size approximately equal to the sensor pixel array size
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+ * Even if available for the camera device, high speed or input configurations will be absent.
+ */
+ public static final int USECASE_SNAPSHOT = 0x3;
+
+ /**
+ * In case the device supports
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING},
+ * the recommended stream configuration map for use case ZSL must contain a subset of efficient
+ * configurations that include the suggested input and output format mappings. Even if
+ * available for the camera device, high speed configurations will be absent.
+ */
+ public static final int USECASE_ZSL = 0x4;
+
+ /**
+ * In case the device supports
+ * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the
+ * recommended stream configuration map for use case RAW must contain a subset of efficient
+ * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other
+ * RAW output formats. Even if available for the camera device, high speed and input
+ * configurations will be absent.
+ */
+ public static final int USECASE_RAW = 0x5;
+
+ /**
+ * Device specific use cases.
+ * @hide
+ */
+ public static final int USECASE_VENDOR_START = 0x18;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"USECASE_"}, value =
+ {USECASE_PREVIEW,
+ USECASE_RECORD,
+ USECASE_VIDEO_SNAPSHOT,
+ USECASE_SNAPSHOT,
+ USECASE_ZSL,
+ USECASE_RAW })
+ public @interface RecommendedUsecase {};
+
+ /**
+ * Create a new {@link RecommendedStreamConfigurationMap}.
+ *
+ * @param recommendedMap stream configuration map that contains for the specific use case
+ * @param usecase Recommended use case
+ * @param supportsPrivate Flag indicating private format support.
+ *
+ * @hide
+ */
+ public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase,
+ boolean supportsPrivate) {
+ mRecommendedMap = recommendedMap;
+ mUsecase = usecase;
+ mSupportsPrivate = supportsPrivate;
+ }
+
+ /**
+ * Get the use case value for the recommended stream configurations.
+ *
+ * @return Use case id.
+ */
+ public int getRecommendedUseCase() {
+ return mUsecase;
+ }
+
+ private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) {
+ if ((intArray != null) && (intArray.length > 0)) {
+ ArraySet<Integer> integerSet = new ArraySet<Integer>();
+ integerSet.ensureCapacity(intArray.length);
+ for (int intEntry : intArray) {
+ integerSet.add(intEntry);
+ }
+
+ return Collections.unmodifiableSet(integerSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the image {@code format} output formats in this stream configuration.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getOutputFormats}.
+ * </p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @NonNull Set<Integer> getOutputFormats() {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats());
+ }
+
+ /**
+ * Get the image {@code format} output formats for a reprocessing input format.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}.
+ * </p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
+ inputFormat));
+ }
+
+ /**
+ * Get the image {@code format} input formats in this stream configuration.
+ *
+ * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+ * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+ *
+ * @return a non-modifiable set of Integer formats
+ */
+ public @Nullable Set<Integer> getInputFormats() {
+ return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats());
+ }
+
+ private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) {
+ if ((sizeArray != null) && (sizeArray.length > 0)) {
+ ArraySet<Size> sizeSet = new ArraySet<Size>();
+ sizeSet.addAll(Arrays.asList(sizeArray));
+ return Collections.unmodifiableSet(sizeSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the supported input sizes for this input format.
+ *
+ * <p>The format must have come from {@link #getInputFormats}; otherwise
+ * {@code null} is returned.</p>
+ *
+ * @param format a format from {@link #getInputFormats}
+ * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
+ */
+ public @Nullable Set<Size> getInputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
+ }
+
+ /**
+ * Determine whether or not output surfaces with a particular user-defined format can be passed
+ * {@link CameraDevice#createCaptureSession createCaptureSession}.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+ * </p>
+ *
+ *
+ * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
+ * @return
+ * {@code true} if using a {@code surface} with this {@code format} will be
+ * supported with {@link CameraDevice#createCaptureSession}
+ *
+ * @throws IllegalArgumentException
+ * if the image format was not a defined named constant
+ * from either {@link ImageFormat} or {@link PixelFormat}
+ */
+ public boolean isOutputSupportedFor(int format) {
+ return mRecommendedMap.isOutputSupportedFor(format);
+ }
+
+ /**
+ * Get a list of sizes compatible with the requested image {@code format}.
+ *
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getOutputSizes}.
+ * </p>
+ *
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @return a non-modifiable set of supported sizes,
+ * or {@code null} if the {@code format} is not a supported output
+ */
+ public @Nullable Set<Size> getOutputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
+ }
+
+ /**
+ * Get a list of supported high speed video recording sizes.
+ * <p>
+ * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}.
+ * </p>
+ *
+ * @return a non-modifiable set of supported high speed video recording sizes
+ */
+ public @Nullable Set<Size> getHighSpeedVideoSizes() {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes());
+ }
+
+ private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) {
+ if ((rangeArray != null) && (rangeArray.length > 0)) {
+ ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>();
+ rangeSet.addAll(Arrays.asList(rangeArray));
+ return Collections.unmodifiableSet(rangeSet);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
+ *
+ * <p>
+ * For further information refer to
+ * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}.
+ * </p>
+ * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
+ * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+ * bound of returned ranges is guaranteed to be greater than or equal to 120.
+ * @throws IllegalArgumentException if input size does not exist in the return value of
+ * getHighSpeedVideoSizes
+ */
+ public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) {
+ return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
+ }
+
+ /**
+ * Get a list of supported high speed video recording FPS ranges.
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}.
+ * </p>
+ * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
+ * bound of returned ranges is guaranteed to be larger or equal to 120.
+ */
+ public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() {
+ return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges());
+ }
+
+ /**
+ * Get the supported video sizes for an input high speed FPS range.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
+ * </p>
+ *
+ * @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
+ * @return A non-modifiable set of video sizes to create high speed capture sessions for high
+ * speed streaming use cases.
+ *
+ * @throws IllegalArgumentException if input FPS range does not exist in the return value of
+ * getHighSpeedVideoFpsRanges
+ */
+ public @Nullable Set<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
+ }
+
+ /**
+ * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
+ * rate.
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}.
+ * </p>
+ *
+ * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
+ * the BURST_CAPTURE capability is not supported
+ */
+ public @Nullable Set<Size> getHighResolutionOutputSizes(int format) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
+ }
+
+ /**
+ * Get the minimum
+ * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the format/size combination (in nanoseconds).
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}.
+ * </p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+ * 0 if the minimum frame duration is not available.
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ *
+ */
+ public long getOutputMinFrameDuration(int format, Size size) {
+ return mRecommendedMap.getOutputMinFrameDuration(format, size);
+ }
+
+ /**
+ * Get the stall duration for the format/size combination (in nanoseconds).
+ *
+ * <p>
+ * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}.
+ * </p>
+ *
+ * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
+ * @param size an output-compatible size
+ * @return a stall duration {@code >=} 0 in nanoseconds
+ *
+ * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} was {@code null}
+ */
+ public long getOutputStallDuration(int format, Size size) {
+ return mRecommendedMap.getOutputStallDuration(format, size);
+ }
+
+ /**
+ * Get a list of sizes compatible with {@code klass} to use as an output.
+ *
+ * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}.
+ * </p>
+ *
+ * @param klass
+ * a non-{@code null} {@link Class} object reference
+ * @return
+ * a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
+ * or {@code null} if the {@code klass} is not a supported output.
+ *
+ *
+ * @throws NullPointerException if {@code klass} was {@code null}
+ *
+ */
+ public <T> @Nullable Set<Size> getOutputSizes(Class<T> klass) {
+ if (mSupportsPrivate) {
+ return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
+ * for the class/size combination (in nanoseconds).
+ *
+ * <p>For more information refer to
+ * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
+ *
+ * @param klass
+ * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >} 0 in nanoseconds, or
+ * 0 if the minimum frame duration is not available.
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ */
+ public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) {
+ if (mSupportsPrivate) {
+ return mRecommendedMap.getOutputMinFrameDuration(klass, size);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Get the stall duration for the class/size combination (in nanoseconds).
+ *
+ * <p>For more information refer to
+ * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}.
+ *
+ * @param klass
+ * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
+ * @param size an output-compatible size
+ * @return a minimum frame duration {@code >=} 0 in nanoseconds, or 0 if the stall duration is
+ * not available.
+ *
+ * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
+ * @throws NullPointerException if {@code size} or {@code klass} was {@code null}
+ *
+ */
+ public <T> long getOutputStallDuration(final Class<T> klass, final Size size) {
+ if (mSupportsPrivate) {
+ return mRecommendedMap.getOutputStallDuration(klass, size);
+ }
+
+ return 0;
+ }
+
+ /**
+ * Determine whether or not the {@code surface} in its current state is suitable to be included
+ * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ *
+ * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
+ * </p>
+ *
+ * @param surface a non-{@code null} {@link Surface} object reference
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @throws NullPointerException if {@code surface} was {@code null}
+ * @throws IllegalArgumentException if the Surface endpoint is no longer valid
+ *
+ */
+ public boolean isOutputSupportedFor(Surface surface) {
+ return mRecommendedMap.isOutputSupportedFor(surface);
+ }
+
+}
diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java
index a6fc10fdcc61..eb92291ac90b 100644
--- a/core/java/android/hardware/camera2/params/StreamConfiguration.java
+++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java
@@ -40,7 +40,7 @@ import android.util.Size;
*
* @hide
*/
-public final class StreamConfiguration {
+public class StreamConfiguration {
/**
* Create a new {@link StreamConfiguration}.
@@ -164,8 +164,8 @@ public final class StreamConfiguration {
return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0);
}
- private final int mFormat;
- private final int mWidth;
- private final int mHeight;
- private final boolean mInput;
+ protected int mFormat;
+ protected int mWidth;
+ protected int mHeight;
+ protected boolean mInput;
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 414c463b4545..dd052a8db1d9 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -98,6 +98,43 @@ public final class StreamConfigurationMap {
HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
ReprocessFormatsMap inputOutputFormatsMap,
boolean listHighResolution) {
+ this(configurations, minFrameDurations, stallDurations,
+ depthConfigurations, depthMinFrameDurations, depthStallDurations,
+ highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
+ /*enforceImplementationDefined*/ true);
+ }
+
+ /**
+ * Create a new {@link StreamConfigurationMap}.
+ *
+ * <p>The array parameters ownership is passed to this object after creation; do not
+ * write to them after this constructor is invoked.</p>
+ *
+ * @param configurations a non-{@code null} array of {@link StreamConfiguration}
+ * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+ * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
+ * camera device does not support high speed video recording
+ * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
+ * and thus needs a separate list of slow high-resolution output sizes
+ * @param enforceImplementationDefined a flag indicating whether
+ * IMPLEMENTATION_DEFINED format configuration must be present
+ * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
+ * were {@code null} or any subelements were {@code null}
+ *
+ * @hide
+ */
+ public StreamConfigurationMap(
+ StreamConfiguration[] configurations,
+ StreamConfigurationDuration[] minFrameDurations,
+ StreamConfigurationDuration[] stallDurations,
+ StreamConfiguration[] depthConfigurations,
+ StreamConfigurationDuration[] depthMinFrameDurations,
+ StreamConfigurationDuration[] depthStallDurations,
+ HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
+ ReprocessFormatsMap inputOutputFormatsMap,
+ boolean listHighResolution,
+ boolean enforceImplementationDefined) {
if (configurations == null) {
// If no color configurations exist, ensure depth ones do
@@ -169,7 +206,7 @@ public final class StreamConfigurationMap {
mDepthOutputFormats.get(config.getFormat()) + 1);
}
- if (configurations != null &&
+ if (configurations != null && enforceImplementationDefined &&
mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
throw new AssertionError(
"At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
@@ -208,7 +245,7 @@ public final class StreamConfigurationMap {
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getOutputFormats() {
+ public int[] getOutputFormats() {
return getPublicFormats(/*output*/true);
}
@@ -232,7 +269,7 @@ public final class StreamConfigurationMap {
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getValidOutputFormatsForInput(int inputFormat) {
+ public int[] getValidOutputFormatsForInput(int inputFormat) {
if (mInputOutputFormatsMap == null) {
return new int[0];
}
@@ -250,7 +287,7 @@ public final class StreamConfigurationMap {
* @see ImageFormat
* @see PixelFormat
*/
- public final int[] getInputFormats() {
+ public int[] getInputFormats() {
return getPublicFormats(/*output*/false);
}
@@ -426,6 +463,34 @@ public final class StreamConfigurationMap {
}
/**
+ * Determine whether or not the particular stream configuration is suitable to be included
+ * in a {@link CameraDevice#createCaptureSession capture session} as an output.
+ *
+ * @param size stream configuration size
+ * @param format stream configuration format
+ * @return {@code true} if this is supported, {@code false} otherwise
+ *
+ * @see CameraDevice#createCaptureSession
+ * @see #isOutputSupportedFor(Class)
+ * @hide
+ */
+ public boolean isOutputSupportedFor(Size size, int format) {
+ int internalFormat = imageFormatToInternal(format);
+ int dataspace = imageFormatToDataspace(format);
+
+ StreamConfiguration[] configs =
+ dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+ for (StreamConfiguration config : configs) {
+ if ((config.getFormat() == internalFormat) && config.isOutput() &&
+ config.getSize().equals(size)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Get a list of sizes compatible with {@code klass} to use as an output.
*
* <p>Some of the supported classes may support additional formats beyond
@@ -1062,8 +1127,9 @@ public final class StreamConfigurationMap {
* @see ImageFormat
* @see PixelFormat
* @see #checkArgumentFormat
+ * @hide
*/
- static int imageFormatToPublic(int format) {
+ public static int imageFormatToPublic(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_BLOB:
return ImageFormat.JPEG;
@@ -1105,8 +1171,9 @@ public final class StreamConfigurationMap {
* @see ImageFormat
* @see PixelFormat
* @see #checkArgumentFormat
+ * @hide
*/
- static int depthFormatToPublic(int format) {
+ public static int depthFormatToPublic(int format) {
switch (format) {
case HAL_PIXEL_FORMAT_BLOB:
return ImageFormat.DEPTH_POINT_CLOUD;