diff options
| author | Shuzhen Wang <shuzhenwang@google.com> | 2018-11-07 22:54:02 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-11-07 22:54:02 +0000 |
| commit | 89d277a982472074fd7184f21c37f4d994b9b57a (patch) | |
| tree | d02b7773bfe3f72a891fcd7e6355479927b1f90f /core/java/android | |
| parent | 7c62638354e5c2d228194af7fb1110babd991b63 (diff) | |
| parent | 2776ca3f4e877709e0e313e25d2d9f86cbd89b8b (diff) | |
Merge "Camera: Add support for recommended stream configurations"
Diffstat (limited to 'core/java/android')
7 files changed, 1172 insertions, 20 deletions
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 33cc7a84b335..444ca87a68ef 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -22,12 +22,14 @@ import android.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; +import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.SessionConfiguration; import android.hardware.camera2.utils.ArrayUtils; import android.hardware.camera2.utils.TypeReference; import android.util.Rational; import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -193,6 +195,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri private List<CaptureRequest.Key<?>> mAvailableSessionKeys; private List<CaptureRequest.Key<?>> mAvailablePhysicalRequestKeys; private List<CaptureResult.Key<?>> mAvailableResultKeys; + private ArrayList<RecommendedStreamConfigurationMap> mRecommendedConfigurations; /** * Takes ownership of the passed-in properties object @@ -313,6 +316,103 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri } /** + * <p>Retrieve camera device recommended stream configuration map + * {@link RecommendedStreamConfigurationMap} for a given use case.</p> + * + * <p>The stream configurations advertised here are efficient in terms of power and performance + * for common use cases like preview, video, snapshot, etc. The recommended maps are usually + * only small subsets of the exhaustive list provided in + * {@link #SCALER_STREAM_CONFIGURATION_MAP} and suggested for a particular use case by the + * camera device implementation. For further information about the expected configurations in + * various scenarios please refer to: + * <ul> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_PREVIEW}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_RECORD}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_VIDEO_SNAPSHOT}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li> + * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li> + * </ul> + * </p> + * + * <p>For example on how this can be used by camera clients to find out the maximum recommended + * preview and snapshot resolution, consider the following pseudo-code: + * </p> + * <pre><code> + * public static Size getMaxSize(Size... sizes) { + * if (sizes == null || sizes.length == 0) { + * throw new IllegalArgumentException("sizes was empty"); + * } + * + * Size sz = sizes[0]; + * for (Size size : sizes) { + * if (size.getWidth() * size.getHeight() > sz.getWidth() * sz.getHeight()) { + * sz = size; + * } + * } + * + * return sz; + * } + * + * CameraCharacteristics characteristics = + * cameraManager.getCameraCharacteristics(cameraId); + * RecommendedStreamConfigurationMap previewConfig = + * characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_PREVIEW); + * RecommendedStreamConfigurationMap snapshotConfig = + * characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_SNAPSHOT); + * + * if ((previewConfig != null) && (snapshotConfig != null)) { + * + * Set<Size> snapshotSizeSet = snapshotConfig.getOutputSizes( + * ImageFormat.JPEG); + * Size[] snapshotSizes = new Size[snapshotSizeSet.size()]; + * snapshotSizes = snapshotSizeSet.toArray(snapshotSizes); + * Size suggestedMaxJpegSize = getMaxSize(snapshotSizes); + * + * Set<Size> previewSizeSet = snapshotConfig.getOutputSizes( + * ImageFormat.PRIVATE); + * Size[] previewSizes = new Size[previewSizeSet.size()]; + * previewSizes = previewSizeSet.toArray(previewSizes); + * Size suggestedMaxPreviewSize = getMaxSize(previewSizes); + * } + * + * </code></pre> + * + * <p>Similar logic can be used for other use cases as well.</p> + * + * <p>Support for recommended stream configurations is optional. In case there a no + * suggested configurations for the particular use case, please refer to + * {@link #SCALER_STREAM_CONFIGURATION_MAP} for the exhaustive available list.</p> + * + * @param usecase Use case id. + * + * @throws IllegalArgumentException In case the use case argument is invalid. + * @return Valid {@link RecommendedStreamConfigurationMap} or null in case the camera device + * doesn't have any recommendation for this use case or the recommended configurations + * are invalid. + */ + public RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap( + @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) { + if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) && + (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) || + ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) && + (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) { + if (mRecommendedConfigurations == null) { + mRecommendedConfigurations = mProperties.getRecommendedStreamConfigurations(); + if (mRecommendedConfigurations == null) { + return null; + } + } + + return mRecommendedConfigurations.get(usecase); + } + + throw new IllegalArgumentException(String.format("Invalid use case: %d", usecase)); + } + + /** * <p>Returns a subset of {@link #getAvailableCaptureRequestKeys} keys that the * camera device can pass as part of the capture session initialization.</p> * @@ -329,7 +429,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * but clients should be aware and expect delays during their application. * An example usage scenario could look like this:</p> * <ul> - * <li>The camera client starts by quering the session parameter key list via + * <li>The camera client starts by querying the session parameter key list via * {@link android.hardware.camera2.CameraCharacteristics#getAvailableSessionKeys }.</li> * <li>Before triggering the capture session create sequence, a capture request * must be built via {@link CameraDevice#createCaptureRequest } using an @@ -2478,6 +2578,37 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Integer>("android.scaler.croppingType", int.class); /** + * <p>Recommended stream configurations for common client use cases.</p> + * <p>Optional subset of the android.scaler.availableStreamConfigurations that contains + * similar tuples listed as + * (i.e. width, height, format, output/input stream, usecase bit field). + * Camera devices will be able to suggest particular stream configurations which are + * power and performance efficient for specific use cases. For more information about + * retrieving the suggestions see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.scaler.availableRecommendedStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class); + + /** + * <p>Recommended mappings of image formats that are supported by this + * camera device for input streams, to their corresponding output formats.</p> + * <p>This is a recommended subset of the complete list of mappings found in + * android.scaler.availableInputOutputFormatsMap. The same requirements apply here as well. + * The list however doesn't need to contain all available and supported mappings. Instead of + * this developers must list only recommended and efficient entries. + * If set, the information will be available in the ZERO_SHUTTER_LAG recommended stream + * configuration see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP = + new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableRecommendedInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class); + + /** * <p>The area of the image sensor which corresponds to active pixels after any geometric * distortion correction has been applied.</p> * <p>This is the rectangle representing the size of the active region of the sensor (i.e. @@ -3518,6 +3649,21 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<Boolean>("android.depth.depthIsExclusive", boolean.class); /** + * <p>Recommended depth stream configurations for common client use cases.</p> + * <p>Optional subset of the android.depth.availableDepthStreamConfigurations that + * contains similar tuples listed as + * (i.e. width, height, format, output/input stream, usecase bit field). + * Camera devices will be able to suggest particular depth stream configurations which are + * power and performance efficient for specific use cases. For more information about + * retrieving the suggestions see + * {@link android.hardware.camera2.CameraCharacteristics#getRecommendedStreamConfigurationMap }.</p> + * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> + * @hide + */ + public static final Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]> DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = + new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class); + + /** * <p>String containing the ids of the underlying physical cameras.</p> * <p>For a logical camera, this is concatenation of all underlying physical camera ids. * The null terminator for physical camera id must be preserved so that the whole string diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 0610d7a3746b..f81bd1377a7a 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -21,6 +21,7 @@ import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.marshal.MarshalQueryable; @@ -38,6 +39,7 @@ import android.hardware.camera2.marshal.impl.MarshalQueryablePair; import android.hardware.camera2.marshal.impl.MarshalQueryableParcelable; import android.hardware.camera2.marshal.impl.MarshalQueryablePrimitive; import android.hardware.camera2.marshal.impl.MarshalQueryableRange; +import android.hardware.camera2.marshal.impl.MarshalQueryableRecommendedStreamConfiguration; import android.hardware.camera2.marshal.impl.MarshalQueryableRect; import android.hardware.camera2.marshal.impl.MarshalQueryableReprocessFormatsMap; import android.hardware.camera2.marshal.impl.MarshalQueryableRggbChannelVector; @@ -50,6 +52,8 @@ import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; import android.hardware.camera2.params.OisSample; +import android.hardware.camera2.params.RecommendedStreamConfiguration; +import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.ReprocessFormatsMap; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; @@ -911,6 +915,252 @@ public class CameraMetadataNative implements Parcelable { return true; } + private void parseRecommendedConfigurations(RecommendedStreamConfiguration[] configurations, + StreamConfigurationMap fullMap, boolean isDepth, + ArrayList<ArrayList<StreamConfiguration>> /*out*/streamConfigList, + ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamDurationList, + ArrayList<ArrayList<StreamConfigurationDuration>> /*out*/streamStallList, + boolean[] /*out*/supportsPrivate) { + + streamConfigList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + streamDurationList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + streamStallList.ensureCapacity(RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + streamConfigList.add(new ArrayList<StreamConfiguration> ()); + streamDurationList.add(new ArrayList<StreamConfigurationDuration> ()); + streamStallList.add(new ArrayList<StreamConfigurationDuration> ()); + } + + for (RecommendedStreamConfiguration c : configurations) { + int width = c.getWidth(); + int height = c.getHeight(); + int internalFormat = c.getFormat(); + int publicFormat = + (isDepth) ? StreamConfigurationMap.depthFormatToPublic(internalFormat) : + StreamConfigurationMap.imageFormatToPublic(internalFormat); + Size sz = new Size(width, height); + int usecaseBitmap = c.getUsecaseBitmap(); + + if (!c.isInput()) { + StreamConfigurationDuration minDurationConfiguration = null; + StreamConfigurationDuration stallDurationConfiguration = null; + + StreamConfiguration streamConfiguration = new StreamConfiguration(internalFormat, + width, height, /*input*/ false); + + long minFrameDuration = fullMap.getOutputMinFrameDuration(publicFormat, sz); + if (minFrameDuration > 0) { + minDurationConfiguration = new StreamConfigurationDuration(internalFormat, + width, height, minFrameDuration); + } + + long stallDuration = fullMap.getOutputStallDuration(publicFormat, sz); + if (stallDuration > 0) { + stallDurationConfiguration = new StreamConfigurationDuration(internalFormat, + width, height, stallDuration); + } + + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + if ((usecaseBitmap & (1 << i)) != 0) { + ArrayList<StreamConfiguration> sc = streamConfigList.get(i); + sc.add(streamConfiguration); + + if (minFrameDuration > 0) { + ArrayList<StreamConfigurationDuration> scd = streamDurationList.get(i); + scd.add(minDurationConfiguration); + } + + if (stallDuration > 0) { + ArrayList<StreamConfigurationDuration> scs = streamStallList.get(i); + scs.add(stallDurationConfiguration); + } + + if ((supportsPrivate != null) && !supportsPrivate[i] && + (publicFormat == ImageFormat.PRIVATE)) { + supportsPrivate[i] = true; + } + } + } + } else { + if (usecaseBitmap != (1 << RecommendedStreamConfigurationMap.USECASE_ZSL)) { + throw new IllegalArgumentException("Recommended input stream configurations " + + "should only be advertised in the ZSL use case!"); + } + + ArrayList<StreamConfiguration> sc = streamConfigList.get( + RecommendedStreamConfigurationMap.USECASE_ZSL); + sc.add(new StreamConfiguration(internalFormat, + width, height, /*input*/ true)); + } + } + } + + private class StreamConfigurationData { + StreamConfiguration [] streamConfigurationArray = null; + StreamConfigurationDuration [] minDurationArray = null; + StreamConfigurationDuration [] stallDurationArray = null; + } + + public void initializeStreamConfigurationData(ArrayList<StreamConfiguration> sc, + ArrayList<StreamConfigurationDuration> scd, ArrayList<StreamConfigurationDuration> scs, + StreamConfigurationData /*out*/scData) { + if ((scData == null) || (sc == null)) { + return; + } + + scData.streamConfigurationArray = new StreamConfiguration[sc.size()]; + scData.streamConfigurationArray = sc.toArray(scData.streamConfigurationArray); + + if ((scd != null) && !scd.isEmpty()) { + scData.minDurationArray = new StreamConfigurationDuration[scd.size()]; + scData.minDurationArray = scd.toArray(scData.minDurationArray); + } else { + scData.minDurationArray = new StreamConfigurationDuration[0]; + } + + if ((scs != null) && !scs.isEmpty()) { + scData.stallDurationArray = new StreamConfigurationDuration[scs.size()]; + scData.stallDurationArray = scs.toArray(scData.stallDurationArray); + } else { + scData.stallDurationArray = new StreamConfigurationDuration[0]; + } + } + + /** + * Retrieve the list of recommended stream configurations. + * + * @return A list of recommended stream configuration maps for each common use case or null + * in case the recommended stream configurations are invalid or incomplete. + * @hide + */ + public ArrayList<RecommendedStreamConfigurationMap> getRecommendedStreamConfigurations() { + RecommendedStreamConfiguration[] configurations = getBase( + CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS); + RecommendedStreamConfiguration[] depthConfigurations = getBase( + CameraCharacteristics.DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS); + if ((configurations == null) && (depthConfigurations == null)) { + return null; + } + + StreamConfigurationMap fullMap = getStreamConfigurationMap(); + ArrayList<RecommendedStreamConfigurationMap> recommendedConfigurations = + new ArrayList<RecommendedStreamConfigurationMap> (); + + ArrayList<ArrayList<StreamConfiguration>> streamConfigList = + new ArrayList<ArrayList<StreamConfiguration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> streamDurationList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> streamStallList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + boolean[] supportsPrivate = + new boolean[RecommendedStreamConfigurationMap.MAX_USECASE_COUNT]; + try { + if (configurations != null) { + parseRecommendedConfigurations(configurations, fullMap, /*isDepth*/ false, + streamConfigList, streamDurationList, streamStallList, supportsPrivate); + } + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed parsing the recommended stream configurations!"); + return null; + } + + ArrayList<ArrayList<StreamConfiguration>> depthStreamConfigList = + new ArrayList<ArrayList<StreamConfiguration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamDurationList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + ArrayList<ArrayList<StreamConfigurationDuration>> depthStreamStallList = + new ArrayList<ArrayList<StreamConfigurationDuration>>(); + if (depthConfigurations != null) { + try { + parseRecommendedConfigurations(depthConfigurations, fullMap, /*isDepth*/ true, + depthStreamConfigList, depthStreamDurationList, depthStreamStallList, + /*supportsPrivate*/ null); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Failed parsing the recommended depth stream configurations!"); + return null; + } + } + + ReprocessFormatsMap inputOutputFormatsMap = getBase( + CameraCharacteristics.SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP); + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase( + CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); + boolean listHighResolution = isBurstSupported(); + recommendedConfigurations.ensureCapacity( + RecommendedStreamConfigurationMap.MAX_USECASE_COUNT); + for (int i = 0; i < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT; i++) { + StreamConfigurationData scData = new StreamConfigurationData(); + if (configurations != null) { + initializeStreamConfigurationData(streamConfigList.get(i), + streamDurationList.get(i), streamStallList.get(i), scData); + } + + StreamConfigurationData depthScData = new StreamConfigurationData(); + if (depthConfigurations != null) { + initializeStreamConfigurationData(depthStreamConfigList.get(i), + depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData); + } + + if ((scData.streamConfigurationArray == null) && + (depthScData.streamConfigurationArray == null)) { + recommendedConfigurations.add(null); + continue; + } + + StreamConfigurationMap map = null; + switch (i) { + case RecommendedStreamConfigurationMap.USECASE_PREVIEW: + case RecommendedStreamConfigurationMap.USECASE_RAW: + case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + /*depthconfiguration*/ null, /*depthminduration*/ null, + /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null, + /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); + break; + case RecommendedStreamConfigurationMap.USECASE_RECORD: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + /*depthconfiguration*/ null, /*depthminduration*/ null, + /*depthstallduration*/ null, highSpeedVideoConfigurations, + /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]); + break; + case RecommendedStreamConfigurationMap.USECASE_ZSL: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + depthScData.streamConfigurationArray, depthScData.minDurationArray, + depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null, + inputOutputFormatsMap, listHighResolution, supportsPrivate[i]); + break; + default: + map = new StreamConfigurationMap(scData.streamConfigurationArray, + scData.minDurationArray, scData.stallDurationArray, + depthScData.streamConfigurationArray, depthScData.minDurationArray, + depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null, + /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]); + } + + recommendedConfigurations.add(new RecommendedStreamConfigurationMap(map, /*usecase*/i, + supportsPrivate[i])); + } + + return recommendedConfigurations; + } + + private boolean isBurstSupported() { + boolean ret = false; + + int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); + for (int capability : capabilities) { + if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { + ret = true; + break; + } + } + + return ret; + } + private StreamConfigurationMap getStreamConfigurationMap() { StreamConfiguration[] configurations = getBase( CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); @@ -928,14 +1178,7 @@ public class CameraMetadataNative implements Parcelable { CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); ReprocessFormatsMap inputOutputFormatsMap = getBase( CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP); - int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); - boolean listHighResolution = false; - for (int capability : capabilities) { - if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) { - listHighResolution = true; - break; - } - } + boolean listHighResolution = isBurstSupported(); return new StreamConfigurationMap( configurations, minFrameDurations, stallDurations, depthConfigurations, depthMinFrameDurations, depthStallDurations, @@ -1399,6 +1642,7 @@ public class CameraMetadataNative implements Parcelable { new MarshalQueryableRggbChannelVector(), new MarshalQueryableBlackLevelPattern(), new MarshalQueryableHighSpeedVideoConfiguration(), + new MarshalQueryableRecommendedStreamConfiguration(), // generic parcelable marshaler (MUST BE LAST since it has lowest priority) new MarshalQueryableParcelable(), diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java new file mode 100644 index 000000000000..22a76b7346e8 --- /dev/null +++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRecommendedStreamConfiguration.java @@ -0,0 +1,84 @@ +/* + * 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.marshal.impl; + +import android.hardware.camera2.marshal.Marshaler; +import android.hardware.camera2.marshal.MarshalQueryable; +import android.hardware.camera2.params.RecommendedStreamConfiguration; +import android.hardware.camera2.utils.TypeReference; + +import static android.hardware.camera2.impl.CameraMetadataNative.*; +import static android.hardware.camera2.marshal.MarshalHelpers.*; + +import java.nio.ByteBuffer; + +/** + * Marshaler for {@code android.scaler.availableRecommendedStreamConfigurations} custom class + * {@link RecommendedStreamConfiguration} + * + * <p>Data is stored as {@code (width, height, format, input, usecaseBitmap)} tuples (int32).</p> + */ +public class MarshalQueryableRecommendedStreamConfiguration + implements MarshalQueryable<RecommendedStreamConfiguration> { + private static final int SIZE = SIZEOF_INT32 * 5; + + private class MarshalerRecommendedStreamConfiguration + extends Marshaler<RecommendedStreamConfiguration> { + protected MarshalerRecommendedStreamConfiguration( + TypeReference<RecommendedStreamConfiguration> typeReference, int nativeType) { + super(MarshalQueryableRecommendedStreamConfiguration.this, typeReference, nativeType); + } + + @Override + public void marshal(RecommendedStreamConfiguration value, ByteBuffer buffer) { + buffer.putInt(value.getWidth()); + buffer.putInt(value.getHeight()); + buffer.putInt(value.getFormat()); + buffer.putInt(value.isInput() ? 1 : 0); + buffer.putInt(value.getUsecaseBitmap()); + } + + @Override + public RecommendedStreamConfiguration unmarshal(ByteBuffer buffer) { + int width = buffer.getInt(); + int height = buffer.getInt(); + int format = buffer.getInt(); + boolean input = buffer.getInt() != 0; + int usecaseBitmap = buffer.getInt(); + + return new RecommendedStreamConfiguration(format, width, height, input, usecaseBitmap); + } + + @Override + public int getNativeSize() { + return SIZE; + } + + } + + @Override + public Marshaler<RecommendedStreamConfiguration> createMarshaler( + TypeReference<RecommendedStreamConfiguration> managedType, int nativeType) { + return new MarshalerRecommendedStreamConfiguration(managedType, nativeType); + } + + @Override + public boolean isTypeMappingSupported(TypeReference<RecommendedStreamConfiguration> managedType, + int nativeType) { + return nativeType == + TYPE_INT32 && managedType.getType().equals(RecommendedStreamConfiguration.class); + } +} diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java new file mode 100644 index 000000000000..5dd0517ae47e --- /dev/null +++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfiguration.java @@ -0,0 +1,102 @@ +/* + * 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.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.utils.HashCodeHelpers; + +/** + * Immutable class to store the recommended stream configurations to set up + * {@link android.view.Surface Surfaces} for creating a {@link CameraCaptureSession capture session} + * with {@link CameraDevice#createCaptureSession}. + * + * @see CameraCharacteristics#getRecommendedStreamConfigurationMap + * + * @hide + */ +public final class RecommendedStreamConfiguration extends StreamConfiguration{ + + /** + * Create a new {@link RecommendedStreamConfiguration}. + * + * @param format image format + * @param width image width, in pixels (positive) + * @param height image height, in pixels (positive) + * @param input true if this is an input configuration, false for output configurations + * @param usecaseBitmap Use case bitmap + * + * @throws IllegalArgumentException + * if width/height were not positive + * or if the format was not user-defined in ImageFormat/PixelFormat + * (IMPL_DEFINED is ok) + * + * @hide + */ + public RecommendedStreamConfiguration( + final int format, final int width, final int height, final boolean input, final int + usecaseBitmap) { + super(format, width, height, input); + mUsecaseBitmap = usecaseBitmap; + } + + /** + * Return usecase bitmap. + * + * @return usecase bitmap + */ + public int getUsecaseBitmap() { + return mUsecaseBitmap; + } + + /** + * Check if this {@link RecommendedStreamConfiguration} is equal to another + * {@link RecommendedStreamConfiguration}. + * + * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> + * + * @return {@code true} if the objects were equal, {@code false} otherwise + */ + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (obj instanceof RecommendedStreamConfiguration) { + final RecommendedStreamConfiguration other = (RecommendedStreamConfiguration) obj; + return mFormat == other.mFormat && + mWidth == other.mWidth && + mHeight == other.mHeight && + mUsecaseBitmap == other.mUsecaseBitmap && + mInput == other.mInput; + } + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0, mUsecaseBitmap); + } + + private final int mUsecaseBitmap; +} diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java new file mode 100644 index 000000000000..59e4a3366995 --- /dev/null +++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java @@ -0,0 +1,509 @@ +/* + * 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.NonNull; +import android.annotation.Nullable; +import android.graphics.ImageFormat; +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}. + * + * <p>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.</p> + * + * <p>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. + * </p> + * + * <p>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}.</p> + * + * <pre><code>{@code + * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + * RecommendedStreamConfigurationMap configs = characteristics.getRecommendedStreamConfigurationMap( + * RecommendedStreamConfigurationMap.USECASE_PREVIEW); + * }</code></pre> + * + * @see CameraCharacteristics#getRecommendedStreamConfigurationMap + * @see CameraDevice#createCaptureSession + */ +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; + + /** + * 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 }) + 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 int getRecommendedUseCase() { + return mUsecase; + } + + private Set<Integer> getUnmodifiableIntegerSet(int[] intArray) { + if ((intArray != null) && (intArray.length > 0)) { + ArraySet<Integer> integerSet = new ArraySet<Integer>(); + 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. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getOutputFormats}. + * </p> + * + * @return a non-modifiable set of Integer formats + */ + public @NonNull Set<Integer> getOutputFormats() { + return getUnmodifiableIntegerSet(mRecommendedMap.getOutputFormats()); + } + + /** + * Get the image {@code format} output formats for a reprocessing input format. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getValidOutputFormatsForInput}. + * </p> + * + * @return a non-modifiable set of Integer formats + */ + public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) { + return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput( + inputFormat)); + } + + /** + * Get the image {@code format} input formats in this stream configuration. + * + * <p>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).</p> + * + * @return a non-modifiable set of Integer formats + */ + public @Nullable Set<Integer> getInputFormats() { + return getUnmodifiableIntegerSet(mRecommendedMap.getInputFormats()); + } + + private Set<Size> getUnmodifiableSizeSet(Size[] sizeArray) { + if ((sizeArray != null) && (sizeArray.length > 0)) { + ArraySet<Size> sizeSet = new ArraySet<Size>(); + sizeSet.addAll(Arrays.asList(sizeArray)); + return Collections.unmodifiableSet(sizeSet); + } + + return null; + } + + /** + * Get the supported input sizes for this input format. + * + * <p>The format must have come from {@link #getInputFormats}; otherwise + * {@code null} is returned.</p> + * + * @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<Size> getInputSizes(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 createCaptureSession}. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. + * </p> + * + * + * @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} + * + * @throws IllegalArgumentException + * if the image format was not a defined named constant + * from either {@link ImageFormat} or {@link PixelFormat} + */ + public boolean isOutputSupportedFor(int format) { + return mRecommendedMap.isOutputSupportedFor(format); + } + + /** + * Get a list of sizes compatible with the requested image {@code format}. + * + * <p> + * For more information refer to {@link StreamConfigurationMap#getOutputSizes}. + * </p> + * + * + * @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<Size> getOutputSizes(int format) { + return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format)); + } + + /** + * Get a list of supported high speed video recording sizes. + * <p> + * For more information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizes}. + * </p> + * + * @return a non-modifiable set of supported high speed video recording sizes + */ + public @Nullable Set<Size> getHighSpeedVideoSizes() { + return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizes()); + } + + private Set<Range<Integer>> getUnmodifiableRangeSet(Range<Integer>[] rangeArray) { + if ((rangeArray != null) && (rangeArray.length > 0)) { + ArraySet<Range<Integer>> rangeSet = new ArraySet<Range<Integer>>(); + 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. + * + * <p> + * For further information refer to + * {@link StreamConfigurationMap#getHighSpeedVideoFpsRangesFor}. + * </p> + * @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<Range<Integer>> getHighSpeedVideoFpsRangesFor(Size size) { + return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRangesFor(size)); + } + + /** + * Get a list of supported high speed video recording FPS ranges. + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoFpsRanges}. + * </p> + * @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<Range<Integer>> getHighSpeedVideoFpsRanges() { + return getUnmodifiableRangeSet(mRecommendedMap.getHighSpeedVideoFpsRanges()); + } + + /** + * Get the supported video sizes for an input high speed FPS range. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighSpeedVideoSizesFor}. + * </p> + * + * @param fpsRange one of the FPS range 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<Size> getHighSpeedVideoSizesFor(Range<Integer> fpsRange) { + return getUnmodifiableSizeSet(mRecommendedMap.getHighSpeedVideoSizesFor(fpsRange)); + } + + /** + * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE + * rate. + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getHighResolutionOutputSizes}. + * </p> + * + * @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<Size> getHighResolutionOutputSizes(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). + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getOutputMinFrameDuration}. + * </p> + * + * @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 + * @throws NullPointerException if {@code size} was {@code null} + * + */ + public long getOutputMinFrameDuration(int format, Size size) { + return mRecommendedMap.getOutputMinFrameDuration(format, size); + } + + /** + * Get the stall duration for the format/size combination (in nanoseconds). + * + * <p> + * For further information refer to {@link StreamConfigurationMap#getOutputStallDuration}. + * </p> + * + * @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 + * @throws NullPointerException if {@code size} was {@code null} + */ + public long getOutputStallDuration(int format, Size size) { + return mRecommendedMap.getOutputStallDuration(format, size); + } + + /** + * Get a list of sizes compatible with {@code klass} to use as an output. + * + * <p>For further information refer to {@link StreamConfigurationMap#getOutputSizes(Class)}. + * </p> + * + * @param klass + * a non-{@code null} {@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. + * + * + * @throws NullPointerException if {@code klass} was {@code null} + * + */ + public <T> @Nullable Set<Size> getOutputSizes(Class<T> 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). + * + * <p>For more information refer to + * {@link StreamConfigurationMap#getOutputMinFrameDuration(Class, Size)}.</p> + * + * @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 + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + */ + public <T> long getOutputMinFrameDuration(final Class<T> klass, final Size size) { + if (mSupportsPrivate) { + return mRecommendedMap.getOutputMinFrameDuration(klass, size); + } + + return 0; + } + + /** + * Get the stall duration for the class/size combination (in nanoseconds). + * + * <p>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 + * @throws NullPointerException if {@code size} or {@code klass} was {@code null} + * + */ + public <T> long getOutputStallDuration(final Class<T> klass, 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 capture session} as an output. + * + * <p>For more information refer to {@link StreamConfigurationMap#isOutputSupportedFor}. + * </p> + * + * @param surface a non-{@code null} {@link Surface} object reference + * @return {@code true} if this is supported, {@code false} otherwise + * + * @throws NullPointerException if {@code surface} was {@code null} + * @throws IllegalArgumentException if the Surface endpoint is no longer valid + * + */ + public boolean isOutputSupportedFor(Surface surface) { + return mRecommendedMap.isOutputSupportedFor(surface); + } + +} diff --git a/core/java/android/hardware/camera2/params/StreamConfiguration.java b/core/java/android/hardware/camera2/params/StreamConfiguration.java index a6fc10fdcc61..eb92291ac90b 100644 --- a/core/java/android/hardware/camera2/params/StreamConfiguration.java +++ b/core/java/android/hardware/camera2/params/StreamConfiguration.java @@ -40,7 +40,7 @@ import android.util.Size; * * @hide */ -public final class StreamConfiguration { +public class StreamConfiguration { /** * Create a new {@link StreamConfiguration}. @@ -164,8 +164,8 @@ public final class StreamConfiguration { return HashCodeHelpers.hashCode(mFormat, mWidth, mHeight, mInput ? 1 : 0); } - private final int mFormat; - private final int mWidth; - private final int mHeight; - private final boolean mInput; + protected int mFormat; + protected int mWidth; + protected int mHeight; + protected boolean mInput; } diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java index 414c463b4545..dd052a8db1d9 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -98,6 +98,43 @@ public final class StreamConfigurationMap { HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, ReprocessFormatsMap inputOutputFormatsMap, boolean listHighResolution) { + this(configurations, minFrameDurations, stallDurations, + depthConfigurations, depthMinFrameDurations, depthStallDurations, + highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution, + /*enforceImplementationDefined*/ true); + } + + /** + * Create a new {@link StreamConfigurationMap}. + * + * <p>The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.</p> + * + * @param configurations a non-{@code null} array of {@link StreamConfiguration} + * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if + * camera device does not support high speed video recording + * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE + * and thus needs a separate list of slow high-resolution output sizes + * @param enforceImplementationDefined a flag indicating whether + * IMPLEMENTATION_DEFINED format configuration must be present + * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations + * were {@code null} or any subelements were {@code null} + * + * @hide + */ + public StreamConfigurationMap( + StreamConfiguration[] configurations, + StreamConfigurationDuration[] minFrameDurations, + StreamConfigurationDuration[] stallDurations, + StreamConfiguration[] depthConfigurations, + StreamConfigurationDuration[] depthMinFrameDurations, + StreamConfigurationDuration[] depthStallDurations, + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, + ReprocessFormatsMap inputOutputFormatsMap, + boolean listHighResolution, + boolean enforceImplementationDefined) { if (configurations == null) { // If no color configurations exist, ensure depth ones do @@ -169,7 +206,7 @@ public final class StreamConfigurationMap { mDepthOutputFormats.get(config.getFormat()) + 1); } - if (configurations != null && + if (configurations != null && enforceImplementationDefined && mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) { throw new AssertionError( "At least one stream configuration for IMPLEMENTATION_DEFINED must exist"); @@ -208,7 +245,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getOutputFormats() { + public int[] getOutputFormats() { return getPublicFormats(/*output*/true); } @@ -232,7 +269,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getValidOutputFormatsForInput(int inputFormat) { + public int[] getValidOutputFormatsForInput(int inputFormat) { if (mInputOutputFormatsMap == null) { return new int[0]; } @@ -250,7 +287,7 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat */ - public final int[] getInputFormats() { + public int[] getInputFormats() { return getPublicFormats(/*output*/false); } @@ -426,6 +463,34 @@ public final class StreamConfigurationMap { } /** + * Determine whether or not the particular stream configuration is suitable to be included + * in a {@link CameraDevice#createCaptureSession capture session} as an output. + * + * @param size stream configuration size + * @param format stream configuration format + * @return {@code true} if this is supported, {@code false} otherwise + * + * @see CameraDevice#createCaptureSession + * @see #isOutputSupportedFor(Class) + * @hide + */ + public boolean isOutputSupportedFor(Size size, int format) { + int internalFormat = imageFormatToInternal(format); + int dataspace = imageFormatToDataspace(format); + + StreamConfiguration[] configs = + dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations; + for (StreamConfiguration config : configs) { + if ((config.getFormat() == internalFormat) && config.isOutput() && + config.getSize().equals(size)) { + return true; + } + } + + return false; + } + + /** * Get a list of sizes compatible with {@code klass} to use as an output. * * <p>Some of the supported classes may support additional formats beyond @@ -1062,8 +1127,9 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat * @see #checkArgumentFormat + * @hide */ - static int imageFormatToPublic(int format) { + public static int imageFormatToPublic(int format) { switch (format) { case HAL_PIXEL_FORMAT_BLOB: return ImageFormat.JPEG; @@ -1105,8 +1171,9 @@ public final class StreamConfigurationMap { * @see ImageFormat * @see PixelFormat * @see #checkArgumentFormat + * @hide */ - static int depthFormatToPublic(int format) { + public static int depthFormatToPublic(int format) { switch (format) { case HAL_PIXEL_FORMAT_BLOB: return ImageFormat.DEPTH_POINT_CLOUD; |
