1 /* 2 * Copyright (C) 2021 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.LongDef; 20 import android.annotation.NonNull; 21 22 import android.hardware.camera2.CameraMetadata; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 import java.util.Collections; 28 import java.util.HashMap; 29 import java.util.HashSet; 30 import java.util.Set; 31 32 /** 33 * Immutable class with information about supported 10-bit dynamic range profiles. 34 * 35 * <p>An instance of this class can be queried by retrieving the value of 36 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. 37 * </p> 38 * 39 * <p>All camera devices supporting the 40 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT} 41 * capability must advertise the supported 10-bit dynamic range profiles in 42 * {@link #getSupportedProfiles}</p> 43 * 44 * <p>Some devices may not be able to support 8-bit and/or 10-bit output with different dynamic 45 * range profiles within the same capture request. Such device specific constraints can be queried 46 * by calling {@link #getProfileCaptureRequestConstraints}. Do note that unsupported 47 * combinations will result in {@link IllegalArgumentException} when trying to submit a capture 48 * request. Capture requests that only reference outputs configured using the same dynamic range 49 * profile value will never fail due to such constraints.</p> 50 * 51 * @see OutputConfiguration#setDynamicRangeProfile 52 */ 53 public final class DynamicRangeProfiles { 54 /** 55 * This the default 8-bit standard profile that will be used in case where camera clients do not 56 * explicitly configure a supported dynamic range profile by calling 57 * {@link OutputConfiguration#setDynamicRangeProfile}. 58 */ 59 public static final long STANDARD = 60 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD; 61 62 /** 63 * 10-bit pixel samples encoded using the Hybrid log-gamma transfer function 64 * 65 * <p>All 10-bit output capable devices are required to support this profile.</p> 66 */ 67 public static final long HLG10 = 68 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10; 69 70 /** 71 * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. 72 * 73 * <p>This profile utilizes internal static metadata to increase the quality 74 * of the capture.</p> 75 */ 76 public static final long HDR10 = 77 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10; 78 79 /** 80 * 10-bit pixel samples encoded using the SMPTE ST 2084 transfer function. 81 * 82 * <p>In contrast to HDR10, this profile uses internal per-frame metadata 83 * to further enhance the quality of the capture.</p> 84 */ 85 public static final long HDR10_PLUS = 86 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS; 87 88 /** 89 * <p>This is a camera mode for Dolby Vision capture optimized for a more scene 90 * accurate capture. This would typically differ from what a specific device 91 * might want to tune for a consumer optimized Dolby Vision general capture.</p> 92 */ 93 public static final long DOLBY_VISION_10B_HDR_REF = 94 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF; 95 96 /** 97 * <p>This is the power optimized mode for 10-bit Dolby Vision HDR Reference Mode.</p> 98 */ 99 public static final long DOLBY_VISION_10B_HDR_REF_PO = 100 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO; 101 102 /** 103 * <p>This is the camera mode for the default Dolby Vision capture mode for the 104 * specific device. This would be tuned by each specific device for consumer 105 * pleasing results that resonate with their particular audience. We expect 106 * that each specific device would have a different look for their default 107 * Dolby Vision capture.</p> 108 */ 109 public static final long DOLBY_VISION_10B_HDR_OEM = 110 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM; 111 112 /** 113 * <p>This is the power optimized mode for 10-bit Dolby Vision HDR device specific capture 114 * Mode.</p> 115 */ 116 public static final long DOLBY_VISION_10B_HDR_OEM_PO = 117 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO; 118 119 /** 120 * <p>This is the 8-bit version of the Dolby Vision reference capture mode optimized 121 * for scene accuracy.</p> 122 */ 123 public static final long DOLBY_VISION_8B_HDR_REF = 124 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF; 125 126 /** 127 * <p>This is the power optimized mode for 8-bit Dolby Vision HDR Reference Mode.</p> 128 */ 129 public static final long DOLBY_VISION_8B_HDR_REF_PO = 130 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO; 131 132 /** 133 * <p>This is the 8-bit version of device specific tuned and optimized Dolby Vision 134 * capture mode.</p> 135 */ 136 public static final long DOLBY_VISION_8B_HDR_OEM = 137 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM; 138 139 /** 140 * <p>This is the power optimized mode for 8-bit Dolby Vision HDR device specific 141 * capture Mode.</p> 142 */ 143 public static final long DOLBY_VISION_8B_HDR_OEM_PO = 144 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO; 145 146 /* 147 * @hide 148 */ 149 public static final long PUBLIC_MAX = 150 CameraMetadata.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX; 151 152 /** @hide */ 153 @Retention(RetentionPolicy.SOURCE) 154 @LongDef(prefix = {"PROFILE_"}, value = 155 {STANDARD, 156 HLG10, 157 HDR10, 158 HDR10_PLUS, 159 DOLBY_VISION_10B_HDR_REF, 160 DOLBY_VISION_10B_HDR_REF_PO, 161 DOLBY_VISION_10B_HDR_OEM, 162 DOLBY_VISION_10B_HDR_OEM_PO, 163 DOLBY_VISION_8B_HDR_REF, 164 DOLBY_VISION_8B_HDR_REF_PO, 165 DOLBY_VISION_8B_HDR_OEM, 166 DOLBY_VISION_8B_HDR_OEM_PO}) 167 public @interface Profile { 168 } 169 170 private final HashMap<Long, Set<Long>> mProfileMap = new HashMap<>(); 171 private final HashMap<Long, Boolean> mLookahedLatencyMap = new HashMap<>(); 172 173 /** 174 * Create a new immutable DynamicRangeProfiles instance. 175 * 176 * <p>This constructor takes over the array; do not write to the array afterwards.</p> 177 * 178 * <p>Do note that the constructor is available for testing purposes only! 179 * Camera clients must always retrieve the value of 180 * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES}. 181 * for a given camera id in order to retrieve the device capabilities.</p> 182 * 183 * @param elements 184 * An array of elements describing the map. It contains two elements per entry which 185 * describe the supported dynamic range profile value in the first element and in the 186 * second element a bitmap of concurrently supported dynamic range profiles within the 187 * same capture request. Bitmap values of 0 indicate that there are no constraints. 188 * 189 * @throws IllegalArgumentException 190 * if the {@code elements} array length is invalid, not divisible by 2 or contains 191 * invalid element values 192 * @throws NullPointerException 193 * if {@code elements} is {@code null} 194 * 195 */ DynamicRangeProfiles(@onNull final long[] elements)196 public DynamicRangeProfiles(@NonNull final long[] elements) { 197 if ((elements.length % 3) != 0) { 198 throw new IllegalArgumentException("Dynamic range profile map length " + 199 elements.length + " is not even!"); 200 } 201 202 for (int i = 0; i < elements.length; i += 3) { 203 checkProfileValue(elements[i]); 204 // STANDARD is not expected to be included 205 if (elements[i] == STANDARD) { 206 throw new IllegalArgumentException("Dynamic range profile map must not include a" 207 + " STANDARD profile entry!"); 208 } 209 HashSet<Long> profiles = new HashSet<>(); 210 211 if (elements[i+1] != 0) { 212 for (long profile = STANDARD; profile < PUBLIC_MAX; profile <<= 1) { 213 if ((elements[i+1] & profile) != 0) { 214 profiles.add(profile); 215 } 216 } 217 } 218 219 mProfileMap.put(elements[i], profiles); 220 mLookahedLatencyMap.put(elements[i], elements[i+2] != 0L); 221 } 222 223 // Build the STANDARD constraints depending on the advertised 10-bit limitations 224 HashSet<Long> standardConstraints = new HashSet<>(); 225 standardConstraints.add(STANDARD); 226 for(Long profile : mProfileMap.keySet()) { 227 if (mProfileMap.get(profile).isEmpty() || mProfileMap.get(profile).contains(STANDARD)) { 228 standardConstraints.add(profile); 229 } 230 } 231 232 mProfileMap.put(STANDARD, standardConstraints); 233 mLookahedLatencyMap.put(STANDARD, false); 234 } 235 236 237 /** 238 * @hide 239 */ checkProfileValue(long profile)240 public static void checkProfileValue(long profile) { 241 if (profile == STANDARD || profile == HLG10 || profile == HDR10 || profile == HDR10_PLUS 242 || profile == DOLBY_VISION_10B_HDR_REF || profile == DOLBY_VISION_10B_HDR_REF_PO 243 || profile == DOLBY_VISION_10B_HDR_OEM || profile == DOLBY_VISION_10B_HDR_OEM_PO 244 || profile == DOLBY_VISION_8B_HDR_REF || profile == DOLBY_VISION_8B_HDR_REF_PO 245 || profile == DOLBY_VISION_8B_HDR_OEM 246 || profile == DOLBY_VISION_8B_HDR_OEM_PO) {//No-op 247 } else { 248 throw new IllegalArgumentException("Unknown profile " + profile); 249 } 250 } 251 252 /** 253 * Return a set of supported dynamic range profiles. 254 * 255 * @return non-modifiable set of dynamic range profiles 256 */ getSupportedProfiles()257 public @NonNull Set<Long> getSupportedProfiles() { 258 return Collections.unmodifiableSet(mProfileMap.keySet()); 259 } 260 261 /** 262 * Return a list of supported dynamic range profiles that 263 * can be referenced in a single capture request along with a given 264 * profile. 265 * 266 * <p>For example if assume that a particular 10-bit output capable device 267 * returns ({@link #STANDARD}, {@link #HLG10}, {@link #HDR10}) as result from calling 268 * {@link #getSupportedProfiles()} and {@link #getProfileCaptureRequestConstraints} 269 * returns ({@link #STANDARD}, {@link #HLG10}) when given an argument of {@link #STANDARD}. 270 * This means that the corresponding camera device will only accept and process capture requests 271 * that reference outputs configured using {@link #HDR10} dynamic profile or alternatively 272 * some combination of {@link #STANDARD} and {@link #HLG10}. However trying to 273 * queue capture requests to outputs that reference both {@link #HDR10} and 274 * {@link #STANDARD}/{@link #HLG10} will result in {@link IllegalArgumentException}.</p> 275 * 276 * <p>The list will be empty in case there are no constraints for the given 277 * profile.</p> 278 * 279 * @return non-modifiable set of dynamic range profiles 280 * @throws IllegalArgumentException If the profile argument is not 281 * within the list returned by 282 * getSupportedProfiles() 283 * 284 * @see OutputConfiguration#setDynamicRangeProfile 285 */ getProfileCaptureRequestConstraints(@rofile long profile)286 public @NonNull Set<Long> getProfileCaptureRequestConstraints(@Profile long profile) { 287 Set<Long> ret = mProfileMap.get(profile); 288 if (ret == null) { 289 throw new IllegalArgumentException("Unsupported profile!"); 290 } 291 292 return Collections.unmodifiableSet(ret); 293 } 294 295 /** 296 * Check whether a given dynamic range profile is suitable for latency sensitive use cases. 297 * 298 * <p>Due to internal lookahead logic, camera outputs configured with some dynamic range 299 * profiles may experience additional latency greater than 3 buffers. Using camera outputs 300 * with such profiles for latency sensitive use cases such as camera preview is not 301 * recommended. Profiles that have such extra streaming delay are typically utilized for 302 * scenarios such as offscreen video recording.</p> 303 * 304 * @return true if the given profile is not suitable for latency sensitive use cases, false 305 * otherwise 306 * @throws IllegalArgumentException If the profile argument is not 307 * within the list returned by 308 * getSupportedProfiles() 309 * 310 * @see OutputConfiguration#setDynamicRangeProfile 311 */ isExtraLatencyPresent(@rofile long profile)312 public boolean isExtraLatencyPresent(@Profile long profile) { 313 Boolean ret = mLookahedLatencyMap.get(profile); 314 if (ret == null) { 315 throw new IllegalArgumentException("Unsupported profile!"); 316 } 317 318 return ret; 319 } 320 } 321