• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 "Camera3-ZoomRatioMapper"
18 //#define LOG_NDEBUG 0
19 
20 #include <algorithm>
21 
22 #include "device3/ZoomRatioMapper.h"
23 #include "utils/SessionConfigurationUtils.h"
24 
25 namespace android {
26 
27 namespace camera3 {
28 
initRemappedKeys()29 void ZoomRatioMapper::initRemappedKeys() {
30     mRemappedKeys.insert(
31             kMeteringRegionsToCorrect.begin(),
32             kMeteringRegionsToCorrect.end());
33     mRemappedKeys.insert(
34             kRectsToCorrect.begin(),
35             kRectsToCorrect.end());
36     mRemappedKeys.insert(
37             kResultPointsToCorrectNoClamp.begin(),
38             kResultPointsToCorrectNoClamp.end());
39 
40     mRemappedKeys.insert(ANDROID_CONTROL_ZOOM_RATIO);
41 }
42 
initZoomRatioInTemplate(CameraMetadata * request)43 status_t ZoomRatioMapper::initZoomRatioInTemplate(CameraMetadata *request) {
44     camera_metadata_entry_t entry;
45     entry = request->find(ANDROID_CONTROL_ZOOM_RATIO);
46     float defaultZoomRatio = 1.0f;
47     if (entry.count == 0) {
48         return request->update(ANDROID_CONTROL_ZOOM_RATIO, &defaultZoomRatio, 1);
49     }
50     return OK;
51 }
52 
overrideZoomRatioTags(CameraMetadata * deviceInfo,bool * supportNativeZoomRatio)53 status_t ZoomRatioMapper::overrideZoomRatioTags(
54         CameraMetadata* deviceInfo, bool* supportNativeZoomRatio) {
55     if (deviceInfo == nullptr || supportNativeZoomRatio == nullptr) {
56         return BAD_VALUE;
57     }
58 
59     camera_metadata_entry_t entry;
60     entry = deviceInfo->find(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
61     if (entry.count != 2 && entry.count != 0) return BAD_VALUE;
62 
63     // Hal has zoom ratio support
64     if (entry.count == 2) {
65         *supportNativeZoomRatio = true;
66         return OK;
67     }
68 
69     // Hal has no zoom ratio support
70     *supportNativeZoomRatio = false;
71 
72     entry = deviceInfo->find(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
73     if (entry.count != 1) {
74         ALOGI("%s: Camera device doesn't support SCALER_AVAILABLE_MAX_DIGITAL_ZOOM key!",
75                 __FUNCTION__);
76         return OK;
77     }
78 
79     float zoomRange[] = {1.0f, entry.data.f[0]};
80     status_t res = deviceInfo->update(ANDROID_CONTROL_ZOOM_RATIO_RANGE, zoomRange, 2);
81     if (res != OK) {
82         ALOGE("%s: Failed to update CONTROL_ZOOM_RATIO_RANGE key: %s (%d)",
83                 __FUNCTION__, strerror(-res), res);
84         return res;
85     }
86 
87     std::vector<int32_t> requestKeys;
88     entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
89     if (entry.count > 0) {
90         requestKeys.insert(requestKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
91     }
92     requestKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO);
93     res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
94             requestKeys.data(), requestKeys.size());
95     if (res != OK) {
96         ALOGE("%s: Failed to update REQUEST_AVAILABLE_REQUEST_KEYS: %s (%d)",
97                 __FUNCTION__, strerror(-res), res);
98         return res;
99     }
100 
101     std::vector<int32_t> resultKeys;
102     entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS);
103     if (entry.count > 0) {
104         resultKeys.insert(resultKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
105     }
106     resultKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO);
107     res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
108             resultKeys.data(), resultKeys.size());
109     if (res != OK) {
110         ALOGE("%s: Failed to update REQUEST_AVAILABLE_RESULT_KEYS: %s (%d)",
111                 __FUNCTION__, strerror(-res), res);
112         return res;
113     }
114 
115     std::vector<int32_t> charKeys;
116     entry = deviceInfo->find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
117     if (entry.count > 0) {
118         charKeys.insert(charKeys.end(), entry.data.i32, entry.data.i32 + entry.count);
119     }
120     charKeys.push_back(ANDROID_CONTROL_ZOOM_RATIO_RANGE);
121     res = deviceInfo->update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
122             charKeys.data(), charKeys.size());
123     if (res != OK) {
124         ALOGE("%s: Failed to update REQUEST_AVAILABLE_CHARACTERISTICS_KEYS: %s (%d)",
125                 __FUNCTION__, strerror(-res), res);
126         return res;
127     }
128 
129     return OK;
130 }
131 
ZoomRatioMapper(const CameraMetadata * deviceInfo,bool supportNativeZoomRatio,bool usePrecorrectArray)132 ZoomRatioMapper::ZoomRatioMapper(const CameraMetadata* deviceInfo,
133         bool supportNativeZoomRatio, bool usePrecorrectArray) {
134     initRemappedKeys();
135 
136     int32_t arrayW = 0;
137     int32_t arrayH = 0;
138     int32_t arrayMaximumResolutionW = 0;
139     int32_t arrayMaximumResolutionH = 0;
140     int32_t activeW = 0;
141     int32_t activeH = 0;
142     int32_t activeMaximumResolutionW = 0;
143     int32_t activeMaximumResolutionH = 0;
144 
145     if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
146             ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, &arrayW, &arrayH)) {
147         ALOGE("%s: Couldn't get pre correction active array size", __FUNCTION__);
148         return;
149     }
150      if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
151             ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &activeW, &activeH)) {
152         ALOGE("%s: Couldn't get active array size", __FUNCTION__);
153         return;
154     }
155 
156     bool isUltraHighResolutionSensor =
157             camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(*deviceInfo);
158     if (isUltraHighResolutionSensor) {
159         if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
160                 ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
161                 &arrayMaximumResolutionW, &arrayMaximumResolutionH)) {
162             ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
163                     __FUNCTION__);
164             return;
165         }
166          if (!SessionConfigurationUtils::getArrayWidthAndHeight(deviceInfo,
167                 ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
168                 &activeMaximumResolutionW, &activeMaximumResolutionH)) {
169             ALOGE("%s: Couldn't get maximum resolution pre correction active array size",
170                     __FUNCTION__);
171             return;
172         }
173     }
174 
175     if (usePrecorrectArray) {
176         mArrayWidth = arrayW;
177         mArrayHeight = arrayH;
178         mArrayWidthMaximumResolution = arrayMaximumResolutionW;
179         mArrayHeightMaximumResolution = arrayMaximumResolutionH;
180     } else {
181         mArrayWidth = activeW;
182         mArrayHeight = activeH;
183         mArrayWidthMaximumResolution = activeMaximumResolutionW;
184         mArrayHeightMaximumResolution = activeMaximumResolutionH;
185     }
186     mHalSupportsZoomRatio = supportNativeZoomRatio;
187 
188     ALOGV("%s: array size: %d x %d, full res array size: %d x %d,  mHalSupportsZoomRatio %d",
189             __FUNCTION__, mArrayWidth, mArrayHeight, mArrayWidthMaximumResolution,
190             mArrayHeightMaximumResolution, mHalSupportsZoomRatio);
191     mIsValid = true;
192 }
193 
getArrayDimensionsToBeUsed(const CameraMetadata * settings,int32_t * arrayWidth,int32_t * arrayHeight)194 status_t ZoomRatioMapper::getArrayDimensionsToBeUsed(const CameraMetadata *settings,
195         int32_t *arrayWidth, int32_t *arrayHeight) {
196     if (settings == nullptr || arrayWidth == nullptr || arrayHeight == nullptr) {
197         return BAD_VALUE;
198     }
199     // First we get the sensorPixelMode from the settings metadata.
200     int32_t sensorPixelMode = ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
201     camera_metadata_ro_entry sensorPixelModeEntry = settings->find(ANDROID_SENSOR_PIXEL_MODE);
202     if (sensorPixelModeEntry.count != 0) {
203         sensorPixelMode = sensorPixelModeEntry.data.u8[0];
204         if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT &&
205             sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
206             ALOGE("%s: Request sensor pixel mode is not one of the valid values %d",
207                       __FUNCTION__, sensorPixelMode);
208             return BAD_VALUE;
209         }
210     }
211     if (sensorPixelMode == ANDROID_SENSOR_PIXEL_MODE_DEFAULT) {
212         *arrayWidth = mArrayWidth;
213         *arrayHeight = mArrayHeight;
214     } else {
215         *arrayWidth = mArrayWidthMaximumResolution;
216         *arrayHeight = mArrayHeightMaximumResolution;
217     }
218     return OK;
219 }
220 
updateCaptureRequest(CameraMetadata * request)221 status_t ZoomRatioMapper::updateCaptureRequest(CameraMetadata* request) {
222     if (!mIsValid) return INVALID_OPERATION;
223 
224     status_t res = OK;
225     bool zoomRatioIs1 = true;
226     camera_metadata_entry_t entry;
227     int arrayHeight, arrayWidth = 0;
228     res = getArrayDimensionsToBeUsed(request, &arrayWidth, &arrayHeight);
229     if (res != OK) {
230         return res;
231     }
232     entry = request->find(ANDROID_CONTROL_ZOOM_RATIO);
233     if (entry.count == 1 && entry.data.f[0] != 1.0f) {
234         zoomRatioIs1 = false;
235 
236         // If cropRegion is windowboxing, override it with activeArray
237         camera_metadata_entry_t cropRegionEntry = request->find(ANDROID_SCALER_CROP_REGION);
238         if (cropRegionEntry.count == 4) {
239             int cropWidth = cropRegionEntry.data.i32[2];
240             int cropHeight = cropRegionEntry.data.i32[3];
241             if (cropWidth < arrayWidth && cropHeight < arrayHeight) {
242                 cropRegionEntry.data.i32[0] = 0;
243                 cropRegionEntry.data.i32[1] = 0;
244                 cropRegionEntry.data.i32[2] = arrayWidth;
245                 cropRegionEntry.data.i32[3] = arrayHeight;
246             }
247         }
248     }
249 
250     if (mHalSupportsZoomRatio && zoomRatioIs1) {
251         res = separateZoomFromCropLocked(request, false/*isResult*/, arrayWidth, arrayHeight);
252     } else if (!mHalSupportsZoomRatio && !zoomRatioIs1) {
253         res = combineZoomAndCropLocked(request, false/*isResult*/, arrayWidth, arrayHeight);
254     }
255 
256     // If CONTROL_ZOOM_RATIO is in request, but HAL doesn't support
257     // CONTROL_ZOOM_RATIO, remove it from the request.
258     if (!mHalSupportsZoomRatio && entry.count == 1) {
259         request->erase(ANDROID_CONTROL_ZOOM_RATIO);
260     }
261 
262     return res;
263 }
264 
updateCaptureResult(CameraMetadata * result,bool requestedZoomRatioIs1)265 status_t ZoomRatioMapper::updateCaptureResult(CameraMetadata* result, bool requestedZoomRatioIs1) {
266     if (!mIsValid) return INVALID_OPERATION;
267 
268     status_t res = OK;
269 
270     int arrayHeight, arrayWidth = 0;
271     res = getArrayDimensionsToBeUsed(result, &arrayWidth, &arrayHeight);
272     if (res != OK) {
273         return res;
274     }
275     if (mHalSupportsZoomRatio && requestedZoomRatioIs1) {
276         res = combineZoomAndCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
277     } else if (!mHalSupportsZoomRatio && !requestedZoomRatioIs1) {
278         res = separateZoomFromCropLocked(result, true/*isResult*/, arrayWidth, arrayHeight);
279     } else {
280         camera_metadata_entry_t entry = result->find(ANDROID_CONTROL_ZOOM_RATIO);
281         if (entry.count == 0) {
282             float zoomRatio1x = 1.0f;
283             result->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio1x, 1);
284         }
285     }
286 
287     return res;
288 }
289 
deriveZoomRatio(const CameraMetadata * metadata,float * zoomRatioRet,int arrayWidth,int arrayHeight)290 status_t ZoomRatioMapper::deriveZoomRatio(const CameraMetadata* metadata, float *zoomRatioRet,
291         int arrayWidth, int arrayHeight) {
292     if (metadata == nullptr || zoomRatioRet == nullptr) {
293         return BAD_VALUE;
294     }
295     float zoomRatio = 1.0;
296 
297     camera_metadata_ro_entry_t entry;
298     entry = metadata->find(ANDROID_SCALER_CROP_REGION);
299     if (entry.count != 4) {
300         *zoomRatioRet = 1;
301         return OK;
302     }
303     // Center of the preCorrection/active size
304     float arrayCenterX = arrayWidth / 2.0;
305     float arrayCenterY = arrayHeight / 2.0;
306 
307     // Re-map crop region to coordinate system centered to (arrayCenterX,
308     // arrayCenterY).
309     float cropRegionLeft = arrayCenterX - entry.data.i32[0] ;
310     float cropRegionTop = arrayCenterY - entry.data.i32[1];
311     float cropRegionRight = entry.data.i32[0] + entry.data.i32[2] - arrayCenterX;
312     float cropRegionBottom = entry.data.i32[1] + entry.data.i32[3] - arrayCenterY;
313 
314     // Calculate the scaling factor for left, top, bottom, right
315     float zoomRatioLeft = std::max(arrayWidth / (2 * cropRegionLeft), 1.0f);
316     float zoomRatioTop = std::max(arrayHeight / (2 * cropRegionTop), 1.0f);
317     float zoomRatioRight = std::max(arrayWidth / (2 * cropRegionRight), 1.0f);
318     float zoomRatioBottom = std::max(arrayHeight / (2 * cropRegionBottom), 1.0f);
319 
320     // Use minimum scaling factor to handle letterboxing or pillarboxing
321     zoomRatio = std::min(std::min(zoomRatioLeft, zoomRatioRight),
322             std::min(zoomRatioTop, zoomRatioBottom));
323 
324     ALOGV("%s: derived zoomRatio is %f", __FUNCTION__, zoomRatio);
325     *zoomRatioRet = zoomRatio;
326     return OK;
327 }
328 
separateZoomFromCropLocked(CameraMetadata * metadata,bool isResult,int arrayWidth,int arrayHeight)329 status_t ZoomRatioMapper::separateZoomFromCropLocked(CameraMetadata* metadata, bool isResult,
330         int arrayWidth, int arrayHeight) {
331     float zoomRatio = 1.0;
332     status_t res = deriveZoomRatio(metadata, &zoomRatio, arrayWidth, arrayHeight);
333 
334     if (res != OK) {
335         ALOGE("%s: Failed to derive zoom ratio: %s(%d)",
336                 __FUNCTION__, strerror(-res), res);
337         return res;
338     }
339 
340     // Update zoomRatio metadata tag
341     res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
342     if (res != OK) {
343         ALOGE("%s: Failed to update ANDROID_CONTROL_ZOOM_RATIO: %s(%d)",
344                 __FUNCTION__, strerror(-res), res);
345         return res;
346     }
347 
348     // Scale regions using zoomRatio
349     camera_metadata_entry_t entry;
350     for (auto region : kMeteringRegionsToCorrect) {
351         entry = metadata->find(region);
352         for (size_t j = 0; j < entry.count; j += 5) {
353             int32_t weight = entry.data.i32[j + 4];
354             if (weight == 0) {
355                 continue;
356             }
357             // Top left (inclusive)
358             scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, true /*clamp*/, arrayWidth,
359                     arrayHeight);
360             // Bottom right (exclusive): Use adjacent inclusive pixel to
361             // calculate.
362             entry.data.i32[j+2] -= 1;
363             entry.data.i32[j+3] -= 1;
364             scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, true /*clamp*/, arrayWidth,
365                     arrayHeight);
366             entry.data.i32[j+2] += 1;
367             entry.data.i32[j+3] += 1;
368         }
369     }
370 
371     for (auto rect : kRectsToCorrect) {
372         entry = metadata->find(rect);
373         scaleRects(entry.data.i32, entry.count / 4, zoomRatio, arrayWidth, arrayHeight);
374     }
375 
376     if (isResult) {
377         for (auto pts : kResultPointsToCorrectNoClamp) {
378             entry = metadata->find(pts);
379             scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, false /*clamp*/,
380                     arrayWidth, arrayHeight);
381         }
382     }
383 
384     return OK;
385 }
386 
combineZoomAndCropLocked(CameraMetadata * metadata,bool isResult,int arrayWidth,int arrayHeight)387 status_t ZoomRatioMapper::combineZoomAndCropLocked(CameraMetadata* metadata, bool isResult,
388         int arrayWidth, int arrayHeight) {
389     float zoomRatio = 1.0f;
390     camera_metadata_entry_t entry;
391     entry = metadata->find(ANDROID_CONTROL_ZOOM_RATIO);
392     if (entry.count == 1) {
393         zoomRatio = entry.data.f[0];
394     }
395 
396     // Unscale regions with zoomRatio
397     for (auto region : kMeteringRegionsToCorrect) {
398         entry = metadata->find(region);
399         for (size_t j = 0; j < entry.count; j += 5) {
400             int32_t weight = entry.data.i32[j + 4];
401             if (weight == 0) {
402                 continue;
403             }
404             // Top-left (inclusive)
405             scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, true /*clamp*/, arrayWidth,
406                     arrayHeight);
407             // Bottom-right (exclusive): Use adjacent inclusive pixel to
408             // calculate.
409             entry.data.i32[j+2] -= 1;
410             entry.data.i32[j+3] -= 1;
411             scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, true /*clamp*/, arrayWidth,
412                     arrayHeight);
413             entry.data.i32[j+2] += 1;
414             entry.data.i32[j+3] += 1;
415         }
416     }
417     for (auto rect : kRectsToCorrect) {
418         entry = metadata->find(rect);
419         scaleRects(entry.data.i32, entry.count / 4, 1.0 / zoomRatio, arrayWidth, arrayHeight);
420     }
421     if (isResult) {
422         for (auto pts : kResultPointsToCorrectNoClamp) {
423             entry = metadata->find(pts);
424             scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, false /*clamp*/,
425                     arrayWidth, arrayHeight);
426         }
427     }
428 
429     zoomRatio = 1.0;
430     status_t res = metadata->update(ANDROID_CONTROL_ZOOM_RATIO, &zoomRatio, 1);
431     if (res != OK) {
432         return res;
433     }
434 
435     return OK;
436 }
437 
scaleCoordinates(int32_t * coordPairs,int coordCount,float scaleRatio,bool clamp,int32_t arrayWidth,int32_t arrayHeight)438 void ZoomRatioMapper::scaleCoordinates(int32_t* coordPairs, int coordCount,
439         float scaleRatio, bool clamp, int32_t arrayWidth, int32_t arrayHeight) {
440     // A pixel's coordinate is represented by the position of its top-left corner.
441     // To avoid the rounding error, we use the coordinate for the center of the
442     // pixel instead:
443     // 1. First shift the coordinate system half pixel both horizontally and
444     // vertically, so that [x, y] is the center of the pixel, not the top-left corner.
445     // 2. Do zoom operation to scale the coordinate relative to the center of
446     // the active array (shifted by 0.5 pixel as well).
447     // 3. Shift the coordinate system back by directly using the pixel center
448     // coordinate.
449     for (int i = 0; i < coordCount * 2; i += 2) {
450         float x = coordPairs[i];
451         float y = coordPairs[i + 1];
452         float xCentered = x - (arrayWidth - 2) / 2;
453         float yCentered = y - (arrayHeight - 2) / 2;
454         float scaledX = xCentered * scaleRatio;
455         float scaledY = yCentered * scaleRatio;
456         scaledX += (arrayWidth - 2) / 2;
457         scaledY += (arrayHeight - 2) / 2;
458         coordPairs[i] = static_cast<int32_t>(std::round(scaledX));
459         coordPairs[i+1] = static_cast<int32_t>(std::round(scaledY));
460         // Clamp to within activeArray/preCorrectionActiveArray
461         if (clamp) {
462             int32_t right = arrayWidth - 1;
463             int32_t bottom = arrayHeight - 1;
464             coordPairs[i] =
465                     std::min(right, std::max(0, coordPairs[i]));
466             coordPairs[i+1] =
467                     std::min(bottom, std::max(0, coordPairs[i+1]));
468         }
469         ALOGV("%s: coordinates: %d, %d", __FUNCTION__, coordPairs[i], coordPairs[i+1]);
470     }
471 }
472 
scaleRects(int32_t * rects,int rectCount,float scaleRatio,int32_t arrayWidth,int32_t arrayHeight)473 void ZoomRatioMapper::scaleRects(int32_t* rects, int rectCount,
474         float scaleRatio, int32_t arrayWidth, int32_t arrayHeight) {
475     for (int i = 0; i < rectCount * 4; i += 4) {
476         // Map from (l, t, width, height) to (l, t, l+width-1, t+height-1),
477         // where both top-left and bottom-right are inclusive.
478         int32_t coords[4] = {
479             rects[i],
480             rects[i + 1],
481             rects[i] + rects[i + 2] - 1,
482             rects[i + 1] + rects[i + 3] - 1
483         };
484 
485         // top-left
486         scaleCoordinates(coords, 1, scaleRatio, true /*clamp*/, arrayWidth, arrayHeight);
487         // bottom-right
488         scaleCoordinates(coords+2, 1, scaleRatio, true /*clamp*/, arrayWidth, arrayHeight);
489 
490         // Map back to (l, t, width, height)
491         rects[i] = coords[0];
492         rects[i + 1] = coords[1];
493         rects[i + 2] = coords[2] - coords[0] + 1;
494         rects[i + 3] = coords[3] - coords[1] + 1;
495     }
496 }
497 
498 } // namespace camera3
499 
500 } // namespace android
501