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(SessionConfiguration)}.
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(SessionConfiguration)
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      * If supported, the recommended 10-bit output stream configurations must include
153      * a subset of the advertised {@link android.graphics.ImageFormat#YCBCR_P010} and
154      * {@link android.graphics.ImageFormat#PRIVATE} outputs that are optimized for power
155      * and performance when registered along with a supported 10-bit dynamic range profile.
156      * {@see android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} for
157      * details.
158      */
159      public static final int USECASE_10BIT_OUTPUT = 0x8;
160 
161     /**
162      * Device specific use cases.
163      * @hide
164      */
165     public static final int USECASE_VENDOR_START = 0x18;
166 
167     /** @hide */
168     @Retention(RetentionPolicy.SOURCE)
169     @IntDef(prefix = {"USECASE_"}, value =
170         {USECASE_PREVIEW,
171         USECASE_RECORD,
172         USECASE_VIDEO_SNAPSHOT,
173         USECASE_SNAPSHOT,
174         USECASE_ZSL,
175         USECASE_RAW,
176         USECASE_LOW_LATENCY_SNAPSHOT,
177         USECASE_10BIT_OUTPUT})
178      public @interface RecommendedUsecase {};
179 
180     /**
181      * Create a new {@link RecommendedStreamConfigurationMap}.
182      *
183      * @param recommendedMap stream configuration map that contains for the specific use case
184      * @param usecase Recommended use case
185      * @param supportsPrivate Flag indicating private format support.
186      *
187      * @hide
188      */
RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase, boolean supportsPrivate)189     public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase,
190             boolean supportsPrivate) {
191         mRecommendedMap = recommendedMap;
192         mUsecase = usecase;
193         mSupportsPrivate = supportsPrivate;
194     }
195 
196     /**
197      * Get the use case value for the recommended stream configurations.
198      *
199      * @return Use case id.
200      */
getRecommendedUseCase()201     public @RecommendedUsecase int getRecommendedUseCase() {
202         return mUsecase;
203     }
204 
getUnmodifiableIntegerSet(int[] intArray)205     private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) {
206         if ((intArray != null) && (intArray.length > 0)) {
207             ArraySet<Integer> integerSet = new ArraySet<Integer>();
208             integerSet.ensureCapacity(intArray.length);
209             for (int intEntry : intArray) {
210                 integerSet.add(intEntry);
211             }
212 
213             return Collections.unmodifiableSet(integerSet);
214         }
215 
216         return null;
217     }
218 
219     /**
220      * Get the image {@code format} output formats in this stream configuration.
221      *
222      * <p>
223      * For more information refer to {@link StreamConfigurationMap#getOutputFormats}.
224      * </p>
225      *
226      * @return a non-modifiable set of Integer formats
227      */
getOutputFormats()228     public @NonNull Set<Integer> getOutputFormats() {
229         return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats());
230     }
231 
232     /**
233      * Get the image {@code format} output formats for a reprocessing input format.
234      *
235      * <p>
236      * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}.
237      * </p>
238      *
239      * @return a non-modifiable set of Integer formats
240      */
getValidOutputFormatsForInput(@ormat int inputFormat)241     public @Nullable Set<Integer> getValidOutputFormatsForInput(@Format int inputFormat) {
242         return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
243                     inputFormat));
244     }
245 
246     /**
247      * Get the image {@code format} input formats in this stream configuration.
248      *
249      * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
250      * or in {@link PixelFormat} (and there is no possibility of collision).</p>
251      *
252      * @return a non-modifiable set of Integer formats
253      */
getInputFormats()254     public @Nullable Set<Integer> getInputFormats() {
255         return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats());
256     }
257 
getUnmodifiableSizeSet(Size[] sizeArray)258     private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) {
259         if ((sizeArray != null) && (sizeArray.length > 0)) {
260             ArraySet<Size> sizeSet = new ArraySet<Size>();
261             sizeSet.addAll(Arrays.asList(sizeArray));
262             return Collections.unmodifiableSet(sizeSet);
263         }
264 
265         return  null;
266     }
267 
268     /**
269      * Get the supported input sizes for this input format.
270      *
271      * <p>The format must have come from {@link #getInputFormats}; otherwise
272      * {@code null} is returned.</p>
273      *
274      * @param format a format from {@link #getInputFormats}
275      * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
276      */
getInputSizes(@ormat int format)277     public @Nullable Set<Size> getInputSizes(@Format int format) {
278         return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
279     }
280 
281     /**
282      * Determine whether or not output surfaces with a particular user-defined format can be passed
283      * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}.
284      *
285      * <p>
286      * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
287      * </p>
288      *
289      *
290      * @param format an image format from either {@link ImageFormat} or {@link PixelFormat}
291      * @return
292      *          {@code true} if using a {@code surface} with this {@code format} will be
293      *          supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)}
294      *
295      * @throws IllegalArgumentException
296      *          if the image format was not a defined named constant
297      *          from either {@link ImageFormat} or {@link PixelFormat}
298      */
isOutputSupportedFor(@ormat int format)299     public boolean isOutputSupportedFor(@Format int format) {
300         return mRecommendedMap.isOutputSupportedFor(format);
301     }
302 
303     /**
304      * Get a list of sizes compatible with the requested image {@code format}.
305      *
306      * <p>
307      * For more information refer to {@link StreamConfigurationMap#getOutputSizes}.
308      * </p>
309      *
310      *
311      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
312      * @return  a non-modifiable set of supported sizes,
313      *          or {@code null} if the {@code format} is not a supported output
314      */
getOutputSizes(@ormat int format)315     public @Nullable Set<Size> getOutputSizes(@Format int format) {
316         return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
317     }
318 
319     /**
320      * Get a list of supported high speed video recording sizes.
321      * <p>
322      * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}.
323      * </p>
324      *
325      * @return a non-modifiable set of supported high speed video recording sizes
326      */
getHighSpeedVideoSizes()327     public @Nullable Set<Size> getHighSpeedVideoSizes() {
328         return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes());
329     }
330 
getUnmodifiableRangeSet(Range<Integer>[] rangeArray)331     private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) {
332         if ((rangeArray != null) && (rangeArray.length > 0)) {
333             ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>();
334             rangeSet.addAll(Arrays.asList(rangeArray));
335             return Collections.unmodifiableSet(rangeSet);
336         }
337 
338         return null;
339     }
340 
341     /**
342      * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
343      *
344      * <p>
345      * For further information refer to
346      * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}.
347      * </p>
348      * @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
349      * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
350      *         bound of returned ranges is guaranteed to be greater than or equal to 120.
351      * @throws IllegalArgumentException if input size does not exist in the return value of
352      *             getHighSpeedVideoSizes
353      */
getHighSpeedVideoFpsRangesFor(@onNull Size size)354     public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRangesFor(@NonNull Size size) {
355         return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size));
356     }
357 
358     /**
359      * Get a list of supported high speed video recording FPS ranges.
360      * <p>
361      * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}.
362      * </p>
363      * @return a non-modifiable set of supported high speed video recording FPS ranges The upper
364      *         bound of returned ranges is guaranteed to be larger or equal to 120.
365      */
getHighSpeedVideoFpsRanges()366     public @Nullable Set<Range<Integer>> getHighSpeedVideoFpsRanges() {
367         return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges());
368     }
369 
370     /**
371      * Get the supported video sizes for an input high speed FPS range.
372      *
373      * <p>
374      * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}.
375      * </p>
376      *
377      * @param fpsRange one of the FPS ranges returned by {@link #getHighSpeedVideoFpsRanges()}
378      * @return A non-modifiable set of video sizes to create high speed capture sessions for high
379      *         speed streaming use cases.
380      *
381      * @throws IllegalArgumentException if input FPS range does not exist in the return value of
382      *         getHighSpeedVideoFpsRanges
383      */
getHighSpeedVideoSizesFor(@onNull Range<Integer> fpsRange)384     public @Nullable Set<Size> getHighSpeedVideoSizesFor(@NonNull Range<Integer> fpsRange) {
385         return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange));
386     }
387 
388     /**
389      * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
390      * rate.
391      *
392      * <p>
393      * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}.
394      * </p>
395      *
396      * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
397      *         the BURST_CAPTURE capability is not supported
398      */
getHighResolutionOutputSizes(@ormat int format)399     public @Nullable Set<Size> getHighResolutionOutputSizes(@Format int format) {
400         return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
401     }
402 
403     /**
404      * Get the minimum
405      * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration}
406      * for the format/size combination (in nanoseconds).
407      *
408      * <p>
409      * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}.
410      * </p>
411      *
412      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
413      * @param size an output-compatible size
414      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
415      *          0 if the minimum frame duration is not available.
416      *
417      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
418      */
getOutputMinFrameDuration(@ormat int format, @NonNull Size size)419     public @IntRange(from = 0) long getOutputMinFrameDuration(@Format int format,
420             @NonNull Size size) {
421         return mRecommendedMap.getOutputMinFrameDuration(format, size);
422     }
423 
424     /**
425      * Get the stall duration for the format/size combination (in nanoseconds).
426      *
427      * <p>
428      * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}.
429      * </p>
430      *
431      * @param format an image format from {@link ImageFormat} or {@link PixelFormat}
432      * @param size an output-compatible size
433      * @return a stall duration {@code >=} 0 in nanoseconds
434      *
435      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
436      */
getOutputStallDuration(@ormat int format, @NonNull Size size)437     public @IntRange(from = 0) long getOutputStallDuration(@Format int format, @NonNull Size size) {
438         return mRecommendedMap.getOutputStallDuration(format, size);
439     }
440 
441     /**
442      * Get a list of sizes compatible with {@code klass} to use as an output.
443      *
444      * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}.
445      * </p>
446      *
447      * @param klass
448      *          a {@link Class} object reference
449      * @return
450      *          a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
451      *          or {@code null} if the {@code klass} is not a supported output.
452      */
getOutputSizes(@onNull Class<T> klass)453     public @Nullable <T> Set<Size> getOutputSizes(@NonNull Class<T> klass) {
454         if (mSupportsPrivate) {
455             return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
456         }
457 
458         return null;
459     }
460 
461     /**
462      * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
463      * for the class/size combination (in nanoseconds).
464      *
465      * <p>For more information refer to
466      * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p>
467      *
468      * @param klass
469      *          a class which has a non-empty array returned by {@link #getOutputSizes(Class)}
470      * @param size an output-compatible size
471      * @return a minimum frame duration {@code >} 0 in nanoseconds, or
472      *          0 if the minimum frame duration is not available.
473      *
474      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
475      */
getOutputMinFrameDuration(@onNull final Class<T> klass, @NonNull final Size size)476     public @IntRange(from = 0) <T> long getOutputMinFrameDuration(@NonNull final Class<T> klass,
477             @NonNull final Size size) {
478         if (mSupportsPrivate) {
479             return mRecommendedMap.getOutputMinFrameDuration(klass, size);
480         }
481 
482         return 0;
483     }
484 
485     /**
486      * Get the stall duration for the class/size combination (in nanoseconds).
487      *
488      * <p>For more information refer to
489      * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}.
490      *
491      * @param klass
492      *          a class which has a non-empty array returned by {@link #getOutputSizes(Class)}.
493      * @param size an output-compatible size
494      * @return a minimum frame duration {@code >} 0 in nanoseconds, or 0 if the stall duration is
495      *         not available.
496      *
497      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
498      */
getOutputStallDuration(@onNull final Class<T> klass, @NonNull final Size size)499     public @IntRange(from = 0) <T> long getOutputStallDuration(@NonNull final Class<T> klass,
500             @NonNull final Size size) {
501         if (mSupportsPrivate) {
502             return mRecommendedMap.getOutputStallDuration(klass, size);
503         }
504 
505         return 0;
506     }
507 
508     /**
509      * Determine whether or not the {@code surface} in its current
510      * state is suitable to be included in a {@link
511      * CameraDevice#createCaptureSession(SessionConfiguration) capture
512      * session} as an output.
513      *
514      * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}.
515      * </p>
516      *
517      * @param surface a {@link Surface} object reference
518      * @return {@code true} if this is supported, {@code false} otherwise
519      *
520      * @throws IllegalArgumentException if the Surface endpoint is no longer valid
521      *
522      */
isOutputSupportedFor(@onNull Surface surface)523     public boolean isOutputSupportedFor(@NonNull Surface surface) {
524         return mRecommendedMap.isOutputSupportedFor(surface);
525     }
526 
527 }
528