From f665d50639cd8dafafe0d2a6784595768755bcc1 Mon Sep 17 00:00:00 2001 From: Austin Borger Date: Fri, 15 Jul 2022 11:27:37 -0700 Subject: 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 --- core/api/current.txt | 14 ++ core/api/test-current.txt | 14 ++ core/java/android/hardware/CameraStreamStats.java | 12 +- .../hardware/camera2/CameraCharacteristics.java | 78 +++++++ .../android/hardware/camera2/CameraMetadata.java | 30 +++ .../camera2/impl/CameraMetadataNative.java | 21 ++ .../camera2/params/ColorSpaceProfiles.java | 257 +++++++++++++++++++++ .../camera2/params/OutputConfiguration.java | 67 +++++- .../camera2/params/SessionConfiguration.java | 45 ++++ proto/src/camera.proto | 2 + 10 files changed, 534 insertions(+), 6 deletions(-) create mode 100644 core/java/android/hardware/camera2/params/ColorSpaceProfiles.java diff --git a/core/api/current.txt b/core/api/current.txt index 74ff6726cad2..bcce8bf83824 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -17626,6 +17626,7 @@ 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_COLOR_SPACE_PROFILES; 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; @@ -17989,6 +17990,7 @@ package android.hardware.camera2 { 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 @@ package android.hardware.camera2.params { method @NonNull public android.util.Range getZoomRatioRange(); } + public final class ColorSpaceProfiles { + ctor public ColorSpaceProfiles(@NonNull long[]); + method @NonNull public java.util.Set getSupportedColorSpaces(int); + method @NonNull public java.util.Set getSupportedColorSpacesForDynamicRange(int, long); + method @NonNull public java.util.Set getSupportedDynamicRangeProfiles(@NonNull android.graphics.ColorSpace.Named, int); + method @NonNull public java.util.Set 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 @@ package android.hardware.camera2.params { public final class SessionConfiguration implements android.os.Parcelable { ctor public SessionConfiguration(int, @NonNull java.util.List, @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 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 1e4023eeee18..2602e7887edf 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1170,6 +1170,20 @@ package android.hardware.camera2 { } +package android.hardware.camera2.params { + + public final class ColorSpaceProfiles { + method @NonNull public java.util.Map>> 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 3952467324fe..aed5a129bd0b 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 @@ public class CameraStreamStats implements Parcelable { private long[] mHistogramCounts; private long mDynamicRangeProfile; private long mStreamUseCase; + private int mColorSpace; private static final String TAG = "CameraStreamStats"; @@ -68,12 +70,13 @@ public class CameraStreamStats implements Parcelable { 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 @@ public class CameraStreamStats implements Parcelable { mHistogramType = HISTOGRAM_TYPE_UNKNOWN; mDynamicRangeProfile = dynamicRangeProfile; mStreamUseCase = streamUseCase; + mColorSpace = colorSpace; } public static final @android.annotation.NonNull Parcelable.Creator CREATOR = @@ -136,6 +140,7 @@ public class CameraStreamStats implements Parcelable { dest.writeLongArray(mHistogramCounts); dest.writeLong(mDynamicRangeProfile); dest.writeLong(mStreamUseCase); + dest.writeInt(mColorSpace); } public void readFromParcel(Parcel in) { @@ -155,6 +160,7 @@ public class CameraStreamStats implements Parcelable { mHistogramCounts = in.createLongArray(); mDynamicRangeProfile = in.readLong(); mStreamUseCase = in.readLong(); + mColorSpace = in.readInt(); } public int getWidth() { @@ -217,6 +223,10 @@ public class CameraStreamStats implements Parcelable { 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 8873807b7a98..f63472680bb0 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2224,6 +2224,7 @@ public final class CameraCharacteristics extends CameraMetadata{@link #REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING REMOSAIC_REPROCESSING} *
  • {@link #REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT DYNAMIC_RANGE_TEN_BIT}
  • *
  • {@link #REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE STREAM_USE_CASE}
  • + *
  • {@link #REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES COLOR_SPACE_PROFILES}
  • * * *

    This key is available on all devices.

    @@ -2249,6 +2250,7 @@ public final class CameraCharacteristics extends CameraMetadata REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE = new Key("android.request.recommendedTenBitDynamicRangeProfile", long.class); + /** + *

    An interface for querying the color space profiles supported by a camera device.

    + *

    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 }.

    + *

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

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

    A list of all possible color space profiles supported by a camera device.

    + *

    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.

    + *

    Possible values:

    + *
      + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED UNSPECIFIED}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB SRGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_SRGB LINEAR_SRGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_EXTENDED_SRGB EXTENDED_SRGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_LINEAR_EXTENDED_SRGB LINEAR_EXTENDED_SRGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT709 BT709}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020 BT2020}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DCI_P3 DCI_P3}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3 DISPLAY_P3}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_NTSC_1953 NTSC_1953}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SMPTE_C SMPTE_C}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ADOBE_RGB ADOBE_RGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_PRO_PHOTO_RGB PRO_PHOTO_RGB}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACES ACES}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_ACESCG ACESCG}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_XYZ CIE_XYZ}
    • + *
    • {@link #REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_CIE_LAB CIE_LAB}
    • + *
    + * + *

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

    + * @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 REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP = + new Key("android.request.availableColorSpaceProfilesMap", long[].class); + /** *

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

    diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index c67a560b5885..1e1d44368713 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1257,6 +1257,24 @@ public abstract class CameraMetadata { */ public static final int REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19; + /** + *

    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 }.

    + *

    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.

    + * @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 // @@ -1366,6 +1384,18 @@ public abstract class CameraMetadata { */ public static final int REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000; + // + // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP + // + + /** + *

    Default value, when not explicitly specified. The Camera device will choose the color + * space to employ.

    + * @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 ee12df547291..012fad52fddf 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.MarshalQueryableStreamConfiguration 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; @@ -812,6 +813,15 @@ public class CameraMetadataNative implements Parcelable { return (T) metadata.getDynamicRangeProfiles(); } }); + sGetCommandMap.put( + CameraCharacteristics.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public T getValue(CameraMetadataNative metadata, Key key) { + return (T) metadata.getColorSpaceProfiles(); + } + }); sGetCommandMap.put( CaptureResult.STATISTICS_OIS_SAMPLES.getNativeKey(), new GetCommand() { @@ -1068,6 +1078,17 @@ public class CameraMetadataNative implements Parcelable { 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 000000000000..2e3af80f9cc0 --- /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. + * + *

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

    + * + *

    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}

    + * + * @see SessionConfiguration#setColorSpace + */ +public final class ColorSpaceProfiles { + /* + * @hide + */ + public static final int UNSPECIFIED = + CameraMetadata.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED; + + private final Map>> mProfileMap = new ArrayMap<>(); + + /** + * Create a new immutable ColorSpaceProfiles 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_COLOR_SPACE_PROFILES}. + * for a given camera id in order to retrieve the device capabilities.

    + * + * @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> imageFormatMap = new ArrayMap<>(); + mProfileMap.put(namedColorSpace, imageFormatMap); + } + + if (!mProfileMap.get(namedColorSpace).containsKey(imageFormat)) { + ArraySet 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>> 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 getSupportedColorSpaces( + @ImageFormat.Format int imageFormat) { + ArraySet supportedColorSpaceProfiles = new ArraySet<>(); + for (ColorSpace.Named colorSpace : mProfileMap.keySet()) { + if (imageFormat == ImageFormat.UNKNOWN) { + supportedColorSpaceProfiles.add(colorSpace); + } else { + Map> 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 getSupportedImageFormatsForColorSpace( + @NonNull ColorSpace.Named colorSpace) { + Map> imageFormatMap = mProfileMap.get(colorSpace); + if (imageFormatMap == null) { + return new ArraySet(); + } + + 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 getSupportedDynamicRangeProfiles(@NonNull ColorSpace.Named colorSpace, + @ImageFormat.Format int imageFormat) { + Map> imageFormatMap = mProfileMap.get(colorSpace); + if (imageFormatMap == null) { + return new ArraySet(); + } + + Set dynamicRangeProfiles = null; + if (imageFormat == ImageFormat.UNKNOWN) { + dynamicRangeProfiles = new ArraySet<>(); + for (int supportedImageFormat : imageFormatMap.keySet()) { + Set 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 getSupportedColorSpacesForDynamicRange( + @ImageFormat.Format int imageFormat, + @DynamicRangeProfiles.Profile long dynamicRangeProfile) { + ArraySet supportedColorSpaceProfiles = new ArraySet<>(); + for (ColorSpace.Named colorSpace : mProfileMap.keySet()) { + Map> imageFormatMap = mProfileMap.get(colorSpace); + if (imageFormat == ImageFormat.UNKNOWN) { + for (int supportedImageFormat : imageFormatMap.keySet()) { + Set dynamicRangeProfiles = imageFormatMap.get(supportedImageFormat); + if (dynamicRangeProfiles.contains(dynamicRangeProfile)) { + supportedColorSpaceProfiles.add(colorSpace); + } + } + } else if (imageFormatMap.containsKey(imageFormat)) { + Set 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 90e92dbe2ab0..a0d8f8db6853 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -22,7 +22,10 @@ import static com.android.internal.util.Preconditions.*; 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.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; @@ -454,7 +456,7 @@ public final class OutputConfiguration implements Parcelable { * {@link android.media.MediaCodec} etc.) * or {@link ImageFormat#YCBCR_P010}.

    */ - public void setDynamicRangeProfile(@Profile long profile) { + public void setDynamicRangeProfile(@DynamicRangeProfiles.Profile long profile) { mDynamicRangeProfile = profile; } @@ -463,10 +465,53 @@ public final class OutputConfiguration implements Parcelable { * * @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. + * + *

    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.

    + * + * @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. * @@ -530,6 +575,7 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList(); 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 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = false; mSensorPixelModesUsed = new ArrayList(); mDynamicRangeProfile = DynamicRangeProfiles.STANDARD; + mColorSpace = ColorSpaceProfiles.UNSPECIFIED; mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT; } @@ -1079,6 +1126,7 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { mIsMultiResolution = isMultiResolutionOutput; mSensorPixelModesUsed = convertIntArrayToIntegerList(sensorPixelModesUsed); mDynamicRangeProfile = dynamicRangeProfile; + mColorSpace = colorSpace; mStreamUseCase = streamUseCase; mTimestampBase = timestampBase; mMirrorMode = mirrorMode; @@ -1251,6 +1301,7 @@ public final class OutputConfiguration implements Parcelable { // 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 @@ public final class OutputConfiguration implements Parcelable { if (mDynamicRangeProfile != other.mDynamicRangeProfile) { return false; } + if (mColorSpace != other.mColorSpace) { + return false; + } return true; } @@ -1325,7 +1379,8 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { 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 @@ public final class OutputConfiguration implements Parcelable { private ArrayList 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 cfb6efa9ba3c..385f10719509 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.CallbackExecutor; 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.CaptureRequest; 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 @@ public final class SessionConfiguration implements Parcelable { 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 final class SessionConfiguration implements Parcelable { public CaptureRequest getSessionParameters() { return mSessionParameters; } + + /** + * Set a specific device-supported color space. + * + *

    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.

    + */ + 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 38d74e4a73ce..205e806f534d 100644 --- a/proto/src/camera.proto +++ b/proto/src/camera.proto @@ -67,4 +67,6 @@ message CameraStreamProto { 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; } -- cgit v1.2.3-59-g8ed1b