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 androidx.camera.core.impl.CameraMode.ULTRA_HIGH_RESOLUTION_CAMERA;
20 
21 import android.graphics.ImageFormat;
22 import android.hardware.camera2.CameraCaptureSession.StateCallback;
23 import android.os.Handler;
24 import android.util.Size;
25 
26 import androidx.camera.core.internal.utils.SizeUtil;
27 
28 import com.google.auto.value.AutoValue;
29 
30 import org.jspecify.annotations.NonNull;
31 
32 import java.util.List;
33 
34 /**
35  * Surface configuration type and size pair
36  *
37  * <p>{@link android.hardware.camera2.CameraDevice#createCaptureSession} defines the default
38  * guaranteed stream combinations for different hardware level devices. It defines what combination
39  * of surface configuration type and size pairs can be supported for different hardware level camera
40  * devices.
41  */
42 @AutoValue
43 public abstract class SurfaceConfig {
44     public static final long DEFAULT_STREAM_USE_CASE_VALUE = 0;
45     /** Prevent subclassing */
SurfaceConfig()46     SurfaceConfig() {
47     }
48 
49     /**
50      * Creates a new instance of SurfaceConfig with the given parameters.
51      */
create(@onNull ConfigType type, @NonNull ConfigSize size)52     public static @NonNull SurfaceConfig create(@NonNull ConfigType type,
53             @NonNull ConfigSize size) {
54         return new AutoValue_SurfaceConfig(type, size, DEFAULT_STREAM_USE_CASE_VALUE);
55     }
56 
57     /**
58      * Creates a new instance of SurfaceConfig with the given parameters.
59      */
create(@onNull ConfigType type, @NonNull ConfigSize size, long streamUseCase)60     public static @NonNull SurfaceConfig create(@NonNull ConfigType type, @NonNull ConfigSize size,
61             long streamUseCase) {
62         return new AutoValue_SurfaceConfig(type, size, streamUseCase);
63     }
64 
65     /** Returns the configuration type. */
getConfigType()66     public abstract @NonNull ConfigType getConfigType();
67 
68     /** Returns the configuration size. */
getConfigSize()69     public abstract @NonNull ConfigSize getConfigSize();
70 
71     /**
72      * Returns the stream use case.
73      * <p>Stream use case constants are implementation-specific constants that allow the
74      * implementation to optimize power and quality characteristics of a stream depending on how
75      * it will be used.
76      * <p> Stream use case is an int flag used to specify the purpose of the stream associated
77      * with this surface. Use cases for the camera2 implementation that are available on devices can
78      * be found in
79      * {@link android.hardware.camera2.CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES}
80      *
81      * <p>See {@link android.hardware.camera2.params.OutputConfiguration#setStreamUseCase}
82      * to see how Camera2 framework uses this.
83      */
getStreamUseCase()84     public abstract long getStreamUseCase();
85 
86     /**
87      * Check whether the input surface configuration has a smaller size than this object and can be
88      * supported
89      *
90      * @param surfaceConfig the surface configuration to be compared
91      * @return the check result that whether it could be supported
92      */
isSupported(@onNull SurfaceConfig surfaceConfig)93     public final boolean isSupported(@NonNull SurfaceConfig surfaceConfig) {
94         boolean isSupported = false;
95         ConfigType configType = surfaceConfig.getConfigType();
96         ConfigSize configSize = surfaceConfig.getConfigSize();
97 
98         // Check size and type to make sure it could be supported
99         if (configSize.getId() <= getConfigSize().getId() && configType == getConfigType()) {
100             isSupported = true;
101         }
102         return isSupported;
103     }
104 
105     /**
106      * Gets {@link ConfigType} from image format.
107      *
108      * <p> PRIV refers to any target whose available sizes are found using
109      * StreamConfigurationMap.getOutputSizes(Class) with no direct application-visible format,
110      * YUV refers to a target Surface using the ImageFormat.YUV_420_888 format, JPEG refers to
111      * the ImageFormat.JPEG or ImageFormat.JPEG_R format, and RAW refers to the
112      * ImageFormat.RAW_SENSOR format.
113      */
getConfigType(int imageFormat)114     public static SurfaceConfig.@NonNull ConfigType getConfigType(int imageFormat) {
115         if (imageFormat == ImageFormat.YUV_420_888) {
116             return SurfaceConfig.ConfigType.YUV;
117         } else if (imageFormat == ImageFormat.JPEG) {
118             return SurfaceConfig.ConfigType.JPEG;
119         } else if (imageFormat == ImageFormat.JPEG_R) {
120             return SurfaceConfig.ConfigType.JPEG_R;
121         } else if (imageFormat == ImageFormat.RAW_SENSOR) {
122             return SurfaceConfig.ConfigType.RAW;
123         } else {
124             return SurfaceConfig.ConfigType.PRIV;
125         }
126     }
127 
128     /**
129      * Transform to a SurfaceConfig object with image format and size info
130      *
131      * @param cameraMode            the working camera mode.
132      * @param imageFormat           the image format info for the surface configuration object
133      * @param size                  the size info for the surface configuration object
134      * @param surfaceSizeDefinition the surface definition for the surface configuration object
135      * @return new {@link SurfaceConfig} object
136      */
transformSurfaceConfig( @ameraMode.Mode int cameraMode, int imageFormat, @NonNull Size size, @NonNull SurfaceSizeDefinition surfaceSizeDefinition)137     public static @NonNull SurfaceConfig transformSurfaceConfig(
138             @CameraMode.Mode int cameraMode,
139             int imageFormat,
140             @NonNull Size size,
141             @NonNull SurfaceSizeDefinition surfaceSizeDefinition) {
142         ConfigType configType =
143                 SurfaceConfig.getConfigType(imageFormat);
144         ConfigSize configSize = ConfigSize.NOT_SUPPORT;
145 
146         // Compare with surface size definition to determine the surface configuration size
147         int sizeArea = SizeUtil.getArea(size);
148 
149         if (cameraMode == CameraMode.CONCURRENT_CAMERA) {
150             if (sizeArea <= SizeUtil.getArea(surfaceSizeDefinition.getS720pSize(imageFormat))) {
151                 configSize = ConfigSize.s720p;
152             } else if (sizeArea <= SizeUtil.getArea(surfaceSizeDefinition.getS1440pSize(
153                     imageFormat))) {
154                 configSize = ConfigSize.s1440p;
155             }
156         } else {
157             if (sizeArea <= SizeUtil.getArea(surfaceSizeDefinition.getAnalysisSize())) {
158                 configSize = ConfigSize.VGA;
159             } else if (sizeArea <= SizeUtil.getArea(surfaceSizeDefinition.getPreviewSize())) {
160                 configSize = ConfigSize.PREVIEW;
161             } else if (sizeArea <= SizeUtil.getArea(surfaceSizeDefinition.getRecordSize())) {
162                 configSize = ConfigSize.RECORD;
163             } else {
164                 Size maximumSize = surfaceSizeDefinition.getMaximumSize(imageFormat);
165                 Size ultraMaximumSize = surfaceSizeDefinition.getUltraMaximumSize(imageFormat);
166                 // On some devices, when extensions is on, some extra formats might be supported
167                 // for extensions. But those formats are not supported in the normal mode. In
168                 // that case, MaximumSize could be null. Directly make configSize as MAXIMUM for
169                 // the case.
170                 if ((maximumSize == null || sizeArea <= SizeUtil.getArea(maximumSize))
171                         && cameraMode != ULTRA_HIGH_RESOLUTION_CAMERA) {
172                     configSize = ConfigSize.MAXIMUM;
173                 } else if (ultraMaximumSize != null && sizeArea <= SizeUtil.getArea(
174                         ultraMaximumSize)) {
175                     configSize = ConfigSize.ULTRA_MAXIMUM;
176                 }
177             }
178         }
179 
180         return SurfaceConfig.create(configType, configSize);
181     }
182 
183     /**
184      * The Camera2 configuration type for the surface.
185      *
186      * <p>These are the enumerations defined in {@link
187      * android.hardware.camera2.CameraDevice#createCaptureSession(List, StateCallback, Handler)}.
188      */
189     public enum ConfigType {
190         PRIV,
191         YUV,
192         JPEG,
193         JPEG_R,
194         RAW
195     }
196 
197     /**
198      * The Camera2 stream sizes for the surface.
199      *
200      * <p>These are the enumerations defined in {@link
201      * android.hardware.camera2.CameraDevice#createCaptureSession(List, StateCallback, Handler)}.
202      */
203     public enum ConfigSize {
204         /** Default VGA size is 640x480, which is the default size of Image Analysis. */
205         VGA(0),
206         /**
207          * s720p refers to the best size match to the device's screen resolution, or to 720p
208          * (1280x720), whichever is smaller.
209          */
210         s720p(1),
211         /**
212          * PREVIEW refers to the best size match to the device's screen resolution, or to 1080p
213          * (1920x1080), whichever is smaller.
214          */
215         PREVIEW(2),
216         /**
217          * s1440p refers to the best size match to the device's screen resolution, or to 1440p
218          * (1920x1440), whichever is smaller.
219          */
220         s1440p(3),
221         /**
222          * RECORD refers to the camera device's maximum supported recording resolution, as
223          * determined by CamcorderProfile.
224          */
225         RECORD(4),
226         /**
227          * MAXIMUM refers to the camera device's maximum output resolution for that format or
228          * target from StreamConfigurationMap.getOutputSizes() or getHighResolutionOutputSizes()
229          * in the default sensor pixel mode.
230          */
231         MAXIMUM(5),
232         /**
233          * ULTRA_MAXIMUM refers to the camera device's maximum output resolution for that format or
234          * target from StreamConfigurationMap.getOutputSizes() or getHighResolutionOutputSizes()
235          * in the maximum resolution sensor pixel mode.
236          */
237         ULTRA_MAXIMUM(6),
238         /** NOT_SUPPORT is for the size larger than MAXIMUM */
239         NOT_SUPPORT(7);
240 
241         final int mId;
242 
ConfigSize(int id)243         ConfigSize(int id) {
244             mId = id;
245         }
246 
getId()247         int getId() {
248             return mId;
249         }
250     }
251 }
252