1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30
31 #define ATRACE_TAG ATRACE_TAG_CAMERA
32 #define LOG_TAG "QCamera3CropRegionMapper"
33
34 #include <cmath>
35
36 // Camera dependencies
37 #include "QCamera3CropRegionMapper.h"
38 #include "QCamera3HWI.h"
39
40 extern "C" {
41 #include "mm_camera_dbg.h"
42 }
43
44 using namespace android;
45
46 namespace qcamera {
47
48 /*===========================================================================
49 * FUNCTION : QCamera3CropRegionMapper
50 *
51 * DESCRIPTION: Constructor
52 *
53 * PARAMETERS : None
54 *
55 * RETURN : None
56 *==========================================================================*/
QCamera3CropRegionMapper()57 QCamera3CropRegionMapper::QCamera3CropRegionMapper()
58 : mSensorW(0),
59 mSensorH(0),
60 mActiveArrayW(0),
61 mActiveArrayH(0)
62 {
63 }
64
65 /*===========================================================================
66 * FUNCTION : ~QCamera3CropRegionMapper
67 *
68 * DESCRIPTION: destructor
69 *
70 * PARAMETERS : none
71 *
72 * RETURN : none
73 *==========================================================================*/
74
~QCamera3CropRegionMapper()75 QCamera3CropRegionMapper::~QCamera3CropRegionMapper()
76 {
77 }
78
79 /*===========================================================================
80 * FUNCTION : update
81 *
82 * DESCRIPTION: update sensor active array size and sensor output size
83 *
84 * PARAMETERS :
85 * @active_array_w : active array width
86 * @active_array_h : active array height
87 * @sensor_w : sensor output width
88 * @sensor_h : sensor output height
89 *
90 * RETURN : none
91 *==========================================================================*/
update(uint32_t active_array_w,uint32_t active_array_h,uint32_t sensor_w,uint32_t sensor_h)92 void QCamera3CropRegionMapper::update(uint32_t active_array_w,
93 uint32_t active_array_h, uint32_t sensor_w,
94 uint32_t sensor_h)
95 {
96 // Sanity check
97 if (active_array_w == 0 || active_array_h == 0 ||
98 sensor_w == 0 || sensor_h == 0) {
99 LOGE("active_array size and sensor output size must be non zero");
100 return;
101 }
102 if (active_array_w < sensor_w || active_array_h < sensor_h) {
103 LOGE("invalid input: active_array [%d, %d], sensor size [%d, %d]",
104 active_array_w, active_array_h, sensor_w, sensor_h);
105 return;
106 }
107 mSensorW = sensor_w;
108 mSensorH = sensor_h;
109 mActiveArrayW = active_array_w;
110 mActiveArrayH = active_array_h;
111
112 LOGH("active_array: %d x %d, sensor size %d x %d",
113 mActiveArrayW, mActiveArrayH, mSensorW, mSensorH);
114 }
115
116 /*===========================================================================
117 * FUNCTION : toActiveArray
118 *
119 * DESCRIPTION: Map crop rectangle from sensor output space to active array space
120 *
121 * PARAMETERS :
122 * @crop_left : x coordinate of top left corner of rectangle
123 * @crop_top : y coordinate of top left corner of rectangle
124 * @crop_width : width of rectangle
125 * @crop_height : height of rectangle
126 * @zoom_ratio : zoom ratio to be reverted for the input rectangles
127 *
128 * RETURN : none
129 *==========================================================================*/
toActiveArray(int32_t & crop_left,int32_t & crop_top,int32_t & crop_width,int32_t & crop_height,float zoom_ratio)130 void QCamera3CropRegionMapper::toActiveArray(int32_t& crop_left, int32_t& crop_top,
131 int32_t& crop_width, int32_t& crop_height, float zoom_ratio)
132 {
133 if (mSensorW == 0 || mSensorH == 0 ||
134 mActiveArrayW == 0 || mActiveArrayH == 0) {
135 LOGE("sensor/active array sizes are not initialized!");
136 return;
137 }
138 if (zoom_ratio < MIN_ZOOM_RATIO) {
139 LOGE("Invalid zoom ratio %f", zoom_ratio);
140 return;
141 }
142
143 // Map back to activeArray space
144 float left = crop_left * mActiveArrayW / mSensorW;
145 float top = crop_top * mActiveArrayH / mSensorH;
146 float width = crop_width * mActiveArrayW / mSensorW;
147 float height = crop_height * mActiveArrayH / mSensorH;
148
149 // Revert zoom_ratio, so that now the crop rectangle is separate from
150 // zoom_ratio. The coordinate is within the active array space which covers
151 // the post-zoom FOV.
152 left = left * zoom_ratio - (zoom_ratio - 1) * 0.5f * mActiveArrayW;
153 top = top * zoom_ratio - (zoom_ratio - 1) * 0.5f * mActiveArrayH;
154 width = width * zoom_ratio;
155 height = height * zoom_ratio;
156
157 crop_left = std::round(left);
158 crop_top = std::round(top);
159 crop_width = std::round(width);
160 crop_height = std::round(height);
161
162 boundToSize(crop_left, crop_top, crop_width, crop_height,
163 mActiveArrayW, mActiveArrayH);
164 }
165
166 /*===========================================================================
167 * FUNCTION : toSensor
168 *
169 * DESCRIPTION: Map crop rectangle from active array space to sensor output space
170 *
171 * PARAMETERS :
172 * @crop_left : x coordinate of top left corner of rectangle
173 * @crop_top : y coordinate of top left corner of rectangle
174 * @crop_width : width of rectangle
175 * @crop_height : height of rectangle
176 * @zoom_ratio : zoom ratio to be applied to the input rectangles
177 *
178 * RETURN : none
179 *==========================================================================*/
180
toSensor(int32_t & crop_left,int32_t & crop_top,int32_t & crop_width,int32_t & crop_height,float zoom_ratio)181 void QCamera3CropRegionMapper::toSensor(int32_t& crop_left, int32_t& crop_top,
182 int32_t& crop_width, int32_t& crop_height, float zoom_ratio)
183 {
184 if (mSensorW == 0 || mSensorH == 0 ||
185 mActiveArrayW == 0 || mActiveArrayH == 0) {
186 LOGE("sensor/active array sizes are not initialized!");
187 return;
188 }
189
190 applyZoomRatioHelper(crop_left, crop_top, crop_width, crop_height, zoom_ratio,
191 true /*to_sensor*/);
192 }
193
194 /*===========================================================================
195 * FUNCTION : applyZoomRatioHelper
196 *
197 * DESCRIPTION: Apply zoom ratio to the crop region, and optionally map
198 * to sensor coordinate system
199 *
200 * PARAMETERS :
201 * @crop_left : x coordinate of top left corner of rectangle
202 * @crop_top : y coordinate of top left corner of rectangle
203 * @crop_width : width of rectangle
204 * @crop_height : height of rectangle
205 * @zoom_ratio : zoom ratio to be applied to the input rectangles
206 * @to_sensor : whether the crop region is to be mapped to sensor coordinate
207 * system
208 *
209 * RETURN : none
210 *==========================================================================*/
applyZoomRatioHelper(int32_t & crop_left,int32_t & crop_top,int32_t & crop_width,int32_t & crop_height,float zoom_ratio,bool to_sensor)211 void QCamera3CropRegionMapper::applyZoomRatioHelper(int32_t& crop_left, int32_t& crop_top,
212 int32_t& crop_width, int32_t& crop_height, float zoom_ratio, bool to_sensor)
213 {
214 if (zoom_ratio < MIN_ZOOM_RATIO) {
215 LOGE("Invalid zoom ratio %f", zoom_ratio);
216 return;
217 }
218
219 // Apply zoom_ratio to the input rectangle in activeArray space, so that
220 // crop rectangle already takes zoom_ratio into account (in other words,
221 // coordinate within the sensor native active array space).
222 float left = crop_left / zoom_ratio +
223 0.5f * mActiveArrayW * (1.0f - 1.0f / zoom_ratio);
224 float top = crop_top / zoom_ratio +
225 0.5f * mActiveArrayH * (1.0f - 1.0f / zoom_ratio);
226 float width = crop_width / zoom_ratio;
227 float height = crop_height / zoom_ratio;
228
229 if (to_sensor) {
230 // Map to sensor space.
231 left = left * mSensorW / mActiveArrayW;
232 top = top * mSensorH / mActiveArrayH;
233 width = width * mSensorW / mActiveArrayW;
234 height = height * mSensorH / mActiveArrayH;
235 }
236
237 crop_left = std::round(left);
238 crop_top = std::round(top);
239 crop_width = std::round(width);
240 crop_height = std::round(height);
241
242 LOGD("before bounding left %d, top %d, width %d, height %d",
243 crop_left, crop_top, crop_width, crop_height);
244 boundToSize(crop_left, crop_top, crop_width, crop_height,
245 to_sensor ? mSensorW : mActiveArrayW,
246 to_sensor ? mSensorH : mActiveArrayH);
247 LOGD("after bounding left %d, top %d, width %d, height %d",
248 crop_left, crop_top, crop_width, crop_height);
249 }
250
251 /*===========================================================================
252 * FUNCTION : applyZoomRatio
253 *
254 * DESCRIPTION: Apply zoom ratio to the crop region
255 *
256 * PARAMETERS :
257 * @crop_left : x coordinate of top left corner of rectangle
258 * @crop_top : y coordinate of top left corner of rectangle
259 * @crop_width : width of rectangle
260 * @crop_height : height of rectangle
261 * @zoom_ratio : zoom ratio to be applied to the input rectangles
262 *
263 * RETURN : none
264 *==========================================================================*/
applyZoomRatio(int32_t & crop_left,int32_t & crop_top,int32_t & crop_width,int32_t & crop_height,float zoom_ratio)265 void QCamera3CropRegionMapper::applyZoomRatio(int32_t& crop_left, int32_t& crop_top,
266 int32_t& crop_width, int32_t& crop_height, float zoom_ratio)
267 {
268 if (mActiveArrayW == 0 || mActiveArrayH == 0) {
269 LOGE("active array sizes are not initialized!");
270 return;
271 }
272
273 applyZoomRatioHelper(crop_left, crop_top, crop_width, crop_height, zoom_ratio,
274 false /*to_sensor*/);
275 }
276
277 /*===========================================================================
278 * FUNCTION : boundToSize
279 *
280 * DESCRIPTION: Bound a particular rectangle inside a bounding box
281 *
282 * PARAMETERS :
283 * @left : x coordinate of top left corner of rectangle
284 * @top : y coordinate of top left corner of rectangle
285 * @width : width of rectangle
286 * @height : height of rectangle
287 * @bound_w : width of bounding box
288 * @bound_y : height of bounding box
289 *
290 * RETURN : none
291 *==========================================================================*/
boundToSize(int32_t & left,int32_t & top,int32_t & width,int32_t & height,int32_t bound_w,int32_t bound_h)292 void QCamera3CropRegionMapper::boundToSize(int32_t& left, int32_t& top,
293 int32_t& width, int32_t& height, int32_t bound_w, int32_t bound_h)
294 {
295 if (left < 0) {
296 left = 0;
297 }
298 if (left >= bound_w) {
299 left = bound_w - 1;
300 }
301 if (top < 0) {
302 top = 0;
303 }
304 if (top >= bound_h) {
305 top = bound_h - 1;
306 }
307
308 if ((left + width) > bound_w) {
309 width = bound_w - left;
310 }
311 if ((top + height) > bound_h) {
312 height = bound_h - top;
313 }
314 }
315
316 /*===========================================================================
317 * FUNCTION : toActiveArray
318 *
319 * DESCRIPTION: Map co-ordinate from sensor output space to active array space
320 *
321 * PARAMETERS :
322 * @x : x coordinate
323 * @y : y coordinate
324 * @zoom_ratio : zoom ratio to be applied to the input coordinates
325 *
326 * RETURN : none
327 *==========================================================================*/
toActiveArray(uint32_t & x,uint32_t & y,float zoom_ratio)328 void QCamera3CropRegionMapper::toActiveArray(uint32_t& x, uint32_t& y, float zoom_ratio)
329 {
330 if (mSensorW == 0 || mSensorH == 0 ||
331 mActiveArrayW == 0 || mActiveArrayH == 0) {
332 LOGE("sensor/active array sizes are not initialized!");
333 return;
334 }
335 if ((x > static_cast<uint32_t>(mSensorW)) ||
336 (y > static_cast<uint32_t>(mSensorH))) {
337 LOGE("invalid co-ordinate (%d, %d) in (0, 0, %d, %d) space",
338 x, y, mSensorW, mSensorH);
339 return;
340 }
341 if (zoom_ratio < MIN_ZOOM_RATIO) {
342 LOGE("Invalid zoom ratio %f", zoom_ratio);
343 return;
344 }
345
346 // Map back to activeArray space
347 x = x * mActiveArrayW / mSensorW;
348 y = y * mActiveArrayH / mSensorH;
349
350 // Revert zoom_ratio, so that now the crop rectangle is separate from
351 // zoom_ratio. The coordinate is within the active array space which covers
352 // the post-zoom FOV.
353 x = x * zoom_ratio - (zoom_ratio - 1) * 0.5f * mActiveArrayW;
354 y = y * zoom_ratio - (zoom_ratio - 1) * 0.5f * mActiveArrayH;
355 }
356
357 /*===========================================================================
358 * FUNCTION : toSensor
359 *
360 * DESCRIPTION: Map co-ordinate from active array space to sensor output space
361 *
362 * PARAMETERS :
363 * @x : x coordinate
364 * @y : y coordinate
365 * @zoom_ratio : zoom ratio to be applied to the input coordinates
366 *
367 * RETURN : none
368 *==========================================================================*/
369
toSensor(uint32_t & x,uint32_t & y,float zoom_ratio)370 void QCamera3CropRegionMapper::toSensor(uint32_t& x, uint32_t& y, float zoom_ratio)
371 {
372 if (mSensorW == 0 || mSensorH == 0 ||
373 mActiveArrayW == 0 || mActiveArrayH == 0) {
374 LOGE("sensor/active array sizes are not initialized!");
375 return;
376 }
377 if ((x > static_cast<uint32_t>(mActiveArrayW)) ||
378 (y > static_cast<uint32_t>(mActiveArrayH))) {
379 LOGE("invalid co-ordinate (%d, %d) in (0, 0, %d, %d) space",
380 x, y, mSensorW, mSensorH);
381 return;
382 }
383 if (zoom_ratio < MIN_ZOOM_RATIO) {
384 LOGE("Invalid zoom ratio %f", zoom_ratio);
385 return;
386 }
387
388 // Apply zoom_ratio to the input coordinate in activeArray space, so that
389 // coordinate already takes zoom_ratio into account (in other words,
390 // coordinate within the sensor native active array space).
391 x = x / zoom_ratio +
392 0.5f * mActiveArrayW * (1.0f - 1.0f / zoom_ratio);
393 y = y / zoom_ratio +
394 0.5f * mActiveArrayH * (1.0f - 1.0f / zoom_ratio);
395
396 // Map to sensor space.
397 x = x * mSensorW / mActiveArrayW;
398 y = y * mSensorH / mActiveArrayH;
399 }
400
401 }; //end namespace android
402