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