ResolutionSelector.java
/*
* Copyright 2023 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 androidx.camera.core.resolutionselector;
import static androidx.camera.core.resolutionselector.AspectRatioStrategy.RATIO_4_3_FALLBACK_AUTO_STRATEGY;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.camera.core.UseCase;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* A set of requirements and priorities used to select a resolution for the {@link UseCase}.
*
* <p>The resolution selection mechanism is determined by the following three steps:
* <ol>
* <li> Collect the supported output sizes and add them to the candidate resolution list.
* <li> Filter and sort the candidate resolution list according to the {@link Builder}
* resolution settings.
* <li> Consider all the resolution selector settings of bound {@link UseCase}s to find the
* resolution that best suits each {@link UseCase}.
* </ol>
*
* <p>For the first step, all supported resolution output sizes are added to the candidate
* resolution list as the starting point.
*
* <p>ResolutionSelector provides the following function for applications to adjust the candidate
* resolution settings.
* <ul>
* <li> {@link Builder#setAllowedResolutionMode(int)}
* </ul>
*
* <p>For the second step, ResolutionSelector provides the following three functions for
* applications to determine which resolution should be selected with higher priority.
* <ul>
* <li> {@link Builder#setAspectRatioStrategy(AspectRatioStrategy)}
* <li> {@link Builder#setResolutionStrategy(ResolutionStrategy)}
* <li> {@link Builder#setResolutionFilter(ResolutionFilter)}
* </ul>
*
* <p>CameraX sorts the collected sizes according to the specified aspect ratio and resolution
* strategies. The aspect ratio strategy has precedence over the resolution strategy for sorting
* the resolution candidate list. If applications specify a custom resolution filter, CameraX
* passes the resulting sizes list, sorted by the specified aspect ratio and resolution
* strategies, to the resolution filter to get the final desired list.
*
* <p>Different types of {@link UseCase}s might have their own default settings. You can see the
* {@link UseCase} builders’ {@code setResolutionSelector()} function to know the details for each
* type of {@link UseCase}.
*
* <p>In the third step, CameraX selects the final resolution for the {@link UseCase} based on the
* camera device's hardware level, capabilities, and the bound {@link UseCase} combination.
* Applications can check which resolution is finally selected by using the {@link UseCase}'s
* {@code getResolutionInfo()} function.
*
* <p>Note that a ResolutionSelector with more restricted settings may result in that no
* resolution can be selected to use. Applications will receive {@link IllegalArgumentException}
* when binding the {@link UseCase}s with such kind of ResolutionSelector. Applications can
* specify the {@link AspectRatioStrategy} and {@link ResolutionStrategy} with proper fallback
* rules to avoid the {@link IllegalArgumentException} or try-catch it and show a proper message
* to the end users.
*
* <p>When creating a ResolutionSelector instance, the
* {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be the default
* {@link AspectRatioStrategy} if it is not set.
* {@link ResolutionSelector#PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION} is the default allowed
* resolution mode. However, if neither the {@link ResolutionStrategy} nor the
* {@link ResolutionFilter} are set, there will be no default value specified.
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public final class ResolutionSelector {
/**
* This mode allows CameraX to select the normal output sizes on the camera device.
*
* <p>The available resolutions for this mode are obtained from the
* {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(int)} method
* from the stream configuration map obtained with the
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
* camera characteristics.
*/
public static final int PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION = 0;
/**
* This mode allows CameraX to select the output sizes which might result in slower capture
* times.
*
* <p>The available resolutions for this mode are obtained from the
* {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(int)} and
* {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
* methods from the stream configuration map obtained with the
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
* camera characteristics. However, please note that using a resolution obtained from the
* {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
* may result in slower capture times. Please see the javadoc of
* {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes(int)}
* for more details.
*
* <p>Since Android 12, some devices might support a maximum resolution sensor pixel mode,
* which allows them to capture additional ultra high resolutions retrieved from
* {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION}
* . This mode does not allow applications to select those ultra high resolutions.
*/
public static final int PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE = 1;
@IntDef({PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION,
PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public @interface AllowedResolutionMode {
}
@NonNull
private final AspectRatioStrategy mAspectRatioStrategy;
@Nullable
private final ResolutionStrategy mResolutionStrategy;
@Nullable
private final ResolutionFilter mResolutionFilter;
@AllowedResolutionMode
private final int mAllowedResolutionMode;
ResolutionSelector(
@NonNull AspectRatioStrategy aspectRatioStrategy,
@Nullable ResolutionStrategy resolutionStrategy,
@Nullable ResolutionFilter resolutionFilter,
@AllowedResolutionMode int allowedResolutionMode) {
mAspectRatioStrategy = aspectRatioStrategy;
mResolutionStrategy = resolutionStrategy;
mResolutionFilter = resolutionFilter;
mAllowedResolutionMode = allowedResolutionMode;
}
/**
* Returns the specified {@link AspectRatioStrategy}, or
* {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} if none is specified when
* creating the ResolutionSelector.
*/
@NonNull
public AspectRatioStrategy getAspectRatioStrategy() {
return mAspectRatioStrategy;
}
/**
* Returns the specified {@link ResolutionStrategy}, or null if not specified.
*/
@Nullable
public ResolutionStrategy getResolutionStrategy() {
return mResolutionStrategy;
}
/**
* Returns the specified {@link ResolutionFilter} implementation, or null if not specified.
*/
@Nullable
public ResolutionFilter getResolutionFilter() {
return mResolutionFilter;
}
/**
* Returns the specified allowed resolution mode.
*/
@AllowedResolutionMode
public int getAllowedResolutionMode() {
return mAllowedResolutionMode;
}
/**
* Builder for a {@link ResolutionSelector}.
*/
public static final class Builder {
@Nullable
private AspectRatioStrategy mAspectRatioStrategy = RATIO_4_3_FALLBACK_AUTO_STRATEGY;
@Nullable
private ResolutionStrategy mResolutionStrategy = null;
@Nullable
private ResolutionFilter mResolutionFilter = null;
@AllowedResolutionMode
private int mAllowedResolutionMode = PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION;
/**
* Creates a Builder instance.
*/
public Builder() {
}
private Builder(@NonNull ResolutionSelector resolutionSelector) {
mAspectRatioStrategy = resolutionSelector.getAspectRatioStrategy();
mResolutionStrategy = resolutionSelector.getResolutionStrategy();
mResolutionFilter = resolutionSelector.getResolutionFilter();
mAllowedResolutionMode = resolutionSelector.getAllowedResolutionMode();
}
/**
* Creates a Builder from an existing resolution selector.
*/
@NonNull
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static Builder fromResolutionSelector(
@NonNull ResolutionSelector resolutionSelector) {
return new Builder(resolutionSelector);
}
/**
* Sets the aspect ratio selection strategy for the {@link UseCase}. The aspect ratio
* selection strategy determines how the {@link UseCase} will choose the aspect ratio of
* the captured image.
*
* <p>If the aspect ratio strategy is not specified,
* {@link AspectRatioStrategy#RATIO_4_3_FALLBACK_AUTO_STRATEGY} will be used as the default.
*/
@NonNull
public Builder setAspectRatioStrategy(@NonNull AspectRatioStrategy aspectRatioStrategy) {
mAspectRatioStrategy = aspectRatioStrategy;
return this;
}
/**
* Sets the resolution selection strategy for the {@link UseCase}. The resolution selection
* strategy determines how the {@link UseCase} will choose the resolution of the captured
* image.
*/
@NonNull
public Builder setResolutionStrategy(@NonNull ResolutionStrategy resolutionStrategy) {
mResolutionStrategy = resolutionStrategy;
return this;
}
/**
* Sets the resolution filter to output the final desired sizes list. The resolution
* filter will filter out unsuitable sizes and sort the resolution list in the preferred
* order. The preferred order is the order in which the resolutions should be tried first.
*/
@NonNull
public Builder setResolutionFilter(@NonNull ResolutionFilter resolutionFilter) {
mResolutionFilter = resolutionFilter;
return this;
}
/**
* Sets the allowed resolution mode.
*
* <p>If not specified, the default setting is
* {@link ResolutionSelector#PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION}.
*/
@NonNull
public Builder setAllowedResolutionMode(@AllowedResolutionMode int mode) {
mAllowedResolutionMode = mode;
return this;
}
/**
* Builds the resolution selector. This will create a resolution selector that can be
* used to select the desired resolution for the captured image.
*/
@NonNull
public ResolutionSelector build() {
return new ResolutionSelector(mAspectRatioStrategy, mResolutionStrategy,
mResolutionFilter, mAllowedResolutionMode);
}
}
}