Create API for reporting color space support to Camera2 framework consumers.
Test: Ran CtsCameraTestCases
Test: Ran new VTS test for color space reporting
Test: Created app to test display P3 camera, switching between color spaces
Bug: 238359088
Change-Id: I5c74ea438970cbe55f93b925a6744f4343bc545a
diff --git a/core/api/current.txt b/core/api/current.txt
index 74ff672..bcce8bf 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -17626,6 +17626,7 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REPROCESS_MAX_CAPTURE_STALL;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceProfiles> REQUEST_AVAILABLE_COLOR_SPACE_PROFILES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.DynamicRangeProfiles> REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC;
@@ -17989,6 +17990,7 @@
field public static final int NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG = 4; // 0x4
field public static final int REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE = 0; // 0x0
field public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6; // 0x6
+ field public static final int REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES = 20; // 0x14
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
@@ -18340,6 +18342,15 @@
method @NonNull public android.util.Range<java.lang.Float> getZoomRatioRange();
}
+ public final class ColorSpaceProfiles {
+ ctor public ColorSpaceProfiles(@NonNull long[]);
+ method @NonNull public java.util.Set<android.graphics.ColorSpace.Named> getSupportedColorSpaces(int);
+ method @NonNull public java.util.Set<android.graphics.ColorSpace.Named> getSupportedColorSpacesForDynamicRange(int, long);
+ method @NonNull public java.util.Set<java.lang.Long> getSupportedDynamicRangeProfiles(@NonNull android.graphics.ColorSpace.Named, int);
+ method @NonNull public java.util.Set<java.lang.Integer> getSupportedImageFormatsForColorSpace(@NonNull android.graphics.ColorSpace.Named);
+ field public static final int UNSPECIFIED = -1; // 0xffffffff
+ }
+
public final class ColorSpaceTransform {
ctor public ColorSpaceTransform(android.util.Rational[]);
ctor public ColorSpaceTransform(int[]);
@@ -18571,13 +18582,16 @@
public final class SessionConfiguration implements android.os.Parcelable {
ctor public SessionConfiguration(int, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method public void clearColorSpace();
method public int describeContents();
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
method public java.util.concurrent.Executor getExecutor();
method public android.hardware.camera2.params.InputConfiguration getInputConfiguration();
method public java.util.List<android.hardware.camera2.params.OutputConfiguration> getOutputConfigurations();
method public android.hardware.camera2.CaptureRequest getSessionParameters();
method public int getSessionType();
method public android.hardware.camera2.CameraCaptureSession.StateCallback getStateCallback();
+ method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
method public void setInputConfiguration(@NonNull android.hardware.camera2.params.InputConfiguration);
method public void setSessionParameters(android.hardware.camera2.CaptureRequest);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1e4023e..2602e78 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1170,6 +1170,20 @@
}
+package android.hardware.camera2.params {
+
+ public final class ColorSpaceProfiles {
+ method @NonNull public java.util.Map<android.graphics.ColorSpace.Named,java.util.Map<java.lang.Integer,java.util.Set<java.lang.Long>>> getProfileMap();
+ }
+
+ public final class OutputConfiguration implements android.os.Parcelable {
+ method public void clearColorSpace();
+ method @Nullable public android.graphics.ColorSpace getColorSpace();
+ method public void setColorSpace(@NonNull android.graphics.ColorSpace.Named);
+ }
+
+}
+
package android.hardware.devicestate {
public final class DeviceStateManager {
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 3952467..aed5a12 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.CameraMetadata;
+import android.hardware.camera2.params.ColorSpaceProfiles;
import android.hardware.camera2.params.DynamicRangeProfiles;
import android.os.Parcel;
import android.os.Parcelable;
@@ -50,6 +51,7 @@
private long[] mHistogramCounts;
private long mDynamicRangeProfile;
private long mStreamUseCase;
+ private int mColorSpace;
private static final String TAG = "CameraStreamStats";
@@ -68,12 +70,13 @@
mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
}
public CameraStreamStats(int width, int height, int format, float maxPreviewFps,
int dataSpace, long usage, long requestCount, long errorCount,
int startLatencyMs, int maxHalBuffers, int maxAppBuffers, long dynamicRangeProfile,
- long streamUseCase) {
+ long streamUseCase, int colorSpace) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -88,6 +91,7 @@
mHistogramType = HISTOGRAM_TYPE_UNKNOWN;
mDynamicRangeProfile = dynamicRangeProfile;
mStreamUseCase = streamUseCase;
+ mColorSpace = colorSpace;
}
public static final @android.annotation.NonNull Parcelable.Creator<CameraStreamStats> CREATOR =
@@ -136,6 +140,7 @@
dest.writeLongArray(mHistogramCounts);
dest.writeLong(mDynamicRangeProfile);
dest.writeLong(mStreamUseCase);
+ dest.writeInt(mColorSpace);
}
public void readFromParcel(Parcel in) {
@@ -155,6 +160,7 @@
mHistogramCounts = in.createLongArray();
mDynamicRangeProfile = in.readLong();
mStreamUseCase = in.readLong();
+ mColorSpace = in.readInt();
}
public int getWidth() {
@@ -217,6 +223,10 @@
return mDynamicRangeProfile;
}
+ public int getColorSpace() {
+ return mColorSpace;
+ }
+
public long getStreamUseCase() {
return mStreamUseCase;
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 8873807..f634726 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2224,6 +2224,7 @@
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE STREAM_USE_CASE}</li>
+ * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES COLOR_SPACE_PROFILES}</li>
* </ul>
*
* <p>This key is available on all devices.</p>
@@ -2249,6 +2250,7 @@
* @see #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING
* @see #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
* @see #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES
*/
@PublicKey
@NonNull
@@ -2473,6 +2475,82 @@
new Key<Long>("android.request.recommendedTenBitDynamicRangeProfile", long.class);
/**
+ * <p>An interface for querying the color space profiles supported by a camera device.</p>
+ * <p>A color space profile is a combination of a color space, an image format, and a dynamic
+ * range profile. Camera clients can retrieve the list of supported color spaces by calling
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpaces } or
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpacesForDynamicRange }.
+ * If a camera does not support the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+ * capability, the dynamic range profile will always be
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD }. Color space
+ * capabilities are queried in combination with an {@link android.graphics.ImageFormat }.
+ * If a camera client wants to know the general color space capabilities of a camera device
+ * regardless of image format, it can specify {@link android.graphics.ImageFormat#UNKNOWN }.
+ * The color space for a session can be configured by setting the SessionConfiguration
+ * color space via {@link android.hardware.camera2.params.SessionConfiguration#setColorSpace }.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ */
+ @PublicKey
+ @NonNull
+ @SyntheticKey
+ public static final Key<android.hardware.camera2.params.ColorSpaceProfiles> REQUEST_AVAILABLE_COLOR_SPACE_PROFILES =
+ new Key<android.hardware.camera2.params.ColorSpaceProfiles>("android.request.availableColorSpaceProfiles", android.hardware.camera2.params.ColorSpaceProfiles.class);
+
+ /**
+ * <p>A list of all possible color space profiles supported by a camera device.</p>
+ * <p>A color space profile is a combination of a color space, an image format, and a dynamic range
+ * profile. If a camera does not support the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
+ * capability, the dynamic range profile will always be
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD }. Camera clients can
+ * use {@link android.hardware.camera2.params.SessionConfiguration#setColorSpace } to select
+ * a color space.</p>
+ * <p><b>Possible values:</b></p>
+ * <ul>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED UNSPECIFIED}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB SRGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_SRGB LINEAR_SRGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_EXTENDED_SRGB EXTENDED_SRGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_EXTENDED_SRGB LINEAR_EXTENDED_SRGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT709 BT709}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020 BT2020}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DCI_P3 DCI_P3}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3 DISPLAY_P3}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_NTSC_1953 NTSC_1953}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SMPTE_C SMPTE_C}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ADOBE_RGB ADOBE_RGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_PRO_PHOTO_RGB PRO_PHOTO_RGB}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACES ACES}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACESCG ACESCG}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_XYZ CIE_XYZ}</li>
+ * <li>{@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_LAB CIE_LAB}</li>
+ * </ul>
+ *
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_SRGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_EXTENDED_SRGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_EXTENDED_SRGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT709
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DCI_P3
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_NTSC_1953
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SMPTE_C
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ADOBE_RGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_PRO_PHOTO_RGB
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACES
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACESCG
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_XYZ
+ * @see #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_LAB
+ * @hide
+ */
+ public static final Key<long[]> REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP =
+ new Key<long[]>("android.request.availableColorSpaceProfilesMap", long[].class);
+
+ /**
* <p>The list of image formats that are supported by this
* camera device for output streams.</p>
* <p>All camera devices will support JPEG and YUV_420_888 formats.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c67a560..1e1d443 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1257,6 +1257,24 @@
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19;
+ /**
+ * <p>The device supports querying the possible combinations of color spaces, image
+ * formats, and dynamic range profiles supported by the camera and requesting a
+ * particular color space for a session via
+ * {@link android.hardware.camera2.params.SessionConfiguration#setColorSpace }.</p>
+ * <p>Cameras that enable this capability may or may not also implement dynamic range
+ * profiles. If they don't,
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles#getSupportedDynamicRangeProfiles }
+ * will return only
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD } and
+ * {@link android.hardware.camera2.params.ColorSpaceProfiles#getSupportedColorSpacesForDynamicRange }
+ * will assume support of the
+ * {@link android.hardware.camera2.params.DynamicRangeProfiles#STANDARD }
+ * profile in all combinations of color spaces and image formats.</p>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES = 20;
+
//
// Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
//
@@ -1367,6 +1385,18 @@
public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000;
//
+ // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP
+ //
+
+ /**
+ * <p>Default value, when not explicitly specified. The Camera device will choose the color
+ * space to employ.</p>
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP
+ * @hide
+ */
+ public static final int REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED = -1;
+
+ //
// Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
//
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index ee12df5..012fad5 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -50,6 +50,7 @@
import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
import android.hardware.camera2.marshal.impl.MarshalQueryableString;
import android.hardware.camera2.params.Capability;
+import android.hardware.camera2.params.ColorSpaceProfiles;
import android.hardware.camera2.params.DeviceStateSensorOrientationMap;
import android.hardware.camera2.params.DynamicRangeProfiles;
import android.hardware.camera2.params.Face;
@@ -813,6 +814,15 @@
}
});
sGetCommandMap.put(
+ CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES.getNativeKey(),
+ new GetCommand() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getValue(CameraMetadataNative metadata, Key<T> key) {
+ return (T) metadata.getColorSpaceProfiles();
+ }
+ });
+ sGetCommandMap.put(
CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(),
new GetCommand() {
@Override
@@ -1068,6 +1078,17 @@
return new DynamicRangeProfiles(profileArray);
}
+ private ColorSpaceProfiles getColorSpaceProfiles() {
+ long[] profileArray = getBase(
+ CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP);
+
+ if (profileArray == null) {
+ return null;
+ }
+
+ return new ColorSpaceProfiles(profileArray);
+ }
+
private Location getGpsLocation() {
String processingMethod = get(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
double[] coords = get(CaptureResult.JPEG_GPS_COORDINATES);
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
new file mode 100644
index 0000000..2e3af80
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/ColorSpaceProfiles.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2022 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.NonNull;
+import android.annotation.TestApi;
+import android.graphics.ColorSpace;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraMetadata;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Immutable class with information about supported color space profiles.
+ *
+ * <p>An instance of this class can be queried by retrieving the value of
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}.
+ * </p>
+ *
+ * <p>All camera devices supporting the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES}
+ * capability must advertise the supported color space profiles in
+ * {@link #getSupportedColorSpaces}</p>
+ *
+ * @see SessionConfiguration#setColorSpace
+ */
+public final class ColorSpaceProfiles {
+ /*
+ * @hide
+ */
+ public static final int UNSPECIFIED =
+ CameraMetadata.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED;
+
+ private final Map<ColorSpace.Named, Map<Integer, Set<Long>>> mProfileMap = new ArrayMap<>();
+
+ /**
+ * Create a new immutable ColorSpaceProfiles instance.
+ *
+ * <p>This constructor takes over the array; do not write to the array afterwards.</p>
+ *
+ * <p>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_COLOR_SPACE_PROFILES}.
+ * for a given camera id in order to retrieve the device capabilities.</p>
+ *
+ * @param elements
+ * An array of elements describing the map. It contains three elements per entry which
+ * describe the supported color space profile value in the first element, a compatible
+ * image format in the second, and in the third element a bitmap of compatible dynamic
+ * range profiles (see {@link DynamicRangeProfiles#STANDARD} and others for the
+ * individual bitmap components).
+ *
+ * @throws IllegalArgumentException
+ * if the {@code elements} array length is invalid, not divisible by 3 or contains
+ * invalid element values
+ * @throws NullPointerException
+ * if {@code elements} is {@code null}
+ *
+ */
+ public ColorSpaceProfiles(@NonNull final long[] elements) {
+ if ((elements.length % 3) != 0) {
+ throw new IllegalArgumentException("Color space profile map length "
+ + elements.length + " is not divisible by 3!");
+ }
+
+ for (int i = 0; i < elements.length; i += 3) {
+ int colorSpace = (int) elements[i];
+ checkProfileValue(colorSpace);
+ ColorSpace.Named namedColorSpace = ColorSpace.Named.values()[colorSpace];
+ int imageFormat = (int) elements[i + 1];
+ long dynamicRangeProfileBitmap = elements[i + 2];
+
+ if (!mProfileMap.containsKey(namedColorSpace)) {
+ ArrayMap<Integer, Set<Long>> imageFormatMap = new ArrayMap<>();
+ mProfileMap.put(namedColorSpace, imageFormatMap);
+ }
+
+ if (!mProfileMap.get(namedColorSpace).containsKey(imageFormat)) {
+ ArraySet<Long> dynamicRangeProfiles = new ArraySet<>();
+ mProfileMap.get(namedColorSpace).put(imageFormat, dynamicRangeProfiles);
+ }
+
+ if (dynamicRangeProfileBitmap != 0) {
+ for (long dynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ dynamicRangeProfile < DynamicRangeProfiles.PUBLIC_MAX;
+ dynamicRangeProfile <<= 1) {
+ if ((dynamicRangeProfileBitmap & dynamicRangeProfile) != 0) {
+ mProfileMap.get(namedColorSpace).get(imageFormat).add(dynamicRangeProfile);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static void checkProfileValue(int colorSpace) {
+ boolean found = false;
+ for (ColorSpace.Named value : ColorSpace.Named.values()) {
+ if (colorSpace == value.ordinal()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ throw new IllegalArgumentException("Unknown ColorSpace " + colorSpace);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ public @NonNull Map<ColorSpace.Named, Map<Integer, Set<Long>>> getProfileMap() {
+ return mProfileMap;
+ }
+
+ /**
+ * Return a list of color spaces that are compatible with an ImageFormat. If ImageFormat.UNKNOWN
+ * is provided, this function will return a set of all unique color spaces supported by the
+ * device, regardless of image format.
+ *
+ * Color spaces which are compatible with ImageFormat.PRIVATE are able to be used with
+ * SurfaceView, SurfaceTexture, MediaCodec and MediaRecorder.
+ *
+ * @return set of color spaces
+ * @see SessionConfiguration#setColorSpace
+ * @see ColorSpace.Named
+ */
+ public @NonNull Set<ColorSpace.Named> getSupportedColorSpaces(
+ @ImageFormat.Format int imageFormat) {
+ ArraySet<ColorSpace.Named> supportedColorSpaceProfiles = new ArraySet<>();
+ for (ColorSpace.Named colorSpace : mProfileMap.keySet()) {
+ if (imageFormat == ImageFormat.UNKNOWN) {
+ supportedColorSpaceProfiles.add(colorSpace);
+ } else {
+ Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace);
+ if (imageFormatMap.containsKey(imageFormat)) {
+ supportedColorSpaceProfiles.add(colorSpace);
+ }
+ }
+ }
+ return supportedColorSpaceProfiles;
+ }
+
+ /**
+ * Return a list of image formats that are compatible with a color space.
+ *
+ * Color spaces which are compatible with ImageFormat.PRIVATE are able to be used with
+ * SurfaceView, SurfaceTexture, MediaCodec and MediaRecorder.
+ *
+ * @return set of image formats
+ * @see SessionConfiguration#setColorSpace
+ * @see ColorSpace.Named
+ */
+ public @NonNull Set<Integer> getSupportedImageFormatsForColorSpace(
+ @NonNull ColorSpace.Named colorSpace) {
+ Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace);
+ if (imageFormatMap == null) {
+ return new ArraySet<Integer>();
+ }
+
+ return imageFormatMap.keySet();
+ }
+
+ /**
+ * Return a list of dynamic range profiles that are compatible with a color space and
+ * ImageFormat. If ImageFormat.UNKNOWN is provided, this function will return a set of
+ * all unique dynamic range profiles supported by the device given a color space,
+ * regardless of image format.
+ *
+ * @return set of dynamic range profiles.
+ * @see OutputConfiguration#setDynamicRangeProfile
+ * @see SessionConfiguration#setColorSpace
+ * @see ColorSpace.Named
+ * @see DynamicRangeProfiles.Profile
+ */
+ public @NonNull Set<Long> getSupportedDynamicRangeProfiles(@NonNull ColorSpace.Named colorSpace,
+ @ImageFormat.Format int imageFormat) {
+ Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace);
+ if (imageFormatMap == null) {
+ return new ArraySet<Long>();
+ }
+
+ Set<Long> dynamicRangeProfiles = null;
+ if (imageFormat == ImageFormat.UNKNOWN) {
+ dynamicRangeProfiles = new ArraySet<>();
+ for (int supportedImageFormat : imageFormatMap.keySet()) {
+ Set<Long> supportedDynamicRangeProfiles = imageFormatMap.get(
+ supportedImageFormat);
+ for (Long supportedDynamicRangeProfile : supportedDynamicRangeProfiles) {
+ dynamicRangeProfiles.add(supportedDynamicRangeProfile);
+ }
+ }
+ } else {
+ dynamicRangeProfiles = imageFormatMap.get(imageFormat);
+ if (dynamicRangeProfiles == null) {
+ return new ArraySet<>();
+ }
+ }
+
+ return dynamicRangeProfiles;
+ }
+
+ /**
+ * Return a list of color spaces that are compatible with an ImageFormat and a dynamic range
+ * profile. If ImageFormat.UNKNOWN is provided, this function will return a set of all unique
+ * color spaces compatible with the given dynamic range profile, regardless of image format.
+ *
+ * @return set of color spaces
+ * @see SessionConfiguration#setColorSpace
+ * @see OutputConfiguration#setDynamicRangeProfile
+ * @see ColorSpace.Named
+ * @see DynamicRangeProfiles.Profile
+ */
+ public @NonNull Set<ColorSpace.Named> getSupportedColorSpacesForDynamicRange(
+ @ImageFormat.Format int imageFormat,
+ @DynamicRangeProfiles.Profile long dynamicRangeProfile) {
+ ArraySet<ColorSpace.Named> supportedColorSpaceProfiles = new ArraySet<>();
+ for (ColorSpace.Named colorSpace : mProfileMap.keySet()) {
+ Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace);
+ if (imageFormat == ImageFormat.UNKNOWN) {
+ for (int supportedImageFormat : imageFormatMap.keySet()) {
+ Set<Long> dynamicRangeProfiles = imageFormatMap.get(supportedImageFormat);
+ if (dynamicRangeProfiles.contains(dynamicRangeProfile)) {
+ supportedColorSpaceProfiles.add(colorSpace);
+ }
+ }
+ } else if (imageFormatMap.containsKey(imageFormat)) {
+ Set<Long> dynamicRangeProfiles = imageFormatMap.get(imageFormat);
+ if (dynamicRangeProfiles.contains(dynamicRangeProfile)) {
+ supportedColorSpaceProfiles.add(colorSpace);
+ }
+ }
+ }
+ return supportedColorSpaceProfiles;
+ }
+}
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 90e92db..a0d8f8d 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -22,7 +22,10 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.graphics.ColorSpace;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -30,7 +33,6 @@
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;
@@ -454,7 +456,7 @@
* {@link android.media.MediaCodec} etc.)
* or {@link ImageFormat#YCBCR_P010}.</p>
*/
- public void setDynamicRangeProfile(@Profile long profile) {
+ public void setDynamicRangeProfile(@DynamicRangeProfiles.Profile long profile) {
mDynamicRangeProfile = profile;
}
@@ -463,11 +465,54 @@
*
* @return the currently set dynamic range profile
*/
- public @Profile long getDynamicRangeProfile() {
+ public @DynamicRangeProfiles.Profile long getDynamicRangeProfile() {
return mDynamicRangeProfile;
}
/**
+ * Set a specific device-supported color space.
+ *
+ * <p>Clients can choose from any profile advertised as supported in
+ * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}
+ * queried using {@link ColorSpaceProfiles#getSupportedColorSpaces}.
+ * When set, the colorSpace will override the default color spaces of the output targets,
+ * or the color space implied by the dataSpace passed into an {@link ImageReader}'s
+ * constructor.</p>
+ *
+ * @hide
+ */
+ @TestApi
+ public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
+ mColorSpace = colorSpace.ordinal();
+ }
+
+ /**
+ * Clear the color space, such that the default color space will be used.
+ *
+ * @hide
+ */
+ @TestApi
+ public void clearColorSpace() {
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
+ }
+
+ /**
+ * Return the current color space.
+ *
+ * @return the currently set color space
+ * @hide
+ */
+ @TestApi
+ @SuppressLint("MethodNameUnits")
+ public @Nullable ColorSpace getColorSpace() {
+ if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+ return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Create a new {@link OutputConfiguration} instance.
*
* <p>This constructor takes an argument for desired camera rotation</p>
@@ -530,6 +575,7 @@
mIsMultiResolution = false;
mSensorPixelModesUsed = new ArrayList<Integer>();
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
mMirrorMode = MIRROR_MODE_AUTO;
@@ -631,6 +677,7 @@
mIsMultiResolution = false;
mSensorPixelModesUsed = new ArrayList<Integer>();
mDynamicRangeProfile = DynamicRangeProfiles.STANDARD;
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
@@ -1079,6 +1126,7 @@
this.mIsMultiResolution = other.mIsMultiResolution;
this.mSensorPixelModesUsed = other.mSensorPixelModesUsed;
this.mDynamicRangeProfile = other.mDynamicRangeProfile;
+ this.mColorSpace = other.mColorSpace;
this.mStreamUseCase = other.mStreamUseCase;
this.mTimestampBase = other.mTimestampBase;
this.mMirrorMode = other.mMirrorMode;
@@ -1105,6 +1153,7 @@
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
long dynamicRangeProfile = source.readLong();
DynamicRangeProfiles.checkProfileValue(dynamicRangeProfile);
+ int colorSpace = source.readInt();
int timestampBase = source.readInt();
int mirrorMode = source.readInt();
@@ -1132,6 +1181,7 @@
mIsMultiResolution = isMultiResolutionOutput;
mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed);
mDynamicRangeProfile = dynamicRangeProfile;
+ mColorSpace = colorSpace;
mStreamUseCase = streamUseCase;
mTimestampBase = timestampBase;
mMirrorMode = mirrorMode;
@@ -1251,6 +1301,7 @@
// writeList doesn't seem to work well with Integer list.
dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
dest.writeLong(mDynamicRangeProfile);
+ dest.writeInt(mColorSpace);
dest.writeLong(mStreamUseCase);
dest.writeInt(mTimestampBase);
dest.writeInt(mMirrorMode);
@@ -1305,6 +1356,9 @@
if (mDynamicRangeProfile != other.mDynamicRangeProfile) {
return false;
}
+ if (mColorSpace != other.mColorSpace) {
+ return false;
+ }
return true;
}
@@ -1325,7 +1379,8 @@
mSurfaceGroupId, mSurfaceType, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile, mStreamUseCase, mTimestampBase, mMirrorMode);
+ mDynamicRangeProfile, mColorSpace, mStreamUseCase,
+ mTimestampBase, mMirrorMode);
}
return HashCodeHelpers.hashCode(
@@ -1334,7 +1389,7 @@
mConfiguredDataspace, mSurfaceGroupId, mIsShared ? 1 : 0,
mPhysicalCameraId == null ? 0 : mPhysicalCameraId.hashCode(),
mIsMultiResolution ? 1 : 0, mSensorPixelModesUsed.hashCode(),
- mDynamicRangeProfile, mStreamUseCase, mTimestampBase,
+ mDynamicRangeProfile, mColorSpace, mStreamUseCase, mTimestampBase,
mMirrorMode);
}
@@ -1369,6 +1424,8 @@
private ArrayList<Integer> mSensorPixelModesUsed;
// Dynamic range profile
private long mDynamicRangeProfile;
+ // Color space
+ private int mColorSpace;
// Stream use case
private long mStreamUseCase;
// Timestamp base
diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java
index cfb6efa..385f107 100644
--- a/core/java/android/hardware/camera2/params/SessionConfiguration.java
+++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java
@@ -23,6 +23,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.graphics.ColorSpace;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
@@ -30,6 +32,7 @@
import android.hardware.camera2.params.InputConfiguration;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.media.ImageReader;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -94,6 +97,7 @@
private Executor mExecutor = null;
private InputConfiguration mInputConfig = null;
private CaptureRequest mSessionParameters = null;
+ private int mColorSpace;
/**
* Create a new {@link SessionConfiguration}.
@@ -314,4 +318,45 @@
public CaptureRequest getSessionParameters() {
return mSessionParameters;
}
+
+ /**
+ * Set a specific device-supported color space.
+ *
+ * <p>Clients can choose from any profile advertised as supported in
+ * {@link CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}
+ * queried using {@link ColorSpaceProfiles#getSupportedColorSpaces}.
+ * When set, the colorSpace will override the default color spaces of the output targets,
+ * or the color space implied by the dataSpace passed into an {@link ImageReader}'s
+ * constructor.</p>
+ */
+ public void setColorSpace(@NonNull ColorSpace.Named colorSpace) {
+ mColorSpace = colorSpace.ordinal();
+ for (OutputConfiguration outputConfiguration : mOutputConfigurations) {
+ outputConfiguration.setColorSpace(colorSpace);
+ }
+ }
+
+ /**
+ * Clear the color space, such that the default color space will be used.
+ */
+ public void clearColorSpace() {
+ mColorSpace = ColorSpaceProfiles.UNSPECIFIED;
+ for (OutputConfiguration outputConfiguration : mOutputConfigurations) {
+ outputConfiguration.clearColorSpace();
+ }
+ }
+
+ /**
+ * Return the current color space.
+ *
+ * @return the currently set color space
+ */
+ @SuppressLint("MethodNameUnits")
+ public @Nullable ColorSpace getColorSpace() {
+ if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) {
+ return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]);
+ } else {
+ return null;
+ }
+ }
}
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 38d74e4..205e806 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -67,4 +67,6 @@
optional int64 dynamic_range_profile = 14;
// The stream use case
optional int64 stream_use_case = 15;
+ // The color space of the stream
+ optional int32 color_space = 16;
}