1 /*
2  * Copyright (C) 2018 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.IntDef;
20 import android.annotation.IntRange;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.graphics.ImageFormat;
24 import android.graphics.ImageFormat.Format;
25 import android.graphics.PixelFormat;
26 import android.hardware.camera2.CameraCharacteristics;
27 import android.hardware.camera2.CameraDevice;
28 import android.hardware.camera2.CameraMetadata;
29 import android.hardware.camera2.CaptureRequest;
30 import android.util.ArraySet;
31 import android.util.Range;
32 import android.util.Size;
33 import android.view.Surface;
34 
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.Set;
41 
42 /**
43  * Immutable class to store the recommended stream configurations to set up
44  * {@link android.view.Surface Surfaces} for creating a
45  * {@link android.hardware.camera2.CameraCaptureSession capture session} with
46  * {@link android.hardware.camera2.CameraDevice#createCaptureSession}.
47  *
48  * <p>The recommended list does not replace or deprecate the exhaustive complete list found in
49  * {@link StreamConfigurationMap}. It is a suggestion about available power and performance
50  * efficient stream configurations for a specific use case. Per definition it is only a subset
51  * of {@link StreamConfigurationMap} and can be considered by developers for optimization
52  * purposes.</p>
53  *
54  * <p>This also duplicates the minimum frame durations and stall durations from the
55  * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate
56  * effective frame rate when submitting multiple captures.
57  * </p>
58  *
59  * <p>An instance of this object is available by invoking
60  * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective
61  * usecase id. For more information about supported use case constants see
62  * {@link #USECASE_PREVIEW}.</p>
63  *
64  * <pre><code>{@code
65  * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
66  * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap(
67  *         RecommendedStreamConfigurationMap.USECASE_PREVIEW);
68  * }</code></pre>
69  *
70  * @see CameraCharacteristics#getRecommendedStreamConfigurationMap
71  * @see CameraDevice#createCaptureSession
72  */
73 public final class RecommendedStreamConfigurationMap {
74 
75     private static final String TAG = "RecommendedStreamConfigurationMap";
76     private int mUsecase;
77     private boolean mSupportsPrivate;
78     private StreamConfigurationMap mRecommendedMap;
79 
80     /** @hide */
81     public static final int MAX_USECASE_COUNT = 32;
82 
83     /**
84      * The recommended stream configuration map for use case preview must contain a subset of
85      * efficient, non-stalling configurations that must include both
86      * {@link android.graphics.ImageFormat#PRIVATE} and
87      * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the
88      * camera device, high speed or input configurations will be absent.
89      */
90     public static final int USECASE_PREVIEW = 0x0;
91 
92     /**
93      * The recommended stream configuration map for recording must contain a subset of efficient
94      * video configurations that include {@link android.graphics.ImageFormat#PRIVATE}
95      * output format for at least all supported {@link android.media.CamcorderProfile profiles}.
96      * High speed configurations if supported will be available as well. Even if available for the
97      * camera device, input configurations will be absent.
98      */
99     public static final int USECASE_RECORD = 0x1;
100 
101     /**
102      * The recommended stream configuration map for use case video snapshot must only contain a
103      * subset of efficient liveshot configurations that include
104      * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least
105      * the maximum resolution of usecase record and will not cause any preview glitches. Even
106      * if available for the camera device, high speed or input configurations will be absent.
107      */
108     public static final int USECASE_VIDEO_SNAPSHOT = 0x2;
109 
110     /**
111      * The recommended stream configuration map for use case snapshot must contain a subset of
112      * efficient still capture configurations that must include
113      * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with
114      * size approximately equal to the sensor pixel array size
115      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
116      * Even if available for the camera device, high speed or input configurations will be absent.
117      */
118     public static final int USECASE_SNAPSHOT = 0x3;
119 
120     /**
121      * In case the device supports
122      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or
123      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING},
124      * the recommended stream configuration map for use case ZSL must contain a subset of efficient
125      * configurations that include the suggested input and output format mappings. Even if
126      * available for the camera device, high speed configurations will be absent.
127      */
128     public static final int USECASE_ZSL = 0x4;
129 
130     /**
131      * In case the device supports
132      * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the
133      * recommended stream configuration map for use case RAW must contain a subset of efficient
134      * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other
135      * RAW output formats. Even if available for the camera device, high speed and input
136      * configurations will be absent.
137      */
138     public static final int USECASE_RAW = 0x5;
139 
140     /**
141      * The recommended stream configuration map for use case low latency snapshot must contain
142      * subset of configurations with end-to-end latency that does not exceed 200 ms. under standard
143      * operating conditions (reasonable light levels, not loaded system). The expected output format
144      * will be primarily {@link android.graphics.ImageFormat#JPEG} however other image formats can
145      * be present as well.  Even if available for the camera device, high speed and input
146      * configurations will be absent. This suggested configuration map may be absent on some devices
147      * that can not support any low latency requests.
148      */
149     public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6;
150 
151     /**
152      * Device specific use cases.
153      * @hide
154      */
155     public static final int USECASE_VENDOR_START = 0x18;
156 
157     /** @hide */
158     @Retention(RetentionPolicy.SOURCE)
159     @IntDef(prefix = {"USECASE_"}, value =
160         {USECASE_PREVIEW,
161         USECASE_RECORD,
162         USECASE_VIDEO_SNAPSHOT,
163         USECASE_SNAPSHOT,
164         USECASE_ZSL,
165         USECASE_RAW,
166         USECASE_LOW_LATENCY_SNAPSHOT})
167      public @interface RecommendedUsecase {};
168 
169     /**
170      * Create a new {@link RecommendedStreamConfigurationMap}.
171      *
172      * @param recommendedMap stream configuration map that contains for the specific use case
173      * @param usecase Recommended use case
174      * @param supportsPrivate Flag indicating private format support.
175      *
176      * @hide
177      */
RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase, boolean supportsPrivate)178     public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase,
179             boolean supportsPrivate) {
180         mRecommendedMap = recommendedMap;
181         mUsecase = usecase;
182         mSupportsPrivate = supportsPrivate;
183     }
184 
185     /**
186      * Get the use case value for the recommended stream configurations.
187      *
188      * @return Use case id.
189      */
getRecommendedUseCase()190     public @RecommendedUsecase int getRecommendedUseCase() {
191         return mUsecase;
192     }
193 
getUnmodifiableIntegerSet(int[] intArray)194     private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) {
195         if ((intArray != null) && (intArray.length > 0)) {
196             ArraySet<Integer> integerSet = new ArraySet<Integer>();
197             integerSet.ensureCapacity(intArray.length);
198             for (int intEntry : intArray) {
199                 integerSet.add(intEntry);
200             }
201 
202             return Collections.unmodifiableSet(integerSet);
203         }
204 
205         return null;
206     }
207 
208     /**
209      * Get the image {@code format} output formats in this stream configuration.
210      *
211      * <p>
212      * For more information refer to {@link StreamConfigurationMap#getOutputFormats}.
213      * </p>
214      *
215      * @return a non-modifiable set of Integer formats
216      */
getOutputFormats()217     public @NonNull Set<Integer> getOutputFormats() {
218         return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats());
219     }
220 
221     /**
222      * Get the image {@code format} output formats for a reprocessing input format.
223      *
224      * <p>
225      * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}.
226      * </p>
227      *
228      * @return a non-modifiable set of Integer formats
229      */
getValidOutputFormatsForInput(@ormat int inputFormat)230     public @Nullable Set<Integer> getValidOutputFormatsForInput(@Format int inputFormat) {
231         return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
232                     inputFormat));
233     }
234 
235     /**
236      * Get the image {@code format} input formats in this stream configuration.
237      *
238      * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
239      * or in {@link PixelFormat} (and there is no possibility of collision).</p>
240      *
241      * @return a non-modifiable set of Integer formats
242      */
getInputFormats()243     public @Nullable Set<Integer> getInputFormats() {
244         return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats());
245     }
246 
getUnmodifiableSizeSet(Size[] sizeArray)247     private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) {
248         if ((sizeArray != null) && (sizeArray.length > 0)) {
249             ArraySet<Size> sizeSet = new ArraySet<Size>();
250             sizeSet.addAll(Arrays.asList(sizeArray));
251             return Collections.unmodifiableSet(sizeSet);
252         }
253 
254         return  null;
255     }
256 
257     /**
258      * Get the supported input sizes for this input format.
259      *
260      * <p>The format must have come from {@link #getInputFormats}; otherwise
261      * {@code null} is returned.</p>
262      *
263      * @param format a format from {@link #getInputFormats}
264      * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
265      */
getInputSizes(@ormat int format)266     public @Nullable Set<Size> getInputSizes(@Format int format) {
267         return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
268     }
269 
270     /**
271      * Determine whether or not output surfaces with a particular user-defined format can be passed
272      * {@link CameraDevice#createCaptureSession createCaptureSession}.
273      *
274      * <p>
275      * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
276      * </p>
277      *
278      *
279      * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
280      * @return
281      *          {@code true} if using a {@code surface} with this {@code format} will be
282      *          supported with {@link CameraDevice#createCaptureSession}
283      *
284      * @throws IllegalArgumentException
285      *          if the image format was not a defined named constant
286      *          from either {@link ImageFormat} or {@link PixelFormat}
287      */
isOutputSupportedFor(@ormat int format)288     public boolean isOutputSupportedFor(@Format int format) {
289         return mRecommendedMap.isOutputSupportedFor(format);
290     }
291 
292     /**
293      * Get a list of sizes compatible with the requested image {@code format}.
294      *
295      * <p>
296      * For more information refer to {@link StreamConfigurationMap#getOutputSizes}.
297      * </p>
298      *
299      *
300      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
301      * @return  a non-modifiable set of supported sizes,
302      *          or {@code null} if the {@code format} is not a supported output
303      */
getOutputSizes(@ormat int format)304     public @Nullable Set<Size> getOutputSizes(@Format int format) {
305         return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
306     }
307 
308     /**
309      * Get a list of supported high speed video recording sizes.
310      * <p>
311      * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}.
312      * </p>
313      *
314      * @return a non-modifiable set of supported high speed video recording sizes
315      */
getHighSpeedVideoSizes()316     public @Nullable Set<Size> getHighSpeedVideoSizes() {
317         return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes());
318     }
319 
getUnmodifiableRangeSet(Range<Integer>[] rangeArray)320     private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) {
321         if ((rangeArray != null) && (rangeArray.length > 0)) {
322             ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>();
323             rangeSet.addAll(Arrays.asList(rangeArray));
324             return Collections.unmodifiableSet(rangeSet);
325         }
326 
327         return null;
328     }
329 
330     /**
331      * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
332      *
333      * <p>
334      * For further information refer to
335      * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}.
336      * </p>
337      * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
338      * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
339      *         bound of returned ranges is guaranteed to be greater than or equal to 120.
340      * @throws IllegalArgumentException if input size does not exist in the return value of
341      *             getHighSpeedVideoSizes
342      */
getHighSpeedVideoFpsRangesFor(@onNull Size size)343     public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(@NonNull Size size) {
344         return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
345     }
346 
347     /**
348      * Get a list of supported high speed video recording FPS ranges.
349      * <p>
350      * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}.
351      * </p>
352      * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
353      *         bound of returned ranges is guaranteed to be larger or equal to 120.
354      */
getHighSpeedVideoFpsRanges()355     public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() {
356         return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges());
357     }
358 
359     /**
360      * Get the supported video sizes for an input high speed FPS range.
361      *
362      * <p>
363      * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
364      * </p>
365      *
366      * @param fpsRange one of the FPS ranges returned by {@link #getHighSpeedVideoFpsRanges()}
367      * @return A non-modifiable set of video sizes to create high speed capture sessions for high
368      *         speed streaming use cases.
369      *
370      * @throws IllegalArgumentException if input FPS range does not exist in the return value of
371      *         getHighSpeedVideoFpsRanges
372      */
getHighSpeedVideoSizesFor(@onNull Range<Integer> fpsRange)373     public @Nullable Set<Size> getHighSpeedVideoSizesFor(@NonNull Range<Integer> fpsRange) {
374         return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
375     }
376 
377     /**
378      * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
379      * rate.
380      *
381      * <p>
382      * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}.
383      * </p>
384      *
385      * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
386      *         the BURST_CAPTURE capability is not supported
387      */
getHighResolutionOutputSizes(@ormat int format)388     public @Nullable Set<Size> getHighResolutionOutputSizes(@Format int format) {
389         return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
390     }
391 
392     /**
393      * Get the minimum
394      * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration}
395      * for the format/size combination (in nanoseconds).
396      *
397      * <p>
398      * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}.
399      * </p>
400      *
401      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
402      * @param size an output-compatible size
403      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
404      *          0 if the minimum frame duration is not available.
405      *
406      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
407      */
getOutputMinFrameDuration(@ormat int format, @NonNull Size size)408     public @IntRange(from = 0) long getOutputMinFrameDuration(@Format int format,
409             @NonNull Size size) {
410         return mRecommendedMap.getOutputMinFrameDuration(format, size);
411     }
412 
413     /**
414      * Get the stall duration for the format/size combination (in nanoseconds).
415      *
416      * <p>
417      * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}.
418      * </p>
419      *
420      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
421      * @param size an output-compatible size
422      * @return a stall duration {@code >=} 0 in nanoseconds
423      *
424      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
425      */
getOutputStallDuration(@ormat int format, @NonNull Size size)426     public @IntRange(from = 0) long getOutputStallDuration(@Format int format, @NonNull Size size) {
427         return mRecommendedMap.getOutputStallDuration(format, size);
428     }
429 
430     /**
431      * Get a list of sizes compatible with {@code klass} to use as an output.
432      *
433      * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}.
434      * </p>
435      *
436      * @param klass
437      *          a {@link Class} object reference
438      * @return
439      *          a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
440      *          or {@code null} if the {@code klass} is not a supported output.
441      */
getOutputSizes(@onNull Class<T> klass)442     public @Nullable <T> Set<Size> getOutputSizes(@NonNull Class<T> klass) {
443         if (mSupportsPrivate) {
444             return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
445         }
446 
447         return null;
448     }
449 
450     /**
451      * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
452      * for the class/size combination (in nanoseconds).
453      *
454      * <p>For more information refer to
455      * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
456      *
457      * @param klass
458      *          a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
459      * @param size an output-compatible size
460      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
461      *          0 if the minimum frame duration is not available.
462      *
463      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
464      */
getOutputMinFrameDuration(@onNull final Class<T> klass, @NonNull final Size size)465     public @IntRange(from = 0) <T> long getOutputMinFrameDuration(@NonNull final Class<T> klass,
466             @NonNull final Size size) {
467         if (mSupportsPrivate) {
468             return mRecommendedMap.getOutputMinFrameDuration(klass, size);
469         }
470 
471         return 0;
472     }
473 
474     /**
475      * Get the stall duration for the class/size combination (in nanoseconds).
476      *
477      * <p>For more information refer to
478      * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}.
479      *
480      * @param klass
481      *          a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
482      * @param size an output-compatible size
483      * @return a minimum frame duration {@code >} 0 in nanoseconds, or 0 if the stall duration is
484      *         not available.
485      *
486      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
487      */
getOutputStallDuration(@onNull final Class<T> klass, @NonNull final Size size)488     public @IntRange(from = 0) <T> long getOutputStallDuration(@NonNull final Class<T> klass,
489             @NonNull final Size size) {
490         if (mSupportsPrivate) {
491             return mRecommendedMap.getOutputStallDuration(klass, size);
492         }
493 
494         return 0;
495     }
496 
497     /**
498      * Determine whether or not the {@code surface} in its current state is suitable to be included
499      * in a {@link CameraDevice#createCaptureSession capture session} as an output.
500      *
501      * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
502      * </p>
503      *
504      * @param surface a {@link Surface} object reference
505      * @return {@code true} if this is supported, {@code false} otherwise
506      *
507      * @throws IllegalArgumentException if the Surface endpoint is no longer valid
508      *
509      */
isOutputSupportedFor(@onNull Surface surface)510     public boolean isOutputSupportedFor(@NonNull Surface surface) {
511         return mRecommendedMap.isOutputSupportedFor(surface);
512     }
513 
514 }
515