/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2.params; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.ImageFormat; import android.graphics.ImageFormat.Format; import android.graphics.PixelFormat; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.util.ArraySet; import android.util.Range; import android.util.Size; import android.view.Surface; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collections; import java.util.Set; /** * Immutable class to store the recommended stream configurations to set up * {@link android.view.Surface Surfaces} for creating a * {@link android.hardware.camera2.CameraCaptureSession capture session} with * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)}. * *

The recommended list does not replace or deprecate the exhaustive complete list found in * {@link StreamConfigurationMap}. It is a suggestion about available power and performance * efficient stream configurations for a specific use case. Per definition it is only a subset * of {@link StreamConfigurationMap} and can be considered by developers for optimization * purposes.

* *

This also duplicates the minimum frame durations and stall durations from the * {@link StreamConfigurationMap} for each format/size combination that can be used to calculate * effective frame rate when submitting multiple captures. *

* *

An instance of this object is available by invoking * {@link CameraCharacteristics#getRecommendedStreamConfigurationMap} and passing a respective * usecase id. For more information about supported use case constants see * {@link #USECASE_PREVIEW}.

* *
{@code
 * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
 * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap(
 *         RecommendedStreamConfigurationMap.USECASE_PREVIEW);
 * }
* * @see CameraCharacteristics#getRecommendedStreamConfigurationMap * @see CameraDevice#createCaptureSession(SessionConfiguration) */ public final class RecommendedStreamConfigurationMap { private static final String TAG = "RecommendedStreamConfigurationMap"; private int mUsecase; private boolean mSupportsPrivate; private StreamConfigurationMap mRecommendedMap; /** @hide */ public static final int MAX_USECASE_COUNT = 32; /** * The recommended stream configuration map for use case preview must contain a subset of * efficient, non-stalling configurations that must include both * {@link android.graphics.ImageFormat#PRIVATE} and * {@link android.graphics.ImageFormat#YUV_420_888} output formats. Even if available for the * camera device, high speed or input configurations will be absent. */ public static final int USECASE_PREVIEW = 0x0; /** * The recommended stream configuration map for recording must contain a subset of efficient * video configurations that include {@link android.graphics.ImageFormat#PRIVATE} * output format for at least all supported {@link android.media.CamcorderProfile profiles}. * High speed configurations if supported will be available as well. Even if available for the * camera device, input configurations will be absent. */ public static final int USECASE_RECORD = 0x1; /** * The recommended stream configuration map for use case video snapshot must only contain a * subset of efficient liveshot configurations that include * {@link android.graphics.ImageFormat#JPEG} output format. The sizes will match at least * the maximum resolution of usecase record and will not cause any preview glitches. Even * if available for the camera device, high speed or input configurations will be absent. */ public static final int USECASE_VIDEO_SNAPSHOT = 0x2; /** * The recommended stream configuration map for use case snapshot must contain a subset of * efficient still capture configurations that must include * {@link android.graphics.ImageFormat#JPEG} output format and at least one configuration with * size approximately equal to the sensor pixel array size * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}. * Even if available for the camera device, high speed or input configurations will be absent. */ public static final int USECASE_SNAPSHOT = 0x3; /** * In case the device supports * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING} and/or * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING}, * the recommended stream configuration map for use case ZSL must contain a subset of efficient * configurations that include the suggested input and output format mappings. Even if * available for the camera device, high speed configurations will be absent. */ public static final int USECASE_ZSL = 0x4; /** * In case the device supports * {@link android.hardware.camera2.CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW}, the * recommended stream configuration map for use case RAW must contain a subset of efficient * configurations that include the {@link android.graphics.ImageFormat#RAW_SENSOR} and other * RAW output formats. Even if available for the camera device, high speed and input * configurations will be absent. */ public static final int USECASE_RAW = 0x5; /** * The recommended stream configuration map for use case low latency snapshot must contain * subset of configurations with end-to-end latency that does not exceed 200 ms. under standard * operating conditions (reasonable light levels, not loaded system). The expected output format * will be primarily {@link android.graphics.ImageFormat#JPEG} however other image formats can * be present as well. Even if available for the camera device, high speed and input * configurations will be absent. This suggested configuration map may be absent on some devices * that can not support any low latency requests. */ public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6; /** * If supported, the recommended 10-bit output stream configurations must include * a subset of the advertised {@link android.graphics.ImageFormat#YCBCR_P010} and * {@link android.graphics.ImageFormat#PRIVATE} outputs that are optimized for power * and performance when registered along with a supported 10-bit dynamic range profile. * {@see android.hardware.camera2.params.OutputConfiguration#setDynamicRangeProfile} for * details. */ public static final int USECASE_10BIT_OUTPUT = 0x8; /** * Device specific use cases. * @hide */ public static final int USECASE_VENDOR_START = 0x18; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"USECASE_"}, value = {USECASE_PREVIEW, USECASE_RECORD, USECASE_VIDEO_SNAPSHOT, USECASE_SNAPSHOT, USECASE_ZSL, USECASE_RAW, USECASE_LOW_LATENCY_SNAPSHOT, USECASE_10BIT_OUTPUT}) public @interface RecommendedUsecase {}; /** * Create a new {@link RecommendedStreamConfigurationMap}. * * @param recommendedMap stream configuration map that contains for the specific use case * @param usecase Recommended use case * @param supportsPrivate Flag indicating private format support. * * @hide */ public RecommendedStreamConfigurationMap(StreamConfigurationMap recommendedMap, int usecase, boolean supportsPrivate) { mRecommendedMap = recommendedMap; mUsecase = usecase; mSupportsPrivate = supportsPrivate; } /** * Get the use case value for the recommended stream configurations. * * @return Use case id. */ public @RecommendedUsecase int getRecommendedUseCase() { return mUsecase; } private Set getUnmodifiableIntegerSet(int[] intArray) { if ((intArray != null) && (intArray.length > 0)) { ArraySet integerSet = new ArraySet(); integerSet.ensureCapacity(intArray.length); for (int intEntry : intArray) { integerSet.add(intEntry); } return Collections.unmodifiableSet(integerSet); } return null; } /** * Get the image {@code format} output formats in this stream configuration. * *

* For more information refer to {@link StreamConfigurationMap#getOutputFormats}. *

* * @return a non-modifiable set of Integer formats */ public @NonNull Set getOutputFormats() { return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats()); } /** * Get the image {@code format} output formats for a reprocessing input format. * *

* For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}. *

* * @return a non-modifiable set of Integer formats */ public @Nullable Set getValidOutputFormatsForInput(@Format int inputFormat) { return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput( inputFormat)); } /** * Get the image {@code format} input formats in this stream configuration. * *

All image formats returned by this function will be defined in either {@link ImageFormat} * or in {@link PixelFormat} (and there is no possibility of collision).

* * @return a non-modifiable set of Integer formats */ public @Nullable Set getInputFormats() { return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats()); } private Set getUnmodifiableSizeSet(Size[] sizeArray) { if ((sizeArray != null) && (sizeArray.length > 0)) { ArraySet sizeSet = new ArraySet(); sizeSet.addAll(Arrays.asList(sizeArray)); return Collections.unmodifiableSet(sizeSet); } return null; } /** * Get the supported input sizes for this input format. * *

The format must have come from {@link #getInputFormats}; otherwise * {@code null} is returned.

* * @param format a format from {@link #getInputFormats} * @return a non-modifiable set of sizes, or {@code null} if the format was not available. */ public @Nullable Set getInputSizes(@Format int format) { return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format)); } /** * Determine whether or not output surfaces with a particular user-defined format can be passed * {@link CameraDevice#createCaptureSession(SessionConfiguration) createCaptureSession}. * *

* For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. *

* * * @param format an image format from either {@link ImageFormat} or {@link PixelFormat} * @return * {@code true} if using a {@code surface} with this {@code format} will be * supported with {@link CameraDevice#createCaptureSession(SessionConfiguration)} * * @throws IllegalArgumentException * if the image format was not a defined named constant * from either {@link ImageFormat} or {@link PixelFormat} */ public boolean isOutputSupportedFor(@Format int format) { return mRecommendedMap.isOutputSupportedFor(format); } /** * Get a list of sizes compatible with the requested image {@code format}. * *

* For more information refer to {@link StreamConfigurationMap#getOutputSizes}. *

* * * @param format an image format from {@link ImageFormat} or {@link PixelFormat} * @return a non-modifiable set of supported sizes, * or {@code null} if the {@code format} is not a supported output */ public @Nullable Set getOutputSizes(@Format int format) { return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format)); } /** * Get a list of supported high speed video recording sizes. *

* For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}. *

* * @return a non-modifiable set of supported high speed video recording sizes */ public @Nullable Set getHighSpeedVideoSizes() { return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes()); } private Set> getUnmodifiableRangeSet(Range[] rangeArray) { if ((rangeArray != null) && (rangeArray.length > 0)) { ArraySet> rangeSet = new ArraySet>(); rangeSet.addAll(Arrays.asList(rangeArray)); return Collections.unmodifiableSet(rangeSet); } return null; } /** * Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size. * *

* For further information refer to * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}. *

* @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()} * @return a non-modifiable set of supported high speed video recording FPS ranges The upper * bound of returned ranges is guaranteed to be greater than or equal to 120. * @throws IllegalArgumentException if input size does not exist in the return value of * getHighSpeedVideoSizes */ public @Nullable Set> getHighSpeedVideoFpsRangesFor(@NonNull Size size) { return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size)); } /** * Get a list of supported high speed video recording FPS ranges. *

* For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}. *

* @return a non-modifiable set of supported high speed video recording FPS ranges The upper * bound of returned ranges is guaranteed to be larger or equal to 120. */ public @Nullable Set> getHighSpeedVideoFpsRanges() { return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges()); } /** * Get the supported video sizes for an input high speed FPS range. * *

* For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}. *

* * @param fpsRange one of the FPS ranges returned by {@link #getHighSpeedVideoFpsRanges()} * @return A non-modifiable set of video sizes to create high speed capture sessions for high * speed streaming use cases. * * @throws IllegalArgumentException if input FPS range does not exist in the return value of * getHighSpeedVideoFpsRanges */ public @Nullable Set getHighSpeedVideoSizesFor(@NonNull Range fpsRange) { return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange)); } /** * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE * rate. * *

* For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}. *

* * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if * the BURST_CAPTURE capability is not supported */ public @Nullable Set getHighResolutionOutputSizes(@Format int format) { return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format)); } /** * Get the minimum * {@link android.hardware.camera2.CaptureRequest#SENSOR_FRAME_DURATION frame duration} * for the format/size combination (in nanoseconds). * *

* For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}. *

* * @param format an image format from {@link ImageFormat} or {@link PixelFormat} * @param size an output-compatible size * @return a minimum frame duration {@code >} 0 in nanoseconds, or * 0 if the minimum frame duration is not available. * * @throws IllegalArgumentException if {@code format} or {@code size} was not supported */ public @IntRange(from = 0) long getOutputMinFrameDuration(@Format int format, @NonNull Size size) { return mRecommendedMap.getOutputMinFrameDuration(format, size); } /** * Get the stall duration for the format/size combination (in nanoseconds). * *

* For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}. *

* * @param format an image format from {@link ImageFormat} or {@link PixelFormat} * @param size an output-compatible size * @return a stall duration {@code >=} 0 in nanoseconds * * @throws IllegalArgumentException if {@code format} or {@code size} was not supported */ public @IntRange(from = 0) long getOutputStallDuration(@Format int format, @NonNull Size size) { return mRecommendedMap.getOutputStallDuration(format, size); } /** * Get a list of sizes compatible with {@code klass} to use as an output. * *

For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}. *

* * @param klass * a {@link Class} object reference * @return * a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format, * or {@code null} if the {@code klass} is not a supported output. */ public @Nullable Set getOutputSizes(@NonNull Class klass) { if (mSupportsPrivate) { return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass)); } return null; } /** * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration} * for the class/size combination (in nanoseconds). * *

For more information refer to * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.

* * @param klass * a class which has a non-empty array returned by {@link #getOutputSizes(Class)} * @param size an output-compatible size * @return a minimum frame duration {@code >} 0 in nanoseconds, or * 0 if the minimum frame duration is not available. * * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported */ public @IntRange(from = 0) long getOutputMinFrameDuration(@NonNull final Class klass, @NonNull final Size size) { if (mSupportsPrivate) { return mRecommendedMap.getOutputMinFrameDuration(klass, size); } return 0; } /** * Get the stall duration for the class/size combination (in nanoseconds). * *

For more information refer to * {@link StreamConfigurationMap#getOutputStallDuration(Class, Size)}. * * @param klass * a class which has a non-empty array returned by {@link #getOutputSizes(Class)}. * @param size an output-compatible size * @return a minimum frame duration {@code >} 0 in nanoseconds, or 0 if the stall duration is * not available. * * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported */ public @IntRange(from = 0) long getOutputStallDuration(@NonNull final Class klass, @NonNull final Size size) { if (mSupportsPrivate) { return mRecommendedMap.getOutputStallDuration(klass, size); } return 0; } /** * Determine whether or not the {@code surface} in its current * state is suitable to be included in a {@link * CameraDevice#createCaptureSession(SessionConfiguration) capture * session} as an output. * *

For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. *

* * @param surface a {@link Surface} object reference * @return {@code true} if this is supported, {@code false} otherwise * * @throws IllegalArgumentException if the Surface endpoint is no longer valid * */ public boolean isOutputSupportedFor(@NonNull Surface surface) { return mRecommendedMap.isOutputSupportedFor(surface); } }