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 */
16
17 #define LOG_TAG "GCH_ZoomRatioMapper"
18
19 #include "zoom_ratio_mapper.h"
20
21 #include <log/log.h>
22
23 #include <cmath>
24
25 #include "utils.h"
26
27 namespace android {
28 namespace google_camera_hal {
29
30 int32_t kWeightedRectToConvert[] = {ANDROID_CONTROL_AE_REGIONS,
31 ANDROID_CONTROL_AF_REGIONS,
32 ANDROID_CONTROL_AWB_REGIONS};
33
34 int32_t kRectToConvert[] = {ANDROID_SCALER_CROP_REGION};
35
36 int32_t kResultPointsToConvert[] = {ANDROID_STATISTICS_FACE_LANDMARKS,
37 ANDROID_STATISTICS_FACE_RECTANGLES};
38
GetSensorPixelMode(const HalCameraMetadata & metadata)39 camera_metadata_enum_android_sensor_pixel_mode GetSensorPixelMode(
40 const HalCameraMetadata& metadata) {
41 camera_metadata_ro_entry sensor_pixel_mode_metadata = {};
42 auto res =
43 metadata.Get(ANDROID_SENSOR_PIXEL_MODE, &sensor_pixel_mode_metadata);
44 if (res == OK && sensor_pixel_mode_metadata.data.u8 != nullptr &&
45 sensor_pixel_mode_metadata.data.u8[0] ==
46 ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
47 return ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION;
48 }
49 return ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
50 }
51
Initialize(InitParams * params)52 void ZoomRatioMapper::Initialize(InitParams* params) {
53 if (params == nullptr) {
54 ALOGE("%s: invalid param", __FUNCTION__);
55 return;
56 }
57 memcpy(&active_array_dimension_, ¶ms->active_array_dimension,
58 sizeof(active_array_dimension_));
59 memcpy(&active_array_maximum_resolution_dimension_,
60 ¶ms->active_array_maximum_resolution_dimension,
61 sizeof(active_array_maximum_resolution_dimension_));
62 physical_cam_active_array_dimension_ =
63 params->physical_cam_active_array_dimension;
64 physical_cam_active_array_maximum_resolution_dimension_ =
65 params->physical_cam_active_array_maximum_resolution_dimension;
66 memcpy(&zoom_ratio_range_, ¶ms->zoom_ratio_range,
67 sizeof(zoom_ratio_range_));
68 zoom_ratio_mapper_hwl_ = std::move(params->zoom_ratio_mapper_hwl);
69 is_zoom_ratio_supported_ = true;
70 camera_id_ = params->camera_id;
71 }
72
GetActiveArrayDimension(const HalCameraMetadata & metadata,bool is_physical,uint32_t camera_id) const73 Dimension ZoomRatioMapper::GetActiveArrayDimension(
74 const HalCameraMetadata& metadata, bool is_physical,
75 uint32_t camera_id) const {
76 Dimension active_array_dimension = active_array_dimension_;
77
78 // Overwrite based on zoom_ratio_mapper_hwl_
79 Dimension override_dimension;
80 if (zoom_ratio_mapper_hwl_ &&
81 zoom_ratio_mapper_hwl_->GetActiveArrayDimensionToBeUsed(
82 camera_id, &metadata, &override_dimension)) {
83 active_array_dimension = override_dimension;
84 }
85
86 // Overwrite based on sensor pixel mode
87 if (is_physical) {
88 if (GetSensorPixelMode(metadata) ==
89 ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
90 auto physical_cam_iter =
91 physical_cam_active_array_maximum_resolution_dimension_.find(
92 camera_id);
93 LOG_ALWAYS_FATAL_IF(
94 physical_cam_iter ==
95 physical_cam_active_array_maximum_resolution_dimension_.end(),
96 "%s: cannot process a max-res request or result on the physical "
97 "camera %d because it does not have max-res dimension",
98 __FUNCTION__, camera_id);
99 return physical_cam_iter->second;
100 } else {
101 auto physical_cam_iter =
102 physical_cam_active_array_dimension_.find(camera_id);
103 LOG_ALWAYS_FATAL_IF(
104 physical_cam_iter == physical_cam_active_array_dimension_.end(),
105 "%s: cannot process a request or result on the physical "
106 "camera %d because it does not have active array dimension",
107 __FUNCTION__, camera_id);
108 return physical_cam_iter->second;
109 }
110 } else {
111 if (GetSensorPixelMode(metadata) ==
112 ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
113 return active_array_maximum_resolution_dimension_;
114 } else {
115 return active_array_dimension;
116 }
117 }
118 return active_array_dimension;
119 }
120
UpdateCaptureRequest(CaptureRequest * request)121 void ZoomRatioMapper::UpdateCaptureRequest(CaptureRequest* request) {
122 if (request == nullptr) {
123 ALOGE("%s: request is nullptr", __FUNCTION__);
124 return;
125 }
126
127 if (!is_zoom_ratio_supported_) {
128 ALOGV("%s: zoom ratio is not supported", __FUNCTION__);
129 return;
130 }
131
132 if (request->settings != nullptr) {
133 Dimension active_array_dimension = GetActiveArrayDimension(
134 *request->settings, /*is_physical*/ false, camera_id_);
135 ApplyZoomRatio(active_array_dimension, true, request->settings.get());
136 }
137
138 for (auto& [camera_id, metadata] : request->physical_camera_settings) {
139 if (metadata != nullptr) {
140 Dimension physical_active_array_dimension =
141 GetActiveArrayDimension(*metadata, /*is_physical*/ true, camera_id);
142 ApplyZoomRatio(physical_active_array_dimension, true, metadata.get());
143 }
144 }
145 if (zoom_ratio_mapper_hwl_) {
146 zoom_ratio_mapper_hwl_->UpdateCaptureRequest(request);
147 }
148 }
149
UpdateCaptureResult(CaptureResult * result)150 void ZoomRatioMapper::UpdateCaptureResult(CaptureResult* result) {
151 if (result == nullptr) {
152 ALOGE("%s: result is nullptr", __FUNCTION__);
153 return;
154 }
155
156 if (!is_zoom_ratio_supported_) {
157 ALOGV("%s: zoom ratio is not supported", __FUNCTION__);
158 return;
159 }
160
161 if (result->result_metadata != nullptr) {
162 Dimension active_array_dimension = GetActiveArrayDimension(
163 *result->result_metadata, /*is_physical*/ false, camera_id_);
164 ApplyZoomRatio(active_array_dimension, false, result->result_metadata.get());
165 }
166
167 for (auto& [camera_id, metadata] : result->physical_metadata) {
168 if (metadata != nullptr) {
169 Dimension physical_active_array_dimension =
170 GetActiveArrayDimension(*metadata, /*is_physical*/ true, camera_id);
171 ApplyZoomRatio(physical_active_array_dimension, false, metadata.get());
172 }
173 }
174 if (zoom_ratio_mapper_hwl_) {
175 zoom_ratio_mapper_hwl_->UpdateCaptureResult(result);
176 }
177 }
178
ApplyZoomRatio(const Dimension & active_array_dimension,const bool is_request,HalCameraMetadata * metadata)179 void ZoomRatioMapper::ApplyZoomRatio(const Dimension& active_array_dimension,
180 const bool is_request,
181 HalCameraMetadata* metadata) {
182 if (metadata == nullptr) {
183 ALOGE("%s: metadata is nullptr", __FUNCTION__);
184 return;
185 }
186
187 camera_metadata_ro_entry entry = {};
188 status_t res = metadata->Get(ANDROID_CONTROL_ZOOM_RATIO, &entry);
189 if (res != OK) {
190 ALOGV("%s: zoom ratio doesn't exist, cancel the conversion", __FUNCTION__);
191 return;
192 }
193 float zoom_ratio = entry.data.f[0];
194
195 if (zoom_ratio < zoom_ratio_range_.min) {
196 ALOGE("%s, zoom_ratio(%f) is smaller than lower bound(%f)", __FUNCTION__,
197 zoom_ratio, zoom_ratio_range_.min);
198 zoom_ratio = zoom_ratio_range_.min;
199 } else if (zoom_ratio > zoom_ratio_range_.max) {
200 ALOGE("%s, zoom_ratio(%f) is larger than upper bound(%f)", __FUNCTION__,
201 zoom_ratio, zoom_ratio_range_.max);
202 zoom_ratio = zoom_ratio_range_.max;
203 }
204
205 if (zoom_ratio_mapper_hwl_ != nullptr && is_request) {
206 zoom_ratio_mapper_hwl_->LimitZoomRatioIfConcurrent(&zoom_ratio);
207 }
208
209 if (fabs(zoom_ratio - entry.data.f[0]) > 1e-9) {
210 metadata->Set(ANDROID_CONTROL_ZOOM_RATIO, &zoom_ratio, entry.count);
211 }
212
213 for (auto tag_id : kRectToConvert) {
214 UpdateRects(zoom_ratio, tag_id, active_array_dimension, is_request,
215 metadata);
216 }
217
218 for (auto tag_id : kWeightedRectToConvert) {
219 UpdateWeightedRects(zoom_ratio, tag_id, active_array_dimension, is_request,
220 metadata);
221 }
222
223 if (!is_request) {
224 for (auto tag_id : kResultPointsToConvert) {
225 UpdatePoints(zoom_ratio, tag_id, active_array_dimension, metadata);
226 }
227 }
228 }
229
UpdateRects(const float zoom_ratio,const uint32_t tag_id,const Dimension & active_array_dimension,const bool is_request,HalCameraMetadata * metadata)230 void ZoomRatioMapper::UpdateRects(const float zoom_ratio, const uint32_t tag_id,
231 const Dimension& active_array_dimension,
232 const bool is_request,
233 HalCameraMetadata* metadata) {
234 if (metadata == nullptr) {
235 ALOGE("%s: metadata is nullptr", __FUNCTION__);
236 return;
237 }
238 camera_metadata_ro_entry entry = {};
239 status_t res = metadata->Get(tag_id, &entry);
240 if (res != OK || entry.count == 0) {
241 ALOGE("%s: Failed to get the region: %d, res: %d", __FUNCTION__, tag_id,
242 res);
243 return;
244 }
245 int32_t left = entry.data.i32[0];
246 int32_t top = entry.data.i32[1];
247 int32_t width = entry.data.i32[2];
248 int32_t height = entry.data.i32[3];
249
250 if (is_request) {
251 utils::ConvertZoomRatio(zoom_ratio, active_array_dimension, &left, &top,
252 &width, &height);
253 } else {
254 utils::RevertZoomRatio(zoom_ratio, active_array_dimension, true, &left,
255 &top, &width, &height);
256 }
257 int32_t rect[4] = {left, top, width, height};
258
259 ALOGV(
260 "%s: is request: %d, zoom ratio: %f, set rect: [%d, %d, %d, %d] -> [%d, "
261 "%d, %d, %d]",
262 __FUNCTION__, is_request, zoom_ratio, entry.data.i32[0], entry.data.i32[1],
263 entry.data.i32[2], entry.data.i32[3], rect[0], rect[1], rect[2], rect[3]);
264
265 res = metadata->Set(tag_id, rect, sizeof(rect) / sizeof(int32_t));
266 if (res != OK) {
267 ALOGE("%s: Updating region: %u failed: %s (%d)", __FUNCTION__, tag_id,
268 strerror(-res), res);
269 }
270 }
271
UpdateWeightedRects(const float zoom_ratio,const uint32_t tag_id,const Dimension & active_array_dimension,const bool is_request,HalCameraMetadata * metadata)272 void ZoomRatioMapper::UpdateWeightedRects(
273 const float zoom_ratio, const uint32_t tag_id,
274 const Dimension& active_array_dimension, const bool is_request,
275 HalCameraMetadata* metadata) {
276 if (metadata == nullptr) {
277 ALOGE("%s: metadata is nullptr", __FUNCTION__);
278 return;
279 }
280 camera_metadata_ro_entry entry = {};
281 status_t res = metadata->Get(tag_id, &entry);
282 if (res != OK || entry.count == 0) {
283 ALOGV("%s: Failed to get the region: %d, res: %d", __FUNCTION__, tag_id,
284 res);
285 return;
286 }
287 const WeightedRect* regions =
288 reinterpret_cast<const WeightedRect*>(entry.data.i32);
289 const size_t kNumElementsInTuple = sizeof(WeightedRect) / sizeof(int32_t);
290 std::vector<WeightedRect> updated_regions(entry.count / kNumElementsInTuple);
291
292 for (size_t i = 0; i < updated_regions.size(); i++) {
293 int32_t left = regions[i].left;
294 int32_t top = regions[i].top;
295 int32_t width = regions[i].right - regions[i].left + 1;
296 int32_t height = regions[i].bottom - regions[i].top + 1;
297
298 if (is_request) {
299 utils::ConvertZoomRatio(zoom_ratio, active_array_dimension, &left, &top,
300 &width, &height);
301 } else {
302 utils::RevertZoomRatio(zoom_ratio, active_array_dimension, true, &left,
303 &top, &width, &height);
304 }
305
306 updated_regions[i].left = left;
307 updated_regions[i].top = top;
308 updated_regions[i].right = left + width - 1;
309 updated_regions[i].bottom = top + height - 1;
310 updated_regions[i].weight = regions[i].weight;
311
312 ALOGV("%s: set region(%d): [%d, %d, %d, %d, %d]", __FUNCTION__, tag_id,
313 updated_regions[i].left, updated_regions[i].top,
314 updated_regions[i].right, updated_regions[i].bottom,
315 updated_regions[i].weight);
316 }
317 res = metadata->Set(tag_id, reinterpret_cast<int32_t*>(updated_regions.data()),
318 updated_regions.size() * kNumElementsInTuple);
319 if (res != OK) {
320 ALOGE("%s: Updating region(%d) failed: %s (%d)", __FUNCTION__, tag_id,
321 strerror(-res), res);
322 }
323 }
324
UpdatePoints(const float zoom_ratio,const uint32_t tag_id,const Dimension & active_array_dimension,HalCameraMetadata * metadata)325 void ZoomRatioMapper::UpdatePoints(const float zoom_ratio, const uint32_t tag_id,
326 const Dimension& active_array_dimension,
327 HalCameraMetadata* metadata) {
328 if (metadata == nullptr) {
329 ALOGE("%s: metadata is nullptr", __FUNCTION__);
330 return;
331 }
332 camera_metadata_ro_entry entry = {};
333 if (metadata->Get(tag_id, &entry) != OK) {
334 ALOGV("%s: tag: %u not published.", __FUNCTION__, tag_id);
335 return;
336 }
337
338 if (entry.count <= 0) {
339 ALOGV("%s: No data found, tag: %u", __FUNCTION__, tag_id);
340 return;
341 }
342 // x, y
343 const uint32_t kDataSizePerPoint = 2;
344 const uint32_t point_num = entry.count / kDataSizePerPoint;
345 std::vector<PointI> points(point_num);
346 uint32_t data_index = 0;
347
348 for (uint32_t i = 0; i < point_num; i++) {
349 data_index = i * kDataSizePerPoint;
350 PointI* transformed = &points.at(i);
351 transformed->x = entry.data.i32[data_index];
352 transformed->y = entry.data.i32[data_index + 1];
353 utils::RevertZoomRatio(zoom_ratio, active_array_dimension, true,
354 &transformed->x, &transformed->y);
355 }
356
357 status_t res = metadata->Set(
358 tag_id, reinterpret_cast<int32_t*>(points.data()), entry.count);
359
360 if (res != OK) {
361 ALOGE("%s: Updating tag: %u failed: %s (%d)", __FUNCTION__, tag_id,
362 strerror(-res), res);
363 }
364 }
365
366 } // namespace google_camera_hal
367 } // namespace android
368