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