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