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