1 /* 2 * Copyright 2019 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.impl; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.graphics.ImageFormat; 22 import android.util.Pair; 23 import android.util.Size; 24 import android.view.Surface; 25 26 import androidx.annotation.IntDef; 27 import androidx.camera.core.AspectRatio; 28 import androidx.camera.core.MirrorMode; 29 import androidx.camera.core.resolutionselector.ResolutionSelector; 30 31 import org.jspecify.annotations.NonNull; 32 import org.jspecify.annotations.Nullable; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * Configuration containing options for configuring the output image data of a pipeline. 41 */ 42 public interface ImageOutputConfig extends ReadableConfig { 43 /** 44 * Invalid integer rotation. 45 */ 46 int INVALID_ROTATION = -1; 47 48 /** 49 * Rotation not specified. 50 */ 51 int ROTATION_NOT_SPECIFIED = -1; 52 53 // Option Declarations: 54 // ********************************************************************************************* 55 56 /** 57 * Option: camerax.core.imageOutput.targetAspectRatio 58 */ 59 Option<Integer> OPTION_TARGET_ASPECT_RATIO = 60 Option.create("camerax.core.imageOutput.targetAspectRatio", AspectRatio.class); 61 62 /** 63 * Option: camerax.core.imageOutput.targetRotation 64 */ 65 Option<Integer> OPTION_TARGET_ROTATION = 66 Option.create("camerax.core.imageOutput.targetRotation", int.class); 67 68 /** 69 * Option: camerax.core.imageOutput.appTargetRotation 70 */ 71 Option<Integer> OPTION_APP_TARGET_ROTATION = 72 Option.create("camerax.core.imageOutput.appTargetRotation", int.class); 73 74 /** 75 * Option: camerax.core.imageOutput.mirrorMode 76 */ 77 Option<Integer> OPTION_MIRROR_MODE = 78 Option.create("camerax.core.imageOutput.mirrorMode", int.class); 79 80 /** 81 * Option: camerax.core.imageOutput.targetResolution 82 */ 83 Option<Size> OPTION_TARGET_RESOLUTION = 84 Option.create("camerax.core.imageOutput.targetResolution", Size.class); 85 /** 86 * Option: camerax.core.imageOutput.defaultResolution 87 */ 88 Option<Size> OPTION_DEFAULT_RESOLUTION = 89 Option.create("camerax.core.imageOutput.defaultResolution", Size.class); 90 /** 91 * Option: camerax.core.imageOutput.maxResolution 92 */ 93 Option<Size> OPTION_MAX_RESOLUTION = 94 Option.create("camerax.core.imageOutput.maxResolution", Size.class); 95 /** 96 * Option: camerax.core.imageOutput.supportedResolutions 97 */ 98 Option<List<Pair<Integer, Size[]>>> OPTION_SUPPORTED_RESOLUTIONS = 99 Option.create("camerax.core.imageOutput.supportedResolutions", List.class); 100 101 /** 102 * Option: camerax.core.imageOutput.resolutionSelector 103 */ 104 Option<ResolutionSelector> OPTION_RESOLUTION_SELECTOR = 105 Option.create("camerax.core.imageOutput.resolutionSelector", ResolutionSelector.class); 106 107 /** 108 * Option: camerax.core.imageOutput.customOrderedResolutions 109 */ 110 Option<List<Size>> OPTION_CUSTOM_ORDERED_RESOLUTIONS = 111 Option.create("camerax.core.imageOutput.customOrderedResolutions", List.class); 112 113 // ********************************************************************************************* 114 115 /** 116 * Verifies whether the aspect ratio of the target intending to use images from this 117 * configuration is set. 118 * 119 * @return true is the value exists in this configuration, false otherwise. 120 */ hasTargetAspectRatio()121 default boolean hasTargetAspectRatio() { 122 return containsOption(OPTION_TARGET_ASPECT_RATIO); 123 } 124 125 /** 126 * Retrieves the aspect ratio of the target intending to use images from this configuration. 127 * 128 * @return The stored value, if it exists in this configuration. 129 * @throws IllegalArgumentException if the option does not exist in this configuration. 130 */ 131 @AspectRatio.Ratio getTargetAspectRatio()132 default int getTargetAspectRatio() { 133 return retrieveOption(OPTION_TARGET_ASPECT_RATIO); 134 } 135 136 /** 137 * Retrieves the rotation of the target intending to use images from this configuration. 138 * 139 * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90}, 140 * {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. Rotation values are relative to 141 * the device's "natural" rotation, {@link Surface#ROTATION_0}. 142 * 143 * @param valueIfMissing The value to return if this configuration option has not been set. 144 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 145 * configuration. 146 */ 147 @RotationValue getTargetRotation(int valueIfMissing)148 default int getTargetRotation(int valueIfMissing) { 149 return retrieveOption(OPTION_TARGET_ROTATION, valueIfMissing); 150 } 151 152 /** 153 * Retrieves the target rotation set by app explicitly. 154 * 155 * @param valueIfMissing The value to return if this configuration option has not been set. 156 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 157 * configuration. 158 */ 159 @RotationValue getAppTargetRotation(int valueIfMissing)160 default int getAppTargetRotation(int valueIfMissing) { 161 return retrieveOption(OPTION_APP_TARGET_ROTATION, valueIfMissing); 162 } 163 164 /** 165 * Retrieves the rotation of the target intending to use images from this configuration. 166 * 167 * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90}, 168 * {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. Rotation values are relative to 169 * the device's "natural" rotation, {@link Surface#ROTATION_0}. 170 * 171 * @return The stored value, if it exists in this configuration. 172 * @throws IllegalArgumentException if the option does not exist in this configuration. 173 */ 174 @RotationValue getTargetRotation()175 default int getTargetRotation() { 176 return retrieveOption(OPTION_TARGET_ROTATION); 177 } 178 179 /** 180 * Retrieves the resolution of the target intending to use from this configuration. 181 * 182 * @param valueIfMissing The value to return if this configuration option has not been set. 183 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 184 * configuration. 185 */ getTargetResolution(@ullable Size valueIfMissing)186 default @Nullable Size getTargetResolution(@Nullable Size valueIfMissing) { 187 return retrieveOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION, valueIfMissing); 188 } 189 190 /** 191 * Retrieves the mirror mode of the target intending to use from this configuration. 192 * 193 * @param valueIfMissing The value to return if this configuration option has not been set. 194 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in 195 * this configuration. 196 */ 197 @MirrorMode.Mirror getMirrorMode(int valueIfMissing)198 default int getMirrorMode(int valueIfMissing) { 199 return retrieveOption(ImageOutputConfig.OPTION_MIRROR_MODE, valueIfMissing); 200 } 201 202 /** 203 * Retrieves the resolution of the target intending to use from this configuration. 204 * 205 * @return The stored value, if it exists in this configuration. 206 * @throws IllegalArgumentException if the option does not exist in this configuration. 207 */ getTargetResolution()208 default @NonNull Size getTargetResolution() { 209 return retrieveOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION); 210 } 211 212 /** 213 * Retrieves the default resolution of the target intending to use from this configuration. 214 * 215 * @param valueIfMissing The value to return if this configuration option has not been set. 216 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 217 * configuration. 218 */ getDefaultResolution(@ullable Size valueIfMissing)219 default @Nullable Size getDefaultResolution(@Nullable Size valueIfMissing) { 220 return retrieveOption(OPTION_DEFAULT_RESOLUTION, valueIfMissing); 221 } 222 223 /** 224 * Retrieves the default resolution of the target intending to use from this configuration. 225 * 226 * @return The stored value, if it exists in this configuration. 227 * @throws IllegalArgumentException if the option does not exist in this configuration. 228 */ getDefaultResolution()229 default @NonNull Size getDefaultResolution() { 230 return retrieveOption(OPTION_DEFAULT_RESOLUTION); 231 } 232 233 /** 234 * Retrieves the max resolution limitation of the target intending to use from this 235 * configuration. 236 * 237 * @param valueIfMissing The value to return if this configuration option has not been set. 238 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 239 * configuration. 240 */ getMaxResolution(@ullable Size valueIfMissing)241 default @Nullable Size getMaxResolution(@Nullable Size valueIfMissing) { 242 return retrieveOption(OPTION_MAX_RESOLUTION, valueIfMissing); 243 } 244 245 /** 246 * Retrieves the max resolution limitation of the target intending to use from this 247 * configuration. 248 * 249 * @return The stored value, if it exists in this configuration. 250 * @throws IllegalArgumentException if the option does not exist in this configuration. 251 */ getMaxResolution()252 default @NonNull Size getMaxResolution() { 253 return retrieveOption(OPTION_MAX_RESOLUTION); 254 } 255 256 /** 257 * Retrieves the supported resolutions can be used by the target from this configuration. 258 * 259 * <p>Pair list is composed with {@link ImageFormat} and {@link Size} array. The returned 260 * {@link Size} array should be subset of the complete supported sizes list for the camera 261 * device. 262 * 263 * @param valueIfMissing The value to return if this configuration option has not been set. 264 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 265 * configuration. 266 */ getSupportedResolutions( @ullable List<Pair<Integer, Size[]>> valueIfMissing)267 default @Nullable List<Pair<Integer, Size[]>> getSupportedResolutions( 268 @Nullable List<Pair<Integer, Size[]>> valueIfMissing) { 269 return retrieveOption(OPTION_SUPPORTED_RESOLUTIONS, valueIfMissing); 270 } 271 272 /** 273 * Retrieves the resolution selector can be used by the target from this configuration. 274 * 275 * @param valueIfMissing The value to return if this configuration option has not been set. 276 * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this 277 * configuration. 278 */ getResolutionSelector( @ullable ResolutionSelector valueIfMissing)279 default @Nullable ResolutionSelector getResolutionSelector( 280 @Nullable ResolutionSelector valueIfMissing) { 281 return retrieveOption(OPTION_RESOLUTION_SELECTOR, valueIfMissing); 282 } 283 284 /** 285 * Retrieves the resolution selector can be used by the target from this configuration. 286 * 287 * @return The stored value, if it exists in this configuration. 288 * @throws IllegalArgumentException if the option does not exist in this configuration. 289 */ getResolutionSelector()290 default @NonNull ResolutionSelector getResolutionSelector() { 291 return retrieveOption(OPTION_RESOLUTION_SELECTOR); 292 } 293 294 /** 295 * Retrieves the supported resolutions can be used by the target from this configuration. 296 * 297 * <p>Pair list is composed with {@link ImageFormat} and {@link Size} array. The returned 298 * {@link Size} array should be subset of the complete supported sizes list for the camera 299 * device. 300 * 301 * @return The stored value, if it exists in this configuration. 302 * @throws IllegalArgumentException if the option does not exist in this configuration. 303 */ getSupportedResolutions()304 default @NonNull List<Pair<Integer, Size[]>> getSupportedResolutions() { 305 return retrieveOption(OPTION_SUPPORTED_RESOLUTIONS); 306 } 307 308 /** 309 * Retrieves the custom ordered resolutions can be used by the target from this configuration. 310 * 311 * <p>The returned {@link Size} list contains preferred priority from high to low and should 312 * be the subset of the supported sizes for the camera device. 313 * 314 * @return The stored value, if it exists in this configuration. 315 * @throws IllegalArgumentException if the option does not exist in this configuration. 316 */ getCustomOrderedResolutions(@ullable List<Size> valueIfMissing)317 default @Nullable List<Size> getCustomOrderedResolutions(@Nullable List<Size> valueIfMissing) { 318 List<Size> list = retrieveOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS, valueIfMissing); 319 return list != null ? new ArrayList<>(list) : null; 320 } 321 322 /** 323 * Retrieves the custom resolutions can be used by the target from this configuration. 324 * 325 * <p>The returned {@link Size} list contains preferred priority from high to low and should 326 * be the subset of the supported sizes for the camera device. 327 * 328 * @return The stored value, if it exists in this configuration. 329 * @throws IllegalArgumentException if the option does not exist in this configuration. 330 */ getCustomOrderedResolutions()331 default @NonNull List<Size> getCustomOrderedResolutions() { 332 return new ArrayList<>(requireNonNull(retrieveOption(OPTION_CUSTOM_ORDERED_RESOLUTIONS))); 333 } 334 335 /** 336 * Checks whether the input config contains any conflicted settings. 337 * 338 * @param config to be validated. 339 * @throws IllegalArgumentException if both the target aspect ratio and the target resolution 340 * settings are contained in the config, or if either the target aspect ratio or the target 341 * resolution is contained when a resolution selector has been set in the config. 342 */ validateConfig(@onNull ImageOutputConfig config)343 static void validateConfig(@NonNull ImageOutputConfig config) { 344 boolean hasTargetAspectRatio = config.hasTargetAspectRatio(); 345 boolean hasTargetResolution = config.getTargetResolution(null) != null; 346 347 // Case 1. Error at runtime for using both setTargetResolution and setTargetAspectRatio on 348 // the same config. 349 if (hasTargetAspectRatio && hasTargetResolution) { 350 throw new IllegalArgumentException( 351 "Cannot use both setTargetResolution and setTargetAspectRatio on the same " 352 + "config."); 353 } 354 355 ResolutionSelector resolutionSelector = config.getResolutionSelector(null); 356 357 if (resolutionSelector != null) { 358 // Case 2. Error at runtime for using setTargetResolution or setTargetAspectRatio 359 // with setResolutionSelector on the same config. 360 if (hasTargetAspectRatio || hasTargetResolution) { 361 throw new IllegalArgumentException( 362 "Cannot use setTargetResolution or setTargetAspectRatio with " 363 + "setResolutionSelector on the same config."); 364 } 365 } 366 } 367 368 /** 369 * Builder for a {@link ImageOutputConfig}. 370 * 371 * @param <B> The top level builder type for which this builder is composed with. 372 */ 373 interface Builder<B> { 374 375 /** 376 * Sets the aspect ratio of the intended target for images from this configuration. 377 * 378 * <p>It is not allowed to set both target aspect ratio and target resolution on the same 379 * use case. 380 * 381 * @param aspectRatio A {@link AspectRatio} representing the ratio of the 382 * target's width and height. 383 * @return The current Builder. 384 */ setTargetAspectRatio(@spectRatio.Ratio int aspectRatio)385 @NonNull B setTargetAspectRatio(@AspectRatio.Ratio int aspectRatio); 386 387 /** 388 * Sets the rotation of the intended target for images from this configuration. 389 * 390 * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link 391 * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. 392 * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}. 393 * 394 * @param rotation The rotation of the intended target. 395 * @return The current Builder. 396 */ setTargetRotation(@otationValue int rotation)397 @NonNull B setTargetRotation(@RotationValue int rotation); 398 399 /** 400 * Sets the mirror mode of the intended target for images from this configuration. 401 * 402 * <p>Valid values include: {@link MirrorMode#MIRROR_MODE_OFF}, 403 * {@link MirrorMode#MIRROR_MODE_ON} and {@link MirrorMode#MIRROR_MODE_ON_FRONT_ONLY}. 404 * 405 * @param mirrorMode The mirror mode of the intended target. 406 * @return The current Builder. 407 */ setMirrorMode(@irrorMode.Mirror int mirrorMode)408 @NonNull B setMirrorMode(@MirrorMode.Mirror int mirrorMode); 409 410 /** 411 * Sets the resolution of the intended target from this configuration. 412 * 413 * <p>It is not allowed to set both target aspect ratio and target resolution on the same 414 * use case. 415 * 416 * <p>The target aspect ratio will also be set the same as the aspect ratio of the provided 417 * {@link Size}. Make sure to set the target resolution with the correct orientation. 418 * 419 * @param resolution The target resolution to choose from supported output sizes list. 420 * @return The current Builder. 421 */ setTargetResolution(@onNull Size resolution)422 @NonNull B setTargetResolution(@NonNull Size resolution); 423 424 /** 425 * Sets the default resolution of the intended target from this configuration. 426 * 427 * @param resolution The default resolution to choose from supported output sizes list. 428 * @return The current Builder. 429 */ setDefaultResolution(@onNull Size resolution)430 @NonNull B setDefaultResolution(@NonNull Size resolution); 431 432 /** 433 * Sets the max resolution limitation of the intended target from this configuration. 434 * 435 * @param resolution The max resolution limitation to choose from supported output sizes 436 * list. 437 * @return The current Builder. 438 */ setMaxResolution(@onNull Size resolution)439 @NonNull B setMaxResolution(@NonNull Size resolution); 440 441 /** 442 * Sets the supported resolutions can be used by target from this configuration. 443 * 444 * <p>Pair list is composed with {@link ImageFormat} and {@link Size} array. The 445 * {@link Size} array should be subset of the complete supported sizes list for the camera 446 * device. 447 * 448 * @param resolutionsList The resolutions can be supported for image formats. 449 * @return The current Builder. 450 */ setSupportedResolutions(@onNull List<Pair<Integer, Size[]>> resolutionsList)451 @NonNull B setSupportedResolutions(@NonNull List<Pair<Integer, Size[]>> resolutionsList); 452 453 /** 454 * Sets the custom resolutions can be used by target from this configuration. 455 * 456 * <p>The {@link Size} list should contain preferred priority from high to low and should 457 * be the subset of the supported sizes for the camera device. The list will be fully 458 * respected, meaning it will not be sorted or filtered by other configurations such as 459 * max/default/target/supported resolutions. 460 * 461 * @param resolutionsList The resolutions can be supported for this image config. 462 * @return The current Builder. 463 */ setCustomOrderedResolutions(@onNull List<Size> resolutionsList)464 @NonNull B setCustomOrderedResolutions(@NonNull List<Size> resolutionsList); 465 466 /** 467 * Sets the resolution selector can be used by target from this configuration. 468 * 469 * @param resolutionSelector The resolution selector to select a preferred resolution. 470 * @return The current Builder. 471 */ setResolutionSelector(@onNull ResolutionSelector resolutionSelector)472 @NonNull B setResolutionSelector(@NonNull ResolutionSelector resolutionSelector); 473 } 474 475 /** 476 * Valid integer rotation values. 477 */ 478 @IntDef({Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, Surface.ROTATION_270}) 479 @Retention(RetentionPolicy.SOURCE) 480 @interface RotationValue { 481 } 482 483 /** 484 * Valid integer rotation values including option indicating value not specified. 485 */ 486 @IntDef({ROTATION_NOT_SPECIFIED, Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, 487 Surface.ROTATION_270}) 488 @Retention(RetentionPolicy.SOURCE) 489 @interface OptionalRotationValue { 490 } 491 492 /** 493 * Valid integer rotation degrees values. 494 */ 495 @IntDef({0, 90, 180, 270}) 496 @Retention(RetentionPolicy.SOURCE) 497 @interface RotationDegreesValue { 498 } 499 } 500