1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.params; 18 19 import android.annotation.NonNull; 20 import android.annotation.TestApi; 21 import android.graphics.ColorSpace; 22 import android.graphics.ImageFormat; 23 import android.hardware.camera2.CameraMetadata; 24 import android.util.ArrayMap; 25 import android.util.ArraySet; 26 27 import java.util.Map; 28 import java.util.Set; 29 30 /** 31 * Immutable class with information about supported color space profiles. 32 * 33 * <p>An instance of this class can be queried by retrieving the value of 34 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}. 35 * </p> 36 * 37 * <p>All camera devices supporting the 38 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_COLOR_SPACE_PROFILES} 39 * capability must advertise the supported color space profiles in 40 * {@link #getSupportedColorSpaces}</p> 41 * 42 * @see SessionConfiguration#setColorSpace 43 */ 44 public final class ColorSpaceProfiles { 45 /* 46 * @hide 47 */ 48 public static final int UNSPECIFIED = 49 CameraMetadata.REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED; 50 51 private final Map<ColorSpace.Named, Map<Integer, Set<Long>>> mProfileMap = new ArrayMap<>(); 52 53 /** 54 * Create a new immutable ColorSpaceProfiles instance. 55 * 56 * <p>This constructor takes over the array; do not write to the array afterwards.</p> 57 * 58 * <p>Do note that the constructor is available for testing purposes only! 59 * Camera clients must always retrieve the value of 60 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_COLOR_SPACE_PROFILES}. 61 * for a given camera id in order to retrieve the device capabilities.</p> 62 * 63 * @param elements 64 * An array of elements describing the map. It contains three elements per entry which 65 * describe the supported color space profile value in the first element, a compatible 66 * image format in the second, and in the third element a bitmap of compatible dynamic 67 * range profiles (see {@link DynamicRangeProfiles#STANDARD} and others for the 68 * individual bitmap components). 69 * 70 * @throws IllegalArgumentException 71 * if the {@code elements} array length is invalid, not divisible by 3 or contains 72 * invalid element values 73 * @throws NullPointerException 74 * if {@code elements} is {@code null} 75 * 76 */ ColorSpaceProfiles(@onNull final long[] elements)77 public ColorSpaceProfiles(@NonNull final long[] elements) { 78 if ((elements.length % 3) != 0) { 79 throw new IllegalArgumentException("Color space profile map length " 80 + elements.length + " is not divisible by 3!"); 81 } 82 83 for (int i = 0; i < elements.length; i += 3) { 84 int colorSpace = (int) elements[i]; 85 checkProfileValue(colorSpace); 86 ColorSpace.Named namedColorSpace = ColorSpace.Named.values()[colorSpace]; 87 int imageFormat = (int) elements[i + 1]; 88 long dynamicRangeProfileBitmap = elements[i + 2]; 89 90 if (!mProfileMap.containsKey(namedColorSpace)) { 91 ArrayMap<Integer, Set<Long>> imageFormatMap = new ArrayMap<>(); 92 mProfileMap.put(namedColorSpace, imageFormatMap); 93 } 94 95 if (!mProfileMap.get(namedColorSpace).containsKey(imageFormat)) { 96 ArraySet<Long> dynamicRangeProfiles = new ArraySet<>(); 97 mProfileMap.get(namedColorSpace).put(imageFormat, dynamicRangeProfiles); 98 } 99 100 if (dynamicRangeProfileBitmap != 0) { 101 for (long dynamicRangeProfile = DynamicRangeProfiles.STANDARD; 102 dynamicRangeProfile < DynamicRangeProfiles.PUBLIC_MAX; 103 dynamicRangeProfile <<= 1) { 104 if ((dynamicRangeProfileBitmap & dynamicRangeProfile) != 0) { 105 mProfileMap.get(namedColorSpace).get(imageFormat).add(dynamicRangeProfile); 106 } 107 } 108 } 109 } 110 } 111 112 /** 113 * @hide 114 */ checkProfileValue(int colorSpace)115 public static void checkProfileValue(int colorSpace) { 116 boolean found = false; 117 for (ColorSpace.Named value : ColorSpace.Named.values()) { 118 if (colorSpace == value.ordinal()) { 119 found = true; 120 break; 121 } 122 } 123 124 if (!found) { 125 throw new IllegalArgumentException("Unknown ColorSpace " + colorSpace); 126 } 127 } 128 129 /** 130 * @hide 131 */ 132 @TestApi getProfileMap()133 public @NonNull Map<ColorSpace.Named, Map<Integer, Set<Long>>> getProfileMap() { 134 return mProfileMap; 135 } 136 137 /** 138 * Return a list of color spaces that are compatible with an ImageFormat. If ImageFormat.UNKNOWN 139 * is provided, this function will return a set of all unique color spaces supported by the 140 * device, regardless of image format. 141 * 142 * Color spaces which are compatible with ImageFormat.PRIVATE are able to be used with 143 * SurfaceView, SurfaceTexture, MediaCodec and MediaRecorder. 144 * 145 * @return set of color spaces 146 * @see SessionConfiguration#setColorSpace 147 * @see ColorSpace.Named 148 */ getSupportedColorSpaces( @mageFormat.Format int imageFormat)149 public @NonNull Set<ColorSpace.Named> getSupportedColorSpaces( 150 @ImageFormat.Format int imageFormat) { 151 ArraySet<ColorSpace.Named> supportedColorSpaceProfiles = new ArraySet<>(); 152 for (ColorSpace.Named colorSpace : mProfileMap.keySet()) { 153 if (imageFormat == ImageFormat.UNKNOWN) { 154 supportedColorSpaceProfiles.add(colorSpace); 155 } else { 156 Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace); 157 if (imageFormatMap.containsKey(imageFormat)) { 158 supportedColorSpaceProfiles.add(colorSpace); 159 } 160 } 161 } 162 return supportedColorSpaceProfiles; 163 } 164 165 /** 166 * Return a list of image formats that are compatible with a color space. 167 * 168 * Color spaces which are compatible with ImageFormat.PRIVATE are able to be used with 169 * SurfaceView, SurfaceTexture, MediaCodec and MediaRecorder. 170 * 171 * @return set of image formats 172 * @see SessionConfiguration#setColorSpace 173 * @see ColorSpace.Named 174 */ getSupportedImageFormatsForColorSpace( @onNull ColorSpace.Named colorSpace)175 public @NonNull Set<Integer> getSupportedImageFormatsForColorSpace( 176 @NonNull ColorSpace.Named colorSpace) { 177 Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace); 178 if (imageFormatMap == null) { 179 return new ArraySet<Integer>(); 180 } 181 182 return imageFormatMap.keySet(); 183 } 184 185 /** 186 * Return a list of dynamic range profiles that are compatible with a color space and 187 * ImageFormat. If ImageFormat.UNKNOWN is provided, this function will return a set of 188 * all unique dynamic range profiles supported by the device given a color space, 189 * regardless of image format. 190 * 191 * @return set of dynamic range profiles. 192 * @see OutputConfiguration#setDynamicRangeProfile 193 * @see SessionConfiguration#setColorSpace 194 * @see ColorSpace.Named 195 * @see DynamicRangeProfiles 196 */ getSupportedDynamicRangeProfiles(@onNull ColorSpace.Named colorSpace, @ImageFormat.Format int imageFormat)197 public @NonNull Set<Long> getSupportedDynamicRangeProfiles(@NonNull ColorSpace.Named colorSpace, 198 @ImageFormat.Format int imageFormat) { 199 Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace); 200 if (imageFormatMap == null) { 201 return new ArraySet<Long>(); 202 } 203 204 Set<Long> dynamicRangeProfiles = null; 205 if (imageFormat == ImageFormat.UNKNOWN) { 206 dynamicRangeProfiles = new ArraySet<>(); 207 for (int supportedImageFormat : imageFormatMap.keySet()) { 208 Set<Long> supportedDynamicRangeProfiles = imageFormatMap.get( 209 supportedImageFormat); 210 for (Long supportedDynamicRangeProfile : supportedDynamicRangeProfiles) { 211 dynamicRangeProfiles.add(supportedDynamicRangeProfile); 212 } 213 } 214 } else { 215 dynamicRangeProfiles = imageFormatMap.get(imageFormat); 216 if (dynamicRangeProfiles == null) { 217 return new ArraySet<>(); 218 } 219 } 220 221 return dynamicRangeProfiles; 222 } 223 224 /** 225 * Return a list of color spaces that are compatible with an ImageFormat and a dynamic range 226 * profile. If ImageFormat.UNKNOWN is provided, this function will return a set of all unique 227 * color spaces compatible with the given dynamic range profile, regardless of image format. 228 * 229 * @return set of color spaces 230 * @see SessionConfiguration#setColorSpace 231 * @see OutputConfiguration#setDynamicRangeProfile 232 * @see ColorSpace.Named 233 * @see DynamicRangeProfiles 234 */ getSupportedColorSpacesForDynamicRange( @mageFormat.Format int imageFormat, @DynamicRangeProfiles.Profile long dynamicRangeProfile)235 public @NonNull Set<ColorSpace.Named> getSupportedColorSpacesForDynamicRange( 236 @ImageFormat.Format int imageFormat, 237 @DynamicRangeProfiles.Profile long dynamicRangeProfile) { 238 ArraySet<ColorSpace.Named> supportedColorSpaceProfiles = new ArraySet<>(); 239 for (ColorSpace.Named colorSpace : mProfileMap.keySet()) { 240 Map<Integer, Set<Long>> imageFormatMap = mProfileMap.get(colorSpace); 241 if (imageFormat == ImageFormat.UNKNOWN) { 242 for (int supportedImageFormat : imageFormatMap.keySet()) { 243 Set<Long> dynamicRangeProfiles = imageFormatMap.get(supportedImageFormat); 244 if (dynamicRangeProfiles.contains(dynamicRangeProfile)) { 245 supportedColorSpaceProfiles.add(colorSpace); 246 } 247 } 248 } else if (imageFormatMap.containsKey(imageFormat)) { 249 Set<Long> dynamicRangeProfiles = imageFormatMap.get(imageFormat); 250 if (dynamicRangeProfiles.contains(dynamicRangeProfile)) { 251 supportedColorSpaceProfiles.add(colorSpace); 252 } 253 } 254 } 255 return supportedColorSpaceProfiles; 256 } 257 } 258