• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormat;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.graphics.ImageFormat;
24 import android.graphics.ImageFormat.Format;
25 import android.hardware.camera2.CameraCharacteristics;
26 import android.hardware.camera2.CameraDevice;
27 import android.hardware.camera2.CameraManager;
28 import android.hardware.camera2.CameraMetadata;
29 import android.hardware.camera2.params.OutputConfiguration;
30 import android.hardware.camera2.params.OutputConfiguration.StreamUseCase;
31 import android.hardware.camera2.params.StreamConfigurationMap;
32 import android.hardware.camera2.utils.HashCodeHelpers;
33 import android.media.CamcorderProfile;
34 import android.util.Log;
35 import android.util.Pair;
36 import android.util.Size;
37 
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.Comparator;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 
46 /**
47  * Immutable class to store the available mandatory stream combination.
48  *
49  * <p>A mandatory stream combination refers to a specific entry in the documented sets of
50  * required stream {@link CameraDevice#createCaptureSession combinations}.
51  * These combinations of streams are required to be supported by the camera device.
52  *
53  * <p>The list of stream combinations is available by invoking
54  * {@link CameraCharacteristics#get} and passing key
55  * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_STREAM_COMBINATIONS}.</p>
56  */
57 public final class MandatoryStreamCombination {
58     private static final String TAG = "MandatoryStreamCombination";
59     /**
60      * Immutable class to store available mandatory stream information.
61      */
62     public static final class MandatoryStreamInformation {
63         private final int mFormat;
64         private final ArrayList<Size> mAvailableSizes = new ArrayList<Size> ();
65         private final boolean mIsInput;
66         private final boolean mIsUltraHighResolution;
67         private final boolean mIsMaximumSize;
68         private final boolean mIs10BitCapable;
69         private final long mStreamUseCase;
70 
71         /**
72          * Create a new {@link MandatoryStreamInformation}.
73          *
74          * @param availableSizes List of possible stream sizes.
75          * @param format Image format.
76          * @param isMaximumSize Whether this is a maximum size stream.
77          *
78          * @throws IllegalArgumentException
79          *              if sizes is empty or if the format was not user-defined in
80          *              ImageFormat/PixelFormat.
81          * @hide
82          */
MandatoryStreamInformation(@onNull List<Size> availableSizes, @Format int format, boolean isMaximumSize)83         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
84                 boolean isMaximumSize) {
85             this(availableSizes, format, isMaximumSize, /*isInput*/false,
86                     /*isUltraHighResolution*/false);
87         }
88 
89         /**
90          * Create a new {@link MandatoryStreamInformation}.
91          *
92          * @param availableSizes List of possible stream sizes.
93          * @param format Image format.
94          * @param isMaximumSize Whether this is a maximum size stream.
95          * @param isInput Flag indicating whether this stream is input.
96          *
97          * @throws IllegalArgumentException
98          *              if sizes is empty or if the format was not user-defined in
99          *              ImageFormat/PixelFormat.
100          * @hide
101          */
MandatoryStreamInformation(@onNull List<Size> availableSizes, @Format int format, boolean isMaximumSize, boolean isInput)102         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
103                 boolean isMaximumSize, boolean isInput) {
104             this(availableSizes, format, isMaximumSize, isInput,
105                     /*isUltraHighResolution*/ false);
106         }
107 
108         /**
109          * Create a new {@link MandatoryStreamInformation}.
110          *
111          * @param availableSizes List of possible stream sizes.
112          * @param format Image format.
113          * @param isMaximumSize Whether this is a maximum size stream.
114          * @param isInput Flag indicating whether this stream is input.
115          * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
116          *                              stream.
117          *
118          * @throws IllegalArgumentException
119          *              if sizes is empty or if the format was not user-defined in
120          *              ImageFormat/PixelFormat.
121          * @hide
122          */
MandatoryStreamInformation(@onNull List<Size> availableSizes, @Format int format, boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution)123         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
124                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution) {
125             this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution,
126                     /*is10bitCapable*/ false);
127         }
128 
129         /**
130          * Create a new {@link MandatoryStreamInformation}.
131          *
132          * @param availableSizes List of possible stream sizes.
133          * @param format Image format.
134          * @param isMaximumSize Whether this is a maximum size stream.
135          * @param isInput Flag indicating whether this stream is input.
136          * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
137          *                              stream.
138          * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit
139          *
140          * @throws IllegalArgumentException
141          *              if sizes is empty or if the format was not user-defined in
142          *              ImageFormat/PixelFormat.
143          * @hide
144          */
MandatoryStreamInformation(@onNull List<Size> availableSizes, @Format int format, boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution, boolean is10BitCapable)145         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
146                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
147                 boolean is10BitCapable) {
148             this(availableSizes, format, isMaximumSize, isInput, isUltraHighResolution,
149                     is10BitCapable, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
150         }
151 
152         /**
153          * Create a new {@link MandatoryStreamInformation}.
154          *
155          * @param availableSizes List of possible stream sizes.
156          * @param format Image format.
157          * @param isMaximumSize Whether this is a maximum size stream.
158          * @param isInput Flag indicating whether this stream is input.
159          * @param isUltraHighResolution Flag indicating whether this is a ultra-high resolution
160          *                              stream.
161          * @param is10BitCapable Flag indicating whether this stream is able to support 10-bit
162          * @param streamUseCase The stream use case.
163          *
164          * @throws IllegalArgumentException
165          *              if sizes is empty or if the format was not user-defined in
166          *              ImageFormat/PixelFormat.
167          * @hide
168          */
MandatoryStreamInformation(@onNull List<Size> availableSizes, @Format int format, boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution, boolean is10BitCapable, @StreamUseCase long streamUseCase)169         public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
170                 boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
171                 boolean is10BitCapable, @StreamUseCase long streamUseCase) {
172             if (availableSizes.isEmpty()) {
173                 throw new IllegalArgumentException("No available sizes");
174             }
175             mAvailableSizes.addAll(availableSizes);
176             mFormat = checkArgumentFormat(format);
177             mIsMaximumSize = isMaximumSize;
178             mIsInput = isInput;
179             mIsUltraHighResolution = isUltraHighResolution;
180             mIs10BitCapable = is10BitCapable;
181             mStreamUseCase = streamUseCase;
182         }
183 
184         /**
185          * Confirms whether or not this is an input stream.
186          * @return true in case the stream is input, false otherwise.
187          */
isInput()188         public boolean isInput() {
189             return mIsInput;
190         }
191 
192         /**
193          * Confirms whether or not this is an ultra high resolution stream.
194          *
195          * <p>An 'ultra high resolution' stream is one which has a configuration which appears in
196          * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION},
197          * Streams which are ultra high resolution must not be included with streams which are not
198          * ultra high resolution in the same {@link android.hardware.camera2.CaptureRequest}.</p>
199          *
200          * @return true in case the stream is ultra high resolution, false otherwise.
201         */
isUltraHighResolution()202         public boolean isUltraHighResolution() {
203             return mIsUltraHighResolution;
204         }
205 
206         /**
207          * Confirms whether or not this is a maximum size stream.
208          *
209          * <p>A stream with maximum size is one with the camera device's maximum resolution
210          * for the stream's format as appears in {@link
211          * android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}. This
212          * maximum size has the same meaning as the 'MAXIMUM' target size documented in the camera
213          * capture session {@link CameraDevice#createCaptureSession guideline}.</p>
214          *
215          * <p>The application can use a
216          * {@link android.hardware.camera2.MultiResolutionImageReader} for a maximum size
217          * output stream if the camera device supports multi-resolution outputs for the stream's
218          * format. See {@link
219          * android.hardware.camera2.CameraCharacteristics#SCALER_MULTI_RESOLUTION_STREAM_CONFIGURATION_MAP}
220          * for details.</p>
221          *
222          * <p>This is different from the ultra high resolution flag, which applies only to
223          * ultra high resolution sensor camera devices and refers to a stream in
224          * {@link
225          * android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP_MAXIMUM_RESOLUTION}
226          * instead.</p>
227          *
228          * @return true if the stream is a maximum size stream.
229          */
isMaximumSize()230         public boolean isMaximumSize() {
231             return mIsMaximumSize;
232         }
233 
234         /**
235          * Indicates whether this stream is able to support 10-bit output.
236          *
237          * <p>10-bit capable streams can be configured to output 10-bit sample data via calls to
238          * {@link android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} and
239          * selecting the appropriate output Surface pixel format which can be queried via
240          * {@link #get10BitFormat()} and will be either
241          * {@link ImageFormat#PRIVATE} (the default for Surfaces initialized by
242          * {@link android.view.SurfaceView}, {@link android.view.TextureView},
243          * {@link android.media.MediaRecorder}, {@link android.media.MediaCodec} etc.) or
244          * {@link ImageFormat#YCBCR_P010}.</p>
245          *
246          * @return true if stream is able to output 10-bit pixels
247          *
248          * @see android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT
249          * @see OutputConfiguration#setDynamicRangeProfile
250          */
is10BitCapable()251         public boolean is10BitCapable() {
252             return mIs10BitCapable;
253         }
254 
255         /**
256          * Return the list of available sizes for this mandatory stream.
257          *
258          * <p>Per documented {@link CameraDevice#createCaptureSession guideline} the largest
259          * resolution in the result will be tested and guaranteed to work. If clients want to use
260          * smaller sizes, then the resulting
261          * {@link android.hardware.camera2.params.SessionConfiguration session configuration} can
262          * be tested either by calling {@link CameraDevice#createCaptureSession} or
263          * {@link CameraDevice#isSessionConfigurationSupported}.
264          *
265          * @return non-modifiable ascending list of available sizes.
266          */
getAvailableSizes()267         public @NonNull List<Size> getAvailableSizes() {
268             return Collections.unmodifiableList(mAvailableSizes);
269         }
270 
271         /**
272          * Retrieve the mandatory stream {@code format}.
273          *
274          * @return integer format.
275          */
getFormat()276         public @Format int getFormat() {
277             // P010 YUV streams must be supported along with SDR 8-bit YUV streams
278             if ((mIs10BitCapable)  && (mFormat == ImageFormat.YCBCR_P010)) {
279                 return ImageFormat.YUV_420_888;
280             }
281             return mFormat;
282         }
283 
284         /**
285          * Retrieve the mandatory stream 10-bit {@code format} for 10-bit capable streams.
286          *
287          * <p>In case {@link #is10BitCapable()} returns {@code true}, then this method
288          * will return the corresponding 10-bit output Surface pixel format. Depending on
289          * the stream type it will be either {@link ImageFormat#PRIVATE} or
290          * {@link ImageFormat#YCBCR_P010}.</p>
291          *
292          * @return integer format.
293          * @throws UnsupportedOperationException in case the stream is not capable of 10-bit output
294          * @see #is10BitCapable()
295          */
get10BitFormat()296         public @Format int get10BitFormat() {
297             if (!mIs10BitCapable) {
298                 throw new UnsupportedOperationException("10-bit output is not supported!");
299             }
300             return mFormat;
301         }
302 
303         /**
304          * Retrieve the mandatory stream use case.
305          *
306          * <p>If this {@link MandatoryStreamInformation} is part of a mandatory stream
307          * combination for stream use cases, the return value will be a non-DEFAULT value.
308          * For {@link MandatoryStreamInformation} belonging to other mandatory stream
309          * combinations, the return value will be DEFAULT. </p>
310          *
311          * @return the long integer stream use case.
312          */
getStreamUseCase()313         public @StreamUseCase long getStreamUseCase() {
314             return mStreamUseCase;
315         }
316 
317         /**
318          * Check if this {@link MandatoryStreamInformation} is equal to another
319          * {@link MandatoryStreamInformation}.
320          *
321          * <p>Two vectors are only equal if and only if each of the respective elements is
322          * equal.</p>
323          *
324          * @return {@code true} if the objects were equal, {@code false} otherwise
325          */
326         @Override
equals(final Object obj)327         public boolean equals(final Object obj) {
328             if (obj == null) {
329                 return false;
330             }
331             if (this == obj) {
332                 return true;
333             }
334             if (obj instanceof MandatoryStreamInformation) {
335                 final MandatoryStreamInformation other = (MandatoryStreamInformation) obj;
336                 if ((mFormat != other.mFormat) || (mIsInput != other.mIsInput) ||
337                         (mIsUltraHighResolution != other.mIsUltraHighResolution) ||
338                         (mStreamUseCase != other.mStreamUseCase) ||
339                         (mAvailableSizes.size() != other.mAvailableSizes.size())) {
340                     return false;
341                 }
342 
343                 return mAvailableSizes.equals(other.mAvailableSizes);
344             }
345 
346             return false;
347         }
348 
349         /**
350          * {@inheritDoc}
351          */
352         @Override
hashCode()353         public int hashCode() {
354             return HashCodeHelpers.hashCode(mFormat, Boolean.hashCode(mIsInput),
355                     Boolean.hashCode(mIsUltraHighResolution), mAvailableSizes.hashCode(),
356                     mStreamUseCase);
357         }
358     }
359 
360     private final String mDescription;
361     private final boolean mIsReprocessable;
362     private final ArrayList<MandatoryStreamInformation> mStreamsInformation =
363             new ArrayList<MandatoryStreamInformation>();
364 
365     /**
366      * Short hand for stream use cases
367      */
368     private static final long STREAM_USE_CASE_PREVIEW =
369             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
370     private static final long STREAM_USE_CASE_STILL_CAPTURE =
371             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
372     private static final long STREAM_USE_CASE_RECORD =
373             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
374     private static final long STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
375             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
376     private static final long STREAM_USE_CASE_VIDEO_CALL =
377             CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
378 
379     /**
380      * Create a new {@link MandatoryStreamCombination}.
381      *
382      * @param streamsInformation list of available streams in the stream combination.
383      * @param description Summary of the stream combination use case.
384      * @param isReprocessable Flag whether the mandatory stream combination is reprocessable.
385      *
386      * @throws IllegalArgumentException
387      *              if stream information is empty
388      * @hide
389      */
MandatoryStreamCombination(@onNull List<MandatoryStreamInformation> streamsInformation, @NonNull String description, boolean isReprocessable)390     public MandatoryStreamCombination(@NonNull List<MandatoryStreamInformation> streamsInformation,
391             @NonNull String description, boolean isReprocessable) {
392         if (streamsInformation.isEmpty()) {
393             throw new IllegalArgumentException("Empty stream information");
394         }
395         mStreamsInformation.addAll(streamsInformation);
396         mDescription = description;
397         mIsReprocessable = isReprocessable;
398     }
399     /**
400      * Get the mandatory stream combination description.
401      *
402      * @return CharSequence with the mandatory combination description.
403      */
getDescription()404     public @NonNull CharSequence getDescription() {
405         return mDescription;
406     }
407 
408     /**
409      * Indicates whether the mandatory stream combination is reprocessable. Reprocessable is defined
410      * as a stream combination that contains one input stream
411      * ({@link MandatoryStreamInformation#isInput} return true).
412      *
413      * @return {@code true} in case the mandatory stream combination contains an input,
414      *         {@code false} otherwise.
415      */
isReprocessable()416     public boolean isReprocessable() {
417         return mIsReprocessable;
418     }
419 
420     /**
421      * Get information about each stream in the mandatory combination.
422      *
423      * @return Non-modifiable list of stream information.
424      *
425      */
getStreamsInformation()426     public @NonNull List<MandatoryStreamInformation> getStreamsInformation() {
427         return Collections.unmodifiableList(mStreamsInformation);
428     }
429 
430     /**
431      * Check if this {@link MandatoryStreamCombination} is equal to another
432      * {@link MandatoryStreamCombination}.
433      *
434      * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
435      *
436      * @return {@code true} if the objects were equal, {@code false} otherwise
437      */
438     @Override
equals(final Object obj)439     public boolean equals(final Object obj) {
440         if (obj == null) {
441             return false;
442         }
443         if (this == obj) {
444             return true;
445         }
446         if (obj instanceof MandatoryStreamCombination) {
447             final MandatoryStreamCombination other = (MandatoryStreamCombination) obj;
448             if ((mDescription != other.mDescription) ||
449                     (mIsReprocessable != other.mIsReprocessable) ||
450                     (mStreamsInformation.size() != other.mStreamsInformation.size())) {
451                 return false;
452             }
453 
454             return mStreamsInformation.equals(other.mStreamsInformation);
455         }
456 
457         return false;
458     }
459 
460     /**
461      * {@inheritDoc}
462      */
463     @Override
hashCode()464     public int hashCode() {
465         return HashCodeHelpers.hashCode(Boolean.hashCode(mIsReprocessable), mDescription.hashCode(),
466                 mStreamsInformation.hashCode());
467     }
468 
469     private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p, s1440p, FULL_RES }
470     private static enum ReprocessType { NONE, PRIVATE, YUV, REMOSAIC }
471     private static final class StreamTemplate {
472         public int mFormat;
473         public SizeThreshold mSizeThreshold;
474         public long mStreamUseCase;
StreamTemplate(int format, SizeThreshold sizeThreshold)475         public StreamTemplate(int format, SizeThreshold sizeThreshold) {
476             this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
477         }
StreamTemplate(@ormat int format, @NonNull SizeThreshold sizeThreshold, @StreamUseCase long streamUseCase)478         public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
479                 @StreamUseCase long streamUseCase) {
480             mFormat = format;
481             mSizeThreshold = sizeThreshold;
482             mStreamUseCase = streamUseCase;
483         }
484     }
485 
486     private static final class StreamCombinationTemplate {
487         public StreamTemplate[] mStreamTemplates;
488         public String mDescription;
489         public ReprocessType mReprocessType;
490         // Substitute MAXIMUM size YUV output stream with JPEG / RAW_SENSOR.
491         public boolean mSubstituteYUV = false;
492 
StreamCombinationTemplate(@onNull StreamTemplate[] streamTemplates, @NonNull String description)493         public StreamCombinationTemplate(@NonNull StreamTemplate[] streamTemplates,
494                 @NonNull String description) {
495             this(streamTemplates, description, /*reprocessType*/ReprocessType.NONE);
496         }
497 
StreamCombinationTemplate(@onNull StreamTemplate[] streamTemplates, @NonNull String description, ReprocessType reprocessType)498         public StreamCombinationTemplate(@NonNull StreamTemplate[] streamTemplates,
499                 @NonNull String description, ReprocessType reprocessType) {
500             this(streamTemplates, description, reprocessType, /*substituteYUV*/ false);
501         }
502 
StreamCombinationTemplate(@onNull StreamTemplate[] streamTemplates, @NonNull String description, boolean substituteYUV)503         public StreamCombinationTemplate(@NonNull StreamTemplate[] streamTemplates,
504                 @NonNull String description, boolean substituteYUV) {
505             this(streamTemplates, description, /*reprocessType*/ ReprocessType.NONE,
506                     substituteYUV);
507         }
508 
StreamCombinationTemplate(@onNull StreamTemplate[] streamTemplates, @NonNull String description, ReprocessType reprocessType, boolean substituteYUV)509         public StreamCombinationTemplate(@NonNull StreamTemplate[] streamTemplates,
510                 @NonNull String description, ReprocessType reprocessType, boolean substituteYUV) {
511             mStreamTemplates = streamTemplates;
512             mReprocessType = reprocessType;
513             mDescription = description;
514             mSubstituteYUV = substituteYUV;
515         }
516     }
517 
518     private static StreamCombinationTemplate sLegacyCombinations[] = {
519         new StreamCombinationTemplate(new StreamTemplate [] {
520                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM) },
521                 "Simple preview, GPU video processing, or no-preview video recording"),
522         new StreamCombinationTemplate(new StreamTemplate [] {
523                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
524                 "No-viewfinder still image capture"),
525         new StreamCombinationTemplate(new StreamTemplate [] {
526                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
527                 "In-application video/image processing"),
528         new StreamCombinationTemplate(new StreamTemplate [] {
529                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
530                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
531                 "Standard still imaging"),
532         new StreamCombinationTemplate(new StreamTemplate [] {
533                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
534                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
535                 "In-app processing plus still capture"),
536         new StreamCombinationTemplate(new StreamTemplate [] {
537                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
538                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW) },
539                 "Standard recording"),
540         new StreamCombinationTemplate(new StreamTemplate [] {
541                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
542                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW) },
543                 "Preview plus in-app processing"),
544         new StreamCombinationTemplate(new StreamTemplate [] {
545                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
546                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
547                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
548                 "Still capture plus in-app processing")
549     };
550 
551     private static StreamCombinationTemplate sLimitedCombinations[] = {
552         new StreamCombinationTemplate(new StreamTemplate [] {
553                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
554                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD)},
555                 "High-resolution video recording with preview"),
556         new StreamCombinationTemplate(new StreamTemplate [] {
557                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
558                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD)},
559                 "High-resolution in-app video processing with preview"),
560         new StreamCombinationTemplate(new StreamTemplate [] {
561                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
562                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD) },
563                 "Two-input in-app video processing"),
564         new StreamCombinationTemplate(new StreamTemplate [] {
565                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
566                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
567                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD) },
568                 "High-resolution recording with video snapshot"),
569         new StreamCombinationTemplate(new StreamTemplate [] {
570                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
571                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD),
572                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD) },
573                 "High-resolution in-app processing with video snapshot"),
574         new StreamCombinationTemplate(new StreamTemplate [] {
575                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
576                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
577                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
578                 "Two-input in-app processing with still capture")
579     };
580 
581     private static StreamCombinationTemplate sBurstCombinations[] = {
582         new StreamCombinationTemplate(new StreamTemplate [] {
583                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
584                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM) },
585                 "Maximum-resolution GPU processing with preview"),
586         new StreamCombinationTemplate(new StreamTemplate [] {
587                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
588                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
589                 "Maximum-resolution in-app processing with preview"),
590         new StreamCombinationTemplate(new StreamTemplate [] {
591                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
592                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
593                 "Maximum-resolution two-input in-app processsing")
594     };
595 
596     private static StreamCombinationTemplate sFullCombinations[] = {
597         new StreamCombinationTemplate(new StreamTemplate [] {
598                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM),
599                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM) },
600                 "Maximum-resolution GPU processing with preview"),
601         new StreamCombinationTemplate(new StreamTemplate [] {
602                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM),
603                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
604                 "Maximum-resolution in-app processing with preview"),
605         new StreamCombinationTemplate(new StreamTemplate [] {
606                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
607                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
608                 "Maximum-resolution two-input in-app processsing"),
609         new StreamCombinationTemplate(new StreamTemplate [] {
610                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
611                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
612                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
613                 "Video recording with maximum-size video snapshot"),
614         new StreamCombinationTemplate(new StreamTemplate [] {
615                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.VGA),
616                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
617                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
618                 "Standard video recording plus maximum-resolution in-app processing"),
619         new StreamCombinationTemplate(new StreamTemplate [] {
620                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.VGA),
621                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
622                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
623                 "Preview plus two-input maximum-resolution in-app processing")
624     };
625 
626     private static StreamCombinationTemplate sRawCombinations[] = {
627         new StreamCombinationTemplate(new StreamTemplate [] {
628                 new StreamTemplate(ImageFormat.RAW_SENSOR,  SizeThreshold.MAXIMUM) },
629                 "No-preview DNG capture"),
630         new StreamCombinationTemplate(new StreamTemplate [] {
631                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
632                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
633                 "Standard DNG capture"),
634         new StreamCombinationTemplate(new StreamTemplate [] {
635                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
636                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
637                 "In-app processing plus DNG capture"),
638         new StreamCombinationTemplate(new StreamTemplate [] {
639                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
640                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
641                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
642                 "Video recording with DNG capture"),
643         new StreamCombinationTemplate(new StreamTemplate [] {
644                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
645                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
646                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
647                 "Preview with in-app processing and DNG capture"),
648         new StreamCombinationTemplate(new StreamTemplate [] {
649                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
650                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
651                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
652                 "Two-input in-app processing plus DNG capture"),
653         new StreamCombinationTemplate(new StreamTemplate [] {
654                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
655                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
656                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
657                 "Still capture with simultaneous JPEG and DNG"),
658         new StreamCombinationTemplate(new StreamTemplate [] {
659                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
660                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
661                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
662                 "In-app processing with simultaneous JPEG and DNG")
663     };
664 
665     private static StreamCombinationTemplate sLevel3Combinations[] = {
666         new StreamCombinationTemplate(new StreamTemplate [] {
667                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
668                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.VGA),
669                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
670                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
671                 "In-app viewfinder analysis with dynamic selection of output format"),
672         new StreamCombinationTemplate(new StreamTemplate [] {
673                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
674                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.VGA),
675                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
676                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
677                 "In-app viewfinder analysis with dynamic selection of output format")
678     };
679 
680     private static StreamCombinationTemplate sLimitedPrivateReprocCombinations[] = {
681         new StreamCombinationTemplate(new StreamTemplate [] {
682                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
683                 "No-viewfinder still image reprocessing",
684                 /*reprocessType*/ ReprocessType.PRIVATE),
685         new StreamCombinationTemplate(new StreamTemplate [] {
686                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
687                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
688                 "ZSL(Zero-Shutter-Lag) still imaging",
689                 /*reprocessType*/ ReprocessType.PRIVATE),
690         new StreamCombinationTemplate(new StreamTemplate [] {
691                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
692                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
693                 "ZSL still and in-app processing imaging",
694                 /*reprocessType*/ ReprocessType.PRIVATE),
695         new StreamCombinationTemplate(new StreamTemplate [] {
696                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
697                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
698                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
699                 "ZSL in-app processing with still capture",
700                 /*reprocessType*/ ReprocessType.PRIVATE),
701     };
702 
703     private static StreamCombinationTemplate sLimitedYUVReprocCombinations[] = {
704         new StreamCombinationTemplate(new StreamTemplate [] {
705                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
706                 "No-viewfinder still image reprocessing",
707                 /*reprocessType*/ ReprocessType.YUV),
708         new StreamCombinationTemplate(new StreamTemplate [] {
709                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
710                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
711                 "ZSL(Zero-Shutter-Lag) still imaging",
712                 /*reprocessType*/ ReprocessType.YUV),
713         new StreamCombinationTemplate(new StreamTemplate [] {
714                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
715                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
716                 "ZSL still and in-app processing imaging",
717                 /*reprocessType*/ ReprocessType.YUV),
718         new StreamCombinationTemplate(new StreamTemplate [] {
719                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
720                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
721                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
722                 "ZSL in-app processing with still capture",
723                 /*reprocessType*/ ReprocessType.YUV),
724     };
725 
726     private static StreamCombinationTemplate sFullPrivateReprocCombinations[] = {
727         new StreamCombinationTemplate(new StreamTemplate [] {
728                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
729                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD) },
730                 "High-resolution ZSL in-app video processing with regular preview",
731                 /*reprocessType*/ ReprocessType.PRIVATE),
732         new StreamCombinationTemplate(new StreamTemplate [] {
733                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
734                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
735                 "Maximum-resolution ZSL in-app processing with regular preview",
736                 /*reprocessType*/ ReprocessType.PRIVATE),
737         new StreamCombinationTemplate(new StreamTemplate [] {
738                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
739                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM) },
740                 "Maximum-resolution two-input ZSL in-app processing",
741                 /*reprocessType*/ ReprocessType.PRIVATE),
742         new StreamCombinationTemplate(new StreamTemplate [] {
743                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
744                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
745                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
746                 "ZSL still capture and in-app processing",
747                 /*reprocessType*/ ReprocessType.PRIVATE),
748     };
749 
750     private static StreamCombinationTemplate sFullYUVReprocCombinations[] = {
751         new StreamCombinationTemplate(new StreamTemplate [] {
752                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW) },
753                 "Maximum-resolution multi-frame image fusion in-app processing with regular "
754                 + "preview",
755                 /*reprocessType*/ ReprocessType.YUV),
756         new StreamCombinationTemplate(new StreamTemplate [] {
757                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW) },
758                 "Maximum-resolution multi-frame image fusion two-input in-app processing",
759                 /*reprocessType*/ ReprocessType.YUV),
760         new StreamCombinationTemplate(new StreamTemplate [] {
761                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
762                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD) },
763                 "High-resolution ZSL in-app video processing with regular preview",
764                 /*reprocessType*/ ReprocessType.YUV),
765         new StreamCombinationTemplate(new StreamTemplate [] {
766                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
767                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
768                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
769                 "ZSL still capture and in-app processing",
770                 /*reprocessType*/ ReprocessType.YUV),
771     };
772 
773     private static StreamCombinationTemplate sRAWPrivateReprocCombinations[] = {
774         new StreamCombinationTemplate(new StreamTemplate [] {
775                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
776                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
777                 "Mutually exclusive ZSL in-app processing and DNG capture",
778                 /*reprocessType*/ ReprocessType.PRIVATE),
779         new StreamCombinationTemplate(new StreamTemplate [] {
780                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
781                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
782                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
783                 "Mutually exclusive ZSL in-app processing and preview with DNG capture",
784                 /*reprocessType*/ ReprocessType.PRIVATE),
785         new StreamCombinationTemplate(new StreamTemplate [] {
786                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
787                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
788                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
789                 "Mutually exclusive ZSL two-input in-app processing and DNG capture",
790                 /*reprocessType*/ ReprocessType.PRIVATE),
791         new StreamCombinationTemplate(new StreamTemplate [] {
792                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
793                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
794                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
795                 "Mutually exclusive ZSL still capture and preview with DNG capture",
796                 /*reprocessType*/ ReprocessType.PRIVATE),
797         new StreamCombinationTemplate(new StreamTemplate [] {
798                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
799                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
800                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
801                 "Mutually exclusive ZSL in-app processing with still capture and DNG capture",
802                 /*reprocessType*/ ReprocessType.PRIVATE),
803     };
804 
805     private static StreamCombinationTemplate sRAWYUVReprocCombinations[] = {
806         new StreamCombinationTemplate(new StreamTemplate [] {
807                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
808                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
809                 "Mutually exclusive ZSL in-app processing and DNG capture",
810                 /*reprocessType*/ ReprocessType.YUV),
811         new StreamCombinationTemplate(new StreamTemplate [] {
812                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
813                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
814                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
815                 "Mutually exclusive ZSL in-app processing and preview with DNG capture",
816                 /*reprocessType*/ ReprocessType.YUV),
817         new StreamCombinationTemplate(new StreamTemplate [] {
818                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
819                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
820                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
821                 "Mutually exclusive ZSL two-input in-app processing and DNG capture",
822                 /*reprocessType*/ ReprocessType.YUV),
823         new StreamCombinationTemplate(new StreamTemplate [] {
824                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
825                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
826                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
827                 "Mutually exclusive ZSL still capture and preview with DNG capture",
828                 /*reprocessType*/ ReprocessType.YUV),
829         new StreamCombinationTemplate(new StreamTemplate [] {
830                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW),
831                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
832                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
833                 "Mutually exclusive ZSL in-app processing with still capture and DNG capture",
834                 /*reprocessType*/ ReprocessType.YUV),
835     };
836 
837     private static StreamCombinationTemplate sLevel3PrivateReprocCombinations[] = {
838         new StreamCombinationTemplate(new StreamTemplate [] {
839                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
840                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.VGA),
841                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM),
842                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
843                 "In-app viewfinder analysis with ZSL, RAW, and JPEG reprocessing output",
844                 /*reprocessType*/ ReprocessType.PRIVATE),
845     };
846 
847     private static StreamCombinationTemplate sLevel3YUVReprocCombinations[] = {
848         new StreamCombinationTemplate(new StreamTemplate [] {
849                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
850                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.VGA),
851                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM) },
852                 "In-app viewfinder analysis with ZSL and RAW",
853                 /*reprocessType*/ ReprocessType.YUV),
854         new StreamCombinationTemplate(new StreamTemplate [] {
855                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
856                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.VGA),
857                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.MAXIMUM),
858                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM) },
859                 "In-app viewfinder analysis with ZSL, RAW, and JPEG reprocessing output",
860                 /*reprocessType*/ ReprocessType.YUV),
861     };
862 
863     private static StreamCombinationTemplate sConcurrentStreamCombinations[] = {
864         new StreamCombinationTemplate(new StreamTemplate [] {
865                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p) },
866                 "In-app video / image processing"),
867         new StreamCombinationTemplate(new StreamTemplate [] {
868                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p) },
869                 "preview / preview to GPU"),
870         new StreamCombinationTemplate(new StreamTemplate [] {
871                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p) },
872                 "No view-finder still image capture"),
873         new StreamCombinationTemplate(new StreamTemplate [] {
874                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
875                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
876                 "Two-input in app video / image processing"),
877         new StreamCombinationTemplate(new StreamTemplate [] {
878                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
879                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
880                 "High resolution video recording with preview"),
881         new StreamCombinationTemplate(new StreamTemplate [] {
882                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
883                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
884                 "In-app video / image processing with preview"),
885         new StreamCombinationTemplate(new StreamTemplate [] {
886                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
887                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
888                 "In-app video / image processing with preview"),
889         new StreamCombinationTemplate(new StreamTemplate [] {
890                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p),
891                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
892                 "Standard stil image capture"),
893         new StreamCombinationTemplate(new StreamTemplate [] {
894                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p),
895                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.s1440p)},
896                 "Standard still image capture"),
897     };
898 
899     private static StreamCombinationTemplate sConcurrentDepthOnlyStreamCombinations[] = {
900         new StreamCombinationTemplate(new StreamTemplate [] {
901                 new StreamTemplate(ImageFormat.DEPTH16, SizeThreshold.VGA) },
902                 "Depth capture for mesh based object rendering"),
903     };
904 
905     private static StreamCombinationTemplate sUltraHighResolutionStreamCombinations[] = {
906         // UH res YUV / RAW / JPEG + PRIV preview size stream
907         new StreamCombinationTemplate(new StreamTemplate [] {
908                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
909                  new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
910                 "Ultra high resolution YUV image capture with preview"),
911         new StreamCombinationTemplate(new StreamTemplate [] {
912                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.FULL_RES),
913                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
914                 "Ultra high resolution RAW_SENSOR image capture with preview"),
915         new StreamCombinationTemplate(new StreamTemplate [] {
916                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
917                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
918                 "Ultra high resolution JPEG image capture with preview"),
919 
920         // UH res YUV / RAW / JPEG + YUV preview size stream
921         new StreamCombinationTemplate(new StreamTemplate [] {
922                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
923                  new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
924                 "No-viewfinder Ultra high resolution YUV image capture with image analysis"),
925         new StreamCombinationTemplate(new StreamTemplate [] {
926                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.FULL_RES),
927                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
928                 "No-viewfinder Ultra high resolution RAW_SENSOR image capture with image analysis"),
929         new StreamCombinationTemplate(new StreamTemplate [] {
930                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
931                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
932                 "No-viewfinder Ultra high resolution JPEG image capture with image analysis"),
933 
934         // UH res YUV / RAW / JPEG + PRIV preview + PRIV RECORD stream
935         new StreamCombinationTemplate(new StreamTemplate [] {
936                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
937                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
938                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD)},
939                 "Ultra high resolution YUV image capture with preview + app-based image analysis"),
940         new StreamCombinationTemplate(new StreamTemplate [] {
941                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.FULL_RES),
942                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
943                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD)},
944                 "Ultra high resolution RAW image capture with preview + app-based image analysis"),
945         new StreamCombinationTemplate(new StreamTemplate [] {
946                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
947                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
948                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD)},
949                 "Ultra high resolution JPEG image capture with preview + app-based image analysis"),
950 
951         // UH res YUV / RAW / JPEG + PRIV preview + YUV RECORD stream
952         new StreamCombinationTemplate(new StreamTemplate [] {
953                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
954                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
955                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD)},
956                 "Ultra high resolution YUV image capture with preview + app-based image analysis"),
957         new StreamCombinationTemplate(new StreamTemplate [] {
958                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.FULL_RES),
959                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
960                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD)},
961                 "Ultra high resolution RAW image capture with preview + app-based image analysis"),
962         new StreamCombinationTemplate(new StreamTemplate [] {
963                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
964                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
965                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD)},
966                 "Ultra high resolution JPEG image capture with preview + app-based image analysis"),
967 
968         // UH RES YUV / RAW / JPEG + PRIV preview + YUV / RAW / JPEG Maximum stream
969         new StreamCombinationTemplate(new StreamTemplate [] {
970                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
971                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
972                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM)},
973                 "Ultra high resolution YUV image capture with preview + default",
974                 /*substituteYUV*/ true),
975         new StreamCombinationTemplate(new StreamTemplate [] {
976                 new StreamTemplate(ImageFormat.RAW_SENSOR, SizeThreshold.FULL_RES),
977                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
978                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM)},
979                 "Ultra high resolution RAW image capture with preview + default",
980                 /*substituteYUV*/ true),
981         new StreamCombinationTemplate(new StreamTemplate [] {
982                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
983                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW),
984                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM)},
985                 "Ultra high resolution JPEG capture with preview + default",
986                 /*substituteYUV*/ true),
987     };
988 
989     private static StreamCombinationTemplate sUltraHighResolutionReprocStreamCombinations[] = {
990         // RAW_SENSOR -> RAW_SENSOR + preview size PRIV / YUV
991         new StreamCombinationTemplate(new StreamTemplate [] {
992                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
993                 "In-app RAW remosaic reprocessing with separate preview",
994                 /*reprocessType*/ ReprocessType.REMOSAIC),
995         new StreamCombinationTemplate(new StreamTemplate [] {
996                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
997                 "In-app RAW remosaic reprocessing with in-app image analysis",
998                 /*reprocessType*/ ReprocessType.REMOSAIC),
999 
1000         // RAW -> JPEG / YUV reprocessing + YUV / PRIV preview size stream
1001         new StreamCombinationTemplate(new StreamTemplate [] {
1002                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1003                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1004                 "In-app RAW -> JPEG reprocessing with separate preview",
1005                 /*reprocessType*/ ReprocessType.REMOSAIC),
1006         new StreamCombinationTemplate(new StreamTemplate [] {
1007                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
1008                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1009                 "In-app RAW -> YUV reprocessing with separate preview",
1010                 /*reprocessType*/ ReprocessType.REMOSAIC),
1011         new StreamCombinationTemplate(new StreamTemplate [] {
1012                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1013                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1014                 "In-app RAW -> JPEG reprocessing with in-app image analysis",
1015                 /*reprocessType*/ ReprocessType.REMOSAIC),
1016         new StreamCombinationTemplate(new StreamTemplate [] {
1017                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
1018                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1019                 "In-app RAW -> YUV reprocessing with in-app image analysis",
1020                 /*reprocessType*/ ReprocessType.REMOSAIC),
1021     };
1022 
1023     private static StreamCombinationTemplate sUltraHighResolutionYUVReprocStreamCombinations[] = {
1024         // YUV -> JPEG reprocess + PRIV / YUV preview size stream
1025         new StreamCombinationTemplate(new StreamTemplate [] {
1026                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1027                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1028                 "Ultra high resolution YUV -> JPEG reprocessing with separate preview",
1029                 /*reprocessType*/ ReprocessType.YUV),
1030         new StreamCombinationTemplate(new StreamTemplate [] {
1031                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1032                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1033                 "Ultra high resolution YUV -> JPEG reprocessing with in-app image analysis",
1034                 /*reprocessType*/ ReprocessType.YUV),
1035 
1036         // YUV -> YUV reprocess + PRIV / YUV preview size stream
1037         new StreamCombinationTemplate(new StreamTemplate [] {
1038                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
1039                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1040                 "Ultra high resolution YUV -> YUV reprocessing with separate preview",
1041                 /*reprocessType*/ ReprocessType.YUV),
1042         new StreamCombinationTemplate(new StreamTemplate [] {
1043                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.FULL_RES),
1044                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1045                 "Ultra high resolution YUV -> YUV reprocessing with in-app image analysis",
1046                 /*reprocessType*/ ReprocessType.YUV),
1047     };
1048 
1049     private static StreamCombinationTemplate sUltraHighResolutionPRIVReprocStreamCombinations[] = {
1050         new StreamCombinationTemplate(new StreamTemplate [] {
1051                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1052                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1053                 "Ultra high resolution PRIVATE -> JPEG reprocessing with separate preview",
1054                 /*reprocessType*/ ReprocessType.PRIVATE),
1055         new StreamCombinationTemplate(new StreamTemplate [] {
1056                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.FULL_RES),
1057                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1058                 "Ultra high resolution PRIVATE -> JPEG reprocessing with in-app image analysis",
1059                 /*reprocessType*/ ReprocessType.PRIVATE),
1060     };
1061 
1062     private static StreamCombinationTemplate s10BitOutputStreamCombinations[] = {
1063             new StreamCombinationTemplate(new StreamTemplate [] {
1064                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.MAXIMUM)},
1065                     "Simple preview, GPU video processing, or no-preview video recording"),
1066             new StreamCombinationTemplate(new StreamTemplate [] {
1067                     new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM)},
1068                     "In-application video/image processing"),
1069             new StreamCombinationTemplate(new StreamTemplate [] {
1070                     new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
1071                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1072                     "Standard still imaging"),
1073             new StreamCombinationTemplate(new StreamTemplate [] {
1074                     new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM),
1075                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1076                     "Maximum-resolution in-app processing with preview"),
1077             new StreamCombinationTemplate(new StreamTemplate [] {
1078                     new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.MAXIMUM),
1079                     new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.PREVIEW)},
1080                     "Maximum-resolution two-input in-app processing"),
1081             new StreamCombinationTemplate(new StreamTemplate [] {
1082                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
1083                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1084                     "High-resolution video recording with preview"),
1085             new StreamCombinationTemplate(new StreamTemplate [] {
1086                     new StreamTemplate(ImageFormat.YCBCR_P010, SizeThreshold.RECORD),
1087                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
1088                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1089                     "High-resolution recording with in-app snapshot"),
1090             new StreamCombinationTemplate(new StreamTemplate [] {
1091                     new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD),
1092                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD),
1093                     new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1094                     "High-resolution recording with video snapshot"),
1095     };
1096 
1097     private static StreamCombinationTemplate sStreamUseCaseCombinations[] = {
1098         // Single stream combinations
1099         new StreamCombinationTemplate(new StreamTemplate [] {
1100                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1101                         STREAM_USE_CASE_PREVIEW) },
1102                 "Simple preview"),
1103         new StreamCombinationTemplate(new StreamTemplate [] {
1104                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
1105                         STREAM_USE_CASE_PREVIEW) },
1106                 "Simple in-application image processing"),
1107         new StreamCombinationTemplate(new StreamTemplate [] {
1108                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
1109                         STREAM_USE_CASE_RECORD) },
1110                 "Simple video recording"),
1111         new StreamCombinationTemplate(new StreamTemplate [] {
1112                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
1113                         STREAM_USE_CASE_RECORD) },
1114                 "Simple in-application video processing"),
1115         new StreamCombinationTemplate(new StreamTemplate [] {
1116                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1117                         STREAM_USE_CASE_STILL_CAPTURE) },
1118                 "Simple JPEG still capture"),
1119         new StreamCombinationTemplate(new StreamTemplate [] {
1120                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
1121                         STREAM_USE_CASE_STILL_CAPTURE) },
1122                 "Simple YUV still capture"),
1123         new StreamCombinationTemplate(new StreamTemplate [] {
1124                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
1125                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
1126                 "Multi-purpose stream for preview, video and still capture"),
1127         new StreamCombinationTemplate(new StreamTemplate [] {
1128                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
1129                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL) },
1130                 "Multi-purpose YUV stream for preview, video and still capture"),
1131         new StreamCombinationTemplate(new StreamTemplate [] {
1132                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
1133                         STREAM_USE_CASE_VIDEO_CALL) },
1134                 "Simple video call"),
1135         new StreamCombinationTemplate(new StreamTemplate [] {
1136                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
1137                         STREAM_USE_CASE_VIDEO_CALL) },
1138                 "Simple YUV video call"),
1139 
1140         // 2-stream combinations
1141         new StreamCombinationTemplate(new StreamTemplate [] {
1142                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1143                         STREAM_USE_CASE_PREVIEW),
1144                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1145                         STREAM_USE_CASE_STILL_CAPTURE)},
1146                 "Preview with JPEG still image capture"),
1147         new StreamCombinationTemplate(new StreamTemplate [] {
1148                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1149                         STREAM_USE_CASE_PREVIEW),
1150                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
1151                         STREAM_USE_CASE_STILL_CAPTURE)},
1152                 "Preview with YUV still image capture"),
1153         new StreamCombinationTemplate(new StreamTemplate [] {
1154                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1155                         STREAM_USE_CASE_PREVIEW),
1156                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
1157                         STREAM_USE_CASE_RECORD)},
1158                 "Preview with video recording"),
1159         new StreamCombinationTemplate(new StreamTemplate [] {
1160                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1161                         STREAM_USE_CASE_PREVIEW),
1162                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
1163                         STREAM_USE_CASE_RECORD)},
1164                 "Preview with in-application video processing"),
1165         new StreamCombinationTemplate(new StreamTemplate [] {
1166                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1167                         STREAM_USE_CASE_PREVIEW),
1168                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
1169                         STREAM_USE_CASE_PREVIEW)},
1170                 "Preview with in-application image processing"),
1171         new StreamCombinationTemplate(new StreamTemplate [] {
1172                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1173                         STREAM_USE_CASE_PREVIEW),
1174                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
1175                         STREAM_USE_CASE_VIDEO_CALL)},
1176                 "Preview with video call"),
1177         new StreamCombinationTemplate(new StreamTemplate [] {
1178                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1179                         STREAM_USE_CASE_PREVIEW),
1180                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
1181                         STREAM_USE_CASE_VIDEO_CALL)},
1182                 "Preview with YUV video call"),
1183         new StreamCombinationTemplate(new StreamTemplate [] {
1184                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
1185                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
1186                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1187                         STREAM_USE_CASE_STILL_CAPTURE)},
1188                 "Multi-purpose stream with JPEG still capture"),
1189         new StreamCombinationTemplate(new StreamTemplate [] {
1190                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p,
1191                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
1192                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
1193                         STREAM_USE_CASE_STILL_CAPTURE)},
1194                 "Multi-purpose stream with YUV still capture"),
1195         new StreamCombinationTemplate(new StreamTemplate [] {
1196                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
1197                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
1198                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1199                         STREAM_USE_CASE_STILL_CAPTURE)},
1200                 "Multi-purpose YUV stream with JPEG still capture"),
1201         new StreamCombinationTemplate(new StreamTemplate [] {
1202                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p,
1203                         STREAM_USE_CASE_PREVIEW_VIDEO_STILL),
1204                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM,
1205                         STREAM_USE_CASE_STILL_CAPTURE)},
1206                 "Multi-purpose YUV stream with YUV still capture"),
1207         new StreamCombinationTemplate(new StreamTemplate [] {
1208                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
1209                         STREAM_USE_CASE_STILL_CAPTURE),
1210                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1211                         STREAM_USE_CASE_STILL_CAPTURE)},
1212                 "YUV and JPEG concurrent still image capture (for testing)"),
1213 
1214         // 3-stream combinations
1215         new StreamCombinationTemplate(new StreamTemplate [] {
1216                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1217                         STREAM_USE_CASE_PREVIEW),
1218                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.RECORD,
1219                         STREAM_USE_CASE_RECORD),
1220                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
1221                         STREAM_USE_CASE_STILL_CAPTURE)},
1222                 "Preview, video record and JPEG video snapshot"),
1223         new StreamCombinationTemplate(new StreamTemplate [] {
1224                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1225                         STREAM_USE_CASE_PREVIEW),
1226                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.RECORD,
1227                         STREAM_USE_CASE_RECORD),
1228                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.RECORD,
1229                         STREAM_USE_CASE_STILL_CAPTURE)},
1230                 "Preview, in-application video processing and JPEG video snapshot"),
1231         new StreamCombinationTemplate(new StreamTemplate [] {
1232                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW,
1233                         STREAM_USE_CASE_PREVIEW),
1234                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW,
1235                         STREAM_USE_CASE_PREVIEW),
1236                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM,
1237                         STREAM_USE_CASE_STILL_CAPTURE)},
1238                 "Preview, in-application image processing, and JPEG still image capture"),
1239     };
1240 
1241     private static StreamCombinationTemplate sPreviewStabilizedStreamCombinations[] = {
1242         // 1 stream combinations
1243         new StreamCombinationTemplate(new StreamTemplate [] {
1244                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
1245                 "Stabilized preview, GPU video processing, or no-preview stabilized recording"),
1246         new StreamCombinationTemplate(new StreamTemplate [] {
1247                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
1248                 "Stabilized preview, GPU video processing, or no-preview stabilized recording"),
1249         //2 stream combinations
1250         new StreamCombinationTemplate(new StreamTemplate [] {
1251                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
1252                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
1253                 "Standard JPEG still imaging with stabilized preview"),
1254         new StreamCombinationTemplate(new StreamTemplate [] {
1255                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
1256                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p)},
1257                 "Standard YUV still imaging with stabilized preview"),
1258         new StreamCombinationTemplate(new StreamTemplate [] {
1259                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.MAXIMUM),
1260                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
1261                 "Standard YUV still imaging with stabilized in-app image processing stream"),
1262         new StreamCombinationTemplate(new StreamTemplate [] {
1263                 new StreamTemplate(ImageFormat.JPEG, SizeThreshold.MAXIMUM),
1264                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p)},
1265                 "Standard JPEG still imaging with stabilized in-app image processing stream"),
1266 
1267         new StreamCombinationTemplate(new StreamTemplate [] {
1268                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p),
1269                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1270                 "High-resolution video recording with preview both streams stabilized"),
1271         new StreamCombinationTemplate(new StreamTemplate [] {
1272                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s1440p),
1273                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1274                 "High-resolution video recording with preview both streams stabilized"),
1275         new StreamCombinationTemplate(new StreamTemplate [] {
1276                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p),
1277                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.PREVIEW)},
1278                 "High-resolution video recording with preview both streams stabilized"),
1279         new StreamCombinationTemplate(new StreamTemplate [] {
1280                 new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s1440p),
1281                 new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.PREVIEW)},
1282                 "High-resolution video recording with preview both streams stabilized"),
1283     };
1284 
1285     /**
1286      * Helper builder class to generate a list of available mandatory stream combinations.
1287      * @hide
1288      */
1289     public static final class Builder {
1290         private Size mDisplaySize;
1291         private List<Integer> mCapabilities;
1292         private int mHwLevel, mCameraId;
1293         private StreamConfigurationMap mStreamConfigMap;
1294         private StreamConfigurationMap mStreamConfigMapMaximumResolution;
1295         private boolean mIsHiddenPhysicalCamera;
1296         private boolean mIsPreviewStabilizationSupported;
1297 
1298         private final Size kPreviewSizeBound = new Size(1920, 1088);
1299 
1300         /**
1301          * Helper class to be used to generate the available mandatory stream combinations.
1302          *
1303          * @param cameraId Current camera id.
1304          * @param hwLevel The camera HW level as reported by android.info.supportedHardwareLevel.
1305          * @param displaySize The device display size.
1306          * @param capabilities The camera device capabilities.
1307          * @param sm The camera device stream configuration map.
1308          * @param smMaxResolution The camera device stream configuration map when it runs in max
1309          *                        resolution mode.
1310          */
Builder(int cameraId, int hwLevel, @NonNull Size displaySize, @NonNull List<Integer> capabilities, @NonNull StreamConfigurationMap sm, StreamConfigurationMap smMaxResolution, boolean previewStabilization)1311         public Builder(int cameraId, int hwLevel, @NonNull Size displaySize,
1312                 @NonNull List<Integer> capabilities, @NonNull StreamConfigurationMap sm,
1313                 StreamConfigurationMap smMaxResolution, boolean previewStabilization) {
1314             mCameraId = cameraId;
1315             mDisplaySize = displaySize;
1316             mCapabilities = capabilities;
1317             mStreamConfigMap = sm;
1318             mStreamConfigMapMaximumResolution = smMaxResolution;
1319             mHwLevel = hwLevel;
1320             mIsHiddenPhysicalCamera =
1321                     CameraManager.isHiddenPhysicalCamera(Integer.toString(mCameraId));
1322             mIsPreviewStabilizationSupported = previewStabilization;
1323         }
1324 
1325         private @Nullable List<MandatoryStreamCombination>
getAvailableMandatoryStreamCombinationsInternal( StreamCombinationTemplate []chosenStreamCombinations, boolean s10Bit)1326         getAvailableMandatoryStreamCombinationsInternal(
1327                 StreamCombinationTemplate []chosenStreamCombinations, boolean s10Bit) {
1328 
1329             HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
1330                     enumerateAvailableSizes();
1331             if (availableSizes == null) {
1332                 Log.e(TAG, "Available size enumeration failed!");
1333                 return null;
1334             }
1335 
1336             ArrayList<MandatoryStreamCombination> availableStreamCombinations = new ArrayList<>();
1337             availableStreamCombinations.ensureCapacity(chosenStreamCombinations.length);
1338             for (StreamCombinationTemplate combTemplate : chosenStreamCombinations) {
1339                 ArrayList<MandatoryStreamInformation> streamsInfo = new ArrayList<>();
1340                 streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
1341                 for (StreamTemplate template : combTemplate.mStreamTemplates) {
1342                     List<Size> sizes = null;
1343                     Pair<SizeThreshold, Integer> pair;
1344                     pair = new Pair<>(template.mSizeThreshold, new Integer(template.mFormat));
1345                     sizes = availableSizes.get(pair);
1346                     if (s10Bit && template.mFormat == ImageFormat.YCBCR_P010) {
1347                         // Make sure that exactly the same 10 and 8-bit YUV streams sizes are
1348                         // supported
1349                         pair = new Pair<>(template.mSizeThreshold,
1350                                 new Integer(ImageFormat.YUV_420_888));
1351                         HashSet<Size> sdrYuvSizes = new HashSet<>(availableSizes.get(pair));
1352                         if (!sdrYuvSizes.equals(new HashSet<>(sizes))) {
1353                             Log.e(TAG, "The supported 10-bit YUV sizes are different from the"
1354                                     + " supported 8-bit YUV sizes!");
1355                             return null;
1356                         }
1357                     }
1358 
1359                     MandatoryStreamInformation streamInfo;
1360                     boolean isMaximumSize =
1361                             (template.mSizeThreshold == SizeThreshold.MAXIMUM);
1362                     try {
1363                         streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
1364                                 isMaximumSize, /*isInput*/ false,
1365                                 /*isUltraHighResolution*/ false,
1366                                 /*is10BitCapable*/ s10Bit ? template.mFormat != ImageFormat.JPEG :
1367                                         false);
1368                     } catch (IllegalArgumentException e) {
1369                         Log.e(TAG, "No available sizes found for format: " + template.mFormat +
1370                                 " size threshold: " + template.mSizeThreshold + " combination: " +
1371                                 combTemplate.mDescription);
1372                         return null;
1373                     }
1374                     streamsInfo.add(streamInfo);
1375                 }
1376 
1377                 MandatoryStreamCombination streamCombination;
1378                 try {
1379                     streamCombination = new MandatoryStreamCombination(streamsInfo,
1380                             combTemplate.mDescription, /*isReprocessable*/ false);
1381                 } catch (IllegalArgumentException e) {
1382                     Log.e(TAG, "No stream information for mandatory combination: "
1383                             + combTemplate.mDescription);
1384                     return null;
1385                 }
1386 
1387                 availableStreamCombinations.add(streamCombination);
1388             }
1389 
1390             return Collections.unmodifiableList(availableStreamCombinations);
1391         }
1392 
1393         /**
1394          * Retrieve a list of all available mandatory stream combinations for devices supporting
1395          * preview stabilization.
1396          *
1397          * @return a non-modifiable list of supported mandatory stream combinations on which
1398          *         preview stabilization is supported.,
1399          *         null in case device is not 10-bit output capable.
1400          */
1401         public @Nullable List<MandatoryStreamCombination>
getAvailableMandatoryPreviewStabilizedStreamCombinations()1402         getAvailableMandatoryPreviewStabilizedStreamCombinations() {
1403             // Since preview stabilization support is optional, we mandate these stream
1404             // combinations regardless of camera device capabilities.
1405 
1406             StreamCombinationTemplate []chosenStreamCombinations =
1407                     sPreviewStabilizedStreamCombinations;
1408 
1409             if (!mIsPreviewStabilizationSupported) {
1410                 Log.v(TAG, "Device does not support preview stabilization");
1411                  return null;
1412              }
1413 
1414             return getAvailableMandatoryStreamCombinationsInternal(chosenStreamCombinations,
1415                     /*10bit*/false);
1416         }
1417 
1418 
1419         /**
1420          * Retrieve a list of all available mandatory 10-bit output capable stream combinations.
1421          *
1422          * @return a non-modifiable list of supported mandatory 10-bit capable stream combinations,
1423          *         null in case device is not 10-bit output capable.
1424          */
1425         public @Nullable List<MandatoryStreamCombination>
getAvailableMandatory10BitStreamCombinations()1426         getAvailableMandatory10BitStreamCombinations() {
1427             // Since 10-bit streaming support is optional, we mandate these stream
1428             // combinations regardless of camera device capabilities.
1429 
1430             StreamCombinationTemplate []chosenStreamCombinations = s10BitOutputStreamCombinations;
1431             if (!is10BitOutputSupported()) {
1432                 Log.v(TAG, "Device is not able to output 10-bit!");
1433                 return null;
1434             }
1435             return getAvailableMandatoryStreamCombinationsInternal(chosenStreamCombinations,
1436                     /*10bit*/true);
1437         }
1438 
1439         /**
1440           * Retrieve a list of all available mandatory stream combinations with stream use cases.
1441           * when the camera device has {@link
1442           * CameraMetdata.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE} capability.
1443           *
1444           * @return a non-modifiable list of supported mandatory stream combinations with stream
1445           *         use cases. Null in case the device doesn't have {@link
1446           *         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE}
1447           *         capability.
1448           */
1449         public @NonNull List<MandatoryStreamCombination>
getAvailableMandatoryStreamUseCaseCombinations()1450                 getAvailableMandatoryStreamUseCaseCombinations() {
1451             if (!isCapabilitySupported(
1452                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE)) {
1453                 return null;
1454             }
1455 
1456             HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
1457                     enumerateAvailableSizes();
1458             if (availableSizes == null) {
1459                 Log.e(TAG, "Available size enumeration failed!");
1460                 return null;
1461             }
1462 
1463             ArrayList<MandatoryStreamCombination> availableStreamCombinations = new ArrayList<>();
1464             availableStreamCombinations.ensureCapacity(sStreamUseCaseCombinations.length);
1465             for (StreamCombinationTemplate combTemplate : sStreamUseCaseCombinations) {
1466                 ArrayList<MandatoryStreamInformation> streamsInfo =
1467                         new ArrayList<MandatoryStreamInformation>();
1468                 streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
1469 
1470                 for (StreamTemplate template : combTemplate.mStreamTemplates) {
1471                     List<Size> sizes = null;
1472                     Pair<SizeThreshold, Integer> pair;
1473                     pair = new Pair<SizeThreshold, Integer>(template.mSizeThreshold,
1474                             new Integer(template.mFormat));
1475                     sizes = availableSizes.get(pair);
1476 
1477                     MandatoryStreamInformation streamInfo;
1478                     boolean isMaximumSize =
1479                             (template.mSizeThreshold == SizeThreshold.MAXIMUM);
1480                     try {
1481                         streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
1482                                 isMaximumSize, /*isInput*/false, /*isUltraHighResolution*/false,
1483                                 /*is10BitCapable*/ false, template.mStreamUseCase);
1484                     } catch (IllegalArgumentException e) {
1485                         Log.e(TAG, "No available sizes found for format: " + template.mFormat +
1486                                 " size threshold: " + template.mSizeThreshold + " combination: " +
1487                                 combTemplate.mDescription);
1488                         return null;
1489                     }
1490                     streamsInfo.add(streamInfo);
1491                 }
1492 
1493                 MandatoryStreamCombination streamCombination;
1494                 try {
1495                     streamCombination = new MandatoryStreamCombination(streamsInfo,
1496                             combTemplate.mDescription, /*isReprocessable*/ false);
1497                 } catch (IllegalArgumentException e) {
1498                     Log.e(TAG, "No stream information for mandatory combination: "
1499                             + combTemplate.mDescription);
1500                     return null;
1501                 }
1502 
1503                 availableStreamCombinations.add(streamCombination);
1504             }
1505 
1506             return Collections.unmodifiableList(availableStreamCombinations);
1507         }
1508 
1509         /**
1510           * Retrieve a list of all available mandatory concurrent stream combinations.
1511           * This method should only be called for devices which are listed in combinations returned
1512           * by CameraManager.getConcurrentCameraIds.
1513           *
1514           * @return a non-modifiable list of supported mandatory concurrent stream combinations.
1515           */
1516         public @NonNull List<MandatoryStreamCombination>
getAvailableMandatoryConcurrentStreamCombinations()1517                 getAvailableMandatoryConcurrentStreamCombinations() {
1518             // Since concurrent streaming support is optional, we mandate these stream
1519             // combinations regardless of camera device capabilities.
1520 
1521             StreamCombinationTemplate []chosenStreamCombinations = sConcurrentStreamCombinations;
1522             if (!isColorOutputSupported()) {
1523                 Log.v(TAG, "Device is not backward compatible, depth streams are mandatory!");
1524                 chosenStreamCombinations = sConcurrentDepthOnlyStreamCombinations;
1525             }
1526             Size sizeVGAp = new Size(640, 480);
1527             Size size720p = new Size(1280, 720);
1528             Size size1440p = new Size(1920, 1440);
1529 
1530             ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations =
1531                     new ArrayList<MandatoryStreamCombination>();
1532             availableConcurrentStreamCombinations.ensureCapacity(
1533                     chosenStreamCombinations.length);
1534             for (StreamCombinationTemplate combTemplate : chosenStreamCombinations) {
1535                 ArrayList<MandatoryStreamInformation> streamsInfo =
1536                         new ArrayList<MandatoryStreamInformation>();
1537                 streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
1538                 for (StreamTemplate template : combTemplate.mStreamTemplates) {
1539                     MandatoryStreamInformation streamInfo;
1540                     List<Size> sizes = new ArrayList<Size>();
1541                     Size formatSize = null;
1542                     switch (template.mSizeThreshold) {
1543                         case s1440p:
1544                             formatSize = size1440p;
1545                             break;
1546                         case VGA:
1547                             formatSize = sizeVGAp;
1548                             break;
1549                         default:
1550                             formatSize = size720p;
1551                     }
1552                     Size sizeChosen =
1553                             getMinSize(formatSize,
1554                                     getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat)));
1555                     sizes.add(sizeChosen);
1556                     try {
1557                         streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
1558                             /*isMaximumSize*/false);
1559                     } catch (IllegalArgumentException e) {
1560                         String cause = "No available sizes found for format: " + template.mFormat
1561                                 + " size threshold: " + template.mSizeThreshold + " combination: "
1562                                 + combTemplate.mDescription;
1563                         throw new RuntimeException(cause, e);
1564                     }
1565                     streamsInfo.add(streamInfo);
1566                 }
1567 
1568                 MandatoryStreamCombination streamCombination;
1569                 try {
1570                     streamCombination = new MandatoryStreamCombination(streamsInfo,
1571                             combTemplate.mDescription, /*isReprocess*/false);
1572                 } catch (IllegalArgumentException e) {
1573                     String cause =  "No stream information for mandatory combination: "
1574                             + combTemplate.mDescription;
1575                     throw new RuntimeException(cause, e);
1576                 }
1577                 availableConcurrentStreamCombinations.add(streamCombination);
1578             }
1579             return Collections.unmodifiableList(availableConcurrentStreamCombinations);
1580         }
1581 
1582         /**
1583          * Retrieve a list of all available mandatory stream combinations supported when
1584          * {@link CaptureRequest#ANDROID_SENSOR_PIXEL_MODE} is set to
1585          * {@link CameraMetadata#ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION}.
1586          *
1587          * @return a non-modifiable list of supported mandatory stream combinations or
1588          *         null in case device is not backward compatible or the method encounters
1589          *         an error.
1590          */
1591         public @NonNull List<MandatoryStreamCombination>
getAvailableMandatoryMaximumResolutionStreamCombinations()1592                 getAvailableMandatoryMaximumResolutionStreamCombinations() {
1593 
1594             if (!isColorOutputSupported()) {
1595                 Log.v(TAG, "Device is not backward compatible!, no mandatory maximum res streams");
1596                 return null;
1597             }
1598 
1599             ArrayList<StreamCombinationTemplate> chosenStreamCombinationTemplates =
1600                     new ArrayList<StreamCombinationTemplate>();
1601 
1602             chosenStreamCombinationTemplates.addAll(
1603                     Arrays.asList(sUltraHighResolutionStreamCombinations));
1604 
1605             ArrayList<MandatoryStreamCombination> availableStreamCombinations =
1606                     new ArrayList<MandatoryStreamCombination>();
1607             boolean addRemosaicReprocessing = isRemosaicReprocessingSupported();
1608 
1609             int remosaicSize = 0;
1610             Size [] maxResYUVInputSizes =
1611                     mStreamConfigMapMaximumResolution.getInputSizes(ImageFormat.YUV_420_888);
1612             Size [] maxResPRIVInputSizes =
1613                     mStreamConfigMapMaximumResolution.getInputSizes(ImageFormat.PRIVATE);
1614 
1615             if (addRemosaicReprocessing) {
1616                 remosaicSize += sUltraHighResolutionReprocStreamCombinations.length;
1617                 chosenStreamCombinationTemplates.addAll(
1618                         Arrays.asList(sUltraHighResolutionReprocStreamCombinations));
1619             }
1620 
1621             if (maxResYUVInputSizes != null && maxResYUVInputSizes.length != 0) {
1622                 remosaicSize += sUltraHighResolutionYUVReprocStreamCombinations.length;
1623                 chosenStreamCombinationTemplates.addAll(
1624                         Arrays.asList(sUltraHighResolutionYUVReprocStreamCombinations));
1625             }
1626 
1627             if (maxResPRIVInputSizes != null && maxResPRIVInputSizes.length != 0) {
1628                 remosaicSize += sUltraHighResolutionPRIVReprocStreamCombinations.length;
1629                 chosenStreamCombinationTemplates.addAll(
1630                         Arrays.asList(sUltraHighResolutionPRIVReprocStreamCombinations));
1631 
1632             }
1633             availableStreamCombinations.ensureCapacity(
1634                     chosenStreamCombinationTemplates.size() + remosaicSize);
1635             fillUHMandatoryStreamCombinations(availableStreamCombinations,
1636                     chosenStreamCombinationTemplates);
1637 
1638             return Collections.unmodifiableList(availableStreamCombinations);
1639         }
1640 
createUHSensorMandatoryStreamCombination( StreamCombinationTemplate combTemplate, int substitutedFormat)1641         private MandatoryStreamCombination createUHSensorMandatoryStreamCombination(
1642                 StreamCombinationTemplate combTemplate, int substitutedFormat) {
1643             ArrayList<MandatoryStreamInformation> streamsInfo =
1644                     new ArrayList<MandatoryStreamInformation>();
1645             streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
1646             boolean isReprocess = combTemplate.mReprocessType != ReprocessType.NONE;
1647             if (isReprocess) {
1648                 int format = -1;
1649                 ArrayList<Size> inputSize = new ArrayList<Size>();
1650                 if (combTemplate.mReprocessType == ReprocessType.PRIVATE) {
1651                     inputSize.add(
1652                             getMaxSize(mStreamConfigMapMaximumResolution.getInputSizes(
1653                                     ImageFormat.PRIVATE)));
1654                     format = ImageFormat.PRIVATE;
1655                 } else if (combTemplate.mReprocessType == ReprocessType.REMOSAIC) {
1656                     inputSize.add(
1657                             getMaxSize(mStreamConfigMapMaximumResolution.getInputSizes(
1658                                     ImageFormat.RAW_SENSOR)));
1659                     format = ImageFormat.RAW_SENSOR;
1660                 } else {
1661                     inputSize.add(
1662                             getMaxSize(mStreamConfigMapMaximumResolution.getInputSizes(
1663                                     ImageFormat.YUV_420_888)));
1664                     format = ImageFormat.YUV_420_888;
1665                 }
1666                 streamsInfo.add(new MandatoryStreamInformation(inputSize, format,
1667                         /*isMaximumSize*/false, /*isInput*/true,
1668                         /*isUltraHighResolution*/ true));
1669                 streamsInfo.add(new MandatoryStreamInformation(inputSize, format,
1670                         /*isMaximumSize*/false, /*isInput*/ false,
1671                         /*isUltraHighResolution*/true));
1672             }
1673             HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableDefaultNonRawSizes =
1674                     enumerateAvailableSizes();
1675             if (availableDefaultNonRawSizes == null) {
1676                 Log.e(TAG, "Available size enumeration failed");
1677                 return null;
1678             }
1679             Size[] defaultRawSizes =
1680                     mStreamConfigMap.getOutputSizes(ImageFormat.RAW_SENSOR);
1681             ArrayList<Size> availableDefaultRawSizes = new ArrayList<>();
1682             if (defaultRawSizes != null) {
1683                 availableDefaultRawSizes.ensureCapacity(defaultRawSizes.length);
1684                 availableDefaultRawSizes.addAll(Arrays.asList(defaultRawSizes));
1685             }
1686             for (StreamTemplate template : combTemplate.mStreamTemplates) {
1687                 MandatoryStreamInformation streamInfo;
1688                 List<Size> sizes = new ArrayList<Size>();
1689                 int formatChosen = template.mFormat;
1690                 boolean isUltraHighResolution =
1691                         (template.mSizeThreshold == SizeThreshold.FULL_RES);
1692                 StreamConfigurationMap sm =
1693                         isUltraHighResolution ?
1694                                 mStreamConfigMapMaximumResolution : mStreamConfigMap;
1695                 boolean isMaximumSize = (template.mSizeThreshold == SizeThreshold.MAXIMUM);
1696 
1697                 if (substitutedFormat != ImageFormat.UNKNOWN && isMaximumSize) {
1698                     formatChosen = substitutedFormat;
1699                 }
1700 
1701                 if (isUltraHighResolution) {
1702                     sizes.add(getMaxSize(sm.getOutputSizes(formatChosen)));
1703                 } else {
1704                     if (formatChosen == ImageFormat.RAW_SENSOR) {
1705                         // RAW_SENSOR always has MAXIMUM threshold.
1706                         sizes = availableDefaultRawSizes;
1707                     } else {
1708                         Pair<SizeThreshold, Integer> pair =
1709                             new Pair<SizeThreshold, Integer>(template.mSizeThreshold,
1710                                     new Integer(formatChosen));
1711                         sizes = availableDefaultNonRawSizes.get(pair);
1712                     }
1713                 }
1714 
1715                 try {
1716                     streamInfo = new MandatoryStreamInformation(sizes, formatChosen,
1717                             isMaximumSize, /*isInput*/ false, isUltraHighResolution);
1718                 } catch (IllegalArgumentException e) {
1719                     String cause = "No available sizes found for format: " + template.mFormat
1720                             + " size threshold: " + template.mSizeThreshold + " combination: "
1721                             + combTemplate.mDescription;
1722                     throw new RuntimeException(cause, e);
1723                 }
1724                 streamsInfo.add(streamInfo);
1725             }
1726 
1727             String formatString = null;
1728             switch (substitutedFormat) {
1729                 case ImageFormat.RAW_SENSOR :
1730                     formatString = "RAW_SENSOR";
1731                     break;
1732                 case ImageFormat.JPEG :
1733                     formatString = "JPEG";
1734                     break;
1735                 default:
1736                     formatString = "YUV";
1737             }
1738 
1739             MandatoryStreamCombination streamCombination;
1740             try {
1741                 streamCombination = new MandatoryStreamCombination(streamsInfo,
1742                         combTemplate.mDescription + " " + formatString + " still-capture",
1743                         isReprocess);
1744             } catch (IllegalArgumentException e) {
1745                 String cause =  "No stream information for mandatory combination: "
1746                         + combTemplate.mDescription;
1747                 throw new RuntimeException(cause, e);
1748             }
1749             return streamCombination;
1750         }
1751 
fillUHMandatoryStreamCombinations( ArrayList<MandatoryStreamCombination> availableStreamCombinations, ArrayList<StreamCombinationTemplate> chosenTemplates)1752         private void fillUHMandatoryStreamCombinations(
1753                 ArrayList<MandatoryStreamCombination> availableStreamCombinations,
1754                 ArrayList<StreamCombinationTemplate> chosenTemplates) {
1755 
1756             for (StreamCombinationTemplate combTemplate : chosenTemplates) {
1757                 MandatoryStreamCombination streamCombination =
1758                         createUHSensorMandatoryStreamCombination(combTemplate,
1759                                   ImageFormat.UNKNOWN);
1760                 availableStreamCombinations.add(streamCombination);
1761                 if (combTemplate.mSubstituteYUV) {
1762                      streamCombination =
1763                             createUHSensorMandatoryStreamCombination(combTemplate,
1764                                     ImageFormat.RAW_SENSOR);
1765                     availableStreamCombinations.add(streamCombination);
1766                     streamCombination =
1767                             createUHSensorMandatoryStreamCombination(combTemplate,
1768                                     ImageFormat.JPEG);
1769                     availableStreamCombinations.add(streamCombination);
1770                 }
1771             }
1772         }
1773 
1774         /**
1775          * Retrieve a list of all available mandatory stream combinations.
1776          *
1777          * @return a non-modifiable list of supported mandatory stream combinations or
1778          *         null in case device is not backward compatible or the method encounters
1779          *         an error.
1780          */
1781         public @Nullable List<MandatoryStreamCombination>
getAvailableMandatoryStreamCombinations()1782             getAvailableMandatoryStreamCombinations() {
1783             if (!isColorOutputSupported()) {
1784                 Log.v(TAG, "Device is not backward compatible!");
1785                 return null;
1786             }
1787 
1788             if ((mCameraId < 0) && !isExternalCamera()) {
1789                 Log.i(TAG, "Invalid camera id");
1790                 return null;
1791             }
1792 
1793             ArrayList<StreamCombinationTemplate> availableTemplates =
1794                     new ArrayList<StreamCombinationTemplate> ();
1795             if (isHardwareLevelAtLeastLegacy()) {
1796                 availableTemplates.addAll(Arrays.asList(sLegacyCombinations));
1797             }
1798 
1799             // External devices are identical to limited devices w.r.t. stream combinations.
1800             if (isHardwareLevelAtLeastLimited() || isExternalCamera()) {
1801                 availableTemplates.addAll(Arrays.asList(sLimitedCombinations));
1802 
1803                 if (isPrivateReprocessingSupported()) {
1804                     availableTemplates.addAll(Arrays.asList(sLimitedPrivateReprocCombinations));
1805                 }
1806 
1807                 if (isYUVReprocessingSupported()) {
1808                     availableTemplates.addAll(Arrays.asList(sLimitedYUVReprocCombinations));
1809                 }
1810 
1811             }
1812 
1813             if (isCapabilitySupported(
1814                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
1815                 availableTemplates.addAll(Arrays.asList(sBurstCombinations));
1816             }
1817 
1818             if (isHardwareLevelAtLeastFull()) {
1819                 availableTemplates.addAll(Arrays.asList(sFullCombinations));
1820 
1821                 if (isPrivateReprocessingSupported()) {
1822                     availableTemplates.addAll(Arrays.asList(sFullPrivateReprocCombinations));
1823                 }
1824 
1825                 if (isYUVReprocessingSupported()) {
1826                     availableTemplates.addAll(Arrays.asList(sFullYUVReprocCombinations));
1827                 }
1828 
1829             }
1830 
1831             if (isCapabilitySupported(
1832                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
1833                 availableTemplates.addAll(Arrays.asList(sRawCombinations));
1834 
1835                 if (isPrivateReprocessingSupported()) {
1836                     availableTemplates.addAll(Arrays.asList(sRAWPrivateReprocCombinations));
1837                 }
1838 
1839                 if (isYUVReprocessingSupported()) {
1840                     availableTemplates.addAll(Arrays.asList(sRAWYUVReprocCombinations));
1841                 }
1842 
1843             }
1844 
1845             if (isHardwareLevelAtLeastLevel3()) {
1846                 availableTemplates.addAll(Arrays.asList(sLevel3Combinations));
1847 
1848                 if (isPrivateReprocessingSupported()) {
1849                     availableTemplates.addAll(Arrays.asList(sLevel3PrivateReprocCombinations));
1850                 }
1851 
1852                 if (isYUVReprocessingSupported()) {
1853                     availableTemplates.addAll(Arrays.asList(sLevel3YUVReprocCombinations));
1854                 }
1855 
1856             }
1857 
1858             return generateAvailableCombinations(availableTemplates);
1859         }
1860 
1861         /**
1862          * Helper method to generate the available stream combinations given the
1863          * list of available combination templates.
1864          *
1865          * @param availableTemplates a list of templates supported by the camera device.
1866          * @return a non-modifiable list of supported mandatory stream combinations or
1867          *         null in case of errors.
1868          */
generateAvailableCombinations( @onNull ArrayList<StreamCombinationTemplate> availableTemplates)1869         private @Nullable List<MandatoryStreamCombination> generateAvailableCombinations(
1870                 @NonNull ArrayList<StreamCombinationTemplate> availableTemplates) {
1871             if (availableTemplates.isEmpty()) {
1872                 Log.e(TAG, "No available stream templates!");
1873                 return null;
1874             }
1875 
1876             HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
1877                 enumerateAvailableSizes();
1878             if (availableSizes == null) {
1879                 Log.e(TAG, "Available size enumeration failed!");
1880                 return null;
1881             }
1882 
1883             // RAW only uses MAXIMUM size threshold
1884             Size[] rawSizes = mStreamConfigMap.getOutputSizes(ImageFormat.RAW_SENSOR);
1885             ArrayList<Size> availableRawSizes = new ArrayList<Size>();
1886             if (rawSizes != null) {
1887                 availableRawSizes.ensureCapacity(rawSizes.length);
1888                 availableRawSizes.addAll(Arrays.asList(rawSizes));
1889             }
1890 
1891             Size maxPrivateInputSize = new Size(0, 0);
1892             if (isPrivateReprocessingSupported()) {
1893                 maxPrivateInputSize = getMaxSize(mStreamConfigMap.getInputSizes(
1894                             ImageFormat.PRIVATE));
1895             }
1896 
1897             Size maxYUVInputSize = new Size(0, 0);
1898             if (isYUVReprocessingSupported()) {
1899                 maxYUVInputSize = getMaxSize(mStreamConfigMap.getInputSizes(
1900                             ImageFormat.YUV_420_888));
1901             }
1902 
1903             // Generate the available mandatory stream combinations given the supported templates
1904             // and size ranges.
1905             ArrayList<MandatoryStreamCombination> availableStreamCombinations =
1906                     new ArrayList<MandatoryStreamCombination>();
1907             availableStreamCombinations.ensureCapacity(availableTemplates.size());
1908             for (StreamCombinationTemplate combTemplate : availableTemplates) {
1909                 ArrayList<MandatoryStreamInformation> streamsInfo =
1910                         new ArrayList<MandatoryStreamInformation>();
1911                 streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length);
1912                 boolean isReprocessable = combTemplate.mReprocessType != ReprocessType.NONE;
1913                 if (isReprocessable) {
1914                     // The first and second streams in a reprocessable combination have the
1915                     // same size and format. The first is the input and the second is the output
1916                     // used for generating the subsequent input buffers.
1917                     ArrayList<Size> inputSize = new ArrayList<Size>();
1918                     int format;
1919                     if (combTemplate.mReprocessType == ReprocessType.PRIVATE) {
1920                         inputSize.add(maxPrivateInputSize);
1921                         format = ImageFormat.PRIVATE;
1922                     } else {
1923                         // Default mandatory streams only have PRIVATE / YUV reprocessing.
1924                         inputSize.add(maxYUVInputSize);
1925                         format = ImageFormat.YUV_420_888;
1926                     }
1927                     streamsInfo.add(new MandatoryStreamInformation(inputSize, format,
1928                                 /*isMaximumSize*/true, /*isInput*/true));
1929                     streamsInfo.add(new MandatoryStreamInformation(inputSize, format,
1930                             /*isMaximumSize*/true));
1931                 }
1932 
1933                 for (StreamTemplate template : combTemplate.mStreamTemplates) {
1934                     List<Size> sizes = null;
1935                     if (template.mFormat == ImageFormat.RAW_SENSOR) {
1936                         sizes = availableRawSizes;
1937                     } else {
1938                         Pair<SizeThreshold, Integer> pair;
1939                         pair = new Pair<SizeThreshold, Integer>(template.mSizeThreshold,
1940                                 new Integer(template.mFormat));
1941                         sizes = availableSizes.get(pair);
1942                     }
1943 
1944                     MandatoryStreamInformation streamInfo;
1945                     boolean isMaximumSize =
1946                             (template.mSizeThreshold == SizeThreshold.MAXIMUM);
1947                     try {
1948                         streamInfo = new MandatoryStreamInformation(sizes, template.mFormat,
1949                                 isMaximumSize);
1950                     } catch (IllegalArgumentException e) {
1951                         Log.e(TAG, "No available sizes found for format: " + template.mFormat +
1952                                 " size threshold: " + template.mSizeThreshold + " combination: " +
1953                                 combTemplate.mDescription);
1954                         return null;
1955                     }
1956                     streamsInfo.add(streamInfo);
1957                 }
1958 
1959                 MandatoryStreamCombination streamCombination;
1960                 try {
1961                     streamCombination = new MandatoryStreamCombination(streamsInfo,
1962                             combTemplate.mDescription, isReprocessable);
1963                 } catch (IllegalArgumentException e) {
1964                     Log.e(TAG, "No stream information for mandatory combination: "
1965                             + combTemplate.mDescription);
1966                     return null;
1967                 }
1968 
1969                 availableStreamCombinations.add(streamCombination);
1970             }
1971 
1972             return Collections.unmodifiableList(availableStreamCombinations);
1973         }
1974 
1975         /**
1976          * Helper method to enumerate all available sizes according to size threshold and format.
1977          */
1978         private @Nullable HashMap<Pair<SizeThreshold, Integer>, List<Size>>
enumerateAvailableSizes()1979             enumerateAvailableSizes() {
1980             final int[] formats = {
1981                 ImageFormat.PRIVATE,
1982                 ImageFormat.YUV_420_888,
1983                 ImageFormat.JPEG,
1984                 ImageFormat.YCBCR_P010
1985             };
1986             Size recordingMaxSize = new Size(0, 0);
1987             Size previewMaxSize = new Size(0, 0);
1988             Size vgaSize = new Size(640, 480);
1989             Size s720pSize = new Size(1280, 720);
1990             Size s1440pSize = new Size(1920, 1440);
1991             // For external camera, or hidden physical camera, CamcorderProfile may not be
1992             // available, so get maximum recording size using stream configuration map.
1993             if (isExternalCamera() || mIsHiddenPhysicalCamera) {
1994                 recordingMaxSize = getMaxCameraRecordingSize();
1995             } else {
1996                 recordingMaxSize = getMaxRecordingSize();
1997             }
1998             if (recordingMaxSize == null) {
1999                 Log.e(TAG, "Failed to find maximum recording size!");
2000                 return null;
2001             }
2002 
2003             HashMap<Integer, Size[]> allSizes = new HashMap<Integer, Size[]>();
2004             for (int format : formats) {
2005                 Integer intFormat = new Integer(format);
2006                 Size[] sizes = mStreamConfigMap.getOutputSizes(format);
2007                 if (sizes == null) {
2008                     sizes = new Size[0];
2009                 }
2010                 allSizes.put(intFormat, sizes);
2011             }
2012 
2013             List<Size> previewSizes = getSizesWithinBound(
2014                     allSizes.get(new Integer(ImageFormat.PRIVATE)), kPreviewSizeBound);
2015             if ((previewSizes == null) || (previewSizes.isEmpty())) {
2016                 Log.e(TAG, "No preview sizes within preview size bound!");
2017                 return null;
2018             }
2019             List<Size> orderedPreviewSizes = getAscendingOrderSizes(previewSizes,
2020                     /*ascending*/false);
2021             previewMaxSize = getMaxPreviewSize(orderedPreviewSizes);
2022 
2023             HashMap<Pair<SizeThreshold, Integer>, List<Size>> availableSizes =
2024                     new HashMap<Pair<SizeThreshold, Integer>, List<Size>>();
2025 
2026             for (int format : formats) {
2027                 Integer intFormat = new Integer(format);
2028                 Size[] sizes = allSizes.get(intFormat);
2029                 Pair<SizeThreshold, Integer> pair = new Pair<SizeThreshold, Integer>(
2030                         SizeThreshold.VGA, intFormat);
2031                 availableSizes.put(pair, getSizesWithinBound(sizes, vgaSize));
2032 
2033                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.PREVIEW, intFormat);
2034                 availableSizes.put(pair, getSizesWithinBound(sizes, previewMaxSize));
2035 
2036                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.RECORD, intFormat);
2037                 availableSizes.put(pair, getSizesWithinBound(sizes, recordingMaxSize));
2038 
2039                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.MAXIMUM, intFormat);
2040                 availableSizes.put(pair, Arrays.asList(sizes));
2041 
2042                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s720p, intFormat);
2043                 availableSizes.put(pair, getSizesWithinBound(sizes, s720pSize));
2044 
2045                 pair = new Pair<SizeThreshold, Integer>(SizeThreshold.s1440p, intFormat);
2046                 availableSizes.put(pair, getSizesWithinBound(sizes, s1440pSize));
2047             }
2048 
2049             return availableSizes;
2050         }
2051 
2052         /**
2053          * Compile a list of sizes smaller than or equal to given bound.
2054          * Return an empty list if there is no size smaller than or equal to the bound.
2055          */
getSizesWithinBound(@onNull Size[] sizes, @NonNull Size bound)2056         private static @Nullable List<Size> getSizesWithinBound(@NonNull Size[] sizes,
2057                 @NonNull Size bound) {
2058             ArrayList<Size> ret = new ArrayList<Size>();
2059             for (Size size : sizes) {
2060                 if (size.getWidth() <= bound.getWidth() && size.getHeight() <= bound.getHeight()) {
2061                     ret.add(size);
2062                 }
2063             }
2064 
2065             return ret;
2066         }
2067 
2068         /**
2069          * Return the lower size
2070          */
getMinSize(Size a, Size b)2071         public static @Nullable Size getMinSize(Size a, Size b) {
2072             if (a == null || b == null) {
2073                 throw new IllegalArgumentException("sizes was empty");
2074             }
2075             if (a.getWidth() * a.getHeight() < b.getHeight() * b.getWidth()) {
2076                 return a;
2077             }
2078             return b;
2079         }
2080         /**
2081          * Get the largest size by area.
2082          *
2083          * @param sizes an array of sizes, must have at least 1 element
2084          *
2085          * @return Largest Size
2086          *
2087          * @throws IllegalArgumentException if sizes was null or had 0 elements
2088          */
getMaxSize(@onNull Size... sizes)2089         public static @Nullable Size getMaxSize(@NonNull Size... sizes) {
2090             if (sizes == null || sizes.length == 0) {
2091                 throw new IllegalArgumentException("sizes was empty");
2092             }
2093 
2094             Size sz = sizes[0];
2095             for (Size size : sizes) {
2096                 if (size.getWidth() * size.getHeight() > sz.getWidth() * sz.getHeight()) {
2097                     sz = size;
2098                 }
2099             }
2100 
2101             return sz;
2102         }
2103 
2104         /**
2105          * Whether or not the hardware level reported by android.info.supportedHardwareLevel is
2106          * at least the desired one (but could be higher)
2107          */
isHardwareLevelAtLeast(int level)2108         private boolean isHardwareLevelAtLeast(int level) {
2109             final int[] sortedHwLevels = {
2110                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
2111                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
2112                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
2113                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
2114                 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
2115             };
2116             if (level == mHwLevel) {
2117                 return true;
2118             }
2119 
2120             for (int sortedlevel : sortedHwLevels) {
2121                 if (sortedlevel == level) {
2122                     return true;
2123                 } else if (sortedlevel == mHwLevel) {
2124                     return false;
2125                 }
2126             }
2127 
2128             return false;
2129         }
2130 
2131         /**
2132          * Whether or not the camera is an external camera.
2133          *
2134          * @return {@code true} if the device is external, {@code false} otherwise.
2135          */
isExternalCamera()2136         private boolean isExternalCamera() {
2137             return mHwLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
2138         }
2139 
2140         /**
2141          * Whether or not the hardware level is at least legacy.
2142          *
2143          * @return {@code true} if the device is {@code LEGACY}, {@code false} otherwise.
2144          */
isHardwareLevelAtLeastLegacy()2145         private boolean isHardwareLevelAtLeastLegacy() {
2146             return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
2147         }
2148 
2149         /**
2150          * Whether or not the hardware level is at least limited.
2151          *
2152          * @return {@code true} if the device is {@code LIMITED} or {@code FULL},
2153          *         {@code false} otherwise (i.e. LEGACY).
2154          */
isHardwareLevelAtLeastLimited()2155         private boolean isHardwareLevelAtLeastLimited() {
2156             return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
2157         }
2158 
2159         /**
2160          * Whether or not the hardware level is at least full.
2161          *
2162          * @return {@code true} if the device is {@code FULL}, {@code false} otherwise.
2163          */
isHardwareLevelAtLeastFull()2164         private boolean isHardwareLevelAtLeastFull() {
2165             return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
2166         }
2167 
2168         /**
2169          * Whether or not the hardware level is at least Level 3.
2170          *
2171          * @return {@code true} if the device is {@code LEVEL3}, {@code false} otherwise.
2172          */
isHardwareLevelAtLeastLevel3()2173         private boolean isHardwareLevelAtLeastLevel3() {
2174             return isHardwareLevelAtLeast(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3);
2175         }
2176 
2177         /**
2178          * Determine whether the current device supports a capability or not.
2179          *
2180          * @param capability (non-negative)
2181          *
2182          * @return {@code true} if the capability is supported, {@code false} otherwise.
2183          *
2184          */
isCapabilitySupported(int capability)2185         private boolean isCapabilitySupported(int capability) {
2186             return mCapabilities.contains(capability);
2187         }
2188 
2189         /**
2190          * Check whether the current device is backward compatible.
2191          */
isColorOutputSupported()2192         private boolean isColorOutputSupported() {
2193             return isCapabilitySupported(
2194                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
2195         }
2196 
2197         /**
2198          * Check whether the current device supports 10-bit output.
2199          */
is10BitOutputSupported()2200         private boolean is10BitOutputSupported() {
2201             return isCapabilitySupported(
2202                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT);
2203         }
2204 
2205         /**
2206          * Check whether the current device supports private reprocessing.
2207          */
isPrivateReprocessingSupported()2208         private boolean isPrivateReprocessingSupported() {
2209             return isCapabilitySupported(
2210                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
2211         }
2212 
2213         /**
2214          * Check whether the current device supports YUV reprocessing.
2215          */
isYUVReprocessingSupported()2216         private boolean isYUVReprocessingSupported() {
2217             return isCapabilitySupported(
2218                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
2219         }
2220 
2221         /**
2222          * Check whether the current device supports YUV reprocessing.
2223          */
isRemosaicReprocessingSupported()2224         private boolean isRemosaicReprocessingSupported() {
2225             return isCapabilitySupported(
2226                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING);
2227         }
2228 
2229         /**
2230          * Return the maximum supported video size using the camcorder profile information.
2231          *
2232          * @return Maximum supported video size.
2233          */
getMaxRecordingSize()2234         private @Nullable Size getMaxRecordingSize() {
2235             int quality =
2236                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_2160P) ?
2237                         CamcorderProfile.QUALITY_2160P :
2238                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_1080P) ?
2239                         CamcorderProfile.QUALITY_1080P :
2240                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_720P) ?
2241                         CamcorderProfile.QUALITY_720P :
2242                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_480P) ?
2243                         CamcorderProfile.QUALITY_480P :
2244                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_QVGA) ?
2245                         CamcorderProfile.QUALITY_QVGA :
2246                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_CIF) ?
2247                         CamcorderProfile.QUALITY_CIF :
2248                     CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_QCIF) ?
2249                         CamcorderProfile.QUALITY_QCIF :
2250                         -1;
2251 
2252             if (quality < 0) {
2253                 return null;
2254             }
2255 
2256             CamcorderProfile maxProfile = CamcorderProfile.get(mCameraId, quality);
2257             return new Size(maxProfile.videoFrameWidth, maxProfile.videoFrameHeight);
2258         }
2259 
2260         /**
2261          * Return the maximum supported video size for cameras using data from
2262          * the stream configuration map.
2263          *
2264          * @return Maximum supported video size.
2265          */
getMaxCameraRecordingSize()2266         private @NonNull Size getMaxCameraRecordingSize() {
2267             final Size FULLHD = new Size(1920, 1080);
2268 
2269             Size[] videoSizeArr = mStreamConfigMap.getOutputSizes(
2270                     android.media.MediaRecorder.class);
2271             List<Size> sizes = new ArrayList<Size>();
2272             for (Size sz: videoSizeArr) {
2273                 if (sz.getWidth() <= FULLHD.getWidth() && sz.getHeight() <= FULLHD.getHeight()) {
2274                     sizes.add(sz);
2275                 }
2276             }
2277             List<Size> videoSizes = getAscendingOrderSizes(sizes, /*ascending*/false);
2278             for (Size sz : videoSizes) {
2279                 long minFrameDuration = mStreamConfigMap.getOutputMinFrameDuration(
2280                         android.media.MediaRecorder.class, sz);
2281                 // Give some margin for rounding error
2282                 if (minFrameDuration > (1e9 / 30.1)) {
2283                     Log.i(TAG, "External camera " + mCameraId + " has max video size:" + sz);
2284                     return sz;
2285                 }
2286             }
2287             Log.w(TAG, "Camera " + mCameraId + " does not support any 30fps video output");
2288             return FULLHD; // doesn't matter what size is returned here
2289         }
2290 
getMaxPreviewSize(List<Size> orderedPreviewSizes)2291         private @NonNull Size getMaxPreviewSize(List<Size> orderedPreviewSizes) {
2292             if (orderedPreviewSizes != null) {
2293                 for (Size size : orderedPreviewSizes) {
2294                     if ((mDisplaySize.getWidth() >= size.getWidth()) &&
2295                             (mDisplaySize.getHeight() >= size.getHeight())) {
2296                         return size;
2297                     }
2298                 }
2299             }
2300 
2301             Log.w(TAG,"Camera " + mCameraId + " maximum preview size search failed with "
2302                     + "display size " + mDisplaySize);
2303             return kPreviewSizeBound;
2304         }
2305 
2306         /**
2307          * Size comparator that compares the number of pixels it covers.
2308          *
2309          * <p>If two the areas of two sizes are same, compare the widths.</p>
2310          */
2311         public static class SizeComparator implements Comparator<Size> {
2312             @Override
compare(@onNull Size lhs, @NonNull Size rhs)2313             public int compare(@NonNull Size lhs, @NonNull Size rhs) {
2314                 return StreamConfigurationMap.compareSizes(lhs.getWidth(), lhs.getHeight(),
2315                         rhs.getWidth(), rhs.getHeight());
2316             }
2317         }
2318 
2319         /**
2320          * Get a sorted list of sizes from a given size list.
2321          *
2322          * <p>
2323          * The size is compare by area it covers, if the areas are same, then
2324          * compare the widths.
2325          * </p>
2326          *
2327          * @param sizeList The input size list to be sorted
2328          * @param ascending True if the order is ascending, otherwise descending order
2329          * @return The ordered list of sizes
2330          */
getAscendingOrderSizes( @onNull final List<Size> sizeList, boolean ascending)2331         private static @NonNull List<Size> getAscendingOrderSizes(
2332                 @NonNull final List<Size> sizeList, boolean ascending) {
2333             Comparator<Size> comparator = new SizeComparator();
2334             List<Size> sortedSizes = new ArrayList<Size>();
2335             sortedSizes.addAll(sizeList);
2336             Collections.sort(sortedSizes, comparator);
2337             if (!ascending) {
2338                 Collections.reverse(sortedSizes);
2339             }
2340 
2341             return sortedSizes;
2342         }
2343     }
2344 }
2345