| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2020 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 | */ | 
| Shuzhen Wang | d4abdf7 | 2021-05-28 11:22:50 -0700 | [diff] [blame] | 16 | #include <cutils/properties.h> | 
|  | 17 |  | 
| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 18 | #include "SessionConfigurationUtils.h" | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 19 | #include "../api2/DepthCompositeStream.h" | 
|  | 20 | #include "../api2/HeicCompositeStream.h" | 
|  | 21 | #include "common/CameraDeviceBase.h" | 
|  | 22 | #include "../CameraService.h" | 
|  | 23 | #include "device3/Camera3Device.h" | 
|  | 24 | #include "device3/Camera3OutputStream.h" | 
|  | 25 |  | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 26 | using android::camera3::OutputStreamInfo; | 
|  | 27 | using android::camera3::OutputStreamInfo; | 
|  | 28 | using android::hardware::camera2::ICameraDeviceUser; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 29 | using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode; | 
| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 30 |  | 
|  | 31 | namespace android { | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 32 | namespace camera3 { | 
|  | 33 |  | 
| Shuzhen Wang | d4abdf7 | 2021-05-28 11:22:50 -0700 | [diff] [blame] | 34 | int32_t SessionConfigurationUtils::PERF_CLASS_LEVEL = | 
|  | 35 | property_get_int32("ro.odm.build.media_performance_class", 0); | 
|  | 36 |  | 
|  | 37 | bool SessionConfigurationUtils::IS_PERF_CLASS = (PERF_CLASS_LEVEL == SDK_VERSION_S); | 
|  | 38 |  | 
| Jayant Chowdhary | cd3d36b | 2021-07-10 10:53:53 -0700 | [diff] [blame] | 39 | camera3::Size SessionConfigurationUtils::getMaxJpegResolution(const CameraMetadata &metadata, | 
|  | 40 | bool ultraHighResolution) { | 
|  | 41 | int32_t maxJpegWidth = 0, maxJpegHeight = 0; | 
|  | 42 | const int STREAM_CONFIGURATION_SIZE = 4; | 
|  | 43 | const int STREAM_FORMAT_OFFSET = 0; | 
|  | 44 | const int STREAM_WIDTH_OFFSET = 1; | 
|  | 45 | const int STREAM_HEIGHT_OFFSET = 2; | 
|  | 46 | const int STREAM_IS_INPUT_OFFSET = 3; | 
|  | 47 |  | 
|  | 48 | int32_t scalerSizesTag = ultraHighResolution ? | 
|  | 49 | ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION : | 
|  | 50 | ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS; | 
|  | 51 | camera_metadata_ro_entry_t availableStreamConfigs = | 
|  | 52 | metadata.find(scalerSizesTag); | 
|  | 53 | if (availableStreamConfigs.count == 0 || | 
|  | 54 | availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) { | 
|  | 55 | return camera3::Size(0, 0); | 
|  | 56 | } | 
|  | 57 |  | 
|  | 58 | // Get max jpeg size (area-wise). | 
|  | 59 | for (size_t i= 0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) { | 
|  | 60 | int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET]; | 
|  | 61 | int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET]; | 
|  | 62 | int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET]; | 
|  | 63 | int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET]; | 
|  | 64 | if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT | 
|  | 65 | && format == HAL_PIXEL_FORMAT_BLOB && | 
|  | 66 | (width * height > maxJpegWidth * maxJpegHeight)) { | 
|  | 67 | maxJpegWidth = width; | 
|  | 68 | maxJpegHeight = height; | 
|  | 69 | } | 
|  | 70 | } | 
|  | 71 |  | 
|  | 72 | return camera3::Size(maxJpegWidth, maxJpegHeight); | 
|  | 73 | } | 
|  | 74 |  | 
|  | 75 | size_t SessionConfigurationUtils::getUHRMaxJpegBufferSize(camera3::Size uhrMaxJpegSize, | 
|  | 76 | camera3::Size defaultMaxJpegSize, size_t defaultMaxJpegBufferSize) { | 
|  | 77 | return (uhrMaxJpegSize.width * uhrMaxJpegSize.height) / | 
|  | 78 | (defaultMaxJpegSize.width * defaultMaxJpegSize.height) * defaultMaxJpegBufferSize; | 
|  | 79 | } | 
|  | 80 |  | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 81 | void StreamConfiguration::getStreamConfigurations( | 
|  | 82 | const CameraMetadata &staticInfo, int configuration, | 
|  | 83 | std::unordered_map<int, std::vector<StreamConfiguration>> *scm) { | 
|  | 84 | if (scm == nullptr) { | 
|  | 85 | ALOGE("%s: StreamConfigurationMap nullptr", __FUNCTION__); | 
|  | 86 | return; | 
|  | 87 | } | 
|  | 88 | const int STREAM_FORMAT_OFFSET = 0; | 
|  | 89 | const int STREAM_WIDTH_OFFSET = 1; | 
|  | 90 | const int STREAM_HEIGHT_OFFSET = 2; | 
|  | 91 | const int STREAM_IS_INPUT_OFFSET = 3; | 
|  | 92 |  | 
|  | 93 | camera_metadata_ro_entry availableStreamConfigs = staticInfo.find(configuration); | 
|  | 94 | for (size_t i = 0; i < availableStreamConfigs.count; i += 4) { | 
|  | 95 | int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET]; | 
|  | 96 | int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET]; | 
|  | 97 | int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET]; | 
|  | 98 | int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET]; | 
|  | 99 | StreamConfiguration sc = {format, width, height, isInput}; | 
|  | 100 | (*scm)[format].push_back(sc); | 
|  | 101 | } | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | void StreamConfiguration::getStreamConfigurations( | 
|  | 105 | const CameraMetadata &staticInfo, bool maxRes, | 
|  | 106 | std::unordered_map<int, std::vector<StreamConfiguration>> *scm) { | 
|  | 107 | int32_t scalerKey = | 
|  | 108 | SessionConfigurationUtils::getAppropriateModeTag( | 
|  | 109 | ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxRes); | 
|  | 110 |  | 
|  | 111 | int32_t depthKey = | 
|  | 112 | SessionConfigurationUtils::getAppropriateModeTag( | 
|  | 113 | ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, maxRes); | 
|  | 114 |  | 
|  | 115 | int32_t dynamicDepthKey = | 
|  | 116 | SessionConfigurationUtils::getAppropriateModeTag( | 
|  | 117 | ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS); | 
|  | 118 |  | 
|  | 119 | int32_t heicKey = | 
|  | 120 | SessionConfigurationUtils::getAppropriateModeTag( | 
|  | 121 | ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS); | 
|  | 122 |  | 
|  | 123 | getStreamConfigurations(staticInfo, scalerKey, scm); | 
|  | 124 | getStreamConfigurations(staticInfo, depthKey, scm); | 
|  | 125 | getStreamConfigurations(staticInfo, dynamicDepthKey, scm); | 
|  | 126 | getStreamConfigurations(staticInfo, heicKey, scm); | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | int32_t SessionConfigurationUtils::getAppropriateModeTag(int32_t defaultTag, bool maxResolution) { | 
|  | 130 | if (!maxResolution) { | 
|  | 131 | return defaultTag; | 
|  | 132 | } | 
|  | 133 | switch (defaultTag) { | 
|  | 134 | case ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS: | 
|  | 135 | return ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION; | 
|  | 136 | case ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS: | 
|  | 137 | return ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION; | 
|  | 138 | case ANDROID_SCALER_AVAILABLE_STALL_DURATIONS: | 
|  | 139 | return ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION; | 
|  | 140 | case ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS: | 
|  | 141 | return ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION; | 
|  | 142 | case ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS: | 
|  | 143 | return ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION; | 
|  | 144 | case ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS: | 
| Jayant Chowdhary | bde9290 | 2021-07-21 15:08:35 -0700 | [diff] [blame] | 145 | return ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 146 | case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS: | 
|  | 147 | return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION; | 
|  | 148 | case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS: | 
|  | 149 | return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION; | 
|  | 150 | case ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS: | 
| Jayant Chowdhary | bde9290 | 2021-07-21 15:08:35 -0700 | [diff] [blame] | 151 | return ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 152 | case ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS: | 
|  | 153 | return ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION; | 
|  | 154 | case ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS: | 
|  | 155 | return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION; | 
|  | 156 | case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS: | 
| Jayant Chowdhary | bde9290 | 2021-07-21 15:08:35 -0700 | [diff] [blame] | 157 | return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 158 | case ANDROID_SENSOR_OPAQUE_RAW_SIZE: | 
|  | 159 | return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION; | 
|  | 160 | case ANDROID_LENS_INTRINSIC_CALIBRATION: | 
|  | 161 | return ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION; | 
|  | 162 | case ANDROID_LENS_DISTORTION: | 
|  | 163 | return ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION; | 
|  | 164 | default: | 
|  | 165 | ALOGE("%s: Tag %d doesn't have a maximum resolution counterpart", __FUNCTION__, | 
|  | 166 | defaultTag); | 
|  | 167 | return -1; | 
|  | 168 | } | 
|  | 169 | return -1; | 
|  | 170 | } | 
|  | 171 |  | 
| Jayant Chowdhary | 9255ce0 | 2021-07-15 11:18:17 -0700 | [diff] [blame] | 172 | bool SessionConfigurationUtils::getArrayWidthAndHeight(const CameraMetadata *deviceInfo, | 
|  | 173 | int32_t arrayTag, int32_t *width, int32_t *height) { | 
|  | 174 | if (width == nullptr || height == nullptr) { | 
|  | 175 | ALOGE("%s: width / height nullptr", __FUNCTION__); | 
|  | 176 | return false; | 
|  | 177 | } | 
|  | 178 | camera_metadata_ro_entry_t entry; | 
|  | 179 | entry = deviceInfo->find(arrayTag); | 
|  | 180 | if (entry.count != 4) return false; | 
|  | 181 | *width = entry.data.i32[2]; | 
|  | 182 | *height = entry.data.i32[3]; | 
|  | 183 | return true; | 
|  | 184 | } | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 185 |  | 
|  | 186 | StreamConfigurationPair | 
|  | 187 | SessionConfigurationUtils::getStreamConfigurationPair(const CameraMetadata &staticInfo) { | 
|  | 188 | camera3::StreamConfigurationPair streamConfigurationPair; | 
|  | 189 | camera3::StreamConfiguration::getStreamConfigurations(staticInfo, false, | 
|  | 190 | &streamConfigurationPair.mDefaultStreamConfigurationMap); | 
|  | 191 | camera3::StreamConfiguration::getStreamConfigurations(staticInfo, true, | 
|  | 192 | &streamConfigurationPair.mMaximumResolutionStreamConfigurationMap); | 
|  | 193 | return streamConfigurationPair; | 
|  | 194 | } | 
| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 195 |  | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 196 | int64_t SessionConfigurationUtils::euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1) { | 
|  | 197 | int64_t d0 = x0 - x1; | 
|  | 198 | int64_t d1 = y0 - y1; | 
|  | 199 | return d0 * d0 + d1 * d1; | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 | bool SessionConfigurationUtils::roundBufferDimensionNearest(int32_t width, int32_t height, | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 203 | int32_t format, android_dataspace dataSpace, | 
|  | 204 | const CameraMetadata& info, bool maxResolution, /*out*/int32_t* outWidth, | 
|  | 205 | /*out*/int32_t* outHeight) { | 
|  | 206 | const int32_t depthSizesTag = | 
|  | 207 | getAppropriateModeTag(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, | 
|  | 208 | maxResolution); | 
|  | 209 | const int32_t scalerSizesTag = | 
|  | 210 | getAppropriateModeTag(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution); | 
|  | 211 | const int32_t heicSizesTag = | 
|  | 212 | getAppropriateModeTag(ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, maxResolution); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 213 |  | 
|  | 214 | camera_metadata_ro_entry streamConfigs = | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 215 | (dataSpace == HAL_DATASPACE_DEPTH) ? info.find(depthSizesTag) : | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 216 | (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_HEIF)) ? | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 217 | info.find(heicSizesTag) : | 
|  | 218 | info.find(scalerSizesTag); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 219 |  | 
|  | 220 | int32_t bestWidth = -1; | 
|  | 221 | int32_t bestHeight = -1; | 
|  | 222 |  | 
|  | 223 | // Iterate through listed stream configurations and find the one with the smallest euclidean | 
|  | 224 | // distance from the given dimensions for the given format. | 
|  | 225 | for (size_t i = 0; i < streamConfigs.count; i += 4) { | 
|  | 226 | int32_t fmt = streamConfigs.data.i32[i]; | 
|  | 227 | int32_t w = streamConfigs.data.i32[i + 1]; | 
|  | 228 | int32_t h = streamConfigs.data.i32[i + 2]; | 
|  | 229 |  | 
|  | 230 | // Ignore input/output type for now | 
|  | 231 | if (fmt == format) { | 
|  | 232 | if (w == width && h == height) { | 
|  | 233 | bestWidth = width; | 
|  | 234 | bestHeight = height; | 
|  | 235 | break; | 
|  | 236 | } else if (w <= ROUNDING_WIDTH_CAP && (bestWidth == -1 || | 
|  | 237 | SessionConfigurationUtils::euclidDistSquare(w, h, width, height) < | 
|  | 238 | SessionConfigurationUtils::euclidDistSquare(bestWidth, bestHeight, width, | 
|  | 239 | height))) { | 
|  | 240 | bestWidth = w; | 
|  | 241 | bestHeight = h; | 
|  | 242 | } | 
|  | 243 | } | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | if (bestWidth == -1) { | 
|  | 247 | // Return false if no configurations for this format were listed | 
|  | 248 | return false; | 
|  | 249 | } | 
|  | 250 |  | 
|  | 251 | // Set the outputs to the closet width/height | 
|  | 252 | if (outWidth != NULL) { | 
|  | 253 | *outWidth = bestWidth; | 
|  | 254 | } | 
|  | 255 | if (outHeight != NULL) { | 
|  | 256 | *outHeight = bestHeight; | 
|  | 257 | } | 
|  | 258 |  | 
|  | 259 | // Return true if at least one configuration for this format was listed | 
|  | 260 | return true; | 
|  | 261 | } | 
|  | 262 |  | 
|  | 263 | bool SessionConfigurationUtils::isPublicFormat(int32_t format) | 
|  | 264 | { | 
|  | 265 | switch(format) { | 
|  | 266 | case HAL_PIXEL_FORMAT_RGBA_8888: | 
|  | 267 | case HAL_PIXEL_FORMAT_RGBX_8888: | 
|  | 268 | case HAL_PIXEL_FORMAT_RGB_888: | 
|  | 269 | case HAL_PIXEL_FORMAT_RGB_565: | 
|  | 270 | case HAL_PIXEL_FORMAT_BGRA_8888: | 
|  | 271 | case HAL_PIXEL_FORMAT_YV12: | 
|  | 272 | case HAL_PIXEL_FORMAT_Y8: | 
|  | 273 | case HAL_PIXEL_FORMAT_Y16: | 
|  | 274 | case HAL_PIXEL_FORMAT_RAW16: | 
|  | 275 | case HAL_PIXEL_FORMAT_RAW10: | 
|  | 276 | case HAL_PIXEL_FORMAT_RAW12: | 
|  | 277 | case HAL_PIXEL_FORMAT_RAW_OPAQUE: | 
|  | 278 | case HAL_PIXEL_FORMAT_BLOB: | 
|  | 279 | case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: | 
|  | 280 | case HAL_PIXEL_FORMAT_YCbCr_420_888: | 
|  | 281 | case HAL_PIXEL_FORMAT_YCbCr_422_SP: | 
|  | 282 | case HAL_PIXEL_FORMAT_YCrCb_420_SP: | 
|  | 283 | case HAL_PIXEL_FORMAT_YCbCr_422_I: | 
|  | 284 | return true; | 
|  | 285 | default: | 
|  | 286 | return false; | 
|  | 287 | } | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | binder::Status SessionConfigurationUtils::createSurfaceFromGbp( | 
|  | 291 | OutputStreamInfo& streamInfo, bool isStreamInfoValid, | 
|  | 292 | sp<Surface>& surface, const sp<IGraphicBufferProducer>& gbp, | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 293 | const String8 &logicalCameraId, const CameraMetadata &physicalCameraMetadata, | 
|  | 294 | const std::vector<int32_t> &sensorPixelModesUsed){ | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 295 | // bufferProducer must be non-null | 
|  | 296 | if (gbp == nullptr) { | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 297 | String8 msg = String8::format("Camera %s: Surface is NULL", logicalCameraId.string()); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 298 | ALOGW("%s: %s", __FUNCTION__, msg.string()); | 
|  | 299 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 300 | } | 
|  | 301 | // HACK b/10949105 | 
|  | 302 | // Query consumer usage bits to set async operation mode for | 
|  | 303 | // GLConsumer using controlledByApp parameter. | 
|  | 304 | bool useAsync = false; | 
|  | 305 | uint64_t consumerUsage = 0; | 
|  | 306 | status_t err; | 
|  | 307 | if ((err = gbp->getConsumerUsage(&consumerUsage)) != OK) { | 
|  | 308 | String8 msg = String8::format("Camera %s: Failed to query Surface consumer usage: %s (%d)", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 309 | logicalCameraId.string(), strerror(-err), err); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 310 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 311 | return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); | 
|  | 312 | } | 
|  | 313 | if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) { | 
|  | 314 | ALOGW("%s: Camera %s with consumer usage flag: %" PRIu64 ": Forcing asynchronous mode for" | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 315 | "stream", __FUNCTION__, logicalCameraId.string(), consumerUsage); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 316 | useAsync = true; | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | uint64_t disallowedFlags = GraphicBuffer::USAGE_HW_VIDEO_ENCODER | | 
|  | 320 | GRALLOC_USAGE_RENDERSCRIPT; | 
|  | 321 | uint64_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK | | 
|  | 322 | GraphicBuffer::USAGE_HW_TEXTURE | | 
|  | 323 | GraphicBuffer::USAGE_HW_COMPOSER; | 
|  | 324 | bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 && | 
|  | 325 | (consumerUsage & allowedFlags) != 0; | 
|  | 326 |  | 
|  | 327 | surface = new Surface(gbp, useAsync); | 
|  | 328 | ANativeWindow *anw = surface.get(); | 
|  | 329 |  | 
|  | 330 | int width, height, format; | 
|  | 331 | android_dataspace dataSpace; | 
|  | 332 | if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) { | 
|  | 333 | String8 msg = String8::format("Camera %s: Failed to query Surface width: %s (%d)", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 334 | logicalCameraId.string(), strerror(-err), err); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 335 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 336 | return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); | 
|  | 337 | } | 
|  | 338 | if ((err = anw->query(anw, NATIVE_WINDOW_HEIGHT, &height)) != OK) { | 
|  | 339 | String8 msg = String8::format("Camera %s: Failed to query Surface height: %s (%d)", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 340 | logicalCameraId.string(), strerror(-err), err); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 341 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 342 | return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); | 
|  | 343 | } | 
|  | 344 | if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) { | 
|  | 345 | String8 msg = String8::format("Camera %s: Failed to query Surface format: %s (%d)", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 346 | logicalCameraId.string(), strerror(-err), err); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 347 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 348 | return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); | 
|  | 349 | } | 
|  | 350 | if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, | 
|  | 351 | reinterpret_cast<int*>(&dataSpace))) != OK) { | 
|  | 352 | String8 msg = String8::format("Camera %s: Failed to query Surface dataspace: %s (%d)", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 353 | logicalCameraId.string(), strerror(-err), err); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 354 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 355 | return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string()); | 
|  | 356 | } | 
|  | 357 |  | 
|  | 358 | // FIXME: remove this override since the default format should be | 
|  | 359 | //       IMPLEMENTATION_DEFINED. b/9487482 & b/35317944 | 
|  | 360 | if ((format >= HAL_PIXEL_FORMAT_RGBA_8888 && format <= HAL_PIXEL_FORMAT_BGRA_8888) && | 
|  | 361 | ((consumerUsage & GRALLOC_USAGE_HW_MASK) && | 
|  | 362 | ((consumerUsage & GRALLOC_USAGE_SW_READ_MASK) == 0))) { | 
|  | 363 | ALOGW("%s: Camera %s: Overriding format %#x to IMPLEMENTATION_DEFINED", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 364 | __FUNCTION__, logicalCameraId.string(), format); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 365 | format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; | 
|  | 366 | } | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 367 | std::unordered_set<int32_t> overriddenSensorPixelModes; | 
|  | 368 | if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed, format, width, height, | 
|  | 369 | physicalCameraMetadata, flexibleConsumer, &overriddenSensorPixelModes) != OK) { | 
|  | 370 | String8 msg = String8::format("Camera %s: sensor pixel modes for stream with " | 
|  | 371 | "format %#x are not valid",logicalCameraId.string(), format); | 
|  | 372 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 373 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 374 | } | 
|  | 375 | bool foundInMaxRes = false; | 
|  | 376 | if (overriddenSensorPixelModes.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) != | 
|  | 377 | overriddenSensorPixelModes.end()) { | 
|  | 378 | // we can use the default stream configuration map | 
|  | 379 | foundInMaxRes = true; | 
|  | 380 | } | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 381 | // Round dimensions to the nearest dimensions available for this format | 
|  | 382 | if (flexibleConsumer && isPublicFormat(format) && | 
|  | 383 | !SessionConfigurationUtils::roundBufferDimensionNearest(width, height, | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 384 | format, dataSpace, physicalCameraMetadata, foundInMaxRes, /*out*/&width, | 
|  | 385 | /*out*/&height)) { | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 386 | String8 msg = String8::format("Camera %s: No supported stream configurations with " | 
|  | 387 | "format %#x defined, failed to create output stream", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 388 | logicalCameraId.string(), format); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 389 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 390 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | if (!isStreamInfoValid) { | 
|  | 394 | streamInfo.width = width; | 
|  | 395 | streamInfo.height = height; | 
|  | 396 | streamInfo.format = format; | 
|  | 397 | streamInfo.dataSpace = dataSpace; | 
|  | 398 | streamInfo.consumerUsage = consumerUsage; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 399 | streamInfo.sensorPixelModesUsed = overriddenSensorPixelModes; | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 400 | return binder::Status::ok(); | 
|  | 401 | } | 
|  | 402 | if (width != streamInfo.width) { | 
|  | 403 | String8 msg = String8::format("Camera %s:Surface width doesn't match: %d vs %d", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 404 | logicalCameraId.string(), width, streamInfo.width); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 405 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 406 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 407 | } | 
|  | 408 | if (height != streamInfo.height) { | 
|  | 409 | String8 msg = String8::format("Camera %s:Surface height doesn't match: %d vs %d", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 410 | logicalCameraId.string(), height, streamInfo.height); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 411 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 412 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 413 | } | 
|  | 414 | if (format != streamInfo.format) { | 
|  | 415 | String8 msg = String8::format("Camera %s:Surface format doesn't match: %d vs %d", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 416 | logicalCameraId.string(), format, streamInfo.format); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 417 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 418 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 419 | } | 
|  | 420 | if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { | 
|  | 421 | if (dataSpace != streamInfo.dataSpace) { | 
|  | 422 | String8 msg = String8::format("Camera %s:Surface dataSpace doesn't match: %d vs %d", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 423 | logicalCameraId.string(), dataSpace, streamInfo.dataSpace); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 424 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 425 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 426 | } | 
|  | 427 | //At the native side, there isn't a way to check whether 2 surfaces come from the same | 
|  | 428 | //surface class type. Use usage flag to approximate the comparison. | 
|  | 429 | if (consumerUsage != streamInfo.consumerUsage) { | 
|  | 430 | String8 msg = String8::format( | 
|  | 431 | "Camera %s:Surface usage flag doesn't match %" PRIu64 " vs %" PRIu64 "", | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 432 | logicalCameraId.string(), consumerUsage, streamInfo.consumerUsage); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 433 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 434 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 435 | } | 
|  | 436 | } | 
|  | 437 | return binder::Status::ok(); | 
|  | 438 | } | 
|  | 439 |  | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 440 | void SessionConfigurationUtils::mapStreamInfo(const OutputStreamInfo &streamInfo, | 
| Emilian Peev | f481670 | 2020-04-03 15:44:51 -0700 | [diff] [blame] | 441 | camera3::camera_stream_rotation_t rotation, String8 physicalId, | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 442 | int32_t groupId, hardware::camera::device::V3_7::Stream *stream /*out*/) { | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 443 | if (stream == nullptr) { | 
|  | 444 | return; | 
|  | 445 | } | 
|  | 446 |  | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 447 | stream->v3_4.v3_2.streamType = hardware::camera::device::V3_2::StreamType::OUTPUT; | 
|  | 448 | stream->v3_4.v3_2.width = streamInfo.width; | 
|  | 449 | stream->v3_4.v3_2.height = streamInfo.height; | 
|  | 450 | stream->v3_4.v3_2.format = Camera3Device::mapToPixelFormat(streamInfo.format); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 451 | auto u = streamInfo.consumerUsage; | 
|  | 452 | camera3::Camera3OutputStream::applyZSLUsageQuirk(streamInfo.format, &u); | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 453 | stream->v3_4.v3_2.usage = Camera3Device::mapToConsumerUsage(u); | 
|  | 454 | stream->v3_4.v3_2.dataSpace = Camera3Device::mapToHidlDataspace(streamInfo.dataSpace); | 
|  | 455 | stream->v3_4.v3_2.rotation = Camera3Device::mapToStreamRotation(rotation); | 
|  | 456 | stream->v3_4.v3_2.id = -1; // Invalid stream id | 
|  | 457 | stream->v3_4.physicalCameraId = std::string(physicalId.string()); | 
|  | 458 | stream->v3_4.bufferSize = 0; | 
|  | 459 | stream->groupId = groupId; | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 460 | stream->sensorPixelModesUsed.resize(streamInfo.sensorPixelModesUsed.size()); | 
|  | 461 | size_t idx = 0; | 
|  | 462 | for (auto mode : streamInfo.sensorPixelModesUsed) { | 
|  | 463 | stream->sensorPixelModesUsed[idx++] = | 
|  | 464 | static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode); | 
|  | 465 | } | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 466 | } | 
|  | 467 |  | 
|  | 468 | binder::Status SessionConfigurationUtils::checkPhysicalCameraId( | 
|  | 469 | const std::vector<std::string> &physicalCameraIds, const String8 &physicalCameraId, | 
|  | 470 | const String8 &logicalCameraId) { | 
|  | 471 | if (physicalCameraId.size() == 0) { | 
|  | 472 | return binder::Status::ok(); | 
|  | 473 | } | 
|  | 474 | if (std::find(physicalCameraIds.begin(), physicalCameraIds.end(), | 
|  | 475 | physicalCameraId.string()) == physicalCameraIds.end()) { | 
|  | 476 | String8 msg = String8::format("Camera %s: Camera doesn't support physicalCameraId %s.", | 
|  | 477 | logicalCameraId.string(), physicalCameraId.string()); | 
|  | 478 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 479 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 480 | } | 
|  | 481 | return binder::Status::ok(); | 
|  | 482 | } | 
|  | 483 |  | 
|  | 484 | binder::Status SessionConfigurationUtils::checkSurfaceType(size_t numBufferProducers, | 
|  | 485 | bool deferredConsumer, int surfaceType)  { | 
|  | 486 | if (numBufferProducers > MAX_SURFACES_PER_STREAM) { | 
|  | 487 | ALOGE("%s: GraphicBufferProducer count %zu for stream exceeds limit of %d", | 
|  | 488 | __FUNCTION__, numBufferProducers, MAX_SURFACES_PER_STREAM); | 
|  | 489 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Surface count is too high"); | 
|  | 490 | } else if ((numBufferProducers == 0) && (!deferredConsumer)) { | 
|  | 491 | ALOGE("%s: Number of consumers cannot be smaller than 1", __FUNCTION__); | 
|  | 492 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "No valid consumers."); | 
|  | 493 | } | 
|  | 494 |  | 
|  | 495 | bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) || | 
|  | 496 | (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE)); | 
|  | 497 |  | 
|  | 498 | if (deferredConsumer && !validSurfaceType) { | 
|  | 499 | ALOGE("%s: Target surface has invalid surfaceType = %d.", __FUNCTION__, surfaceType); | 
|  | 500 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid"); | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | return binder::Status::ok(); | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | binder::Status SessionConfigurationUtils::checkOperatingMode(int operatingMode, | 
|  | 507 | const CameraMetadata &staticInfo, const String8 &cameraId) { | 
|  | 508 | if (operatingMode < 0) { | 
|  | 509 | String8 msg = String8::format( | 
|  | 510 | "Camera %s: Invalid operating mode %d requested", cameraId.string(), operatingMode); | 
|  | 511 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 512 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, | 
|  | 513 | msg.string()); | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | bool isConstrainedHighSpeed = (operatingMode == ICameraDeviceUser::CONSTRAINED_HIGH_SPEED_MODE); | 
|  | 517 | if (isConstrainedHighSpeed) { | 
|  | 518 | camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); | 
|  | 519 | bool isConstrainedHighSpeedSupported = false; | 
|  | 520 | for(size_t i = 0; i < entry.count; ++i) { | 
|  | 521 | uint8_t capability = entry.data.u8[i]; | 
|  | 522 | if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO) { | 
|  | 523 | isConstrainedHighSpeedSupported = true; | 
|  | 524 | break; | 
|  | 525 | } | 
|  | 526 | } | 
|  | 527 | if (!isConstrainedHighSpeedSupported) { | 
|  | 528 | String8 msg = String8::format( | 
|  | 529 | "Camera %s: Try to create a constrained high speed configuration on a device" | 
|  | 530 | " that doesn't support it.", cameraId.string()); | 
|  | 531 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 532 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, | 
|  | 533 | msg.string()); | 
|  | 534 | } | 
|  | 535 | } | 
|  | 536 |  | 
|  | 537 | return binder::Status::ok(); | 
|  | 538 | } | 
|  | 539 |  | 
| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 540 | binder::Status | 
|  | 541 | SessionConfigurationUtils::convertToHALStreamCombination( | 
|  | 542 | const SessionConfiguration& sessionConfiguration, | 
|  | 543 | const String8 &logicalCameraId, const CameraMetadata &deviceInfo, | 
|  | 544 | metadataGetter getMetadata, const std::vector<std::string> &physicalCameraIds, | 
| Shuzhen Wang | d4abdf7 | 2021-05-28 11:22:50 -0700 | [diff] [blame] | 545 | hardware::camera::device::V3_7::StreamConfiguration &streamConfiguration, | 
|  | 546 | bool overrideForPerfClass, bool *earlyExit) { | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 547 |  | 
|  | 548 | auto operatingMode = sessionConfiguration.getOperatingMode(); | 
|  | 549 | binder::Status res = checkOperatingMode(operatingMode, deviceInfo, logicalCameraId); | 
|  | 550 | if (!res.isOk()) { | 
|  | 551 | return res; | 
|  | 552 | } | 
|  | 553 |  | 
|  | 554 | if (earlyExit == nullptr) { | 
|  | 555 | String8 msg("earlyExit nullptr"); | 
|  | 556 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 557 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 558 | } | 
|  | 559 | *earlyExit = false; | 
|  | 560 | auto ret = Camera3Device::mapToStreamConfigurationMode( | 
| Emilian Peev | f481670 | 2020-04-03 15:44:51 -0700 | [diff] [blame] | 561 | static_cast<camera_stream_configuration_mode_t> (operatingMode), | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 562 | /*out*/ &streamConfiguration.operationMode); | 
|  | 563 | if (ret != OK) { | 
|  | 564 | String8 msg = String8::format( | 
|  | 565 | "Camera %s: Failed mapping operating mode %d requested: %s (%d)", | 
|  | 566 | logicalCameraId.string(), operatingMode, strerror(-ret), ret); | 
|  | 567 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 568 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, | 
|  | 569 | msg.string()); | 
|  | 570 | } | 
|  | 571 |  | 
|  | 572 | bool isInputValid = (sessionConfiguration.getInputWidth() > 0) && | 
|  | 573 | (sessionConfiguration.getInputHeight() > 0) && | 
|  | 574 | (sessionConfiguration.getInputFormat() > 0); | 
|  | 575 | auto outputConfigs = sessionConfiguration.getOutputConfigurations(); | 
|  | 576 | size_t streamCount = outputConfigs.size(); | 
|  | 577 | streamCount = isInputValid ? streamCount + 1 : streamCount; | 
|  | 578 | streamConfiguration.streams.resize(streamCount); | 
|  | 579 | size_t streamIdx = 0; | 
|  | 580 | if (isInputValid) { | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 581 | hardware::hidl_vec<CameraMetadataEnumAndroidSensorPixelMode> defaultSensorPixelModes; | 
|  | 582 | defaultSensorPixelModes.resize(1); | 
|  | 583 | defaultSensorPixelModes[0] = | 
|  | 584 | static_cast<CameraMetadataEnumAndroidSensorPixelMode>( | 
|  | 585 | ANDROID_SENSOR_PIXEL_MODE_DEFAULT); | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 586 | streamConfiguration.streams[streamIdx++] = {{{/*streamId*/0, | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 587 | hardware::camera::device::V3_2::StreamType::INPUT, | 
|  | 588 | static_cast<uint32_t> (sessionConfiguration.getInputWidth()), | 
|  | 589 | static_cast<uint32_t> (sessionConfiguration.getInputHeight()), | 
|  | 590 | Camera3Device::mapToPixelFormat(sessionConfiguration.getInputFormat()), | 
|  | 591 | /*usage*/ 0, HAL_DATASPACE_UNKNOWN, | 
|  | 592 | hardware::camera::device::V3_2::StreamRotation::ROTATION_0}, | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 593 | /*physicalId*/ nullptr, /*bufferSize*/0}, /*groupId*/-1, defaultSensorPixelModes}; | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 594 | streamConfiguration.multiResolutionInputImage = | 
|  | 595 | sessionConfiguration.inputIsMultiResolution(); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 596 | } | 
|  | 597 |  | 
|  | 598 | for (const auto &it : outputConfigs) { | 
|  | 599 | const std::vector<sp<IGraphicBufferProducer>>& bufferProducers = | 
|  | 600 | it.getGraphicBufferProducers(); | 
|  | 601 | bool deferredConsumer = it.isDeferred(); | 
|  | 602 | String8 physicalCameraId = String8(it.getPhysicalCameraId()); | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 603 |  | 
|  | 604 | std::vector<int32_t> sensorPixelModesUsed = it.getSensorPixelModesUsed(); | 
| Shuzhen Wang | d4abdf7 | 2021-05-28 11:22:50 -0700 | [diff] [blame] | 605 | const CameraMetadata &physicalDeviceInfo = getMetadata(physicalCameraId, | 
|  | 606 | overrideForPerfClass); | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 607 | const CameraMetadata &metadataChosen = | 
|  | 608 | physicalCameraId.size() > 0 ? physicalDeviceInfo : deviceInfo; | 
|  | 609 |  | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 610 | size_t numBufferProducers = bufferProducers.size(); | 
|  | 611 | bool isStreamInfoValid = false; | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 612 | int32_t groupId = it.isMultiResolution() ? it.getSurfaceSetID() : -1; | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 613 | OutputStreamInfo streamInfo; | 
|  | 614 |  | 
|  | 615 | res = checkSurfaceType(numBufferProducers, deferredConsumer, it.getSurfaceType()); | 
|  | 616 | if (!res.isOk()) { | 
|  | 617 | return res; | 
|  | 618 | } | 
|  | 619 | res = checkPhysicalCameraId(physicalCameraIds, physicalCameraId, | 
|  | 620 | logicalCameraId); | 
|  | 621 | if (!res.isOk()) { | 
|  | 622 | return res; | 
|  | 623 | } | 
|  | 624 |  | 
|  | 625 | if (deferredConsumer) { | 
|  | 626 | streamInfo.width = it.getWidth(); | 
|  | 627 | streamInfo.height = it.getHeight(); | 
|  | 628 | streamInfo.format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; | 
|  | 629 | streamInfo.dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN; | 
|  | 630 | auto surfaceType = it.getSurfaceType(); | 
|  | 631 | streamInfo.consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE; | 
|  | 632 | if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) { | 
|  | 633 | streamInfo.consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER; | 
|  | 634 | } | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 635 | if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed, | 
|  | 636 | streamInfo.format, streamInfo.width, | 
|  | 637 | streamInfo.height, metadataChosen, false /*flexibleConsumer*/, | 
|  | 638 | &streamInfo.sensorPixelModesUsed) != OK) { | 
|  | 639 | ALOGE("%s: Deferred surface sensor pixel modes not valid", | 
|  | 640 | __FUNCTION__); | 
|  | 641 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, | 
|  | 642 | "Deferred surface sensor pixel modes not valid"); | 
|  | 643 | } | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 644 | mapStreamInfo(streamInfo, camera3::CAMERA_STREAM_ROTATION_0, physicalCameraId, groupId, | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 645 | &streamConfiguration.streams[streamIdx++]); | 
|  | 646 | isStreamInfoValid = true; | 
|  | 647 |  | 
|  | 648 | if (numBufferProducers == 0) { | 
|  | 649 | continue; | 
|  | 650 | } | 
|  | 651 | } | 
|  | 652 |  | 
|  | 653 | for (auto& bufferProducer : bufferProducers) { | 
|  | 654 | sp<Surface> surface; | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 655 | res = createSurfaceFromGbp(streamInfo, isStreamInfoValid, surface, bufferProducer, | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 656 | logicalCameraId, metadataChosen, sensorPixelModesUsed); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 657 |  | 
|  | 658 | if (!res.isOk()) | 
|  | 659 | return res; | 
|  | 660 |  | 
|  | 661 | if (!isStreamInfoValid) { | 
|  | 662 | bool isDepthCompositeStream = | 
|  | 663 | camera3::DepthCompositeStream::isDepthCompositeStream(surface); | 
|  | 664 | bool isHeicCompositeStream = | 
|  | 665 | camera3::HeicCompositeStream::isHeicCompositeStream(surface); | 
|  | 666 | if (isDepthCompositeStream || isHeicCompositeStream) { | 
|  | 667 | // We need to take in to account that composite streams can have | 
|  | 668 | // additional internal camera streams. | 
|  | 669 | std::vector<OutputStreamInfo> compositeStreams; | 
|  | 670 | if (isDepthCompositeStream) { | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 671 | // TODO: Take care of composite streams. | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 672 | ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo, | 
|  | 673 | deviceInfo, &compositeStreams); | 
|  | 674 | } else { | 
|  | 675 | ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo, | 
|  | 676 | deviceInfo, &compositeStreams); | 
|  | 677 | } | 
|  | 678 | if (ret != OK) { | 
|  | 679 | String8 msg = String8::format( | 
|  | 680 | "Camera %s: Failed adding composite streams: %s (%d)", | 
|  | 681 | logicalCameraId.string(), strerror(-ret), ret); | 
|  | 682 | ALOGE("%s: %s", __FUNCTION__, msg.string()); | 
|  | 683 | return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string()); | 
|  | 684 | } | 
|  | 685 |  | 
|  | 686 | if (compositeStreams.size() == 0) { | 
|  | 687 | // No internal streams means composite stream not | 
|  | 688 | // supported. | 
|  | 689 | *earlyExit = true; | 
|  | 690 | return binder::Status::ok(); | 
|  | 691 | } else if (compositeStreams.size() > 1) { | 
|  | 692 | streamCount += compositeStreams.size() - 1; | 
|  | 693 | streamConfiguration.streams.resize(streamCount); | 
|  | 694 | } | 
|  | 695 |  | 
|  | 696 | for (const auto& compositeStream : compositeStreams) { | 
|  | 697 | mapStreamInfo(compositeStream, | 
| Emilian Peev | f481670 | 2020-04-03 15:44:51 -0700 | [diff] [blame] | 698 | static_cast<camera_stream_rotation_t> (it.getRotation()), | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 699 | physicalCameraId, groupId, | 
|  | 700 | &streamConfiguration.streams[streamIdx++]); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 701 | } | 
|  | 702 | } else { | 
|  | 703 | mapStreamInfo(streamInfo, | 
| Emilian Peev | f481670 | 2020-04-03 15:44:51 -0700 | [diff] [blame] | 704 | static_cast<camera_stream_rotation_t> (it.getRotation()), | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 705 | physicalCameraId, groupId, &streamConfiguration.streams[streamIdx++]); | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 706 | } | 
|  | 707 | isStreamInfoValid = true; | 
|  | 708 | } | 
|  | 709 | } | 
|  | 710 | } | 
|  | 711 | return binder::Status::ok(); | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 712 | } | 
| Colin Cross | b8a9dbb | 2020-08-27 04:12:26 +0000 | [diff] [blame] | 713 |  | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 714 | static bool inStreamConfigurationMap(int format, int width, int height, | 
|  | 715 | const std::unordered_map<int, std::vector<camera3::StreamConfiguration>> &sm) { | 
|  | 716 | auto scs = sm.find(format); | 
|  | 717 | if (scs == sm.end()) { | 
|  | 718 | return false; | 
|  | 719 | } | 
|  | 720 | for (auto &sc : scs->second) { | 
|  | 721 | if (sc.width == width && sc.height == height && sc.isInput == 0) { | 
|  | 722 | return true; | 
|  | 723 | } | 
|  | 724 | } | 
|  | 725 | return false; | 
|  | 726 | } | 
|  | 727 |  | 
|  | 728 | static std::unordered_set<int32_t> convertToSet(const std::vector<int32_t> &sensorPixelModesUsed) { | 
|  | 729 | return std::unordered_set<int32_t>(sensorPixelModesUsed.begin(), sensorPixelModesUsed.end()); | 
|  | 730 | } | 
|  | 731 |  | 
|  | 732 | status_t SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed( | 
|  | 733 | const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height, | 
|  | 734 | const CameraMetadata &staticInfo, bool flexibleConsumer, | 
|  | 735 | std::unordered_set<int32_t> *overriddenSensorPixelModesUsed) { | 
| Jayant Chowdhary | 84df28c | 2021-05-26 22:32:21 -0700 | [diff] [blame] | 736 |  | 
|  | 737 | const std::unordered_set<int32_t> &sensorPixelModesUsedSet = | 
|  | 738 | convertToSet(sensorPixelModesUsed); | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 739 | if (!isUltraHighResolutionSensor(staticInfo)) { | 
| Jayant Chowdhary | 84df28c | 2021-05-26 22:32:21 -0700 | [diff] [blame] | 740 | if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) != | 
|  | 741 | sensorPixelModesUsedSet.end()) { | 
|  | 742 | // invalid value for non ultra high res sensors | 
|  | 743 | return BAD_VALUE; | 
|  | 744 | } | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 745 | overriddenSensorPixelModesUsed->clear(); | 
|  | 746 | overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT); | 
|  | 747 | return OK; | 
|  | 748 | } | 
|  | 749 |  | 
|  | 750 | StreamConfigurationPair streamConfigurationPair = getStreamConfigurationPair(staticInfo); | 
| Jayant Chowdhary | 84df28c | 2021-05-26 22:32:21 -0700 | [diff] [blame] | 751 |  | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 752 | bool isInDefaultStreamConfigurationMap = | 
|  | 753 | inStreamConfigurationMap(format, width, height, | 
|  | 754 | streamConfigurationPair.mDefaultStreamConfigurationMap); | 
|  | 755 |  | 
|  | 756 | bool isInMaximumResolutionStreamConfigurationMap = | 
|  | 757 | inStreamConfigurationMap(format, width, height, | 
|  | 758 | streamConfigurationPair.mMaximumResolutionStreamConfigurationMap); | 
|  | 759 |  | 
|  | 760 | // Case 1: The client has not changed the sensor mode defaults. In this case, we check if the | 
|  | 761 | // size + format of the OutputConfiguration is found exclusively in 1. | 
|  | 762 | // If yes, add that sensorPixelMode to overriddenSensorPixelModes. | 
|  | 763 | // If no, add 'DEFAULT' to sensorPixelMode. This maintains backwards | 
|  | 764 | // compatibility. | 
|  | 765 | if (sensorPixelModesUsedSet.size() == 0) { | 
|  | 766 | // Ambiguous case, default to only 'DEFAULT' mode. | 
|  | 767 | if (isInDefaultStreamConfigurationMap && isInMaximumResolutionStreamConfigurationMap) { | 
|  | 768 | overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT); | 
|  | 769 | return OK; | 
|  | 770 | } | 
|  | 771 | // We don't allow flexible consumer for max resolution mode. | 
|  | 772 | if (isInMaximumResolutionStreamConfigurationMap) { | 
|  | 773 | overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION); | 
|  | 774 | return OK; | 
|  | 775 | } | 
|  | 776 | if (isInDefaultStreamConfigurationMap || (flexibleConsumer && width < ROUNDING_WIDTH_CAP)) { | 
|  | 777 | overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT); | 
|  | 778 | return OK; | 
|  | 779 | } | 
|  | 780 | return BAD_VALUE; | 
|  | 781 | } | 
|  | 782 |  | 
|  | 783 | // Case2: The app has set sensorPixelModesUsed, we need to verify that they | 
|  | 784 | // are valid / err out. | 
|  | 785 | if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_DEFAULT) != | 
|  | 786 | sensorPixelModesUsedSet.end() && !isInDefaultStreamConfigurationMap) { | 
|  | 787 | return BAD_VALUE; | 
|  | 788 | } | 
|  | 789 |  | 
|  | 790 | if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) != | 
|  | 791 | sensorPixelModesUsedSet.end() && !isInMaximumResolutionStreamConfigurationMap) { | 
|  | 792 | return BAD_VALUE; | 
|  | 793 | } | 
|  | 794 | *overriddenSensorPixelModesUsed = sensorPixelModesUsedSet; | 
|  | 795 | return OK; | 
|  | 796 | } | 
|  | 797 |  | 
|  | 798 | bool SessionConfigurationUtils::isUltraHighResolutionSensor(const CameraMetadata &deviceInfo) { | 
|  | 799 | camera_metadata_ro_entry_t entryCap; | 
|  | 800 | entryCap = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES); | 
|  | 801 | // Go through the capabilities and check if it has | 
|  | 802 | // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR | 
|  | 803 | for (size_t i = 0; i < entryCap.count; ++i) { | 
|  | 804 | uint8_t capability = entryCap.data.u8[i]; | 
|  | 805 | if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) { | 
|  | 806 | return true; | 
|  | 807 | } | 
|  | 808 | } | 
|  | 809 | return false; | 
| Jayant Chowdhary | 2bbdce4 | 2020-01-12 14:55:41 -0800 | [diff] [blame] | 810 | } | 
|  | 811 |  | 
| Shuzhen Wang | 83bff12 | 2020-11-20 15:51:39 -0800 | [diff] [blame] | 812 | bool SessionConfigurationUtils::convertHALStreamCombinationFromV37ToV34( | 
|  | 813 | hardware::camera::device::V3_4::StreamConfiguration &streamConfigV34, | 
|  | 814 | const hardware::camera::device::V3_7::StreamConfiguration &streamConfigV37) { | 
|  | 815 | if (streamConfigV37.multiResolutionInputImage) { | 
|  | 816 | // ICameraDevice older than 3.7 doesn't support multi-resolution input image. | 
|  | 817 | return false; | 
|  | 818 | } | 
|  | 819 |  | 
|  | 820 | streamConfigV34.streams.resize(streamConfigV37.streams.size()); | 
|  | 821 | for (size_t i = 0; i < streamConfigV37.streams.size(); i++) { | 
|  | 822 | if (streamConfigV37.streams[i].groupId != -1) { | 
|  | 823 | // ICameraDevice older than 3.7 doesn't support multi-resolution output | 
|  | 824 | // image | 
|  | 825 | return false; | 
|  | 826 | } | 
|  | 827 | streamConfigV34.streams[i] = streamConfigV37.streams[i].v3_4; | 
|  | 828 | } | 
|  | 829 | streamConfigV34.operationMode = streamConfigV37.operationMode; | 
|  | 830 | streamConfigV34.sessionParams = streamConfigV37.sessionParams; | 
|  | 831 |  | 
|  | 832 | return true; | 
|  | 833 | } | 
|  | 834 |  | 
| Shuzhen Wang | d4abdf7 | 2021-05-28 11:22:50 -0700 | [diff] [blame] | 835 | bool SessionConfigurationUtils::targetPerfClassPrimaryCamera( | 
|  | 836 | const std::set<std::string>& perfClassPrimaryCameraIds, const std::string& cameraId, | 
|  | 837 | int targetSdkVersion) { | 
|  | 838 | bool isPerfClassPrimaryCamera = | 
|  | 839 | perfClassPrimaryCameraIds.find(cameraId) != perfClassPrimaryCameraIds.end(); | 
|  | 840 | return targetSdkVersion >= SDK_VERSION_S && isPerfClassPrimaryCamera; | 
|  | 841 | } | 
|  | 842 |  | 
| Jayant Chowdhary | 13f9b2f | 2020-12-02 22:46:15 -0800 | [diff] [blame] | 843 | } // namespace camera3 | 
|  | 844 | } // namespace android |