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 1Target 2Target 3 Sample use case(s)
    TypeMax sizeUsecaseTypeMax sizeUsecaseTypeMax sizeUsecase
    {@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); } } }