diff --git a/core/api/current.txt b/core/api/current.txt
index 8ca3551eace47..52eba6ed4ab3e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -17334,12 +17334,14 @@ package android.hardware.camera2 {
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_STREAM_USE_CASES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_CROPPING_TYPE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_DEFAULT_SECURE_IMAGE_SIZE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION;
@@ -17668,9 +17670,16 @@ package android.hardware.camera2 {
field public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5; // 0x5
field public static final int REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17; // 0x11
field public static final int REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA = 13; // 0xd
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19; // 0x13
field public static final int REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA = 14; // 0xe
field public static final int REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR = 16; // 0x10
field public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7; // 0x7
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0; // 0x0
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 1; // 0x1
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 4; // 0x4
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 2; // 0x2
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 5; // 0x5
+ field public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 3; // 0x3
field public static final int SCALER_CROPPING_TYPE_CENTER_ONLY = 0; // 0x0
field public static final int SCALER_CROPPING_TYPE_FREEFORM = 1; // 0x1
field public static final int SCALER_ROTATE_AND_CROP_180 = 2; // 0x2
@@ -18078,6 +18087,7 @@ package android.hardware.camera2.params {
method public int get10BitFormat();
method @NonNull public java.util.List getAvailableSizes();
method public int getFormat();
+ method public int getStreamUseCase();
method public boolean is10BitCapable();
method public boolean isInput();
method public boolean isMaximumSize();
@@ -18134,6 +18144,7 @@ package android.hardware.camera2.params {
method public void enableSurfaceSharing();
method public int getDynamicRangeProfile();
method public int getMaxSharedSurfaceCount();
+ method public int getStreamUseCase();
method @Nullable public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method @NonNull public java.util.List getSurfaces();
@@ -18141,6 +18152,7 @@ package android.hardware.camera2.params {
method public void removeSurface(@NonNull android.view.Surface);
method public void setDynamicRangeProfile(int);
method public void setPhysicalCameraId(@Nullable String);
+ method public void setStreamUseCase(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator CREATOR;
field public static final int SURFACE_GROUP_ID_NONE = -1; // 0xffffffff
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index ed22de8dd594d..85890c1912c5d 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -16,6 +16,7 @@
package android.hardware;
import android.hardware.camera2.params.DynamicRangeProfiles;
+import android.hardware.camera2.CameraMetadata;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -47,6 +48,7 @@ public class CameraStreamStats implements Parcelable {
private float[] mHistogramBins;
private long[] mHistogramCounts;
private int mDynamicRangeProfile;
+ private int mStreamUseCase;
private static final String TAG = "CameraStreamStats";
@@ -63,11 +65,13 @@ public class CameraStreamStats implements Parcelable {
mMaxAppBuffers = 0;
mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
public CameraStreamStats(int width, int height, int format,
int dataSpace, long usage, long requestCount, long errorCount,
- int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile) {
+ int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile,
+ int streamUseCase) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -80,6 +84,7 @@ public class CameraStreamStats implements Parcelable {
mMaxAppBuffers = maxAppBuffers;
mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
mDynamicRangeProfile = dynamicRangeProfile;
+ mStreamUseCase = streamUseCase;
}
public static final @android.annotation.NonNull Parcelable.Creator CREATOR =
@@ -126,6 +131,7 @@ public class CameraStreamStats implements Parcelable {
dest.writeFloatArray(mHistogramBins);
dest.writeLongArray(mHistogramCounts);
dest.writeInt(mDynamicRangeProfile);
+ dest.writeInt(mStreamUseCase);
}
public void readFromParcel(Parcel in) {
@@ -143,6 +149,7 @@ public class CameraStreamStats implements Parcelable {
mHistogramBins = in.createFloatArray();
mHistogramCounts = in.createLongArray();
mDynamicRangeProfile = in.readInt();
+ mStreamUseCase = in.readInt();
}
public int getWidth() {
@@ -200,4 +207,8 @@ public class CameraStreamStats implements Parcelable {
public int getDynamicRangeProfile() {
return mDynamicRangeProfile;
}
+
+ public int getStreamUseCase() {
+ return mStreamUseCase;
+ }
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index d2dc314585d6c..34ef8f7d701a4 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2214,6 +2214,7 @@ public final class CameraCharacteristics extends CameraMetadata{@link #REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR ULTRA_HIGH_RESOLUTION_SENSOR}
* {@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING}
* {@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}
+ * {@link #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE STREAM_USE_CASE}
*
*
* This key is available on all devices.
@@ -2238,6 +2239,7 @@ public final class CameraCharacteristics extends CameraMetadata SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED =
new Key("android.scaler.multiResolutionStreamSupported", boolean.class);
+ /**
+ * The stream use cases supported by this camera device.
+ * The stream use case indicates the purpose of a particular camera stream from
+ * the end-user perspective. Some examples of camera use cases are: preview stream for
+ * live viewfinder shown to the user, still capture for generating high quality photo
+ * capture, video record for encoding the camera output for the purpose of future playback,
+ * and video call for live realtime video conferencing.
+ * With this flag, the camera device can optimize the image processing pipeline
+ * parameters, such as tuning, sensor mode, and ISP settings, indepedent of
+ * the properties of the immediate camera output surface. For example, if the output
+ * surface is a SurfaceTexture, the stream use case flag can be used to indicate whether
+ * the camera frames eventually go to display, video encoder,
+ * still image capture, or all of them combined.
+ * The application sets the use case of a camera stream by calling
+ * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase }.
+ * A camera device with
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+ * capability must support the following stream use cases:
+ *
+ * - DEFAULT
+ * - PREVIEW
+ * - STILL_CAPTURE
+ * - VIDEO_RECORD
+ * - PREVIEW_VIDEO_STILL
+ * - VIDEO_CALL
+ *
+ * The guaranteed stream combinations related to stream use case for a camera device with
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+ * capability is documented in the camera device
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline}. The
+ * application is strongly recommended to use one of the guaranteed stream combintations.
+ * If the application creates a session with a stream combination not in the guaranteed
+ * list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
+ * the camera device may ignore some stream use cases due to hardware constraints
+ * and implementation details.
+ * For stream combinations not covered by the stream use case mandatory lists, such as
+ * reprocessable session, constrained high speed session, or RAW stream combinations, the
+ * application should leave stream use cases within the session as DEFAULT.
+ * Possible values:
+ *
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW PREVIEW}
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE STILL_CAPTURE}
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD VIDEO_RECORD}
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL PREVIEW_VIDEO_STILL}
+ * - {@link #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL VIDEO_CALL}
+ *
+ *
+ * Optional - The value for this key may be {@code null} on some devices.
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
+ * @see #SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL
+ */
+ @PublicKey
+ @NonNull
+ public static final Key SCALER_AVAILABLE_STREAM_USE_CASES =
+ new Key("android.scaler.availableStreamUseCases", int[].class);
+
+ /**
+ * An array of mandatory stream combinations with stream use cases.
+ * This is an app-readable conversion of the mandatory stream combination
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables} with
+ * each stream's use case being set.
+ * The array of
+ * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
+ * generated according to the documented
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for a
+ * camera device with
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+ * capability.
+ * The mandatory stream combination array will be {@code null} in case the device doesn't
+ * have {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE }
+ * capability.
+ * Optional - The value for this key may be {@code null} on some devices.
+ */
+ @PublicKey
+ @NonNull
+ @SyntheticKey
+ public static final Key SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS =
+ new Key("android.scaler.mandatoryUseCaseStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class);
+
/**
* The area of the image sensor which corresponds to active pixels after any geometric
* distortion correction has been applied.
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 47eb79d07469b..1a42eaf541cad 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -404,7 +404,10 @@ public abstract class CameraDevice implements AutoCloseable {
* (output format)/(surface type), or if the extension is not
* supported, or if any of the output configurations select
* a dynamic range different from
- * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD}
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD},
+ * or if any of the output configurations sets a stream use
+ * case different from {@link
+ * android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT}.
* @see CameraExtensionCharacteristics#getSupportedExtensions
* @see CameraExtensionCharacteristics#getExtensionSupportedSizes
*/
@@ -855,6 +858,31 @@ public abstract class CameraDevice implements AutoCloseable {
* will cause a capture session initialization failure.
*
*
+ * Devices with the STREAM_USE_CASE capability ({@link
+ * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes {@link
+ * CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}) support below additional
+ * stream combinations:
+ *
+ *
+ * | STREAM_USE_CASE capability additional guaranteed configurations |
+ * | Target 1 | Target 2 | Target 3 | Sample use case(s) |
+ * | Type | Max size | Usecase | Type | Max size | Usecase | Type | Max size | Usecase |
+ * | {@code YUV / PRIV} | {@code PREVIEW} | {@code PREVIEW} | | | Simple preview or in-app image processing |
+ * | {@code YUV / PRIV} | {@code RECORD} | {@code VIDEO_RECORD} | | | Simple video recording or in-app video processing |
+ * | {@code YUV / JPEG} | {@code MAXIMUM} | {@code STILL_CAPTURE} | | | Simple JPEG or YUV still image capture |
+ * | {@code YUV / PRIV} | {@code s1440p} | {@code PREVIEW_VIDEO_STILL} | | | Multi-purpose stream for preview, video and still image capture |
+ * | {@code YUV / PRIV} | {@code s1440p} | {@code VIDEO_CALL} | | | Simple video call |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV / JPEG} | {@code MAXIMUM} | {@code STILL_CAPTURE} | | Preview with JPEG or YUV still image capture |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV / PRIV} | {@code RECORD} | {@code VIDEO_RECORD} | | Preview with video recording or in-app video processing |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV} | {@code PREVIEW} | {@code PREVIEW} | | Preview with in-application image processing |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV / PRIV} | {@code s1440p} | {@code VIDEO_CALL} | | Preview with video call |
+ * | {@code YUV / PRIV} | {@code s1440p} | {@code PREVIEW_VIDEO_STILL} | {@code YUV / JPEG} | {@code MAXIMUM} | {@code STILL_CAPTURE} | | Multi-purpose stream with JPEG or YUV still capture |
+ * | {@code YUV} | {@code PREVIEW} | {@code STILL_CAPTURE} | {@code JPEG} | {@code MAXIMUM} | {@code STILL_CAPTURE} | | YUV and JPEG concurrent still image capture (for testing) |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV / PRIV} | {@code RECORD} | {@code VIDEO_RECORD} | {@code YUV / JPEG} | {@code RECORD} | {@code STILL_CAPTURE} | Preview, video record and JPEG or YUV video snapshot |
+ * | {@code PRIV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV} | {@code PREVIEW} | {@code PREVIEW} | {@code YUV / JPEG} | {@code MAXIMUM} | {@code STILL_CAPTURE} | Preview, in-application image processing, and JPEG or YUV still image capture |
+ *
+ *
+ *
* Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
* by calling {@link #isSessionConfigurationSupported} or attempting to create a session with
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 803684da6ddb0..95238ee4e6a6e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1210,6 +1210,36 @@ public abstract class CameraMetadata {
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18;
+ /**
+ * The camera device supports selecting a per-stream use case via
+ * {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase }
+ * so that the device can optimize camera pipeline parameters such as tuning, sensor
+ * mode, or ISP settings for a specific user scenario.
+ * Some sample usages of this capability are:
+ * * Distinguish high quality YUV captures from a regular YUV stream where
+ * the image quality may not be as good as the JPEG stream, or
+ * * Use one stream to serve multiple purposes: viewfinder, video recording and
+ * still capture. This is common with applications that wish to apply edits equally
+ * to preview, saved images, and saved videos.
+ * This capability requires the camera device to support the following
+ * stream use cases:
+ * * DEFAULT for backward compatibility where the application doesn't set
+ * a stream use case
+ * * PREVIEW for live viewfinder and in-app image analysis
+ * * STILL_CAPTURE for still photo capture
+ * * VIDEO_RECORD for recording video clips
+ * * PREVIEW_VIDEO_STILL for one single stream used for viewfinder, video
+ * recording, and still capture.
+ * * VIDEO_CALL for long running video calls
+ * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES }
+ * lists all of the supported stream use cases.
+ * Refer to {@link android.hardware.camera2.CameraDevice#createCaptureSession } for the
+ * mandatory stream combinations involving stream use cases, which can also be queried
+ * via {@link android.hardware.camera2.params.MandatoryStreamCombination }.
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19;
+
//
// Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
//
@@ -1335,6 +1365,89 @@ public abstract class CameraMetadata {
*/
public static final int SCALER_CROPPING_TYPE_FREEFORM = 1;
+ //
+ // Enumeration values for CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ //
+
+ /**
+ * Default stream use case.
+ * This use case is the same as when the application doesn't set any use case for
+ * the stream. The camera device uses the properties of the output target, such as
+ * format, dataSpace, or surface class type, to optimize the image processing pipeline.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0;
+
+ /**
+ * Live stream shown to the user.
+ * Optimized for performance and usability as a viewfinder, but not necessarily for
+ * image quality. The output is not meant to be persisted as saved images or video.
+ * No stall if android.control. are set to FAST; may have stall if android.control.
+ * are set to HIGH_QUALITY. This use case has the same behavior as the default
+ * SurfaceView and SurfaceTexture targets. Additionally, this use case can be used for
+ * in-app image analysis.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1;
+
+ /**
+ * Still photo capture.
+ * Optimized for high-quality high-resolution capture, and not expected to maintain
+ * preview-like frame rates.
+ * The stream may have stalls regardless of whether android.control.* is HIGH_QUALITY.
+ * This use case has the same behavior as the default JPEG and RAW related formats.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2;
+
+ /**
+ * Recording video clips.
+ * Optimized for high-quality video capture, including high-quality image stabilization
+ * if supported by the device and enabled by the application. As a result, may produce
+ * output frames with a substantial lag from real time, to allow for highest-quality
+ * stabilization or other processing. As such, such an output is not suitable for drawing
+ * to screen directly, and is expected to be persisted to disk or similar for later
+ * playback or processing. Only streams that set the VIDEO_RECORD use case are guaranteed
+ * to have video stabilization applied when the video stabilization control is set
+ * to ON, as opposed to PREVIEW_STABILIZATION.
+ * This use case has the same behavior as the default MediaRecorder and MediaCodec
+ * targets.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3;
+
+ /**
+ * One single stream used for combined purposes of preview, video, and still capture.
+ * For such multi-purpose streams, the camera device aims to make the best tradeoff
+ * between the individual use cases. For example, the STILL_CAPTURE use case by itself
+ * may have stalls for achieving best image quality. But if combined with PREVIEW and
+ * VIDEO_RECORD, the camera device needs to trade off the additional image processing
+ * for speed so that preview and video recording aren't slowed down.
+ * Similarly, VIDEO_RECORD may produce frames with a substantial lag, but
+ * PREVIEW_VIDEO_STILL must have minimal output delay. This means that to enable video
+ * stabilization with this use case, the device must support and the app must select the
+ * PREVIEW_STABILIZATION mode for video stabilization.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4;
+
+ /**
+ * Long-running video call optimized for both power efficienty and video quality.
+ * The camera sensor may run in a lower-resolution mode to reduce power consumption
+ * at the cost of some image and digital zoom quality. Unlike VIDEO_RECORD, VIDEO_CALL
+ * outputs are expected to work in dark conditions, so are usually accompanied with
+ * variable frame rate settings to allow sufficient exposure time in low light.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5;
+
+ /**
+ * Vendor defined use cases. These depend on the vendor implementation.
+ * @see CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES
+ * @hide
+ */
+ public static final int SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000;
+
//
// Enumeration values for CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
//
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 9d2c901ed049f..f58823141032f 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -135,6 +135,11 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
throw new IllegalArgumentException("Unsupported dynamic range profile: " +
c.getDynamicRangeProfile());
}
+ if (c.getStreamUseCase() !=
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ throw new IllegalArgumentException("Unsupported stream use case: " +
+ c.getStreamUseCase());
+ }
}
int suitableSurfaceCount = 0;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index c8ecfd0bdea9f..f19a52879bec1 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -151,6 +151,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
throw new IllegalArgumentException("Unsupported dynamic range profile: " +
c.getDynamicRangeProfile());
}
+ if (c.getStreamUseCase() !=
+ CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+ throw new IllegalArgumentException("Unsupported stream use case: " +
+ c.getStreamUseCase());
+ }
}
Pair extenders =
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0f8bdf64e1326..9b67633fe72bb 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -333,6 +333,7 @@ public class CameraMetadataNative implements Parcelable {
private static final int MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION = 1;
private static final int MANDATORY_STREAM_CONFIGURATIONS_CONCURRENT = 2;
private static final int MANDATORY_STREAM_CONFIGURATIONS_10BIT = 3;
+ private static final int MANDATORY_STREAM_CONFIGURATIONS_USE_CASE = 4;
private static String translateLocationProviderToProcess(final String provider) {
if (provider == null) {
@@ -699,6 +700,16 @@ public class CameraMetadataNative implements Parcelable {
}
});
+ sGetCommandMap.put(
+ CameraCharacteristics.SCALER_MANDATORY_USE_CASE_STREAM_COMBINATIONS.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public T getValue(CameraMetadataNative metadata, Key key) {
+ return (T) metadata.getMandatoryUseCaseStreamCombinations();
+ }
+ });
+
sGetCommandMap.put(
CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() {
@Override
@@ -1413,6 +1424,9 @@ public class CameraMetadataNative implements Parcelable {
case MANDATORY_STREAM_CONFIGURATIONS_10BIT:
combs = build.getAvailableMandatory10BitStreamCombinations();
break;
+ case MANDATORY_STREAM_CONFIGURATIONS_USE_CASE:
+ combs = build.getAvailableMandatoryStreamUseCaseCombinations();
+ break;
default:
combs = build.getAvailableMandatoryStreamCombinations();
}
@@ -1446,6 +1460,10 @@ public class CameraMetadataNative implements Parcelable {
return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_DEFAULT);
}
+ private MandatoryStreamCombination[] getMandatoryUseCaseStreamCombinations() {
+ return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_USE_CASE);
+ }
+
private StreamConfigurationMap getStreamConfigurationMap() {
StreamConfiguration[] configurations = getBase(
CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 32c15da4a909d..0d93c985b7931 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -26,6 +26,9 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.OutputConfiguration.StreamUseCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.media.CamcorderProfile;
import android.util.Log;
@@ -63,6 +66,7 @@ public final class MandatoryStreamCombination {
private final boolean mIsUltraHighResolution;
private final boolean mIsMaximumSize;
private final boolean mIs10BitCapable;
+ private final int mStreamUseCase;
/**
* Create a new {@link MandatoryStreamInformation}.
@@ -141,6 +145,30 @@ public final class MandatoryStreamCombination {
public MandatoryStreamInformation(@NonNull List availableSizes, @Format int format,
boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
boolean is10BitCapable) {
+ this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution,
+ is10BitCapable, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+ }
+
+ /**
+ * Create a new {@link MandatoryStreamInformation}.
+ *
+ * @param availableSizes List of possible stream sizes.
+ * @param format Image format.
+ * @param isMaximumSize Whether this is a maximum size stream.
+ * @param isInput Flag indicating whether this stream is input.
+ * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
+ * stream.
+ * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit
+ * @param streamUseCase The stream use case.
+ *
+ * @throws IllegalArgumentException
+ * if sizes is empty or if the format was not user-defined in
+ * ImageFormat/PixelFormat.
+ * @hide
+ */
+ public MandatoryStreamInformation(@NonNull List availableSizes, @Format int format,
+ boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
+ boolean is10BitCapable, @StreamUseCase int streamUseCase) {
if (availableSizes.isEmpty()) {
throw new IllegalArgumentException("No available sizes");
}
@@ -150,6 +178,7 @@ public final class MandatoryStreamCombination {
mIsInput = isInput;
mIsUltraHighResolution = isUltraHighResolution;
mIs10BitCapable = is10BitCapable;
+ mStreamUseCase = streamUseCase;
}
/**
@@ -271,6 +300,20 @@ public final class MandatoryStreamCombination {
return mFormat;
}
+ /**
+ * Retrieve the mandatory stream use case.
+ *
+ * If this {@link MandatoryStreamInformation} is part of a mandatory stream
+ * combination for stream use cases, the return value will be a non-DEFAULT value.
+ * For {@link MandatoryStreamInformation} belonging to other mandatory stream
+ * combinations, the return value will be DEFAULT.
+ *
+ * @return the integer stream use case.
+ */
+ public @StreamUseCase int getStreamUseCase() {
+ return mStreamUseCase;
+ }
+
/**
* Check if this {@link MandatoryStreamInformation} is equal to another
* {@link MandatoryStreamInformation}.
@@ -292,6 +335,7 @@ public final class MandatoryStreamCombination {
final MandatoryStreamInformation other = (MandatoryStreamInformation) obj;
if ((mFormat != other.mFormat) || (mIsInput != other.mIsInput) ||
(mIsUltraHighResolution != other.mIsUltraHighResolution) ||
+ (mStreamUseCase != other.mStreamUseCase) ||
(mAvailableSizes.size() != other.mAvailableSizes.size())) {
return false;
}
@@ -308,7 +352,8 @@ public final class MandatoryStreamCombination {
@Override
public int hashCode() {
return HashCodeHelpers.hashCode(mFormat, Boolean.hashCode(mIsInput),
- Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode());
+ Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode(),
+ mStreamUseCase);
}
}
@@ -316,6 +361,21 @@ public final class MandatoryStreamCombination {
private final boolean mIsReprocessable;
private final ArrayList mStreamsInformation =
new ArrayList();
+
+ /**
+ * Short hand for stream use cases
+ */
+ private static final int STREAM_USE_CASE_PREVIEW =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
+ private static final int STREAM_USE_CASE_STILL_CAPTURE =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
+ private static final int STREAM_USE_CASE_RECORD =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
+ private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
+ private static final int STREAM_USE_CASE_VIDEO_CALL =
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+
/**
* Create a new {@link MandatoryStreamCombination}.
*
@@ -411,15 +471,15 @@ public final class MandatoryStreamCombination {
private static final class StreamTemplate {
public int mFormat;
public SizeThreshold mSizeThreshold;
- public boolean mIsInput;
+ public int mStreamUseCase;
public StreamTemplate(int format, SizeThreshold sizeThreshold) {
- this(format, sizeThreshold, /*isInput*/false);
+ this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
}
public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
- boolean isInput) {
+ @StreamUseCase int streamUseCase) {
mFormat = format;
mSizeThreshold = sizeThreshold;
- mIsInput = isInput;
+ mStreamUseCase = streamUseCase;
}
}
@@ -1034,6 +1094,174 @@ public final class MandatoryStreamCombination {
"High-resolution recording with video snapshot"),
};
+ private static StreamCombinationTemplate sStreamUseCaseCombinations[] = {
+ // Single stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW) },
+ "Simple preview"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW) },
+ "Simple in-application image processing"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD) },
+ "Simple video recording"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD) },
+ "Simple in-application video processing"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE) },
+ "Simple JPEG still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE) },
+ "Simple YUV still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
+ "Multi-purpose stream for preview, video and still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
+ "Multi-purpose YUV stream for preview, video and still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+ STREAM_USE_CASE_VIDEO_CALL) },
+ "Simple video call"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+ STREAM_USE_CASE_VIDEO_CALL) },
+ "Simple YUV video call"),
+
+ // 2-stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview with JPEG still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview with YUV still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD)},
+ "Preview with video recording"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD)},
+ "Preview with in-application video processing"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW)},
+ "Preview with in-application image processing"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+ STREAM_USE_CASE_VIDEO_CALL)},
+ "Preview with video call"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+ STREAM_USE_CASE_VIDEO_CALL)},
+ "Preview with YUV video call"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Multi-purpose stream with JPEG still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Multi-purpose stream with YUV still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Multi-purpose YUV stream with JPEG still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
+ STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Multi-purpose YUV stream with YUV still capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_STILL_CAPTURE),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "YUV and JPEG concurrent still image capture (for testing)"),
+
+ // 3-stream combinations
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, video record and JPEG video snapshot"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, video record and YUV video snapshot"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, in-application video processing and JPEG video snapshot"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_RECORD),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, in-application video processing and YUV video snapshot"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, in-application image processing, and JPEG still image capture"),
+ new StreamCombinationTemplate(new StreamTemplate [] {
+ new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
+ STREAM_USE_CASE_PREVIEW),
+ new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
+ STREAM_USE_CASE_STILL_CAPTURE)},
+ "Preview, in-application image processing, and YUV still image capture"),
+ };
+
/**
* Helper builder class to generate a list of available mandatory stream combinations.
* @hide
@@ -1152,6 +1380,76 @@ public final class MandatoryStreamCombination {
return Collections.unmodifiableList(availableStreamCombinations);
}
+ /**
+ * Retrieve a list of all available mandatory stream combinations with stream use cases.
+ * when the camera device has {@link
+ * CameraMetdata.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} capability.
+ *
+ * @return a non-modifiable list of supported mandatory stream combinations with stream
+ * use cases. Null in case the device doesn't have {@link
+ * CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}
+ * capability.
+ */
+ public @NonNull List
+ getAvailableMandatoryStreamUseCaseCombinations() {
+ if (!isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) {
+ return null;
+ }
+
+ HashMap, List> availableSizes =
+ enumerateAvailableSizes();
+ if (availableSizes == null) {
+ Log.e(TAG, "Available size enumeration failed!");
+ return null;
+ }
+
+ ArrayList availableStreamCombinations = new ArrayList<>();
+ availableStreamCombinations.ensureCapacity(sStreamUseCaseCombinations.length);
+ for (StreamCombinationTemplate combTemplate : sStreamUseCaseCombinations) {
+ ArrayList streamsInfo =
+ new ArrayList();
+ streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
+
+ for (StreamTemplate template : combTemplate.mStreamTemplates) {
+ List sizes = null;
+ Pair pair;
+ pair = new Pair(template.mSizeThreshold,
+ new Integer(template.mFormat));
+ sizes = availableSizes.get(pair);
+
+ MandatoryStreamInformation streamInfo;
+ boolean isMaximumSize =
+ (template.mSizeThreshold == SizeThreshold.MAXIMUM);
+ try {
+ streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
+ isMaximumSize, /*isInput*/false, /*isUltraHighResolution*/false,
+ /*is10BitCapable*/ false, template.mStreamUseCase);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "No available sizes found for format: " + template.mFormat +
+ " size threshold: " + template.mSizeThreshold + " combination: " +
+ combTemplate.mDescription);
+ return null;
+ }
+ streamsInfo.add(streamInfo);
+ }
+
+ MandatoryStreamCombination streamCombination;
+ try {
+ streamCombination = new MandatoryStreamCombination(streamsInfo,
+ combTemplate.mDescription, /*isReprocessable*/ false);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "No stream information for mandatory combination: "
+ + combTemplate.mDescription);
+ return null;
+ }
+
+ availableStreamCombinations.add(streamCombination);
+ }
+
+ return Collections.unmodifiableList(availableStreamCombinations);
+ }
+
/**
* Retrieve a list of all available mandatory concurrent stream combinations.
* This method should only be called for devices which are listed in combinations returned
@@ -1632,6 +1930,8 @@ public final class MandatoryStreamCombination {
Size recordingMaxSize = new Size(0, 0);
Size previewMaxSize = new Size(0, 0);
Size vgaSize = new Size(640, 480);
+ Size s720pSize = new Size(1280, 720);
+ Size s1440pSize = new Size(1920, 1440);
// For external camera, or hidden physical camera, CamcorderProfile may not be
// available, so get maximum recording size using stream configuration map.
if (isExternalCamera() || mIsHiddenPhysicalCamera) {
@@ -1682,6 +1982,12 @@ public final class MandatoryStreamCombination {
pair = new Pair(SizeThreshold.MAXIMUM, intFormat);
availableSizes.put(pair, Arrays.asList(sizes));
+
+ pair = new Pair(SizeThreshold.s720p, intFormat);
+ availableSizes.put(pair, getSizesWithinBound(sizes, s720pSize));
+
+ pair = new Pair(SizeThreshold.s1440p, intFormat);
+ availableSizes.put(pair, getSizesWithinBound(sizes, s1440pSize));
}
return availableSizes;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index f2b881ba7758b..d8295c9621540 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -159,6 +159,17 @@ public final class OutputConfiguration implements Parcelable {
CameraMetadata.SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION})
public @interface SensorPixelMode {};
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STREAM_USE_CASE_"}, value =
+ {CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+ CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL})
+ public @interface StreamUseCase {};
+
/**
* Create a new {@link OutputConfiguration} instance with a {@link Surface}.
*
@@ -355,6 +366,7 @@ public final class OutputConfiguration implements Parcelable {
mIsMultiResolution = false;
mSensorPixelModesUsed = new ArrayList();
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
/**
@@ -453,6 +465,7 @@ public final class OutputConfiguration implements Parcelable {
mIsMultiResolution = false;
mSensorPixelModesUsed = new ArrayList();
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
/**
@@ -729,6 +742,73 @@ public final class OutputConfiguration implements Parcelable {
}
}
+ /**
+ * Set stream use case for this OutputConfiguration
+ *
+ * Stream use case is used to describe the purpose of the stream, whether it's for live
+ * preview, still image capture, video recording, or their combinations. This flag is useful
+ * for scenarios where the immediate consumer target isn't sufficient to indicate the stream's
+ * usage.
+ *
+ * The main difference beteween stream use case and capture intent is that the former
+ * enables the camera device to optimize camera hardware and software pipelines based on user
+ * scenarios for each stream, whereas the latter is mainly a hint to camera to decide
+ * optimal 3A strategy that's applicable to the whole session. The camera device carries out
+ * configurations such as selecting tuning parameters, choosing camera sensor mode, and
+ * constructing image processing pipeline based on the streams's use cases. Capture intents are
+ * then used to fine tune 3A behaviors such as adjusting AE/AF convergence speed, and capture
+ * intents may change during the lifetime of a session. For example, for a session with a
+ * PREVIEW_VIDEO_STILL use case stream and a STILL_CAPTURE use case stream, the capture intents
+ * may be PREVIEW with fast 3A convergence speed and flash metering with automatic control for
+ * live preview, STILL_CAPTURE with best 3A parameters for still photo capture, or VIDEO_RECORD
+ * with slower 3A convergence speed for better video playback experience.
+ *
+ * The supported stream use cases supported by a camera device can be queried by
+ * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}.
+ *
+ * The mandatory stream combinations involving stream use cases can be found at {@link
+ * android.hardware.camera2.CameraDevice#createCaptureSession}, as well as queried via
+ * {@link android.hardware.camera2.params.MandatoryStreamCombination}. The application is
+ * strongly recommended to select one of the guaranteed stream combinations where all streams'
+ * use cases are set to non-DEFAULT values. If the application chooses a stream combination
+ * not in the mandatory list, the camera device may ignore some use case flags due to
+ * hardware constraints or implementation details.
+ *
+ * This function must be called before {@link CameraDevice#createCaptureSession} or {@link
+ * CameraDevice#createCaptureSessionByOutputConfigurations}. Calling this function after
+ * {@link CameraDevice#createCaptureSession} or
+ * {@link CameraDevice#createCaptureSessionByOutputConfigurations} has no effect to the camera
+ * session.
+ *
+ * @param streamUseCase The stream use case to be set.
+ *
+ * @throws IllegalArgumentException If the streamUseCase isn't within the range of valid
+ * values.
+ */
+ public void setStreamUseCase(@StreamUseCase int streamUseCase) {
+ // Verify that the value is in range
+ int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ if (streamUseCase > maxUseCaseValue &&
+ streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
+ throw new IllegalArgumentException("Not a valid stream use case value " +
+ streamUseCase);
+ }
+
+ mStreamUseCase = streamUseCase;
+ }
+
+ /**
+ * Get the current stream use case
+ *
+ * If no {@link #setStreamUseCase} is called first, this function returns
+ * {@link CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT DEFAULT}.
+ *
+ * @return the currently set stream use case
+ */
+ public int getStreamUseCase() {
+ return mStreamUseCase;
+ }
+
/**
* Create a new {@link OutputConfiguration} instance with another {@link OutputConfiguration}
* instance.
@@ -756,6 +836,7 @@ public final class OutputConfiguration implements Parcelable {
this.mIsMultiResolution = other.mIsMultiResolution;
this.mSensorPixelModesUsed = other.mSensorPixelModesUsed;
this.mDynamicRangeProfile = other.mDynamicRangeProfile;
+ this.mStreamUseCase = other.mStreamUseCase;
}
/**
@@ -774,6 +855,8 @@ public final class OutputConfiguration implements Parcelable {
String physicalCameraId = source.readString();
boolean isMultiResolutionOutput = source.readInt() == 1;
int[] sensorPixelModesUsed = source.createIntArray();
+ int streamUseCase = source.readInt();
+
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
int dynamicRangeProfile = source.readInt();
DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
@@ -801,6 +884,7 @@ public final class OutputConfiguration implements Parcelable {
mIsMultiResolution = isMultiResolutionOutput;
mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed);
mDynamicRangeProfile = dynamicRangeProfile;
+ mStreamUseCase = streamUseCase;
}
/**
@@ -917,6 +1001,7 @@ public final class OutputConfiguration implements Parcelable {
// writeList doesn't seem to work well with Integer list.
dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
dest.writeInt(mDynamicRangeProfile);
+ dest.writeInt(mStreamUseCase);
}
/**
@@ -947,7 +1032,8 @@ public final class OutputConfiguration implements Parcelable {
mConfiguredDataspace != other.mConfiguredDataspace ||
mConfiguredGenerationId != other.mConfiguredGenerationId ||
!Objects.equals(mPhysicalCameraId, other.mPhysicalCameraId) ||
- mIsMultiResolution != other.mIsMultiResolution)
+ mIsMultiResolution != other.mIsMultiResolution ||
+ mStreamUseCase != other.mStreamUseCase)
return false;
if (mSensorPixelModesUsed.size() != other.mSensorPixelModesUsed.size()) {
return false;
@@ -985,7 +1071,7 @@ public final class OutputConfiguration implements Parcelable {
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile);
+ mDynamicRangeProfile, mStreamUseCase);
}
return HashCodeHelpers.hashCode(
@@ -994,7 +1080,7 @@ public final class OutputConfiguration implements Parcelable {
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile);
+ mDynamicRangeProfile, mStreamUseCase);
}
private static final String TAG = "OutputConfiguration";
@@ -1028,4 +1114,6 @@ public final class OutputConfiguration implements Parcelable {
private ArrayList mSensorPixelModesUsed;
// Dynamic range profile
private int mDynamicRangeProfile;
+ // Stream use case
+ private int mStreamUseCase;
}
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 0338b93c88426..2d62f32d3941e 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -65,4 +65,6 @@ message CameraStreamProto {
// The dynamic range profile of the stream
optional int32 dynamic_range_profile = 14;
+ // The stream use case
+ optional int32 stream_use_case = 15;
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 1b0341c1ce26c..e0b768d7c5926 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -808,6 +808,7 @@ public class CameraServiceProxy extends SystemService
streamProtos[i].histogramBins = streamStats.getHistogramBins();
streamProtos[i].histogramCounts = streamStats.getHistogramCounts();
streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile();
+ streamProtos[i].streamUseCase = streamStats.getStreamUseCase();
if (CameraServiceProxy.DEBUG) {
String histogramTypeName =
@@ -828,7 +829,8 @@ public class CameraServiceProxy extends SystemService
+ Arrays.toString(streamProtos[i].histogramBins)
+ ", histogramCounts "
+ Arrays.toString(streamProtos[i].histogramCounts)
- + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile);
+ + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile
+ + ", streamUseCase " + streamProtos[i].streamUseCase);
}
}
}