From 146945464bc9bd4ce01bd29a7981a8a09779bf67 Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Fri, 12 Nov 2021 18:12:25 -0800 Subject: [PATCH] Camera: Enable 10-bit output camera API Allow camera clients to query and select a specific 10-bit dynamic range profile when initializing camera capture sessions. Bug: 195946346 Test: Camera CTS Change-Id: If46c16a7ea95b772dcaa3ae36807ed73d197749f --- core/api/current.txt | 28 ++ .../android/hardware/CameraStreamStats.java | 12 +- .../camera2/CameraCaptureSession.java | 51 ++- .../camera2/CameraCharacteristics.java | 110 ++++++- .../hardware/camera2/CameraDevice.java | 48 ++- .../hardware/camera2/CameraMetadata.java | 129 ++++++++ .../CameraAdvancedExtensionSessionImpl.java | 9 +- .../impl/CameraExtensionSessionImpl.java | 8 + .../camera2/impl/CameraMetadataNative.java | 39 +++ .../camera2/params/DynamicRangeProfiles.java | 301 ++++++++++++++++++ .../params/MandatoryStreamCombination.java | 205 +++++++++++- .../camera2/params/OutputConfiguration.java | 53 ++- .../RecommendedStreamConfigurationMap.java | 15 +- proto/src/camera.proto | 3 + .../server/camera/CameraServiceProxy.java | 4 +- 15 files changed, 992 insertions(+), 23 deletions(-) create mode 100644 core/java/android/hardware/camera2/params/DynamicRangeProfiles.java diff --git a/core/api/current.txt b/core/api/current.txt index e702dadbf2280..9c72c9df520fe 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18452,12 +18452,14 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REPROCESS_MAX_CAPTURE_STALL; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_CAPABILITIES; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_INPUT_STREAMS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC_STALLING; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_RAW; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH; + 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_CROPPING_TYPE; @@ -18465,6 +18467,7 @@ package android.hardware.camera2 { 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_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; @@ -18781,6 +18784,7 @@ package android.hardware.camera2 { field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6 field public static final int REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO = 9; // 0x9 field public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8; // 0x8 + field public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18; // 0x12 field public static final int REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA = 11; // 0xb field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING = 2; // 0x2 field public static final int REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR = 1; // 0x1 @@ -19134,6 +19138,25 @@ package android.hardware.camera2.params { field public static final long NORMAL = 0L; // 0x0L } + public final class DynamicRangeProfiles { + ctor public DynamicRangeProfiles(@NonNull int[]); + method @NonNull public java.util.Set getProfileCaptureRequestConstraints(int); + method @NonNull public java.util.Set getSupportedProfiles(); + field public static final int DOLBY_VISION_10B_HDR_OEM = 64; // 0x40 + field public static final int DOLBY_VISION_10B_HDR_OEM_PO = 128; // 0x80 + field public static final int DOLBY_VISION_10B_HDR_REF = 16; // 0x10 + field public static final int DOLBY_VISION_10B_HDR_REF_PO = 32; // 0x20 + field public static final int DOLBY_VISION_8B_HDR_OEM = 1024; // 0x400 + field public static final int DOLBY_VISION_8B_HDR_OEM_PO = 2048; // 0x800 + field public static final int DOLBY_VISION_8B_HDR_REF = 256; // 0x100 + field public static final int DOLBY_VISION_8B_HDR_REF_PO = 512; // 0x200 + field public static final int HDR10 = 4; // 0x4 + field public static final int HDR10_PLUS = 8; // 0x8 + field public static final int HLG10 = 2; // 0x2 + field public static final int PUBLIC_MAX = 4096; // 0x1000 + field public static final int STANDARD = 1; // 0x1 + } + public final class ExtensionSessionConfiguration { ctor public ExtensionSessionConfiguration(int, @NonNull java.util.List, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraExtensionSession.StateCallback); method @NonNull public java.util.concurrent.Executor getExecutor(); @@ -19180,8 +19203,10 @@ package android.hardware.camera2.params { } public static final class MandatoryStreamCombination.MandatoryStreamInformation { + method public int get10BitFormat(); method @NonNull public java.util.List getAvailableSizes(); method public int getFormat(); + method public boolean is10BitCapable(); method public boolean isInput(); method public boolean isMaximumSize(); method public boolean isUltraHighResolution(); @@ -19235,12 +19260,14 @@ package android.hardware.camera2.params { method @NonNull public static java.util.Collection createInstancesForMultiResolutionOutput(@NonNull android.hardware.camera2.MultiResolutionImageReader); method public int describeContents(); method public void enableSurfaceSharing(); + method public int getDynamicRangeProfile(); method public int getMaxSharedSurfaceCount(); method @Nullable public android.view.Surface getSurface(); method public int getSurfaceGroupId(); method @NonNull public java.util.List getSurfaces(); method public void removeSensorPixelModeUsed(int); method public void removeSurface(@NonNull android.view.Surface); + method public void setDynamicRangeProfile(int); method public void setPhysicalCameraId(@Nullable String); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; @@ -19266,6 +19293,7 @@ package android.hardware.camera2.params { method @Nullable public java.util.Set getValidOutputFormatsForInput(int); method public boolean isOutputSupportedFor(int); method public boolean isOutputSupportedFor(@NonNull android.view.Surface); + field public static final int USECASE_10BIT_OUTPUT = 8; // 0x8 field public static final int USECASE_LOW_LATENCY_SNAPSHOT = 6; // 0x6 field public static final int USECASE_PREVIEW = 0; // 0x0 field public static final int USECASE_RAW = 5; // 0x5 diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java index 41d1e2523a9b3..ed22de8dd594d 100644 --- a/core/java/android/hardware/CameraStreamStats.java +++ b/core/java/android/hardware/CameraStreamStats.java @@ -15,6 +15,7 @@ */ package android.hardware; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -45,6 +46,7 @@ public class CameraStreamStats implements Parcelable { private int mHistogramType; private float[] mHistogramBins; private long[] mHistogramCounts; + private int mDynamicRangeProfile; private static final String TAG = "CameraStreamStats"; @@ -60,11 +62,12 @@ public class CameraStreamStats implements Parcelable { mMaxHalBuffers = 0; mMaxAppBuffers = 0; mHistogramType = HISTOGRAM_TYPE_UNKNOWN; + mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; } public CameraStreamStats(int width, int height, int format, int dataSpace, long usage, long requestCount, long errorCount, - int startLatencyMs, int maxHalBuffers, int maxAppBuffers) { + int startLatencyMs, int maxHalBuffers, int maxAppBuffers, int dynamicRangeProfile) { mWidth = width; mHeight = height; mFormat = format; @@ -76,6 +79,7 @@ public class CameraStreamStats implements Parcelable { mMaxHalBuffers = maxHalBuffers; mMaxAppBuffers = maxAppBuffers; mHistogramType = HISTOGRAM_TYPE_UNKNOWN; + mDynamicRangeProfile = dynamicRangeProfile; } public static final @android.annotation.NonNull Parcelable.Creator CREATOR = @@ -121,6 +125,7 @@ public class CameraStreamStats implements Parcelable { dest.writeInt(mHistogramType); dest.writeFloatArray(mHistogramBins); dest.writeLongArray(mHistogramCounts); + dest.writeInt(mDynamicRangeProfile); } public void readFromParcel(Parcel in) { @@ -137,6 +142,7 @@ public class CameraStreamStats implements Parcelable { mHistogramType = in.readInt(); mHistogramBins = in.createFloatArray(); mHistogramCounts = in.createLongArray(); + mDynamicRangeProfile = in.readInt(); } public int getWidth() { @@ -190,4 +196,8 @@ public class CameraStreamStats implements Parcelable { public long[] getHistogramCounts() { return mHistogramCounts; } + + public int getDynamicRangeProfile() { + return mDynamicRangeProfile; + } } diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index bd47463698110..691690c09e0e0 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -321,6 +321,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * can submit reprocess capture requests. Submitting a reprocess request to a regular capture * session will result in an {@link IllegalArgumentException}.

* + *

Submitting a request that targets Surfaces with an unsupported dynamic range combination + * will result in an {@link IllegalArgumentException}.

+ * * @param request the settings for this capture * @param listener The callback object to notify once this request has been * processed. If null, no metadata will be produced for this capture, @@ -347,13 +350,15 @@ public abstract class CameraCaptureSession implements AutoCloseable { * a different session; or the capture targets a Surface in * the middle of being {@link #prepare prepared}; or the * handler is null, the listener is not null, and the calling - * thread has no looper. + * thread has no looper; or the request targets Surfaces with + * an unsupported dynamic range combination * * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures * @see CameraDevice#createReprocessableCaptureSession + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public abstract int capture(@NonNull CaptureRequest request, @Nullable CaptureCallback listener, @Nullable Handler handler) @@ -389,13 +394,16 @@ public abstract class CameraCaptureSession implements AutoCloseable { * request was created with a {@link TotalCaptureResult} from * a different session; or the capture targets a Surface in * the middle of being {@link #prepare prepared}; or the - * executor is null, or the listener is not null. + * executor is null, or the listener is not null; + * or the request targets Surfaces with an unsupported dynamic + * range combination; * * @see #captureBurst * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures * @see CameraDevice#createReprocessableCaptureSession + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public int captureSingleRequest(@NonNull CaptureRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) @@ -427,6 +435,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * can submit reprocess capture requests. Submitting a reprocess request to a regular * capture session will result in an {@link IllegalArgumentException}.

* + *

Submitting a request that targets Surfaces with an unsupported dynamic range combination + * will result in an {@link IllegalArgumentException}.

+ * * @param requests the list of settings for this burst capture * @param listener The callback object to notify each time one of the * requests in the burst has been processed. If null, no metadata will be @@ -454,12 +465,15 @@ public abstract class CameraCaptureSession implements AutoCloseable { * {@link TotalCaptureResult} from a different session; or one * of the captures targets a Surface in the middle of being * {@link #prepare prepared}; or if the handler is null, the - * listener is not null, and the calling thread has no looper. + * listener is not null, and the calling thread has no looper; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public abstract int captureBurst(@NonNull List requests, @Nullable CaptureCallback listener, @Nullable Handler handler) @@ -499,12 +513,15 @@ public abstract class CameraCaptureSession implements AutoCloseable { * {@link TotalCaptureResult} from a different session; or one * of the captures targets a Surface in the middle of being * {@link #prepare prepared}; or if the executor is null; or if - * the listener is null. + * the listener is null; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #setRepeatingRequest * @see #setRepeatingBurst * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public int captureBurstRequests(@NonNull List requests, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) @@ -545,6 +562,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * single reprocess input image. The request must be capturing images from the camera. If a * reprocess capture request is submitted, this method will throw IllegalArgumentException.

* + *

Submitting a request that targets Surfaces with an unsupported dynamic range combination + * will result in an {@link IllegalArgumentException}.

+ * * @param request the request to repeat indefinitely * @param listener The callback object to notify every time the * request finishes processing. If null, no metadata will be @@ -567,13 +587,16 @@ public abstract class CameraCaptureSession implements AutoCloseable { * is a reprocess capture request; or the capture targets a * Surface in the middle of being {@link #prepare prepared}; or * the handler is null, the listener is not null, and the - * calling thread has no looper; or no requests were passed in. + * calling thread has no looper; or no requests were passed in; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #captureBurst * @see #setRepeatingBurst * @see #stopRepeating * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public abstract int setRepeatingRequest(@NonNull CaptureRequest request, @Nullable CaptureCallback listener, @Nullable Handler handler) @@ -604,13 +627,16 @@ public abstract class CameraCaptureSession implements AutoCloseable { * that are not currently configured as outputs; or the request * is a reprocess capture request; or the capture targets a * Surface in the middle of being {@link #prepare prepared}; or - * the executor is null; or the listener is null. + * the executor is null; or the listener is null; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #captureBurst * @see #setRepeatingBurst * @see #stopRepeating * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public int setSingleRepeatingRequest(@NonNull CaptureRequest request, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) @@ -655,6 +681,9 @@ public abstract class CameraCaptureSession implements AutoCloseable { * single reprocess input image. The request must be capturing images from the camera. If a * reprocess capture request is submitted, this method will throw IllegalArgumentException.

* + *

Submitting a request that targets Surfaces with an unsupported dynamic range combination + * will result in an {@link IllegalArgumentException}.

+ * * @param requests the list of requests to cycle through indefinitely * @param listener The callback object to notify each time one of the * requests in the repeating bursts has finished processing. If null, no @@ -678,13 +707,16 @@ public abstract class CameraCaptureSession implements AutoCloseable { * targets a Surface in the middle of being * {@link #prepare prepared}; or the handler is null, the * listener is not null, and the calling thread has no looper; - * or no requests were passed in. + * or no requests were passed in; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #stopRepeating * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public abstract int setRepeatingBurst(@NonNull List requests, @Nullable CaptureCallback listener, @Nullable Handler handler) @@ -717,13 +749,16 @@ public abstract class CameraCaptureSession implements AutoCloseable { * is a reprocess capture request; or one of the captures * targets a Surface in the middle of being * {@link #prepare prepared}; or the executor is null; or the - * listener is null. + * listener is null; + * or the request targets Surfaces with an unsupported dynamic + * range combination. * * @see #capture * @see #captureBurst * @see #setRepeatingRequest * @see #stopRepeating * @see #abortCaptures + * @see android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints */ public int setRepeatingBurstRequests(@NonNull List requests, @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 48a9121ef7f22..d2dc314585d6c 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -461,7 +461,7 @@ public final class CameraCharacteristics extends CameraMetadata= RecommendedStreamConfigurationMap.USECASE_PREVIEW) && - (usecase <= RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT)) || + (usecase <= RecommendedStreamConfigurationMap.USECASE_10BIT_OUTPUT)) || ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) && (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) { if (mRecommendedConfigurations == null) { @@ -2213,6 +2213,7 @@ public final class CameraCharacteristics extends CameraMetadata{@link #REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING OFFLINE_PROCESSING} *
  • {@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}
  • * * *

    This key is available on all devices.

    @@ -2236,6 +2237,7 @@ public final class CameraCharacteristics extends CameraMetadata REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION = new Key("android.request.characteristicKeysNeedingPermission", int[].class); + /** + *

    Devices supporting the 10-bit output capability + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * must list their supported dynamic range profiles along with capture request + * constraints for specific profile combinations.

    + *

    Camera clients can retrieve the list of supported 10-bit dynamic range profiles by calling + * {@link android.hardware.camera2.params.DynamicRangeProfiles#getSupportedProfiles }. + * Any of them can be configured by setting OutputConfiguration dynamic range profile in + * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }. + * Clients can also check if there are any constraints that limit the combination + * of supported profiles that can be referenced within a single capture request by calling + * {@link android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints }.

    + *

    Optional - The value for this key may be {@code null} on some devices.

    + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES = + new Key("android.request.availableDynamicRangeProfiles", android.hardware.camera2.params.DynamicRangeProfiles.class); + + /** + *

    A map of all available 10-bit dynamic range profiles along with their + * capture request constraints.

    + *

    Devices supporting the 10-bit output capability + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * must list their supported dynamic range profiles. In case the camera is not able to + * support every possible profile combination within a single capture request, then the + * constraints must be listed here as well.

    + *

    Possible values:

    + *
      + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD STANDARD}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 HLG10}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 HDR10}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS HDR10_PLUS}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF DOLBY_VISION_10B_HDR_REF}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO DOLBY_VISION_10B_HDR_REF_PO}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM DOLBY_VISION_10B_HDR_OEM}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO DOLBY_VISION_10B_HDR_OEM_PO}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF DOLBY_VISION_8B_HDR_REF}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO DOLBY_VISION_8B_HDR_REF_PO}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM DOLBY_VISION_8B_HDR_OEM}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO DOLBY_VISION_8B_HDR_OEM_PO}
    • + *
    • {@link #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX MAX}
    • + *
    + * + *

    Optional - The value for this key may be {@code null} on some devices.

    + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO + * @see #REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX + * @hide + */ + public static final Key REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = + new Key("android.request.availableDynamicRangeProfilesMap", int[].class); + + /** + *

    Recommended 10-bit dynamic range profile.

    + *

    Devices supporting the 10-bit output capability + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * must list a 10-bit supported dynamic range profile that is expected to perform + * optimally in terms of image quality, power and performance. + * The value advertised can be used as a hint by camera clients when configuring the dynamic + * range profile when calling + * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }.

    + *

    Optional - The value for this key may be {@code null} on some devices.

    + */ + @PublicKey + @NonNull + public static final Key REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE = + new Key("android.request.recommendedTenBitDynamicRangeProfile", int.class); + /** *

    The list of image formats that are supported by this * camera device for output streams.

    @@ -3339,6 +3421,32 @@ public final class CameraCharacteristics extends CameraMetadata SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS = new Key("android.scaler.mandatoryMaximumResolutionStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class); + /** + *

    An array of mandatory stream combinations which are applicable when device support the + * 10-bit output capability + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * This is an app-readable conversion of the maximum resolution mandatory stream combination + * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.

    + *

    The array of + * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is + * generated according to the documented + * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each + * device which has the + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * capability. + * Clients can use the array as a quick reference to find an appropriate camera stream + * combination. + * The mandatory stream combination array will be {@code null} in case the device is not an + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT } + * device.

    + *

    Optional - The value for this key may be {@code null} on some devices.

    + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS = + new Key("android.scaler.mandatoryTenBitOutputStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class); + /** *

    Whether the camera device supports multi-resolution input or output streams

    *

    A logical multi-camera or an ultra high resolution camera may support multi-resolution diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 3c1ec3e629a9c..47eb79d07469b 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -402,7 +402,9 @@ public abstract class CameraDevice implements AutoCloseable { * registered surfaces do not meet the device-specific * extension requirements such as dimensions and/or * (output format)/(surface type), or if the extension is not - * supported. + * supported, or if any of the output configurations select + * a dynamic range different from + * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD} * @see CameraExtensionCharacteristics#getSupportedExtensions * @see CameraExtensionCharacteristics#getExtensionSupportedSizes */ @@ -822,7 +824,36 @@ public abstract class CameraDevice implements AutoCloseable { * be chosen from. {@code DEFAULT} refers to the default sensor pixel mode {@link * StreamConfigurationMap} and {@code MAX_RES} refers to the maximum resolution {@link * StreamConfigurationMap}. The same capture request must not mix targets from - * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes. + * {@link StreamConfigurationMap}s corresponding to different sensor pixel modes.

    + * + *

    10-bit output capable + * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} + * devices support at least the following stream combinations:

    + * + * + * + * + * } + * } + * + * + * + * + * + * + *
    10-bit output additional guaranteed configurations
    Target 1Target 2Target 3 Sample use case(s)
    TypeMax sizeTypeMax sizeTypeMax size
    {@code PRIV}{@code MAXIMUM} Simple preview, GPU video processing, or no-preview video recording.
    {@code YUV}{@code MAXIMUM} In-application video/image processing.
    {@code PRIV}{@code PREVIEW} {@code JPEG}{@code MAXIMUM } Standard still imaging.
    {@code PRIV}{@code PREVIEW} {@code YUV }{@code MAXIMUM } Maximum-resolution in-app processing with preview.
    {@code YUV}{@code PREVIEW} {@code YUV}{@code MAXIMUM } Maximum-resolution two-input in-app processing.
    {@code PRIV}{@code PREVIEW} {@code PRIV}{@code RECORD } High-resolution video recording with preview.
    {@code PRIV}{@code PREVIEW} {@code PRIV}{@code RECORD } {@code YUV}{@code RECORD } High-resolution recording with in-app snapshot.
    {@code PRIV}{@code PREVIEW} {@code PRIV }{@code RECORD } {@code JPEG}{@code RECORD } High-resolution recording with video snapshot.

    + *

    Here PRIV can be either 8 or 10-bit {@link android.graphics.ImageFormat#PRIVATE} pixel + * format. YUV can be either {@link android.graphics.ImageFormat#YUV_420_888} or + * {@link android.graphics.ImageFormat#YCBCR_P010}. + * For the maximum size column, PREVIEW refers to the best size match to the device's screen + * resolution, or to 1080p (1920x1080), whichever is smaller. RECORD refers to the camera + * device's maximum supported recording resolution, as determined by + * {@link android.media.CamcorderProfile}. MAXIMUM refers to the camera device's maximum output + * resolution for that format or target from {@link StreamConfigurationMap#getOutputSizes(int)}. + * Do note that invalid combinations such as having a camera surface configured to use pixel + * format {@link android.graphics.ImageFormat#YUV_420_888} with a 10-bit profile + * will cause a capture session initialization failure. + *

    * *

    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 @@ -907,6 +938,13 @@ public abstract class CameraDevice implements AutoCloseable { * guaranteed output targets that can be submitted in a regular or reprocess * {@link CaptureRequest} simultaneously.

    * + *

    Reprocessing with 10-bit output targets on 10-bit capable + * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} devices is + * not supported. Trying to initialize a repreocessable capture session with one ore more + * output configurations set {@link OutputConfiguration#setDynamicRangeProfile(int)} to use + * a 10-bit dynamic range profile {@link android.hardware.camera2.params.DynamicRangeProfiles} + * will trigger {@link IllegalArgumentException}.

    + * * @@ -1083,13 +1121,17 @@ public abstract class CameraDevice implements AutoCloseable { * * @throws IllegalArgumentException In case the session configuration is invalid; or the output * configurations are empty; or the session configuration - * executor is invalid. + * executor is invalid; + * or the output dynamic range combination is + * invalid/unsupported. * @throws CameraAccessException In case the camera device is no longer connected or has * encountered a fatal error. * @see #createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) * @see #createCaptureSessionByOutputConfigurations * @see #createReprocessableCaptureSession * @see #createConstrainedHighSpeedCaptureSession + * @see OutputConfiguration#setDynamicRangeProfile(int) + * @see android.hardware.camera2.params.DynamicRangeProfiles */ public void createCaptureSession( SessionConfiguration config) throws CameraAccessException { diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 639abe9d1abf4..803684da6ddb0 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1190,6 +1190,135 @@ public abstract class CameraMetadata { */ public static final int REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17; + /** + *

    The device supports one or more 10-bit camera outputs according to the dynamic range + * profiles specified in + * {@link android.hardware.camera2.params.DynamicRangeProfiles#getSupportedProfiles }. + * They can be configured as part of the capture session initialization via + * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile }. + * Cameras that enable this capability must also support the following: + * * Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 } + * * All mandatory stream combinations for this specific capability as per + * documentation {@link android.hardware.camera2.CameraDevice#createCaptureSession } + * * In case the device is not able to capture some combination of supported + * standard 8-bit and/or 10-bit dynamic range profiles within the same capture request, + * then those constraints must be listed in + * {@link android.hardware.camera2.params.DynamicRangeProfiles#getProfileCaptureRequestConstraints } + * * Recommended dynamic range profile listed in + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE }.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES + */ + public static final int REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18; + + // + // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + // + + /** + *

    8-bit SDR profile which is the default for all non 10-bit output capable devices.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 0x1; + + /** + *

    10-bit pixel samples encoded using the Hybrid log-gamma transfer function.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2; + + /** + *

    10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. + * This profile utilizes internal static metadata to increase the quality + * of the capture.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4; + + /** + *

    10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. + * In contrast to HDR10, this profile uses internal per-frame metadata + * to further enhance the quality of the capture.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS = 0x8; + + /** + *

    This is a camera mode for Dolby Vision capture optimized for a more scene + * accurate capture. This would typically differ from what a specific device + * might want to tune for a consumer optimized Dolby Vision general capture.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF = 0x10; + + /** + *

    This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO = 0x20; + + /** + *

    This is the camera mode for the default Dolby Vision capture mode for the + * specific device. This would be tuned by each specific device for consumer + * pleasing results that resonate with their particular audience. We expect + * that each specific device would have a different look for their default + * Dolby Vision capture.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM = 0x40; + + /** + *

    This is the power optimized mode for 10-bit Dolby Vision HDR device specific + * capture Mode.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO = 0x80; + + /** + *

    This is the 8-bit version of the Dolby Vision reference capture mode optimized + * for scene accuracy.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF = 0x100; + + /** + *

    This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO = 0x200; + + /** + *

    This is the 8-bit version of device specific tuned and optimized Dolby Vision + * capture mode.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM = 0x400; + + /** + *

    This is the power optimized mode for 8-bit Dolby Vision HDR device specific + * capture Mode.

    + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO = 0x800; + + /** + * + * @see CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP + * @hide + */ + public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000; + // // Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE // diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java index b8443fb6d14b9..9d2c901ed049f 100644 --- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java @@ -35,7 +35,6 @@ import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.extension.CameraOutputConfig; import android.hardware.camera2.extension.CameraSessionConfig; -import android.hardware.camera2.extension.CaptureStageImpl; import android.hardware.camera2.extension.IAdvancedExtenderImpl; import android.hardware.camera2.extension.ICaptureCallback; import android.hardware.camera2.extension.IImageProcessorImpl; @@ -49,6 +48,7 @@ import android.hardware.camera2.extension.ParcelCaptureResult; import android.hardware.camera2.extension.ParcelImage; import android.hardware.camera2.extension.ParcelTotalCaptureResult; import android.hardware.camera2.extension.Request; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; @@ -130,6 +130,13 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes config.getOutputConfigurations().size() + " expected <= 2"); } + for (OutputConfiguration c : config.getOutputConfigurations()) { + if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) { + throw new IllegalArgumentException("Unsupported dynamic range profile: " + + c.getDynamicRangeProfile()); + } + } + int suitableSurfaceCount = 0; List supportedPreviewSizes = extensionChars.getExtensionSupportedSizes( config.getExtension(), SurfaceTexture.class); diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java index 71047af69b87a..c8ecfd0bdea9f 100644 --- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java @@ -39,6 +39,7 @@ import android.hardware.camera2.extension.IPreviewExtenderImpl; import android.hardware.camera2.extension.IRequestUpdateProcessorImpl; import android.hardware.camera2.extension.ParcelImage; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; @@ -145,6 +146,13 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession { config.getOutputConfigurations().size() + " expected <= 2"); } + for (OutputConfiguration c : config.getOutputConfigurations()) { + if (c.getDynamicRangeProfile() != DynamicRangeProfiles.STANDARD) { + throw new IllegalArgumentException("Unsupported dynamic range profile: " + + c.getDynamicRangeProfile()); + } + } + Pair extenders = CameraExtensionCharacteristics.initializeExtension(config.getExtension()); diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index e393a66eb7331..0f8bdf64e1326 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -51,6 +51,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration import android.hardware.camera2.marshal.impl.MarshalQueryableString; import android.hardware.camera2.params.Capability; import android.hardware.camera2.params.DeviceStateSensorOrientationMap; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; @@ -331,6 +332,7 @@ public class CameraMetadataNative implements Parcelable { private static final int MANDATORY_STREAM_CONFIGURATIONS_DEFAULT = 0; 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 String translateLocationProviderToProcess(final String provider) { if (provider == null) { @@ -677,6 +679,16 @@ public class CameraMetadataNative implements Parcelable { } }); + sGetCommandMap.put( + CameraCharacteristics.SCALER_MANDATORY_TEN_BIT_OUTPUT_STREAM_COMBINATIONS.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public T getValue(CameraMetadataNative metadata, Key key) { + return (T) metadata.getMandatory10BitStreamCombinations(); + } + }); + sGetCommandMap.put( CameraCharacteristics.SCALER_MANDATORY_MAXIMUM_RESOLUTION_STREAM_COMBINATIONS.getNativeKey(), new GetCommand() { @@ -770,6 +782,15 @@ public class CameraMetadataNative implements Parcelable { return (T) metadata.getDeviceStateOrientationMap(); } }); + sGetCommandMap.put( + CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public T getValue(CameraMetadataNative metadata, Key key) { + return (T) metadata.getDynamicRangeProfiles(); + } + }); sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), new GetCommand() { @@ -1015,6 +1036,17 @@ public class CameraMetadataNative implements Parcelable { return map; } + private DynamicRangeProfiles getDynamicRangeProfiles() { + int[] profileArray = getBase( + CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP); + + if (profileArray == null) { + return null; + } + + return new DynamicRangeProfiles(profileArray); + } + private Location getGpsLocation() { String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD); double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES); @@ -1378,6 +1410,9 @@ public class CameraMetadataNative implements Parcelable { case MANDATORY_STREAM_CONFIGURATIONS_MAX_RESOLUTION: combs = build.getAvailableMandatoryMaximumResolutionStreamCombinations(); break; + case MANDATORY_STREAM_CONFIGURATIONS_10BIT: + combs = build.getAvailableMandatory10BitStreamCombinations(); + break; default: combs = build.getAvailableMandatoryStreamCombinations(); } @@ -1389,6 +1424,10 @@ public class CameraMetadataNative implements Parcelable { return null; } + private MandatoryStreamCombination[] getMandatory10BitStreamCombinations() { + return getMandatoryStreamCombinationsHelper(MANDATORY_STREAM_CONFIGURATIONS_10BIT); + } + private MandatoryStreamCombination[] getMandatoryConcurrentStreamCombinations() { if (!mHasMandatoryConcurrentStreams) { return null; diff --git a/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java new file mode 100644 index 0000000000000..5c1a4aa120ea6 --- /dev/null +++ b/core/java/android/hardware/camera2/params/DynamicRangeProfiles.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2.params; + +import android.annotation.IntDef; +import android.annotation.NonNull; + +import android.hardware.camera2.CameraMetadata; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Immutable class with information about supported 10-bit dynamic range profiles. + * + *

    An instance of this class can be queried by retrieving the value of + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. + *

    + * + *

    All camera devices supporting the + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} + * capability must advertise the supported 10-bit dynamic range profiles in + * {@link #getSupportedProfiles}

    + * + *

    Some devices may not be able to support 8-bit and/or 10-bit output with different dynamic + * range profiles within the same capture request. Such device specific constraints can be queried + * by calling {@link #getProfileCaptureRequestConstraints(int)}. Do note that unsupported + * combinations will result in {@link IllegalArgumentException} when trying to submit a capture + * request. Capture requests that only reference outputs configured using the same dynamic range + * profile value will never fail due to such constraints.

    + * + * @see OutputConfiguration#setDynamicRangeProfile(int) + */ +public final class DynamicRangeProfiles { + /** + * This the default 8-bit standard profile that will be used in case where camera clients do not + * explicitly configure a supported dynamic range profile by calling + * {@link OutputConfiguration#setDynamicRangeProfile(int)}. + */ + public static final int STANDARD = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD; + + /** + * 10-bit pixel samples encoded using the Hybrid log-gamma transfer function + * + *

    All 10-bit output capable devices are required to support this profile.

    + */ + public static final int HLG10 = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10; + + /** + * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. + * + *

    This profile utilizes internal static metadata to increase the quality + * of the capture.

    + */ + public static final int HDR10 = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10; + + /** + * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. + * + *

    In contrast to HDR10, this profile uses internal per-frame metadata + * to further enhance the quality of the capture.

    + */ + public static final int HDR10_PLUS = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS; + + /** + *

    This is a camera mode for Dolby Vision capture optimized for a more scene + * accurate capture. This would typically differ from what a specific device + * might want to tune for a consumer optimized Dolby Vision general capture.

    + */ + public static final int DOLBY_VISION_10B_HDR_REF = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF; + + /** + *

    This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.

    + */ + public static final int DOLBY_VISION_10B_HDR_REF_PO = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO; + + /** + *

    This is the camera mode for the default Dolby Vision capture mode for the + * specific device. This would be tuned by each specific device for consumer + * pleasing results that resonate with their particular audience. We expect + * that each specific device would have a different look for their default + * Dolby Vision capture.

    + */ + public static final int DOLBY_VISION_10B_HDR_OEM = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM; + + /** + *

    This is the power optimized mode for 10-bit Dolby Vision HDR device specific capture + * Mode.

    + */ + public static final int DOLBY_VISION_10B_HDR_OEM_PO = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO; + + /** + *

    This is the 8-bit version of the Dolby Vision reference capture mode optimized + * for scene accuracy.

    + */ + public static final int DOLBY_VISION_8B_HDR_REF = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF; + + /** + *

    This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.

    + */ + public static final int DOLBY_VISION_8B_HDR_REF_PO = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO; + + /** + *

    This is the 8-bit version of device specific tuned and optimized Dolby Vision + * capture mode.

    + */ + public static final int DOLBY_VISION_8B_HDR_OEM = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM; + + /** + *

    This is the power optimized mode for 8-bit Dolby Vision HDR device specific + * capture Mode.

    + */ + public static final int DOLBY_VISION_8B_HDR_OEM_PO = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO; + + /* + * @hide + */ + public static final int PUBLIC_MAX = + CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"PROFILE_"}, value = + {STANDARD, + HLG10, + HDR10, + HDR10_PLUS, + DOLBY_VISION_10B_HDR_REF, + DOLBY_VISION_10B_HDR_REF_PO, + DOLBY_VISION_10B_HDR_OEM, + DOLBY_VISION_10B_HDR_OEM_PO, + DOLBY_VISION_8B_HDR_REF, + DOLBY_VISION_8B_HDR_REF_PO, + DOLBY_VISION_8B_HDR_OEM, + DOLBY_VISION_8B_HDR_OEM_PO}) + public @interface Profile { + } + + private final HashMap> mProfileMap = new HashMap<>(); + + /** + * Create a new immutable DynamicRangeProfiles instance. + * + *

    This constructor takes over the array; do not write to the array afterwards.

    + * + *

    Do note that the constructor is available for testing purposes only! + * Camera clients must always retrieve the value of + * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. + * for a given camera id in order to retrieve the device capabilities.

    + * + * @param elements + * An array of elements describing the map. It contains two elements per entry which + * describe the supported dynamic range profile value in the first element and in the + * second element a bitmap of concurrently supported dynamic range profiles within the + * same capture request. Bitmap values of 0 indicate that there are no constraints. + * + * @throws IllegalArgumentException + * if the {@code elements} array length is invalid, not divisible by 2 or contains + * invalid element values + * @throws NullPointerException + * if {@code elements} is {@code null} + * + */ + public DynamicRangeProfiles(@NonNull final int[] elements) { + if ((elements.length % 2) != 0) { + throw new IllegalArgumentException("Dynamic range profile map length " + + elements.length + " is not even!"); + } + + for (int i = 0; i < elements.length; i += 2) { + checkProfileValue(elements[i]); + // STANDARD is not expected to be included + if (elements[i] == STANDARD) { + throw new IllegalArgumentException("Dynamic range profile map must not include a" + + " STANDARD profile entry!"); + } + HashSet profiles = new HashSet<>(); + + if (elements[i+1] != 0) { + for (int profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) { + if ((elements[i+1] & profile) != 0) { + profiles.add(profile); + } + } + } + + mProfileMap.put(elements[i], profiles); + } + + // Build the STANDARD constraints depending on the advertised 10-bit limitations + HashSet standardConstraints = new HashSet<>(); + standardConstraints.add(STANDARD); + for(Integer profile : mProfileMap.keySet()) { + if (mProfileMap.get(profile).isEmpty() || mProfileMap.get(profile).contains(STANDARD)) { + standardConstraints.add(profile); + } + } + + mProfileMap.put(STANDARD, standardConstraints); + } + + + /** + * @hide + */ + public static void checkProfileValue(int profile) { + switch (profile) { + case STANDARD: + case HLG10: + case HDR10: + case HDR10_PLUS: + case DOLBY_VISION_10B_HDR_REF: + case DOLBY_VISION_10B_HDR_REF_PO: + case DOLBY_VISION_10B_HDR_OEM: + case DOLBY_VISION_10B_HDR_OEM_PO: + case DOLBY_VISION_8B_HDR_REF: + case DOLBY_VISION_8B_HDR_REF_PO: + case DOLBY_VISION_8B_HDR_OEM: + case DOLBY_VISION_8B_HDR_OEM_PO: + //No-op + break; + default: + throw new IllegalArgumentException("Unknown profile " + profile); + } + } + + /** + * Return a set of supported dynamic range profiles. + * + * @return non-modifiable set of dynamic range profiles + */ + public @NonNull Set getSupportedProfiles() { + return Collections.unmodifiableSet(mProfileMap.keySet()); + } + + /** + * Return a list of supported dynamic range profiles that + * can be referenced in a single capture request along with a given + * profile. + * + *

    For example if assume that a particular 10-bit output capable device + * returns ({@link #STANDARD}, {@link #HLG10}, {@link #HDR10}) as result from calling + * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints(int)} + * returns ({@link #STANDARD}, {@link #HLG10}) when given an argument of {@link #STANDARD}. + * This means that the corresponding camera device will only accept and process capture requests + * that reference outputs configured using {@link #HDR10} dynamic profile or alternatively + * some combination of {@link #STANDARD} and {@link #HLG10}. However trying to + * queue capture requests to outputs that reference both {@link #HDR10} and + * {@link #STANDARD}/{@link #HLG10} will result in {@link IllegalArgumentException}.

    + * + *

    The list will be empty in case there are no constraints for the given + * profile.

    + * + * @return non-modifiable set of dynamic range profiles + * @throws IllegalArgumentException - If the profile argument is not + * within the list returned by + * getSupportedProfiles() + * + * @see OutputConfiguration#setDynamicRangeProfile(int) + */ + public @NonNull Set getProfileCaptureRequestConstraints(@Profile int profile) { + Set ret = mProfileMap.get(profile); + if (ret == null) { + throw new IllegalArgumentException("Unsupported profile!"); + } + + return Collections.unmodifiableSet(ret); + } +} diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java index a6789213b50bc..32c15da4a909d 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -18,8 +18,6 @@ package android.hardware.camera2.params; import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormat; -import static com.android.internal.util.Preconditions.*; - import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.ImageFormat; @@ -28,7 +26,6 @@ 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.StreamConfigurationMap; import android.hardware.camera2.utils.HashCodeHelpers; import android.media.CamcorderProfile; import android.util.Log; @@ -40,6 +37,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; /** @@ -64,6 +62,7 @@ public final class MandatoryStreamCombination { private final boolean mIsInput; private final boolean mIsUltraHighResolution; private final boolean mIsMaximumSize; + private final boolean mIs10BitCapable; /** * Create a new {@link MandatoryStreamInformation}. @@ -119,6 +118,29 @@ public final class MandatoryStreamCombination { */ public MandatoryStreamInformation(@NonNull List availableSizes, @Format int format, boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution) { + this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution, + /*is10bitCapable*/ false); + } + + /** + * 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 + * + * @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) { if (availableSizes.isEmpty()) { throw new IllegalArgumentException("No available sizes"); } @@ -127,6 +149,7 @@ public final class MandatoryStreamCombination { mIsMaximumSize = isMaximumSize; mIsInput = isInput; mIsUltraHighResolution = isUltraHighResolution; + mIs10BitCapable = is10BitCapable; } /** @@ -179,6 +202,27 @@ public final class MandatoryStreamCombination { return mIsMaximumSize; } + /** + * Indicates whether this stream is able to support 10-bit output. + * + *

    10-bit capable streams can be configured to output 10-bit sample data via calls to + * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} and + * selecting the appropriate output Surface pixel format which can be queried via + * {@link #get10BitFormat()} and will be either + * {@link ImageFormat#PRIVATE} (the default for Surfaces initialized by + * {@link android.view.SurfaceView}, {@link android.view.TextureView}, + * {@link android.media.MediaRecorder}, {@link android.media.MediaCodec} etc.) or + * {@link ImageFormat#YCBCR_P010}.

    + * + * @return true if stream is able to output 10-bit pixels + * + * @see android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT + * @see OutputConfiguration#setDynamicRangeProfile(int) + */ + public boolean is10BitCapable() { + return mIs10BitCapable; + } + /** * Return the list of available sizes for this mandatory stream. * @@ -201,6 +245,29 @@ public final class MandatoryStreamCombination { * @return integer format. */ public @Format int getFormat() { + // P010 YUV streams must be supported along with SDR 8-bit YUV streams + if ((mIs10BitCapable) && (mFormat == ImageFormat.YCBCR_P010)) { + return ImageFormat.YUV_420_888; + } + return mFormat; + } + + /** + * Retrieve the mandatory stream 10-bit {@code format} for 10-bit capable streams. + * + *

    In case {@link #is10BitCapable()} returns {@code true}, then this method + * will return the corresponding 10-bit output Surface pixel format. Depending on + * the stream type it will be either {@link ImageFormat#PRIVATE} or + * {@link ImageFormat#YCBCR_P010}.

    + * + * @return integer format. + * @throws UnsupportedOperationException in case the stream is not capable of 10-bit output + * @see #is10BitCapable() + */ + public @Format int get10BitFormat() { + if (!mIs10BitCapable) { + throw new UnsupportedOperationException("10-bit output is not supported!"); + } return mFormat; } @@ -932,6 +999,41 @@ public final class MandatoryStreamCombination { /*reprocessType*/ ReprocessType.PRIVATE), }; + private static StreamCombinationTemplate s10BitOutputStreamCombinations[] = { + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM)}, + "Simple preview, GPU video processing, or no-preview video recording"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM)}, + "In-application video/image processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)}, + "Standard still imaging"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)}, + "Maximum-resolution in-app processing with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM), + new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.PREVIEW)}, + "Maximum-resolution two-input in-app processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)}, + "High-resolution video recording with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.RECORD), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)}, + "High-resolution recording with in-app snapshot"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)}, + "High-resolution recording with video snapshot"), + }; + /** * Helper builder class to generate a list of available mandatory stream combinations. * @hide @@ -970,6 +1072,86 @@ public final class MandatoryStreamCombination { CameraManager.isHiddenPhysicalCamera(Integer.toString(mCameraId)); } + /** + * Retrieve a list of all available mandatory 10-bit output capable stream combinations. + * + * @return a non-modifiable list of supported mandatory 10-bit capable stream combinations, + * null in case device is not 10-bit output capable. + */ + public @NonNull List + getAvailableMandatory10BitStreamCombinations() { + // Since 10-bit streaming support is optional, we mandate these stream + // combinations regardless of camera device capabilities. + + StreamCombinationTemplate []chosenStreamCombinations = s10BitOutputStreamCombinations; + if (!is10BitOutputSupported()) { + Log.v(TAG, "Device is not able to output 10-bit!"); + return null; + } + + HashMap, List> availableSizes = + enumerateAvailableSizes(); + if (availableSizes == null) { + Log.e(TAG, "Available size enumeration failed!"); + return null; + } + + ArrayList availableStreamCombinations = new ArrayList<>(); + availableStreamCombinations.ensureCapacity(chosenStreamCombinations.length); + for (StreamCombinationTemplate combTemplate : chosenStreamCombinations) { + 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); + if (template.mFormat == ImageFormat.YCBCR_P010) { + // Make sure that exactly the same 10 and 8-bit YUV streams sizes are + // supported + pair = new Pair<>(template.mSizeThreshold, + new Integer(ImageFormat.YUV_420_888)); + HashSet sdrYuvSizes = new HashSet<>(availableSizes.get(pair)); + if (!sdrYuvSizes.equals(new HashSet<>(sizes))) { + Log.e(TAG, "The supported 10-bit YUV sizes are different from the" + + " supported 8-bit YUV sizes!"); + return null; + } + } + + MandatoryStreamInformation streamInfo; + boolean isMaximumSize = + (template.mSizeThreshold == SizeThreshold.MAXIMUM); + try { + streamInfo = new MandatoryStreamInformation(sizes, template.mFormat, + isMaximumSize, /*isInput*/ false, + /*isUltraHighResolution*/ false, + /*is10BitCapable*/ template.mFormat != ImageFormat.JPEG); + } 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 @@ -1444,7 +1626,8 @@ public final class MandatoryStreamCombination { final int[] formats = { ImageFormat.PRIVATE, ImageFormat.YUV_420_888, - ImageFormat.JPEG + ImageFormat.JPEG, + ImageFormat.YCBCR_P010 }; Size recordingMaxSize = new Size(0, 0); Size previewMaxSize = new Size(0, 0); @@ -1464,7 +1647,11 @@ public final class MandatoryStreamCombination { HashMap allSizes = new HashMap(); for (int format : formats) { Integer intFormat = new Integer(format); - allSizes.put(intFormat, mStreamConfigMap.getOutputSizes(format)); + Size[] sizes = mStreamConfigMap.getOutputSizes(format); + if (sizes == null) { + sizes = new Size[0]; + } + allSizes.put(intFormat, sizes); } List previewSizes = getSizesWithinBound( @@ -1645,6 +1832,14 @@ public final class MandatoryStreamCombination { CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE); } + /** + * Check whether the current device supports 10-bit output. + */ + private boolean is10BitOutputSupported() { + return isCapabilitySupported( + CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT); + } + /** * Check whether the current device supports private reprocessing. */ diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 5bb7201eff65e..f2b881ba7758b 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -29,6 +29,8 @@ import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.MultiResolutionImageReader; +import android.hardware.camera2.params.DynamicRangeProfiles; +import android.hardware.camera2.params.DynamicRangeProfiles.Profile; import android.hardware.camera2.params.MultiResolutionStreamInfo; import android.hardware.camera2.utils.HashCodeHelpers; import android.hardware.camera2.utils.SurfaceUtils; @@ -257,6 +259,39 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = true; } + /** + * Set a specific device supported dynamic range profile. + * + *

    Clients can choose from any profile advertised as supported in + * CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES + * queried using {@link DynamicRangeProfiles#getSupportedProfiles()}. + * If this is not explicitly set, then the default profile will be + * {@link DynamicRangeProfiles#STANDARD}.

    + * + *

    Do note that invalid combinations between the registered output + * surface pixel format and the configured dynamic range profile will + * cause capture session initialization failure. Invalid combinations + * include any 10-bit dynamic range profile advertised in + * {@link DynamicRangeProfiles#getSupportedProfiles()} combined with + * an output Surface pixel format different from {@link ImageFormat#PRIVATE} + * (the default for Surfaces initialized by {@link android.view.SurfaceView}, + * {@link android.view.TextureView}, {@link android.media.MediaRecorder}, + * {@link android.media.MediaCodec} etc.) + * or {@link ImageFormat#YCBCR_P010}.

    + */ + public void setDynamicRangeProfile(@Profile int profile) { + mDynamicRangeProfile = profile; + } + + /** + * Return current dynamic range profile. + * + * @return the currently set dynamic range profile + */ + public @Profile int getDynamicRangeProfile() { + return mDynamicRangeProfile; + } + /** * Create a new {@link OutputConfiguration} instance. * @@ -319,6 +354,7 @@ public final class OutputConfiguration implements Parcelable { mPhysicalCameraId = null; mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList(); + mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; } /** @@ -416,6 +452,7 @@ public final class OutputConfiguration implements Parcelable { mPhysicalCameraId = null; mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList(); + mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; } /** @@ -718,6 +755,7 @@ public final class OutputConfiguration implements Parcelable { this.mPhysicalCameraId = other.mPhysicalCameraId; this.mIsMultiResolution = other.mIsMultiResolution; this.mSensorPixelModesUsed = other.mSensorPixelModesUsed; + this.mDynamicRangeProfile = other.mDynamicRangeProfile; } /** @@ -737,6 +775,8 @@ public final class OutputConfiguration implements Parcelable { boolean isMultiResolutionOutput = source.readInt() == 1; int[] sensorPixelModesUsed = source.createIntArray(); checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); + int dynamicRangeProfile = source.readInt(); + DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile); mSurfaceGroupId = surfaceSetId; mRotation = rotation; @@ -760,6 +800,7 @@ public final class OutputConfiguration implements Parcelable { mPhysicalCameraId = physicalCameraId; mIsMultiResolution = isMultiResolutionOutput; mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed); + mDynamicRangeProfile = dynamicRangeProfile; } /** @@ -875,6 +916,7 @@ public final class OutputConfiguration implements Parcelable { dest.writeInt(mIsMultiResolution ? 1 : 0); // writeList doesn't seem to work well with Integer list. dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed)); + dest.writeInt(mDynamicRangeProfile); } /** @@ -920,6 +962,9 @@ public final class OutputConfiguration implements Parcelable { if (mSurfaces.get(i) != other.mSurfaces.get(i)) return false; } + if (mDynamicRangeProfile != other.mDynamicRangeProfile) { + return false; + } return true; } @@ -939,7 +984,8 @@ public final class OutputConfiguration implements Parcelable { mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0, mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), - mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode()); + mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), + mDynamicRangeProfile); } return HashCodeHelpers.hashCode( @@ -947,7 +993,8 @@ public final class OutputConfiguration implements Parcelable { mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0, mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(), - mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode()); + mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(), + mDynamicRangeProfile); } private static final String TAG = "OutputConfiguration"; @@ -979,4 +1026,6 @@ public final class OutputConfiguration implements Parcelable { private boolean mIsMultiResolution; // The sensor pixel modes that this OutputConfiguration will use private ArrayList mSensorPixelModesUsed; + // Dynamic range profile + private int mDynamicRangeProfile; } diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java index 2d725989af171..80db38fc9d8f5 100644 --- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java @@ -16,6 +16,8 @@ package android.hardware.camera2.params; +import static com.android.internal.R.string.hardware; + import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -148,6 +150,16 @@ public final class RecommendedStreamConfigurationMap { */ public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6; + /** + * If supported, the recommended 10-bit output stream configurations must include + * a subset of the advertised {@link android.graphics.ImageFormat#YCBCR_P010} and + * {@link android.graphics.ImageFormat#PRIVATE} outputs that are optimized for power + * and performance when registered along with a supported 10-bit dynamic range profile. + * {@see android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} for + * details. + */ + public static final int USECASE_10BIT_OUTPUT = 0x8; + /** * Device specific use cases. * @hide @@ -163,7 +175,8 @@ public final class RecommendedStreamConfigurationMap { USECASE_SNAPSHOT, USECASE_ZSL, USECASE_RAW, - USECASE_LOW_LATENCY_SNAPSHOT}) + USECASE_LOW_LATENCY_SNAPSHOT, + USECASE_10BIT_OUTPUT}) public @interface RecommendedUsecase {}; /** diff --git a/proto/src/camera.proto b/proto/src/camera.proto index d07a525fdffa1..0338b93c88426 100644 --- a/proto/src/camera.proto +++ b/proto/src/camera.proto @@ -62,4 +62,7 @@ message CameraStreamProto { // The frame counts for each histogram bins // Expected number of fields: 10 repeated int64 histogram_counts = 13; + + // The dynamic range profile of the stream + optional int32 dynamic_range_profile = 14; } diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 3120dc58eebdc..9d9b90cba39b2 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -788,6 +788,7 @@ public class CameraServiceProxy extends SystemService streamProtos[i].histogramType = streamStats.getHistogramType(); streamProtos[i].histogramBins = streamStats.getHistogramBins(); streamProtos[i].histogramCounts = streamStats.getHistogramCounts(); + streamProtos[i].dynamicRangeProfile = streamStats.getDynamicRangeProfile(); if (CameraServiceProxy.DEBUG) { String histogramTypeName = @@ -807,7 +808,8 @@ public class CameraServiceProxy extends SystemService + ", histogramBins " + Arrays.toString(streamProtos[i].histogramBins) + ", histogramCounts " - + Arrays.toString(streamProtos[i].histogramCounts)); + + Arrays.toString(streamProtos[i].histogramCounts) + + ", dynamicRangeProfile " + streamProtos[i].dynamicRangeProfile); } } }