From 0505d7c2c40a4b1c57360640b79e326a9c4283dc Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Wed, 19 Sep 2018 15:13:08 +0100 Subject: [PATCH] Camera: Use recommended configs for shim supported parameters The legacy camera shim layer currently uses various heuristics in order to determine valid supported preview/video/snapshot sizes and formats. This makes the code complex and in some cases the result is not optimal in terms of power and performance. If the camera supports recommended stream configurations, then use the suggested stream configurations to generate the above supported lists. Bug: 64029608 Test: Camera CTS Change-Id: I6ed1d50b3d1a854421f3d119be2e32211e8a4c35 --- .../include/camera/NdkCameraMetadataTags.h | 162 ++++++++++++++++++ .../api1/client2/Parameters.cpp | 90 +++++++++- .../api1/client2/Parameters.h | 13 ++ 3 files changed, 258 insertions(+), 7 deletions(-) diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h index 8af3c7cc57..5db46152b2 100644 --- a/camera/ndk/include/camera/NdkCameraMetadataTags.h +++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h @@ -3288,6 +3288,81 @@ typedef enum acamera_metadata_tag { */ ACAMERA_SCALER_CROPPING_TYPE = // byte (acamera_metadata_enum_android_scaler_cropping_type_t) ACAMERA_SCALER_START + 13, + /** + *

Recommended stream configurations for common client use cases.

+ * + *

Type: int32[n*5] (acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t)

+ * + *

This tag may appear in: + *

+ * + *

Optional subset of the ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS 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 + * CameraCharacteristics#getRecommendedStreamConfigurationMap.

+ *

The data representation is int[5], which maps to + * (width, height, format, output/input stream, usecase bit field). The array can be + * parsed using the following pseudo code:

+ *

struct StreamConfiguration { + * int32_t format; + * int32_t width; + * int32_t height; + * int32_t isInput; };

+ *

void getPreferredStreamConfigurations( + * int32_t *array, size_t count, int32_t usecaseId, + * Vector < StreamConfiguration > * scs) { + * const size_t STREAM_CONFIGURATION_SIZE = 5; + * const size_t STREAM_WIDTH_OFFSET = 0; + * const size_t STREAM_HEIGHT_OFFSET = 1; + * const size_t STREAM_FORMAT_OFFSET = 2; + * const size_t STREAM_IS_INPUT_OFFSET = 3; + * const size_t STREAM_USECASE_BITMAP_OFFSET = 4;

+ *
for (size_t i = 0; i < count; i+= STREAM_CONFIGURATION_SIZE) {
+     *     int32_t width = array[i + STREAM_WIDTH_OFFSET];
+     *     int32_t height = array[i + STREAM_HEIGHT_OFFSET];
+     *     int32_t format = array[i + STREAM_FORMAT_OFFSET];
+     *     int32_t isInput = array[i + STREAM_IS_INPUT_OFFSET];
+     *     int32_t supportedUsecases = array[i + STREAM_USECASE_BITMAP_OFFSET];
+     *     if (supportedUsecases & (1 << usecaseId)) {
+     *         StreamConfiguration sc = {format, width, height, isInput};
+     *         scs->add(sc);
+     *     }
+     * }
+     * 
+ *

}

+ * + * @see ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS + */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = + // int32[n*5] (acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t) + ACAMERA_SCALER_START + 14, + /** + *

Recommended mappings of image formats that are supported by this + * camera device for input streams, to their corresponding output formats.

+ * + *

Type: int32

+ * + *

This tag may appear in: + *

+ * + *

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 + * CameraCharacteristics#getRecommendedStreamConfigurationMap.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP = + // int32 + ACAMERA_SCALER_START + 15, ACAMERA_SCALER_END, /** @@ -5411,6 +5486,32 @@ typedef enum acamera_metadata_tag { */ ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE = // byte (acamera_metadata_enum_android_depth_depth_is_exclusive_t) ACAMERA_DEPTH_START + 4, + /** + *

Recommended depth stream configurations for common client use cases.

+ * + *

Type: int32[n*5]

+ * + *

This tag may appear in: + *

+ * + *

Optional subset of the ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS 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 + * CameraCharacteristics#getRecommendedStreamConfigurationMap.

+ *

For data representation please refer to + * ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS

+ * + * @see ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS + * @see ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS + */ + ACAMERA_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = + // int32[n*5] + ACAMERA_DEPTH_START + 5, ACAMERA_DEPTH_END, /** @@ -7300,6 +7401,67 @@ typedef enum acamera_metadata_enum_acamera_scaler_cropping_type { } acamera_metadata_enum_android_scaler_cropping_type_t; +// ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS +typedef enum acamera_metadata_enum_acamera_scaler_available_recommended_stream_configurations { + /** + *

Preview must only include non-stalling processed stream configurations with + * output formats like YUV_420_888, IMPLEMENTATION_DEFINED, etc.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW + = 0x0, + + /** + *

Video record must include stream configurations that match the advertised + * supported media profiles CamcorderProfile with + * IMPLEMENTATION_DEFINED format.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD + = 0x1, + + /** + *

Video snapshot must include stream configurations at least as big as + * the maximum RECORD resolutions and only with format BLOB + DATASPACE_JFIF + * format/dataspace combination (JPEG). Additionally the configurations shouldn't cause + * preview glitches and also be able to run at 30 fps.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT + = 0x2, + + /** + *

Recommended snapshot stream configurations must include at least one with + * size close to ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE with BLOB + DATASPACE_JFIF + * format/dataspace combination (JPEG). Taking into account restrictions on aspect + * ratio, alignment etc. the area of the maximum suggested size shouldn’t be less than + * 97% of the sensor array size area.

+ * + * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE + */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT + = 0x3, + + /** + *

If supported, recommended input stream configurations must only be advertised with + * ZSL along with other processed and/or stalling output formats.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_ZSL = 0x4, + + /** + *

If supported, recommended raw stream configurations must only include RAW based + * output formats.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW = 0x5, + + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END + = 0x6, + + /** + *

Vendor defined use cases. These depend on the vendor implementation.

+ */ + ACAMERA_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START + = 0x18, + +} acamera_metadata_enum_android_scaler_available_recommended_stream_configurations_t; + // ACAMERA_SENSOR_REFERENCE_ILLUMINANT1 typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 { diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 28d186abb4..8311a9bf5b 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -69,7 +69,7 @@ status_t Parameters::initialize(CameraDeviceBase *device, int deviceVersion) { res = buildQuirks(); if (res != OK) return res; - const Size MAX_PREVIEW_SIZE = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT }; + Size maxPreviewSize = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT }; // Treat the H.264 max size as the max supported video size. MediaProfiles *videoEncoderProfiles = MediaProfiles::getInstance(); Vector encoders = videoEncoderProfiles->getVideoEncoders(); @@ -90,11 +90,16 @@ status_t Parameters::initialize(CameraDeviceBase *device, int deviceVersion) { } } // This is just an upper bound and may not be an actually valid video size - const Size VIDEO_SIZE_UPPER_BOUND = {maxVideoWidth, maxVideoHeight}; + Size videoSizeUpperBound = {maxVideoWidth, maxVideoHeight}; - res = getFilteredSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes); + if (fastInfo.supportsPreferredConfigs) { + maxPreviewSize = getMaxSize(getPreferredPreviewSizes()); + videoSizeUpperBound = getMaxSize(getPreferredVideoSizes()); + } + + res = getFilteredSizes(maxPreviewSize, &availablePreviewSizes); if (res != OK) return res; - res = getFilteredSizes(VIDEO_SIZE_UPPER_BOUND, &availableVideoSizes); + res = getFilteredSizes(videoSizeUpperBound, &availableVideoSizes); if (res != OK) return res; // Select initial preview and video size that's under the initial bound and @@ -296,9 +301,13 @@ status_t Parameters::initialize(CameraDeviceBase *device, int deviceVersion) { Vector availableJpegSizes = getAvailableJpegSizes(); if (!availableJpegSizes.size()) return NO_INIT; - // TODO: Pick maximum pictureWidth = availableJpegSizes[0].width; pictureHeight = availableJpegSizes[0].height; + if (fastInfo.supportsPreferredConfigs) { + Size suggestedJpegSize = getMaxSize(getPreferredJpegSizes()); + pictureWidth = suggestedJpegSize.width; + pictureHeight = suggestedJpegSize.height; + } pictureWidthLastSet = pictureWidth; pictureHeightLastSet = pictureHeight; pictureSizeOverriden = false; @@ -1010,6 +1019,9 @@ status_t Parameters::buildFastInfo(CameraDeviceBase *device) { arrayHeight = activeArraySize.data.i32[3]; } else return NO_INIT; + fastInfo.supportsPreferredConfigs = + info->exists(ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS); + // We'll set the target FPS range for still captures to be as wide // as possible to give the HAL maximum latitude for exposure selection camera_metadata_ro_entry_t availableFpsRanges = @@ -1021,8 +1033,11 @@ status_t Parameters::buildFastInfo(CameraDeviceBase *device) { // Get supported preview fps ranges, up to default maximum. Vector supportedPreviewSizes; Vector supportedPreviewFpsRanges; - const Size PREVIEW_SIZE_BOUND = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT }; - status_t res = getFilteredSizes(PREVIEW_SIZE_BOUND, &supportedPreviewSizes); + Size previewSizeBound = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT }; + if (fastInfo.supportsPreferredConfigs) { + previewSizeBound = getMaxSize(getPreferredPreviewSizes()); + } + status_t res = getFilteredSizes(previewSizeBound, &supportedPreviewSizes); if (res != OK) return res; for (size_t i=0; i < availableFpsRanges.count; i += 2) { if (!isFpsSupported(supportedPreviewSizes, @@ -3106,6 +3121,67 @@ Vector Parameters::getAvailableJpegSizes() { return jpegSizes; } +Vector Parameters::getPreferredStreamConfigurations( + int32_t usecaseId) const { + const size_t STREAM_CONFIGURATION_SIZE = 5; + const size_t STREAM_WIDTH_OFFSET = 0; + const size_t STREAM_HEIGHT_OFFSET = 1; + const size_t STREAM_FORMAT_OFFSET = 2; + const size_t STREAM_IS_INPUT_OFFSET = 3; + const size_t STREAM_USECASE_BITMAP_OFFSET = 4; + Vector scs; + + if (fastInfo.supportsPreferredConfigs) { + camera_metadata_ro_entry_t availableStreamConfigs = staticInfo( + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS); + for (size_t i = 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) { + int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET]; + int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET]; + int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET]; + int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET]; + int32_t supportedUsecases = + availableStreamConfigs.data.i32[i + STREAM_USECASE_BITMAP_OFFSET]; + if (supportedUsecases & (1 << usecaseId)) { + StreamConfiguration sc = {format, width, height, isInput}; + scs.add(sc); + } + } + } + + return scs; +} + +Vector Parameters::getPreferredFilteredSizes(int32_t usecaseId, + int32_t format) const { + Vector sizes; + Vector scs = getPreferredStreamConfigurations(usecaseId); + for (const auto &it : scs) { + if (it.format == format) { + sizes.add({it.width, it.height}); + } + } + + return sizes; +} + +Vector Parameters::getPreferredJpegSizes() const { + return getPreferredFilteredSizes( + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT, + HAL_PIXEL_FORMAT_BLOB); +} + +Vector Parameters::getPreferredPreviewSizes() const { + return getPreferredFilteredSizes( + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED); +} + +Vector Parameters::getPreferredVideoSizes() const { + return getPreferredFilteredSizes( + ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED); +} + Parameters::CropRegion Parameters::calculateCropRegion(bool previewOnly) const { float zoomLeft, zoomTop, zoomWidth, zoomHeight; diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h index 42e7a47c82..9ef3f33d8f 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.h +++ b/services/camera/libcameraservice/api1/client2/Parameters.h @@ -247,6 +247,7 @@ struct Parameters { bool useFlexibleYuv; Size maxJpegSize; Size maxZslSize; + bool supportsPreferredConfigs; } fastInfo; // Quirks information; these are short-lived flags to enable workarounds for @@ -417,6 +418,9 @@ private: // returns an empty Vector if device HAL version does support it Vector getStreamConfigurations(); + // Helper function to extract the suggested stream configurations + Vector getPreferredStreamConfigurations(int32_t usecaseId) const; + // Helper function to get minimum frame duration for a jpeg size // return -1 if input jpeg size cannot be found in supported size list int64_t getJpegStreamMinFrameDurationNs(Parameters::Size size); @@ -438,6 +442,15 @@ private: // The maximum size is defined by comparing width first, when width ties comparing height. Size getMaxSize(const Vector& sizes); + // Helper function to filter and sort suggested sizes + Vector getPreferredFilteredSizes(int32_t usecaseId, int32_t format) const; + // Helper function to get the suggested jpeg sizes + Vector getPreferredJpegSizes() const; + // Helper function to get the suggested preview sizes + Vector getPreferredPreviewSizes() const; + // Helper function to get the suggested video sizes + Vector getPreferredVideoSizes() const; + int mDeviceVersion; uint8_t mDefaultSceneMode; };