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