1 /* 2 * Copyright 2023 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 androidx.camera.core.resolutionselector; 18 19 import static androidx.camera.core.resolutionselector.AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY; 20 21 import androidx.annotation.IntDef; 22 import androidx.annotation.RestrictTo; 23 import androidx.camera.core.UseCase; 24 import androidx.camera.core.UseCaseGroup; 25 import androidx.camera.core.ViewPort; 26 27 import org.jspecify.annotations.NonNull; 28 import org.jspecify.annotations.Nullable; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * A set of requirements and priorities used to select a resolution for the {@link UseCase}. 35 * 36 * <p>The resolution selection mechanism is determined by the following three steps: 37 * <ol> 38 * <li> Collect the supported output sizes and add them to the candidate resolution list. 39 * <li> Filter and sort the candidate resolution list according to the {@link Builder} 40 * resolution settings. 41 * <li> Consider all the resolution selector settings of bound {@link UseCase}s to find the 42 * resolution that best suits each {@link UseCase}. 43 * </ol> 44 * 45 * <p>For the first step, all supported resolution output sizes are added to the candidate 46 * resolution list as the starting point. 47 * 48 * <p>ResolutionSelector provides the following function for applications to adjust the candidate 49 * resolution settings. 50 * <ul> 51 * <li> {@link Builder#setAllowedResolutionMode(int)} 52 * </ul> 53 * 54 * <p>For the second step, ResolutionSelector provides the following three functions for 55 * applications to determine which resolution should be selected with higher priority. 56 * <ul> 57 * <li> {@link Builder#setAspectRatioStrategy(AspectRatioStrategy)} 58 * <li> {@link Builder#setResolutionStrategy(ResolutionStrategy)} 59 * <li> {@link Builder#setResolutionFilter(ResolutionFilter)} 60 * </ul> 61 * 62 * <p>CameraX sorts the collected sizes according to the specified aspect ratio and resolution 63 * strategies. The aspect ratio strategy has precedence over the resolution strategy for sorting 64 * the resolution candidate list. If applications specify a custom resolution filter, CameraX 65 * passes the resulting sizes list, sorted by the specified aspect ratio and resolution 66 * strategies, to the resolution filter to get the final desired list. 67 * 68 * <p>Different types of {@link UseCase}s might have their own default settings. You can see the 69 * {@link UseCase} builders’ {@code setResolutionSelector()} function to know the details for each 70 * type of {@link UseCase}. 71 * 72 * <p>In the third step, CameraX selects the final resolution for the {@link UseCase} based on the 73 * camera device's hardware level, capabilities, and the bound {@link UseCase} combination. 74 * Applications can check which resolution is finally selected by using the {@link UseCase}'s 75 * {@code getResolutionInfo()} function. 76 * 77 * <p>Note that a ResolutionSelector with more restricted settings may result in that no 78 * resolution can be selected to use. Applications will receive {@link IllegalArgumentException} 79 * when binding the {@link UseCase}s with such kind of ResolutionSelector. Applications can 80 * specify the {@link AspectRatioStrategy} and {@link ResolutionStrategy} with proper fallback 81 * rules to avoid the {@link IllegalArgumentException} or try-catch it and show a proper message 82 * to the end users. 83 * 84 * <p>When creating a ResolutionSelector instance, the 85 * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be the default 86 * {@link AspectRatioStrategy} if it is not set. 87 * {@link ResolutionSelector#PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION} is the default allowed 88 * resolution mode. However, if neither the {@link ResolutionStrategy} nor the 89 * {@link ResolutionFilter} are set, there will be no default value specified. 90 */ 91 public final class ResolutionSelector { 92 /** 93 * This mode allows CameraX to select the normal output sizes on the camera device. 94 * 95 * <p>The available resolutions for this mode are obtained from the 96 * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(int)} method 97 * from the stream configuration map obtained with the 98 * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} 99 * camera characteristics. 100 */ 101 public static final int PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION = 0; 102 /** 103 * This mode allows CameraX to select the output sizes which might result in slower capture 104 * times. 105 * 106 * <p>The available resolutions for this mode are obtained from the 107 * {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(int)} and 108 * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)} 109 * methods from the stream configuration map obtained with the 110 * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP} 111 * camera characteristics. However, please note that using a resolution obtained from the 112 * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)} 113 * may result in slower capture times. Please see the javadoc of 114 * {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)} 115 * for more details. 116 * 117 * <p>Since Android 12, some devices might support a maximum resolution sensor pixel mode, 118 * which allows them to capture additional ultra high resolutions retrieved from 119 * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION} 120 * . This mode does not allow applications to select those ultra high resolutions. 121 */ 122 public static final int PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE = 1; 123 124 @IntDef({PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION, 125 PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE}) 126 @Retention(RetentionPolicy.SOURCE) 127 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 128 public @interface AllowedResolutionMode { 129 } 130 private final @NonNull AspectRatioStrategy mAspectRatioStrategy; 131 private final @Nullable ResolutionStrategy mResolutionStrategy; 132 private final @Nullable ResolutionFilter mResolutionFilter; 133 @AllowedResolutionMode 134 private final int mAllowedResolutionMode; 135 ResolutionSelector( @onNull AspectRatioStrategy aspectRatioStrategy, @Nullable ResolutionStrategy resolutionStrategy, @Nullable ResolutionFilter resolutionFilter, @AllowedResolutionMode int allowedResolutionMode)136 ResolutionSelector( 137 @NonNull AspectRatioStrategy aspectRatioStrategy, 138 @Nullable ResolutionStrategy resolutionStrategy, 139 @Nullable ResolutionFilter resolutionFilter, 140 @AllowedResolutionMode int allowedResolutionMode) { 141 mAspectRatioStrategy = aspectRatioStrategy; 142 mResolutionStrategy = resolutionStrategy; 143 mResolutionFilter = resolutionFilter; 144 mAllowedResolutionMode = allowedResolutionMode; 145 } 146 147 /** 148 * Returns the specified {@link AspectRatioStrategy}, or 149 * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} if none is specified when 150 * creating the ResolutionSelector. 151 */ getAspectRatioStrategy()152 public @NonNull AspectRatioStrategy getAspectRatioStrategy() { 153 return mAspectRatioStrategy; 154 } 155 156 /** 157 * Returns the specified {@link ResolutionStrategy}, or null if not specified. 158 */ getResolutionStrategy()159 public @Nullable ResolutionStrategy getResolutionStrategy() { 160 return mResolutionStrategy; 161 } 162 163 /** 164 * Returns the specified {@link ResolutionFilter} implementation, or null if not specified. 165 */ getResolutionFilter()166 public @Nullable ResolutionFilter getResolutionFilter() { 167 return mResolutionFilter; 168 } 169 170 /** 171 * Returns the specified allowed resolution mode. 172 */ 173 @AllowedResolutionMode getAllowedResolutionMode()174 public int getAllowedResolutionMode() { 175 return mAllowedResolutionMode; 176 } 177 178 /** 179 * Builder for a {@link ResolutionSelector}. 180 */ 181 public static final class Builder { 182 private @Nullable AspectRatioStrategy mAspectRatioStrategy = 183 RATIO_4_3_FALLBACK_AUTO_STRATEGY; 184 private @Nullable ResolutionStrategy mResolutionStrategy = null; 185 private @Nullable ResolutionFilter mResolutionFilter = null; 186 @AllowedResolutionMode 187 private int mAllowedResolutionMode = PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION; 188 189 /** 190 * Creates a Builder instance. 191 */ Builder()192 public Builder() { 193 } 194 Builder(@onNull ResolutionSelector resolutionSelector)195 private Builder(@NonNull ResolutionSelector resolutionSelector) { 196 mAspectRatioStrategy = resolutionSelector.getAspectRatioStrategy(); 197 mResolutionStrategy = resolutionSelector.getResolutionStrategy(); 198 mResolutionFilter = resolutionSelector.getResolutionFilter(); 199 mAllowedResolutionMode = resolutionSelector.getAllowedResolutionMode(); 200 } 201 202 /** 203 * Creates a Builder from an existing resolution selector. 204 */ 205 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) fromResolutionSelector( @onNull ResolutionSelector resolutionSelector)206 public static @NonNull Builder fromResolutionSelector( 207 @NonNull ResolutionSelector resolutionSelector) { 208 return new Builder(resolutionSelector); 209 } 210 211 /** 212 * Sets the aspect ratio selection strategy for the {@link UseCase}. The aspect ratio 213 * selection strategy determines how the {@link UseCase} will choose the aspect ratio of 214 * the captured image. 215 * 216 * <p>If the aspect ratio strategy is not specified, 217 * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be used as the default. 218 * 219 * <p>{@link UseCase}s can be bound by a {@link UseCaseGroup} with a {@link ViewPort} 220 * setting. If a {@link ViewPort} is set, it is recommended that the {@link ViewPort} and 221 * the bound {@link UseCase}s should have matching aspect ratio settings. Otherwise, the 222 * output crop rectangles may be double-cropped from the full camera sensor field of view. 223 * See {@link ViewPort.Builder} for details. 224 * 225 * <p>CameraX only supports the common 4:3 and 16:9 aspect ratio settings. Some devices may 226 * offer additional output sizes. To access these, you'll need to create a 227 * {@link ResolutionSelector} with a {@link ResolutionFilter} to find and select those 228 * specific sizes. 229 */ setAspectRatioStrategy( @onNull AspectRatioStrategy aspectRatioStrategy)230 public @NonNull Builder setAspectRatioStrategy( 231 @NonNull AspectRatioStrategy aspectRatioStrategy) { 232 mAspectRatioStrategy = aspectRatioStrategy; 233 return this; 234 } 235 236 /** 237 * Sets the resolution selection strategy for the {@link UseCase}. The resolution selection 238 * strategy determines how the {@link UseCase} will choose the resolution of the captured 239 * image. 240 * 241 * <p>Note: {@link ResolutionStrategy} works in conjunction with 242 * {@link AspectRatioStrategy} and the default {@link AspectRatioStrategy} is 243 * {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY}. Ensure you set a 244 * corresponding {@link AspectRatioStrategy} alongside your {@link ResolutionStrategy}. 245 * For example, if your {@link ResolutionStrategy} uses a bound size of {@code 1920x1080} 246 * and a 16:9 aspect ratio is preferred, set 247 * {@link AspectRatioStrategy#RATIO_16_9_FALLBACK_AUTO_STRATEGY} when building the 248 * {@link ResolutionSelector}. 249 * 250 * <p>CameraX only supports the common 4:3 and 16:9 aspect ratio settings. To select 251 * resolution of other aspect ratios, you'll need to create a {@link ResolutionSelector} 252 * with a {@link ResolutionFilter} to find and select those specific sizes. 253 */ setResolutionStrategy( @onNull ResolutionStrategy resolutionStrategy)254 public @NonNull Builder setResolutionStrategy( 255 @NonNull ResolutionStrategy resolutionStrategy) { 256 mResolutionStrategy = resolutionStrategy; 257 return this; 258 } 259 260 /** 261 * Sets the resolution filter to output the final desired sizes list. The resolution 262 * filter will filter out unsuitable sizes and sort the resolution list in the preferred 263 * order. The preferred order is the order in which the resolutions should be tried first. 264 */ setResolutionFilter(@onNull ResolutionFilter resolutionFilter)265 public @NonNull Builder setResolutionFilter(@NonNull ResolutionFilter resolutionFilter) { 266 mResolutionFilter = resolutionFilter; 267 return this; 268 } 269 270 /** 271 * Sets the allowed resolution mode. 272 * 273 * <p>If not specified, the default setting is 274 * {@link ResolutionSelector#PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION}. 275 */ setAllowedResolutionMode(@llowedResolutionMode int mode)276 public @NonNull Builder setAllowedResolutionMode(@AllowedResolutionMode int mode) { 277 mAllowedResolutionMode = mode; 278 return this; 279 } 280 281 /** 282 * Builds the resolution selector. This will create a resolution selector that can be 283 * used to select the desired resolution for the captured image. 284 */ build()285 public @NonNull ResolutionSelector build() { 286 return new ResolutionSelector(mAspectRatioStrategy, mResolutionStrategy, 287 mResolutionFilter, mAllowedResolutionMode); 288 } 289 } 290 } 291