1 /* Copyright (c) 2016-2017, 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 #define LOG_TAG "QCameraFOVControl"
31 
32 #include <stdlib.h>
33 #include <cutils/properties.h>
34 #include <utils/Errors.h>
35 #include "QCameraFOVControl.h"
36 #include "QCameraDualCamSettings.h"
37 
38 
39 extern "C" {
40 #include "mm_camera_dbg.h"
41 }
42 
43 namespace qcamera {
44 
45 /*===========================================================================
46  * FUNCTION   : QCameraFOVControl constructor
47  *
48  * DESCRIPTION: class constructor
49  *
50  * PARAMETERS : none
51  *
52  * RETURN     : void
53  *
54  *==========================================================================*/
QCameraFOVControl()55 QCameraFOVControl::QCameraFOVControl()
56 {
57     mZoomTranslator = NULL;
58     memset(&mDualCamParams,    0, sizeof(dual_cam_params_t));
59     memset(&mFovControlConfig, 0, sizeof(fov_control_config_t));
60     memset(&mFovControlData,   0, sizeof(fov_control_data_t));
61     memset(&mFovControlResult, 0, sizeof(fov_control_result_t));
62 }
63 
64 
65 /*===========================================================================
66  * FUNCTION   : QCameraFOVControl destructor
67  *
68  * DESCRIPTION: class destructor
69  *
70  * PARAMETERS : none
71  *
72  * RETURN     : void
73  *
74  *==========================================================================*/
~QCameraFOVControl()75 QCameraFOVControl::~QCameraFOVControl()
76 {
77     // De-initialize zoom translator lib
78     if (mZoomTranslator && mZoomTranslator->isInitialized()) {
79         mZoomTranslator->deInit();
80     }
81 }
82 
83 
84 /*===========================================================================
85  * FUNCTION   : create
86  *
87  * DESCRIPTION: This is a static method to create FOV-control object. It calls
88  *              private constructor of the class and only returns a valid object
89  *              if it can successfully initialize the FOV-control.
90  *
91  * PARAMETERS :
92  *  @capsMain : The capabilities for the main camera
93  *  @capsAux  : The capabilities for the aux camera
94  *
95  * RETURN     : Valid object pointer if succeeds
96  *              NULL if fails
97  *
98  *==========================================================================*/
create(cam_capability_t * capsMainCam,cam_capability_t * capsAuxCam)99 QCameraFOVControl* QCameraFOVControl::create(
100         cam_capability_t *capsMainCam,
101         cam_capability_t *capsAuxCam)
102 {
103     QCameraFOVControl *pFovControl  = NULL;
104 
105     if (capsMainCam && capsAuxCam) {
106         // Create FOV control object
107         pFovControl = new QCameraFOVControl();
108 
109         if (pFovControl) {
110             bool  success = false;
111             if (pFovControl->validateAndExtractParameters(capsMainCam, capsAuxCam)) {
112                 // Based on focal lengths, map main and aux camera to wide and tele
113                 if (pFovControl->mDualCamParams.paramsMain.focalLengthMm <
114                     pFovControl->mDualCamParams.paramsAux.focalLengthMm) {
115                     pFovControl->mFovControlData.camWide  = CAM_TYPE_MAIN;
116                     pFovControl->mFovControlData.camTele  = CAM_TYPE_AUX;
117                     pFovControl->mFovControlData.camState = STATE_WIDE;
118                 } else {
119                     pFovControl->mFovControlData.camWide  = CAM_TYPE_AUX;
120                     pFovControl->mFovControlData.camTele  = CAM_TYPE_MAIN;
121                     pFovControl->mFovControlData.camState = STATE_TELE;
122                 }
123 
124                 // Initialize the master info to main camera
125                 pFovControl->mFovControlResult.camMasterPreview  = CAM_TYPE_MAIN;
126                 pFovControl->mFovControlResult.camMaster3A       = CAM_TYPE_MAIN;
127 
128                 // Check if LPM is enabled
129                 char prop[PROPERTY_VALUE_MAX];
130                 int lpmEnable = 1;
131                 property_get("persist.dualcam.lpm.enable", prop, "1");
132                 lpmEnable = atoi(prop);
133                 if ((lpmEnable == 0) || (DUALCAM_LPM_ENABLE == 0)) {
134                     pFovControl->mFovControlData.lpmEnabled = false;
135                 } else {
136                     pFovControl->mFovControlData.lpmEnabled = true;
137                 }
138 
139                 // Open the external zoom translation library if requested
140                 if (FOVC_USE_EXTERNAL_ZOOM_TRANSLATOR) {
141                     pFovControl->mZoomTranslator =
142                             QCameraExtZoomTranslator::create();
143                     if (!pFovControl->mZoomTranslator) {
144                         LOGE("Unable to open zoom translation lib");
145                     }
146                 }
147                 success = true;
148             }
149 
150             if (!success) {
151                 LOGE("FOV-control: Failed to create an object");
152                 delete pFovControl;
153                 pFovControl = NULL;
154             }
155         } else {
156             LOGE("FOV-control: Failed to allocate memory for FOV-control object");
157         }
158     }
159 
160     return pFovControl;
161 }
162 
163 
164 /*===========================================================================
165  * FUNCTION    : consolidateCapabilities
166  *
167  * DESCRIPTION : Combine the capabilities from main and aux cameras to return
168  *               the consolidated capabilities.
169  *
170  * PARAMETERS  :
171  * @capsMainCam: Capabilities for the main camera
172  * @capsAuxCam : Capabilities for the aux camera
173  *
174  * RETURN      : Consolidated capabilities
175  *
176  *==========================================================================*/
consolidateCapabilities(cam_capability_t * capsMainCam,cam_capability_t * capsAuxCam)177 cam_capability_t QCameraFOVControl::consolidateCapabilities(
178         cam_capability_t *capsMainCam,
179         cam_capability_t *capsAuxCam)
180 {
181     cam_capability_t capsConsolidated;
182     memset(&capsConsolidated, 0, sizeof(cam_capability_t));
183 
184     if ((capsMainCam != NULL) &&
185         (capsAuxCam  != NULL)) {
186 
187         memcpy(&capsConsolidated, capsMainCam, sizeof(cam_capability_t));
188 
189         // Consolidate preview sizes
190         uint32_t previewSizesTblCntMain  = capsMainCam->preview_sizes_tbl_cnt;
191         uint32_t previewSizesTblCntAux   = capsAuxCam->preview_sizes_tbl_cnt;
192         uint32_t previewSizesTblCntFinal = 0;
193 
194         for (uint32_t i = 0; i < previewSizesTblCntMain; ++i) {
195             for (uint32_t j = 0; j < previewSizesTblCntAux; ++j) {
196                 if ((capsMainCam->preview_sizes_tbl[i].width ==
197                      capsAuxCam->preview_sizes_tbl[j].width) &&
198                     (capsMainCam->preview_sizes_tbl[i].height ==
199                      capsAuxCam->preview_sizes_tbl[j].height)) {
200                     if (previewSizesTblCntFinal != i) {
201                         capsConsolidated.preview_sizes_tbl[previewSizesTblCntFinal].width =
202                            capsAuxCam->preview_sizes_tbl[j].width;
203                         capsConsolidated.preview_sizes_tbl[previewSizesTblCntFinal].height =
204                            capsMainCam->preview_sizes_tbl[j].height;
205                     }
206                     ++previewSizesTblCntFinal;
207                     break;
208                 }
209             }
210         }
211         capsConsolidated.preview_sizes_tbl_cnt = previewSizesTblCntFinal;
212 
213         // Consolidate video sizes
214         uint32_t videoSizesTblCntMain  = capsMainCam->video_sizes_tbl_cnt;
215         uint32_t videoSizesTblCntAux   = capsAuxCam->video_sizes_tbl_cnt;
216         uint32_t videoSizesTblCntFinal = 0;
217 
218         for (uint32_t i = 0; i < videoSizesTblCntMain; ++i) {
219             for (uint32_t j = 0; j < videoSizesTblCntAux; ++j) {
220                 if ((capsMainCam->video_sizes_tbl[i].width ==
221                      capsAuxCam->video_sizes_tbl[j].width) &&
222                     (capsMainCam->video_sizes_tbl[i].height ==
223                      capsAuxCam->video_sizes_tbl[j].height)) {
224                     if (videoSizesTblCntFinal != i) {
225                         capsConsolidated.video_sizes_tbl[videoSizesTblCntFinal].width =
226                            capsAuxCam->video_sizes_tbl[j].width;
227                         capsConsolidated.video_sizes_tbl[videoSizesTblCntFinal].height =
228                            capsMainCam->video_sizes_tbl[j].height;
229                     }
230                     ++videoSizesTblCntFinal;
231                     break;
232                 }
233             }
234         }
235         capsConsolidated.video_sizes_tbl_cnt = videoSizesTblCntFinal;
236 
237         // Consolidate livesnapshot sizes
238         uint32_t livesnapshotSizesTblCntMain  = capsMainCam->livesnapshot_sizes_tbl_cnt;
239         uint32_t livesnapshotSizesTblCntAux   = capsAuxCam->livesnapshot_sizes_tbl_cnt;
240         uint32_t livesnapshotSizesTblCntFinal = 0;
241 
242         for (uint32_t i = 0; i < livesnapshotSizesTblCntMain; ++i) {
243             for (uint32_t j = 0; j < livesnapshotSizesTblCntAux; ++j) {
244                 if ((capsMainCam->livesnapshot_sizes_tbl[i].width ==
245                      capsAuxCam->livesnapshot_sizes_tbl[j].width) &&
246                     (capsMainCam->livesnapshot_sizes_tbl[i].height ==
247                      capsAuxCam->livesnapshot_sizes_tbl[j].height)) {
248                     if (livesnapshotSizesTblCntFinal != i) {
249                        capsConsolidated.livesnapshot_sizes_tbl[livesnapshotSizesTblCntFinal].width=
250                           capsAuxCam->livesnapshot_sizes_tbl[j].width;
251                        capsConsolidated.livesnapshot_sizes_tbl[livesnapshotSizesTblCntFinal].height=
252                           capsMainCam->livesnapshot_sizes_tbl[j].height;
253                     }
254                     ++livesnapshotSizesTblCntFinal;
255                     break;
256                 }
257             }
258         }
259         capsConsolidated.livesnapshot_sizes_tbl_cnt = livesnapshotSizesTblCntFinal;
260 
261         // Consolidate picture size
262         // Find max picture dimension for main camera
263         cam_dimension_t maxPicDimMain;
264         maxPicDimMain.width  = 0;
265         maxPicDimMain.height = 0;
266 
267         for(uint32_t i = 0; i < (capsMainCam->picture_sizes_tbl_cnt - 1); ++i) {
268             if ((maxPicDimMain.width * maxPicDimMain.height) <
269                     (capsMainCam->picture_sizes_tbl[i].width *
270                             capsMainCam->picture_sizes_tbl[i].height)) {
271                 maxPicDimMain.width  = capsMainCam->picture_sizes_tbl[i].width;
272                 maxPicDimMain.height = capsMainCam->picture_sizes_tbl[i].height;
273             }
274         }
275 
276         // Find max picture dimension for aux camera
277         cam_dimension_t maxPicDimAux;
278         maxPicDimAux.width  = 0;
279         maxPicDimAux.height = 0;
280 
281         for(uint32_t i = 0; i < (capsAuxCam->picture_sizes_tbl_cnt - 1); ++i) {
282             if ((maxPicDimAux.width * maxPicDimAux.height) <
283                     (capsAuxCam->picture_sizes_tbl[i].width *
284                             capsAuxCam->picture_sizes_tbl[i].height)) {
285                 maxPicDimAux.width  = capsAuxCam->picture_sizes_tbl[i].width;
286                 maxPicDimAux.height = capsAuxCam->picture_sizes_tbl[i].height;
287             }
288         }
289 
290         LOGH("MAIN Max picture wxh %dx%d", maxPicDimMain.width, maxPicDimMain.height);
291         LOGH("AUX Max picture wxh %dx%d", maxPicDimAux.width, maxPicDimAux.height);
292 
293         // Choose the larger of the two max picture dimensions
294         if ((maxPicDimAux.width * maxPicDimAux.height) >
295                 (maxPicDimMain.width * maxPicDimMain.height)) {
296             capsConsolidated.picture_sizes_tbl_cnt = capsAuxCam->picture_sizes_tbl_cnt;
297             memcpy(capsConsolidated.picture_sizes_tbl, capsAuxCam->picture_sizes_tbl,
298                     (capsAuxCam->picture_sizes_tbl_cnt * sizeof(cam_dimension_t)));
299         }
300         LOGH("Consolidated Max picture wxh %dx%d", capsConsolidated.picture_sizes_tbl[0].width,
301                 capsConsolidated.picture_sizes_tbl[0].height);
302 
303         // Consolidate supported preview formats
304         uint32_t supportedPreviewFmtCntMain  = capsMainCam->supported_preview_fmt_cnt;
305         uint32_t supportedPreviewFmtCntAux   = capsAuxCam->supported_preview_fmt_cnt;
306         uint32_t supportedPreviewFmtCntFinal = 0;
307         for (uint32_t i = 0; i < supportedPreviewFmtCntMain; ++i) {
308             for (uint32_t j = 0; j < supportedPreviewFmtCntAux; ++j) {
309                 if (capsMainCam->supported_preview_fmts[i] ==
310                         capsAuxCam->supported_preview_fmts[j]) {
311                     if (supportedPreviewFmtCntFinal != i) {
312                         capsConsolidated.supported_preview_fmts[supportedPreviewFmtCntFinal] =
313                             capsAuxCam->supported_preview_fmts[j];
314                     }
315                     ++supportedPreviewFmtCntFinal;
316                     break;
317                 }
318             }
319         }
320         capsConsolidated.supported_preview_fmt_cnt = supportedPreviewFmtCntFinal;
321 
322         // Consolidate supported picture formats
323         uint32_t supportedPictureFmtCntMain  = capsMainCam->supported_picture_fmt_cnt;
324         uint32_t supportedPictureFmtCntAux   = capsAuxCam->supported_picture_fmt_cnt;
325         uint32_t supportedPictureFmtCntFinal = 0;
326         for (uint32_t i = 0; i < supportedPictureFmtCntMain; ++i) {
327             for (uint32_t j = 0; j < supportedPictureFmtCntAux; ++j) {
328                 if (capsMainCam->supported_picture_fmts[i] ==
329                         capsAuxCam->supported_picture_fmts[j]) {
330                     if (supportedPictureFmtCntFinal != i) {
331                         capsConsolidated.supported_picture_fmts[supportedPictureFmtCntFinal] =
332                             capsAuxCam->supported_picture_fmts[j];
333                     }
334                     ++supportedPictureFmtCntFinal;
335                     break;
336                 }
337             }
338         }
339         capsConsolidated.supported_picture_fmt_cnt = supportedPictureFmtCntFinal;
340 
341         if (mZoomTranslator) {
342             // Copy the opaque calibration data pointer and size
343             mFovControlData.zoomTransInitData.calibData =
344                     capsConsolidated.related_cam_calibration.dc_otp_params;
345             mFovControlData.zoomTransInitData.calibDataSize =
346                     capsConsolidated.related_cam_calibration.dc_otp_size;
347         }
348     }
349     return capsConsolidated;
350 }
351 
352 
353 /*===========================================================================
354  * FUNCTION    : resetVars
355  *
356  * DESCRIPTION : Reset the variables used in FOV-control.
357  *
358  * PARAMETERS  : None
359  *
360  * RETURN      : None
361  *
362  *==========================================================================*/
resetVars()363 void QCameraFOVControl::resetVars()
364 {
365     // Copy the FOV-control settings for camera/camcorder from QCameraFOVControlSettings.h
366     if (mFovControlData.camcorderMode) {
367         mFovControlConfig.snapshotPPConfig.enablePostProcess =
368                 FOVC_CAMCORDER_SNAPSHOT_PP_ENABLE;
369     } else {
370         mFovControlConfig.snapshotPPConfig.enablePostProcess = FOVC_CAM_SNAPSHOT_PP_ENABLE;
371         mFovControlConfig.snapshotPPConfig.zoomMin           = FOVC_CAM_SNAPSHOT_PP_ZOOM_MIN;
372         mFovControlConfig.snapshotPPConfig.zoomMax           = FOVC_CAM_SNAPSHOT_PP_ZOOM_MAX;
373         mFovControlConfig.snapshotPPConfig.luxMin            = FOVC_CAM_SNAPSHOT_PP_LUX_MIN;
374     }
375     mFovControlConfig.auxSwitchBrightnessMin  = FOVC_AUXCAM_SWITCH_LUX_MIN;
376     mFovControlConfig.auxSwitchFocusDistCmMin = FOVC_AUXCAM_SWITCH_FOCUS_DIST_CM_MIN;
377 
378     mFovControlData.fallbackEnabled = FOVC_MAIN_CAM_FALLBACK_MECHANISM;
379 
380     mFovControlConfig.zoomStableCountThreshold       = FOVC_ZOOM_STABLE_COUNT_THRESHOLD;
381     mFovControlConfig.focusDistStableCountThreshold  = FOVC_FOCUS_DIST_STABLE_COUNT_THRESHOLD;
382     mFovControlConfig.brightnessStableCountThreshold = FOVC_BRIGHTNESS_STABLE_COUNT_THRESHOLD;
383 
384     // Reset variables
385     mFovControlData.zoomStableCount       = 0;
386     mFovControlData.brightnessStableCount = 0;
387     mFovControlData.focusDistStableCount  = 0;
388     mFovControlData.zoomDirection         = ZOOM_STABLE;
389     mFovControlData.fallbackToWide        = false;
390 
391     mFovControlData.status3A.main.af.status   = AF_INVALID;
392     mFovControlData.status3A.aux.af.status    = AF_INVALID;
393 
394     mFovControlData.afStatusMain = CAM_AF_STATE_INACTIVE;
395     mFovControlData.afStatusAux  = CAM_AF_STATE_INACTIVE;
396 
397     mFovControlData.wideCamStreaming = false;
398     mFovControlData.teleCamStreaming = false;
399 
400     mFovControlData.spatialAlignResult.readyStatus = 0;
401     mFovControlData.spatialAlignResult.activeCameras = 0;
402     mFovControlData.spatialAlignResult.camMasterHint = 0;
403     mFovControlData.spatialAlignResult.shiftWide.shiftHorz = 0;
404     mFovControlData.spatialAlignResult.shiftWide.shiftVert = 0;
405     mFovControlData.spatialAlignResult.shiftTele.shiftHorz = 0;
406     mFovControlData.spatialAlignResult.shiftTele.shiftVert = 0;
407 
408     // WA for now until the QTI solution is in place writing the spatial alignment ready status
409     mFovControlData.spatialAlignResult.readyStatus = 1;
410 }
411 
412 /*===========================================================================
413  * FUNCTION    : updateConfigSettings
414  *
415  * DESCRIPTION : Update the config settings such as margins and preview size
416  *               and recalculate the transition parameters.
417  *
418  * PARAMETERS  :
419  * @capsMainCam: Capabilities for the main camera
420  * @capsAuxCam : Capabilities for the aux camera
421  *
422  * RETURN :
423  * NO_ERROR           : Success
424  * INVALID_OPERATION  : Failure
425  *
426  *==========================================================================*/
updateConfigSettings(parm_buffer_t * paramsMainCam,parm_buffer_t * paramsAuxCam)427 int32_t QCameraFOVControl::updateConfigSettings(
428         parm_buffer_t* paramsMainCam,
429         parm_buffer_t* paramsAuxCam)
430 {
431     int32_t rc = INVALID_OPERATION;
432 
433     if (paramsMainCam &&
434         paramsAuxCam  &&
435         paramsMainCam->is_valid[CAM_INTF_META_STREAM_INFO] &&
436         paramsAuxCam->is_valid[CAM_INTF_META_STREAM_INFO]) {
437 
438         cam_stream_size_info_t camMainStreamInfo;
439         READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_META_STREAM_INFO, camMainStreamInfo);
440         mFovControlData.camcorderMode = false;
441 
442         // Identify if in camera or camcorder mode
443         for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
444             if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
445                 mFovControlData.camcorderMode = true;
446             }
447         }
448 
449         // Get the margins for the main camera. If video stream is present, the margins correspond
450         // to video stream. Otherwise, margins are copied from preview stream.
451         for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
452             if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
453                 mFovControlData.camMainWidthMargin  = camMainStreamInfo.margins[i].widthMargins;
454                 mFovControlData.camMainHeightMargin = camMainStreamInfo.margins[i].heightMargins;
455             }
456             if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_PREVIEW) {
457                 // Update the preview dimension and ISP output size
458                 mFovControlData.previewSize = camMainStreamInfo.stream_sizes[i];
459                 mFovControlData.ispOutSize  = camMainStreamInfo.stream_sz_plus_margin[i];
460                 if (!mFovControlData.camcorderMode) {
461                     mFovControlData.camMainWidthMargin  =
462                             camMainStreamInfo.margins[i].widthMargins;
463                     mFovControlData.camMainHeightMargin =
464                             camMainStreamInfo.margins[i].heightMargins;
465                     break;
466                 }
467             }
468         }
469 
470         // Get the margins for the aux camera. If video stream is present, the margins correspond
471         // to the video stream. Otherwise, margins are copied from preview stream.
472         cam_stream_size_info_t camAuxStreamInfo;
473         READ_PARAM_ENTRY(paramsAuxCam, CAM_INTF_META_STREAM_INFO, camAuxStreamInfo);
474         for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
475             if (camAuxStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
476                 mFovControlData.camAuxWidthMargin  = camAuxStreamInfo.margins[i].widthMargins;
477                 mFovControlData.camAuxHeightMargin = camAuxStreamInfo.margins[i].heightMargins;
478             }
479             if (camAuxStreamInfo.type[i] == CAM_STREAM_TYPE_PREVIEW) {
480                 // Update the preview dimension
481                 mFovControlData.previewSize = camAuxStreamInfo.stream_sizes[i];
482                 if (!mFovControlData.camcorderMode) {
483                     mFovControlData.camAuxWidthMargin  = camAuxStreamInfo.margins[i].widthMargins;
484                     mFovControlData.camAuxHeightMargin = camAuxStreamInfo.margins[i].heightMargins;
485                     break;
486                 }
487             }
488         }
489 
490 #if 0 // Update to 07.01.01.253.071
491         // Get the sensor out dimensions
492         cam_dimension_t sensorDimMain = {0,0};
493         cam_dimension_t sensorDimAux  = {0,0};
494         if (paramsMainCam->is_valid[CAM_INTF_PARM_RAW_DIMENSION]) {
495             READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_RAW_DIMENSION, sensorDimMain);
496         }
497         if (paramsAuxCam->is_valid[CAM_INTF_PARM_RAW_DIMENSION]) {
498             READ_PARAM_ENTRY(paramsAuxCam, CAM_INTF_PARM_RAW_DIMENSION, sensorDimAux);
499         }
500 #endif // Update to 07.01.01.253.071
501 
502         // Reset the internal variables
503         resetVars();
504 
505         // Recalculate the transition parameters
506         if (calculateBasicFovRatio() && combineFovAdjustment()) {
507 
508             calculateDualCamTransitionParams();
509 
510             // Set initial camera state
511             float zoom = findZoomRatio(mFovControlData.zoomWide) /
512                     (float)mFovControlData.zoomRatioTable[0];
513             if (zoom > mFovControlData.transitionParams.cutOverWideToTele) {
514                 mFovControlResult.camMasterPreview  = mFovControlData.camTele;
515                 mFovControlResult.camMaster3A       = mFovControlData.camTele;
516                 mFovControlResult.activeCameras     = (uint32_t)mFovControlData.camTele;
517                 mFovControlData.camState            = STATE_TELE;
518                 LOGD("start camera state: TELE");
519             } else {
520                 mFovControlResult.camMasterPreview  = mFovControlData.camWide;
521                 mFovControlResult.camMaster3A       = mFovControlData.camWide;
522                 mFovControlResult.activeCameras     = (uint32_t)mFovControlData.camWide;
523                 mFovControlData.camState            = STATE_WIDE;
524                 LOGD("start camera state: WIDE");
525             }
526             mFovControlResult.snapshotPostProcess = false;
527 
528             // Deinit zoom translation lib if needed
529             if (mZoomTranslator && mZoomTranslator->isInitialized()) {
530                 if (mZoomTranslator->deInit() != NO_ERROR) {
531                     ALOGW("deinit failed for zoom translation lib");
532                 }
533             }
534 
535 #if 0 // Update to 07.01.01.253.071
536             // Initialize the zoom translation lib
537             if (mZoomTranslator) {
538                 // Set the initialization data
539                 mFovControlData.zoomTransInitData.previewDimension.width =
540                         mFovControlData.previewSize.width;
541                 mFovControlData.zoomTransInitData.previewDimension.height =
542                         mFovControlData.previewSize.height;
543                 mFovControlData.zoomTransInitData.ispOutDimension.width =
544                         mFovControlData.ispOutSize.width;
545                 mFovControlData.zoomTransInitData.ispOutDimension.height =
546                         mFovControlData.ispOutSize.height;
547                 mFovControlData.zoomTransInitData.sensorOutDimensionMain.width =
548                         sensorDimMain.width;
549                 mFovControlData.zoomTransInitData.sensorOutDimensionMain.height =
550                         sensorDimMain.height;
551                 mFovControlData.zoomTransInitData.sensorOutDimensionAux.width =
552                         sensorDimAux.width;
553                 mFovControlData.zoomTransInitData.sensorOutDimensionAux.height =
554                         sensorDimAux.height;
555                 mFovControlData.zoomTransInitData.zoomRatioTable =
556                         mFovControlData.zoomRatioTable;
557                 mFovControlData.zoomTransInitData.zoomRatioTableCount =
558                         mFovControlData.zoomRatioTableCount;
559                 mFovControlData.zoomTransInitData.mode = mFovControlData.camcorderMode ?
560                         MODE_CAMCORDER : MODE_CAMERA;
561 
562                 if(mZoomTranslator->init(mFovControlData.zoomTransInitData) != NO_ERROR) {
563                     LOGE("init failed for zoom translation lib");
564 
565                     // deinitialize the zoom translator and set to NULL
566                     mZoomTranslator->deInit();
567                     mZoomTranslator = NULL;
568                 }
569             }
570 #endif // Update to 07.01.01.253.071
571 
572             // FOV-control config is complete for the current use case
573             mFovControlData.configCompleted = true;
574             rc = NO_ERROR;
575         }
576     }
577 
578     return rc;
579 }
580 
581 
582 /*===========================================================================
583  * FUNCTION   : translateInputParams
584  *
585  * DESCRIPTION: Translate a subset of input parameters from main camera. As main
586  *              and aux cameras have different properties/params, this translation
587  *              is needed before the input parameters are sent to the aux camera.
588  *
589  * PARAMETERS :
590  * @paramsMainCam : Input parameters for main camera
591  * @paramsAuxCam  : Input parameters for aux camera
592  *
593  * RETURN :
594  * NO_ERROR           : Success
595  * INVALID_OPERATION  : Failure
596  *
597  *==========================================================================*/
translateInputParams(parm_buffer_t * paramsMainCam,parm_buffer_t * paramsAuxCam)598 int32_t QCameraFOVControl::translateInputParams(
599         parm_buffer_t* paramsMainCam,
600         parm_buffer_t* paramsAuxCam)
601 {
602     int32_t rc = INVALID_OPERATION;
603     if (paramsMainCam && paramsAuxCam) {
604         // First copy all the parameters from main to aux and then translate the subset
605         memcpy(paramsAuxCam, paramsMainCam, sizeof(parm_buffer_t));
606 
607         // Translate zoom
608         if (paramsMainCam->is_valid[CAM_INTF_PARM_ZOOM]) {
609             uint32_t userZoom = 0;
610             READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_ZOOM, userZoom);
611             convertUserZoomToWideAndTele(userZoom);
612 
613             // Update zoom values in the param buffers
614             uint32_t zoomMain = isMainCamFovWider() ?
615                     mFovControlData.zoomWide : mFovControlData.zoomTele;
616             ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_ZOOM, zoomMain);
617 
618             uint32_t zoomAux = isMainCamFovWider() ?
619                     mFovControlData.zoomTele : mFovControlData.zoomWide;
620             ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_ZOOM, zoomAux);
621 
622             // Write the user zoom in main and aux param buffers
623             // The user zoom will always correspond to the wider camera
624             paramsMainCam->is_valid[CAM_INTF_PARM_DC_USERZOOM] = 1;
625             paramsAuxCam->is_valid[CAM_INTF_PARM_DC_USERZOOM]  = 1;
626 
627             ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_DC_USERZOOM,
628                     mFovControlData.zoomWide);
629             ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_DC_USERZOOM,
630                     mFovControlData.zoomWide);
631 
632             // Generate FOV-control result
633             generateFovControlResult();
634         }
635 
636         // Translate focus areas
637         if (paramsMainCam->is_valid[CAM_INTF_PARM_AF_ROI]) {
638             cam_roi_info_t roiAfMain;
639             cam_roi_info_t roiAfAux;
640             READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_AF_ROI, roiAfMain);
641             if (roiAfMain.num_roi > 0) {
642                 roiAfAux = translateFocusAreas(roiAfMain, CAM_TYPE_AUX);
643                 roiAfMain = translateFocusAreas(roiAfMain, CAM_TYPE_MAIN);
644                 ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_AF_ROI, roiAfAux);
645                 ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_AF_ROI, roiAfMain);
646             }
647         }
648 
649         // Translate metering areas
650         if (paramsMainCam->is_valid[CAM_INTF_PARM_AEC_ROI]) {
651             cam_set_aec_roi_t roiAecMain;
652             cam_set_aec_roi_t roiAecAux;
653             READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_AEC_ROI, roiAecMain);
654             if (roiAecMain.aec_roi_enable == CAM_AEC_ROI_ON) {
655                 roiAecAux = translateMeteringAreas(roiAecMain, CAM_TYPE_AUX);
656                 roiAecMain = translateMeteringAreas(roiAecMain, CAM_TYPE_MAIN);
657                 ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_AEC_ROI, roiAecAux);
658                 ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_AEC_ROI, roiAecMain);
659             }
660         }
661         rc = NO_ERROR;
662     }
663     return rc;
664 }
665 
666 
667 /*===========================================================================
668  * FUNCTION   : processResultMetadata
669  *
670  * DESCRIPTION: Process the metadata from main and aux cameras to generate the
671  *              result metadata. The result metadata should be the metadata
672  *              coming from the master camera. If aux camera is master, the
673  *              subset of the metadata needs to be translated to main as that's
674  *              the only camera seen by the application.
675  *
676  * PARAMETERS :
677  * @metaMain  : metadata for main camera
678  * @metaAux   : metadata for aux camera
679  *
680  * RETURN :
681  * Result metadata for the logical camera. After successfully processing main
682  * and aux metadata, the result metadata points to either main or aux metadata
683  * based on which one was the master. In case of failure, it returns NULL.
684  *==========================================================================*/
processResultMetadata(metadata_buffer_t * metaMain,metadata_buffer_t * metaAux)685 metadata_buffer_t* QCameraFOVControl::processResultMetadata(
686         metadata_buffer_t*  metaMain,
687         metadata_buffer_t*  metaAux)
688 {
689     metadata_buffer_t* metaResult = NULL;
690 
691     if (metaMain || metaAux) {
692         metadata_buffer_t *meta   = metaMain ? metaMain : metaAux;
693         cam_sync_type_t masterCam = mFovControlResult.camMasterPreview;
694 
695         mMutex.lock();
696         // Book-keep the needed metadata from main camera and aux camera
697         IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
698                 CAM_INTF_META_DC_SAC_OUTPUT_INFO, meta) {
699 
700             // Get master camera hint
701             if (spatialAlignOutput->is_master_hint_valid) {
702                 uint8_t master = spatialAlignOutput->master_hint;
703                 if (master == CAM_ROLE_WIDE) {
704                     mFovControlData.spatialAlignResult.camMasterHint = mFovControlData.camWide;
705                 } else if (master == CAM_ROLE_TELE) {
706                     mFovControlData.spatialAlignResult.camMasterHint = mFovControlData.camTele;
707                 }
708             }
709 
710             // Get master camera used for the preview in the frame corresponding to this metadata
711             if (spatialAlignOutput->is_master_preview_valid) {
712                 uint8_t master = spatialAlignOutput->master_preview;
713                 if (master == CAM_ROLE_WIDE) {
714                     masterCam = mFovControlData.camWide;
715                     mFovControlData.spatialAlignResult.camMasterPreview = masterCam;
716                 } else if (master == CAM_ROLE_TELE) {
717                     masterCam = mFovControlData.camTele;
718                     mFovControlData.spatialAlignResult.camMasterPreview = masterCam;
719                 }
720             }
721 
722             // Get master camera used for 3A in the frame corresponding to this metadata
723             if (spatialAlignOutput->is_master_3A_valid) {
724                 uint8_t master = spatialAlignOutput->master_3A;
725                 if (master == CAM_ROLE_WIDE) {
726                     mFovControlData.spatialAlignResult.camMaster3A = mFovControlData.camWide;
727                 } else if (master == CAM_ROLE_TELE) {
728                     mFovControlData.spatialAlignResult.camMaster3A = mFovControlData.camTele;
729                 }
730             }
731 
732             // Get spatial alignment ready status
733             if (spatialAlignOutput->is_ready_status_valid) {
734                 mFovControlData.spatialAlignResult.readyStatus = spatialAlignOutput->ready_status;
735             }
736         }
737 
738         metadata_buffer_t *metaWide = isMainCamFovWider() ? metaMain : metaAux;
739         metadata_buffer_t *metaTele = isMainCamFovWider() ? metaAux : metaMain;
740 
741         // Get spatial alignment output info for wide camera
742         if (metaWide) {
743             IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
744                 CAM_INTF_META_DC_SAC_OUTPUT_INFO, metaWide) {
745                 // Get spatial alignment output shift for wide camera
746 
747                 if (spatialAlignOutput->is_output_shift_valid) {
748                     // Calculate the spatial alignment shift for the current stream dimensions based
749                     // on the reference resolution used for the output shift.
750                     float horzShiftFactor = (float)mFovControlData.previewSize.width /
751                             spatialAlignOutput->reference_res_for_output_shift.width;
752                     float vertShiftFactor = (float)mFovControlData.previewSize.height /
753                             spatialAlignOutput->reference_res_for_output_shift.height;
754 
755                     mFovControlData.spatialAlignResult.shiftWide.shiftHorz =
756                             spatialAlignOutput->output_shift.shift_horz * horzShiftFactor;
757                     mFovControlData.spatialAlignResult.shiftWide.shiftVert =
758                             spatialAlignOutput->output_shift.shift_vert * vertShiftFactor;
759 
760                     LOGD("SAC output shift for Wide: x:%d, y:%d",
761                             mFovControlData.spatialAlignResult.shiftWide.shiftHorz,
762                             mFovControlData.spatialAlignResult.shiftWide.shiftVert);
763                 }
764 
765                 // Get the AF roi shift for wide camera
766                 if (spatialAlignOutput->is_focus_roi_shift_valid) {
767                     // Calculate the spatial alignment shift for the current stream dimensions based
768                     // on the reference resolution used for the output shift.
769                     float horzShiftFactor = (float)mFovControlData.previewSize.width /
770                             spatialAlignOutput->reference_res_for_focus_roi_shift.width;
771                     float vertShiftFactor = (float)mFovControlData.previewSize.height /
772                             spatialAlignOutput->reference_res_for_focus_roi_shift.height;
773 
774                     mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz =
775                             spatialAlignOutput->focus_roi_shift.shift_horz * horzShiftFactor;
776                     mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert =
777                             spatialAlignOutput->focus_roi_shift.shift_vert * vertShiftFactor;
778 
779                     LOGD("SAC AF ROI shift for Wide: x:%d, y:%d",
780                             mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz,
781                             mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert);
782                 }
783             }
784         }
785 
786         // Get spatial alignment output info for tele camera
787         if (metaTele) {
788             IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
789                 CAM_INTF_META_DC_SAC_OUTPUT_INFO, metaTele) {
790 
791                 // Get spatial alignment output shift for tele camera
792                 if (spatialAlignOutput->is_output_shift_valid) {
793                     // Calculate the spatial alignment shift for the current stream dimensions based
794                     // on the reference resolution used for the output shift.
795                     float horzShiftFactor = (float)mFovControlData.previewSize.width /
796                             spatialAlignOutput->reference_res_for_output_shift.width;
797                     float vertShiftFactor = (float)mFovControlData.previewSize.height /
798                             spatialAlignOutput->reference_res_for_output_shift.height;
799 
800                     mFovControlData.spatialAlignResult.shiftTele.shiftHorz =
801                             spatialAlignOutput->output_shift.shift_horz * horzShiftFactor;
802                     mFovControlData.spatialAlignResult.shiftTele.shiftVert =
803                             spatialAlignOutput->output_shift.shift_vert * vertShiftFactor;
804 
805                     LOGD("SAC output shift for Tele: x:%d, y:%d",
806                             mFovControlData.spatialAlignResult.shiftTele.shiftHorz,
807                             mFovControlData.spatialAlignResult.shiftTele.shiftVert);
808                 }
809 
810                 // Get the AF roi shift for tele camera
811                 if (spatialAlignOutput->is_focus_roi_shift_valid) {
812                     // Calculate the spatial alignment shift for the current stream dimensions based
813                     // on the reference resolution used for the output shift.
814                     float horzShiftFactor = (float)mFovControlData.previewSize.width /
815                             spatialAlignOutput->reference_res_for_focus_roi_shift.width;
816                     float vertShiftFactor = (float)mFovControlData.previewSize.height /
817                             spatialAlignOutput->reference_res_for_focus_roi_shift.height;
818 
819                     mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz =
820                             spatialAlignOutput->focus_roi_shift.shift_horz * horzShiftFactor;
821                     mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert =
822                             spatialAlignOutput->focus_roi_shift.shift_vert * vertShiftFactor;
823 
824                     LOGD("SAC AF ROI shift for Tele: x:%d, y:%d",
825                             mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz,
826                             mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert);
827                 }
828             }
829         }
830 
831         // Update the camera streaming status
832         if (metaWide) {
833             mFovControlData.wideCamStreaming = true;
834             IF_META_AVAILABLE(uint8_t, enableLPM, CAM_INTF_META_DC_LOW_POWER_ENABLE, metaWide) {
835                 if (*enableLPM) {
836                     // If LPM enabled is 1, this is probably the last metadata returned
837                     // before going into LPM state
838                     mFovControlData.wideCamStreaming = false;
839 
840                     // Update active cameras requested by spatial alignment
841                     mFovControlData.spatialAlignResult.activeCameras &= ~mFovControlData.camWide;
842                 } else {
843                     mFovControlData.spatialAlignResult.activeCameras |= mFovControlData.camWide;
844                 }
845             }
846         }
847 
848         if (metaTele) {
849             mFovControlData.teleCamStreaming = true;
850             IF_META_AVAILABLE(uint8_t, enableLPM, CAM_INTF_META_DC_LOW_POWER_ENABLE, metaTele) {
851                 if (*enableLPM) {
852                     // If LPM enabled is 1, this is probably the last metadata returned
853                     // before going into LPM state
854                     mFovControlData.teleCamStreaming = false;
855 
856                     // Update active cameras requested by spatial alignment
857                     mFovControlData.spatialAlignResult.activeCameras &= ~mFovControlData.camTele;
858                 } else {
859                     mFovControlData.spatialAlignResult.activeCameras |= mFovControlData.camTele;
860                 }
861             }
862         }
863 
864         // Get AF status
865         if (metaMain) {
866             IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaMain) {
867                 if ((*afState) != CAM_AF_STATE_INACTIVE) {
868                     mFovControlData.status3A.main.af.status = AF_VALID;
869                 } else {
870                     mFovControlData.status3A.main.af.status = AF_INVALID;
871                 }
872                 mFovControlData.afStatusMain = *afState;
873                 LOGD("AF state: Main cam: %d", mFovControlData.afStatusMain);
874             }
875 
876             IF_META_AVAILABLE(float, luxIndex, CAM_INTF_META_AEC_LUX_INDEX, metaMain) {
877                 mFovControlData.status3A.main.ae.luxIndex = *luxIndex;
878                 LOGD("Lux Index: Main cam: %f", mFovControlData.status3A.main.ae.luxIndex);
879             }
880 
881             IF_META_AVAILABLE(int32_t, objDist, CAM_INTF_META_AF_OBJ_DIST_CM, metaMain) {
882                 mFovControlData.status3A.main.af.focusDistCm = (*objDist < 0) ? 0 : *objDist;
883                 LOGD("Obj Dist: Main cam: %d", mFovControlData.status3A.main.af.focusDistCm);
884             }
885         }
886         if (metaAux) {
887             IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaAux) {
888                 if ((*afState) != CAM_AF_STATE_INACTIVE) {
889                     mFovControlData.status3A.aux.af.status = AF_VALID;
890                 } else {
891                     mFovControlData.status3A.aux.af.status = AF_INVALID;
892                 }
893                 mFovControlData.afStatusAux = *afState;
894                 LOGD("AF state: Aux cam: %d", mFovControlData.afStatusAux);
895             }
896 
897             IF_META_AVAILABLE(float, luxIndex, CAM_INTF_META_AEC_LUX_INDEX, metaAux) {
898                 mFovControlData.status3A.aux.ae.luxIndex = *luxIndex;
899                 LOGD("Lux Index: Aux cam: %f", mFovControlData.status3A.aux.ae.luxIndex);
900             }
901 
902             IF_META_AVAILABLE(int32_t, objDist, CAM_INTF_META_AF_OBJ_DIST_CM, metaAux) {
903                 mFovControlData.status3A.aux.af.focusDistCm = (*objDist < 0) ? 0 : *objDist;
904                 LOGD("Obj Dist: Aux cam: %d", mFovControlData.status3A.aux.af.focusDistCm);
905             }
906         }
907 
908         if ((masterCam == CAM_TYPE_AUX) && metaAux) {
909             // Translate face detection ROI from aux camera
910             IF_META_AVAILABLE(cam_face_detection_data_t, metaFD,
911                     CAM_INTF_META_FACE_DETECTION, metaAux) {
912                 cam_face_detection_data_t metaFDTranslated;
913                 metaFDTranslated = translateRoiFD(*metaFD, CAM_TYPE_AUX);
914                 ADD_SET_PARAM_ENTRY_TO_BATCH(metaAux, CAM_INTF_META_FACE_DETECTION,
915                         metaFDTranslated);
916             }
917             metaResult = metaAux;
918         }
919         else if ((masterCam == CAM_TYPE_MAIN) && metaMain) {
920             // Translate face detection ROI from main camera
921             IF_META_AVAILABLE(cam_face_detection_data_t, metaFD,
922                     CAM_INTF_META_FACE_DETECTION, metaMain) {
923                 cam_face_detection_data_t metaFDTranslated;
924                 metaFDTranslated = translateRoiFD(*metaFD, CAM_TYPE_MAIN);
925                 ADD_SET_PARAM_ENTRY_TO_BATCH(metaMain, CAM_INTF_META_FACE_DETECTION,
926                         metaFDTranslated);
927             }
928             metaResult = metaMain;
929         } else {
930             // Metadata for the master camera was dropped
931             metaResult = NULL;
932         }
933 
934         // If snapshot postprocess is enabled, consolidate the AF status to be sent to the app
935         // when in the transition state.
936         // Only return focused if both are focused.
937         if ((mFovControlResult.snapshotPostProcess == true) &&
938                     (mFovControlData.camState == STATE_TRANSITION) &&
939                     metaResult) {
940             if (((mFovControlData.afStatusMain == CAM_AF_STATE_FOCUSED_LOCKED) ||
941                     (mFovControlData.afStatusMain == CAM_AF_STATE_NOT_FOCUSED_LOCKED)) &&
942                     ((mFovControlData.afStatusAux == CAM_AF_STATE_FOCUSED_LOCKED) ||
943                     (mFovControlData.afStatusAux == CAM_AF_STATE_NOT_FOCUSED_LOCKED))) {
944                 // If both indicate focused, return focused.
945                 // If either one indicates 'not focused', return 'not focused'.
946                 if ((mFovControlData.afStatusMain == CAM_AF_STATE_FOCUSED_LOCKED) &&
947                         (mFovControlData.afStatusAux  == CAM_AF_STATE_FOCUSED_LOCKED)) {
948                     ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
949                             CAM_AF_STATE_FOCUSED_LOCKED);
950                 } else {
951                     ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
952                             CAM_AF_STATE_NOT_FOCUSED_LOCKED);
953                 }
954             } else {
955                 // If either one indicates passive state or active scan, return that state
956                 if ((mFovControlData.afStatusMain != CAM_AF_STATE_FOCUSED_LOCKED) &&
957                         (mFovControlData.afStatusMain != CAM_AF_STATE_NOT_FOCUSED_LOCKED)) {
958                     ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
959                             mFovControlData.afStatusMain);
960                 } else {
961                     ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
962                             mFovControlData.afStatusAux);
963                 }
964             }
965             IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaResult) {
966                 LOGD("Result AF state: %d", *afState);
967             }
968         }
969 
970         mMutex.unlock();
971 
972         // Generate FOV-control result only if the result meta is valid
973         if (metaResult) {
974             generateFovControlResult();
975         }
976     }
977     return metaResult;
978 }
979 
980 
981 /*===========================================================================
982  * FUNCTION   : generateFovControlResult
983  *
984  * DESCRIPTION: Generate FOV control result
985  *
986  * PARAMETERS : None
987  *
988  * RETURN     : None
989  *
990  *==========================================================================*/
generateFovControlResult()991 void QCameraFOVControl::generateFovControlResult()
992 {
993     Mutex::Autolock lock(mMutex);
994 
995     float zoom = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
996     uint32_t zoomWide     = mFovControlData.zoomWide;
997     uint32_t zoomWidePrev = mFovControlData.zoomWidePrev;
998 
999     if (mFovControlData.configCompleted == false) {
1000         // Return as invalid result if the FOV-control configuration is not yet complete
1001         mFovControlResult.isValid = false;
1002         return;
1003     }
1004 
1005     // Update previous zoom value
1006     mFovControlData.zoomWidePrev = mFovControlData.zoomWide;
1007 
1008     uint32_t  currentBrightness = 0;
1009     uint32_t  currentFocusDist  = 0;
1010 
1011     if (mFovControlResult.camMasterPreview == CAM_TYPE_MAIN) {
1012         currentBrightness = mFovControlData.status3A.main.ae.luxIndex;
1013         currentFocusDist  = mFovControlData.status3A.main.af.focusDistCm;
1014     } else if (mFovControlResult.camMasterPreview == CAM_TYPE_AUX) {
1015         currentBrightness = mFovControlData.status3A.aux.ae.luxIndex;
1016         currentFocusDist  = mFovControlData.status3A.aux.af.focusDistCm;
1017     }
1018 
1019     float transitionLow     = mFovControlData.transitionParams.transitionLow;
1020     float transitionHigh    = mFovControlData.transitionParams.transitionHigh;
1021     float cutOverWideToTele = mFovControlData.transitionParams.cutOverWideToTele;
1022     float cutOverTeleToWide = mFovControlData.transitionParams.cutOverTeleToWide;
1023 
1024     cam_sync_type_t camWide = mFovControlData.camWide;
1025     cam_sync_type_t camTele = mFovControlData.camTele;
1026 
1027     uint16_t thresholdBrightness = mFovControlConfig.auxSwitchBrightnessMin;
1028     uint16_t thresholdFocusDist  = mFovControlConfig.auxSwitchFocusDistCmMin;
1029 
1030     if (zoomWide == zoomWidePrev) {
1031         mFovControlData.zoomDirection = ZOOM_STABLE;
1032         ++mFovControlData.zoomStableCount;
1033     } else if (zoomWide > zoomWidePrev) {
1034         mFovControlData.zoomDirection   = ZOOM_IN;
1035         mFovControlData.zoomStableCount = 0;
1036     } else {
1037         mFovControlData.zoomDirection   = ZOOM_OUT;
1038         mFovControlData.zoomStableCount = 0;
1039     }
1040 
1041     // Update snapshot post-process flags
1042     if (mFovControlConfig.snapshotPPConfig.enablePostProcess &&
1043         (zoom >= mFovControlConfig.snapshotPPConfig.zoomMin) &&
1044         (zoom <= mFovControlConfig.snapshotPPConfig.zoomMax)) {
1045         mFovControlResult.snapshotPostProcessZoomRange = true;
1046     } else {
1047         mFovControlResult.snapshotPostProcessZoomRange = false;
1048     }
1049 
1050     if (mFovControlResult.snapshotPostProcessZoomRange &&
1051         (currentBrightness >= mFovControlConfig.snapshotPPConfig.luxMin) &&
1052         (currentFocusDist  >= mFovControlConfig.snapshotPPConfig.focusDistanceMin)) {
1053         mFovControlResult.snapshotPostProcess = true;
1054     } else {
1055         mFovControlResult.snapshotPostProcess = false;
1056     }
1057 
1058     switch (mFovControlData.camState) {
1059         case STATE_WIDE:
1060             // If the scene continues to be bright, update stable count; reset otherwise
1061             if (currentBrightness >= thresholdBrightness) {
1062                 ++mFovControlData.brightnessStableCount;
1063             } else {
1064                 mFovControlData.brightnessStableCount = 0;
1065             }
1066 
1067             // If the scene continues to be non-macro, update stable count; reset otherwise
1068             if (currentFocusDist >= thresholdFocusDist) {
1069                 ++mFovControlData.focusDistStableCount;
1070             } else {
1071                 mFovControlData.focusDistStableCount = 0;
1072             }
1073 
1074             // Reset fallback to main flag if zoom is less than cutover point
1075             if (zoom <= cutOverTeleToWide) {
1076                 mFovControlData.fallbackToWide = false;
1077             }
1078 
1079             // Check if the scene is good for aux (bright and far focused)
1080             if ((currentBrightness >= thresholdBrightness) &&
1081                 (currentFocusDist >= thresholdFocusDist)) {
1082                 // Lower constraint if zooming in or if snapshot postprocessing is true
1083                 if (mFovControlResult.snapshotPostProcess ||
1084                     (((zoom >= transitionLow) ||
1085                      (sacRequestedDualZone())) &&
1086                     (mFovControlData.zoomDirection == ZOOM_IN) &&
1087                     (mFovControlData.fallbackToWide == false))) {
1088                     mFovControlData.camState = STATE_TRANSITION;
1089                     mFovControlResult.activeCameras = (camWide | camTele);
1090                 }
1091                 // Higher constraint if not zooming in
1092                 else if ((zoom > cutOverWideToTele) &&
1093                     (mFovControlData.brightnessStableCount >=
1094                             mFovControlConfig.brightnessStableCountThreshold) &&
1095                     (mFovControlData.focusDistStableCount  >=
1096                             mFovControlConfig.focusDistStableCountThreshold)) {
1097                     // Enter the transition state
1098                     mFovControlData.camState = STATE_TRANSITION;
1099                     mFovControlResult.activeCameras = (camWide | camTele);
1100 
1101                     // Reset fallback to wide flag
1102                     mFovControlData.fallbackToWide = false;
1103 
1104                     // Reset zoom stable count
1105                     mFovControlData.zoomStableCount = 0;
1106                 }
1107             }
1108             break;
1109 
1110         case STATE_TRANSITION:
1111             // Reset brightness stable count
1112             mFovControlData.brightnessStableCount = 0;
1113             // Reset focus distance stable count
1114             mFovControlData.focusDistStableCount  = 0;
1115 
1116             // Set the master info
1117             // Switch to wide
1118             if ((mFovControlResult.camMasterPreview == camTele) &&
1119                 canSwitchMasterTo(CAM_TYPE_WIDE)) {
1120                 mFovControlResult.camMasterPreview = camWide;
1121                 mFovControlResult.camMaster3A      = camWide;
1122             }
1123             // switch to tele
1124             else if ((mFovControlResult.camMasterPreview == camWide) &&
1125                     canSwitchMasterTo(CAM_TYPE_TELE)) {
1126                 mFovControlResult.camMasterPreview = camTele;
1127                 mFovControlResult.camMaster3A      = camTele;
1128             }
1129 
1130             // Change the transition state if necessary.
1131             // If fallback to wide is initiated, try to move to wide state
1132             if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
1133                 if (mFovControlResult.camMasterPreview == camWide) {
1134                     mFovControlData.camState        = STATE_WIDE;
1135                     mFovControlResult.activeCameras = camWide;
1136                 }
1137             }
1138             // If snapshot post processing is required, do not change the state.
1139             else if (mFovControlResult.snapshotPostProcess == false) {
1140                 if ((zoom < transitionLow) &&
1141                         !sacRequestedDualZone() &&
1142                         (mFovControlResult.camMasterPreview == camWide)) {
1143                     mFovControlData.camState        = STATE_WIDE;
1144                     mFovControlResult.activeCameras = camWide;
1145                 } else if ((zoom > transitionHigh) &&
1146                         !sacRequestedDualZone() &&
1147                         (mFovControlResult.camMasterPreview == camTele)) {
1148                     mFovControlData.camState        = STATE_TELE;
1149                     mFovControlResult.activeCameras = camTele;
1150                 } else if (mFovControlData.zoomStableCount >=
1151                         mFovControlConfig.zoomStableCountThreshold) {
1152                     // If the zoom is stable put the non-master camera to LPM for power optimization
1153                     if (mFovControlResult.camMasterPreview == camWide) {
1154                         mFovControlData.camState        = STATE_WIDE;
1155                         mFovControlResult.activeCameras = camWide;
1156                     } else {
1157                         mFovControlData.camState        = STATE_TELE;
1158                         mFovControlResult.activeCameras = camTele;
1159                     }
1160                 }
1161             }
1162             break;
1163 
1164         case STATE_TELE:
1165             // If the scene continues to be dark, update stable count; reset otherwise
1166             if (currentBrightness < thresholdBrightness) {
1167                 ++mFovControlData.brightnessStableCount;
1168             } else {
1169                 mFovControlData.brightnessStableCount = 0;
1170             }
1171 
1172             // If the scene continues to be macro, update stable count; reset otherwise
1173             if (currentFocusDist < thresholdFocusDist) {
1174                 ++mFovControlData.focusDistStableCount;
1175             } else {
1176                 mFovControlData.focusDistStableCount = 0;
1177             }
1178 
1179             // Lower constraint if zooming out or if the snapshot postprocessing is true
1180             if (mFovControlResult.snapshotPostProcess ||
1181                     (((zoom <= transitionHigh) || sacRequestedDualZone()) &&
1182                     (mFovControlData.zoomDirection == ZOOM_OUT))) {
1183                 mFovControlData.camState = STATE_TRANSITION;
1184                 mFovControlResult.activeCameras = (camWide | camTele);
1185             }
1186             // Higher constraint if not zooming out. Only if fallback is enabled
1187             else if (((currentBrightness < thresholdBrightness) ||
1188                     (currentFocusDist < thresholdFocusDist)) &&
1189                     mFovControlData.fallbackEnabled) {
1190                 // Enter transition state if brightness or focus distance is below threshold
1191                 if ((mFovControlData.brightnessStableCount >=
1192                         mFovControlConfig.brightnessStableCountThreshold) ||
1193                     (mFovControlData.focusDistStableCount  >=
1194                         mFovControlConfig.focusDistStableCountThreshold)) {
1195                     mFovControlData.camState = STATE_TRANSITION;
1196                     mFovControlResult.activeCameras = (camWide | camTele);
1197 
1198                     // Reset zoom stable count and set fallback flag to true
1199                     mFovControlData.zoomStableCount = 0;
1200                     mFovControlData.fallbackToWide  = true;
1201                     LOGD("Low light/Macro scene - fall back to Wide from Tele");
1202                 }
1203             }
1204             break;
1205     }
1206 
1207     // Update snapshot postprocess result based on fall back to wide decision
1208     if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
1209         mFovControlResult.snapshotPostProcess = false;
1210     }
1211 
1212     mFovControlResult.isValid = true;
1213     // Debug print for the FOV-control result
1214     LOGD("Effective zoom: %f", zoom);
1215     LOGD("zoom direction: %d", (uint32_t)mFovControlData.zoomDirection);
1216     LOGD("zoomWide: %d, zoomTele: %d", zoomWide, mFovControlData.zoomTele);
1217     LOGD("Snapshot postprocess: %d", mFovControlResult.snapshotPostProcess);
1218     LOGD("Master camera            : %s", (mFovControlResult.camMasterPreview == CAM_TYPE_MAIN) ?
1219             "CAM_TYPE_MAIN" : "CAM_TYPE_AUX");
1220     LOGD("Master camera for preview: %s",
1221             (mFovControlResult.camMasterPreview == camWide ) ? "Wide" : "Tele");
1222     LOGD("Master camera for 3A     : %s",
1223             (mFovControlResult.camMaster3A == camWide ) ? "Wide" : "Tele");
1224     LOGD("Wide camera status : %s",
1225             (mFovControlResult.activeCameras & camWide) ? "Active" : "LPM");
1226     LOGD("Tele camera status : %s",
1227             (mFovControlResult.activeCameras & camTele) ? "Active" : "LPM");
1228     LOGD("transition state: %s", ((mFovControlData.camState == STATE_WIDE) ? "STATE_WIDE" :
1229             ((mFovControlData.camState == STATE_TELE) ? "STATE_TELE" : "STATE_TRANSITION" )));
1230 }
1231 
1232 
1233 /*===========================================================================
1234  * FUNCTION   : getFovControlResult
1235  *
1236  * DESCRIPTION: Return FOV-control result
1237  *
1238  * PARAMETERS : None
1239  *
1240  * RETURN     : FOV-control result
1241  *
1242  *==========================================================================*/
getFovControlResult()1243  fov_control_result_t QCameraFOVControl::getFovControlResult()
1244 {
1245     Mutex::Autolock lock(mMutex);
1246     fov_control_result_t fovControlResult = mFovControlResult;
1247     return fovControlResult;
1248 }
1249 
1250 
1251 /*===========================================================================
1252  * FUNCTION    : isMainCamFovWider
1253  *
1254  * DESCRIPTION : Check if the main camera FOV is wider than aux
1255  *
1256  * PARAMETERS  : None
1257  *
1258  * RETURN      :
1259  * true        : If main cam FOV is wider than tele
1260  * false       : If main cam FOV is narrower than tele
1261  *
1262  *==========================================================================*/
isMainCamFovWider()1263 inline bool QCameraFOVControl::isMainCamFovWider()
1264 {
1265     if (mDualCamParams.paramsMain.focalLengthMm <
1266             mDualCamParams.paramsAux.focalLengthMm) {
1267         return true;
1268     } else {
1269         return false;
1270     }
1271 }
1272 
1273 
1274 /*===========================================================================
1275  * FUNCTION    : sacRequestedDualZone
1276  *
1277  * DESCRIPTION : Check if Spatial alignment block requested both the cameras to be active.
1278  *               The request is valid only when LPM is enabled.
1279  *
1280  * PARAMETERS  : None
1281  *
1282  * RETURN      :
1283  * true        : If dual zone is requested with LPM enabled
1284  * false       : If LPM is disabled or if dual zone is not requested with LPM enabled
1285  *
1286  *==========================================================================*/
sacRequestedDualZone()1287 inline bool QCameraFOVControl::sacRequestedDualZone()
1288 {
1289     bool ret = false;
1290     cam_sync_type_t camWide = mFovControlData.camWide;
1291     cam_sync_type_t camTele = mFovControlData.camTele;
1292 
1293     // Return true if Spatial alignment block requested both the cameras to be active
1294     // in the case of lpm enabled
1295     if ((mFovControlData.spatialAlignResult.activeCameras == (camWide | camTele)) &&
1296             (mFovControlData.lpmEnabled)) {
1297         ret = true;
1298     }
1299     return ret;
1300 }
1301 
1302 
1303 /*===========================================================================
1304  * FUNCTION    : canSwitchMasterTo
1305  *
1306  * DESCRIPTION : Check if the master can be switched to the camera- cam.
1307  *
1308  * PARAMETERS  :
1309  * @cam        : cam type
1310  *
1311  * RETURN      :
1312  * true        : If master can be switched
1313  * false       : If master cannot be switched
1314  *
1315  *==========================================================================*/
canSwitchMasterTo(cam_type cam)1316 bool QCameraFOVControl::canSwitchMasterTo(
1317         cam_type cam)
1318 {
1319     bool ret = false;
1320     float zoom = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
1321     float cutOverWideToTele = mFovControlData.transitionParams.cutOverWideToTele;
1322     float cutOverTeleToWide = mFovControlData.transitionParams.cutOverTeleToWide;
1323     af_status afStatusAux   = mFovControlData.status3A.aux.af.status;
1324 
1325     char prop[PROPERTY_VALUE_MAX];
1326     int override = 0;
1327     property_get("persist.camera.fovc.override", prop, "0");
1328     override = atoi(prop);
1329     if(override) {
1330         afStatusAux = AF_VALID;
1331     }
1332 
1333     if (cam == CAM_TYPE_WIDE) {
1334         if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
1335             // In case of OEM Spatial alignment solution, check the spatial alignment ready
1336             if (mFovControlData.wideCamStreaming && isSpatialAlignmentReady()) {
1337                 ret = true;
1338             }
1339         } else {
1340             // In case of QTI Spatial alignment solution and no spatial alignment solution,
1341             // check the fallback flag or if the zoom level has crossed the threhold.
1342             if ((mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) ||
1343                     (zoom < cutOverTeleToWide)) {
1344                  if (mFovControlData.wideCamStreaming) {
1345                     ret = true;
1346                  }
1347             }
1348         }
1349     } else if (cam == CAM_TYPE_TELE) {
1350         if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
1351             // If fallback to wide is initiated, don't switch the master to tele
1352             ret = false;
1353         } else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
1354             // In case of OEM Spatial alignment solution, check the spatial alignment ready and
1355             // af status
1356             if (mFovControlData.teleCamStreaming &&
1357                     isSpatialAlignmentReady() &&
1358                     (afStatusAux == AF_VALID)) {
1359                 ret = true;
1360             }
1361         } else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_QTI) {
1362             // In case of QTI Spatial alignment solution check the spatial alignment ready flag,
1363             // af status and if the zoom level has crossed the threhold.
1364             if ((zoom > cutOverWideToTele) &&
1365                     isSpatialAlignmentReady() &&
1366                     (afStatusAux == AF_VALID)) {
1367                 ret = true;
1368             }
1369         } else {
1370             // In case of no spatial alignment solution check af status and
1371             // if the zoom level has crossed the threhold.
1372             if ((zoom > cutOverWideToTele) &&
1373                     (afStatusAux == AF_VALID)) {
1374                 ret = true;
1375             }
1376         }
1377     } else {
1378         LOGE("Request to switch to invalid cam type");
1379     }
1380     return ret;
1381 }
1382 
1383 /*===========================================================================
1384  * FUNCTION    : isSpatialAlignmentReady
1385  *
1386  * DESCRIPTION : Check if the spatial alignment is ready.
1387  *               For QTI solution, check ready_status flag
1388  *               For OEM solution, check camMasterHint
1389  *               If the spatial alignment solution is not needed, return true
1390  *
1391  * PARAMETERS  : None
1392  *
1393  * RETURN      :
1394  * true        : If spatial alignment is ready
1395  * false       : If spatial alignment is not yet ready
1396  *
1397  *==========================================================================*/
isSpatialAlignmentReady()1398 bool QCameraFOVControl::isSpatialAlignmentReady()
1399 {
1400     bool ret = true;
1401     cam_sync_type_t camWide = mFovControlData.camWide;
1402     cam_sync_type_t camTele = mFovControlData.camTele;
1403 
1404     if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
1405         uint8_t currentMaster = (uint8_t)mFovControlResult.camMasterPreview;
1406         uint8_t camMasterHint = mFovControlData.spatialAlignResult.camMasterHint;
1407 
1408         if (((currentMaster == camWide) && (camMasterHint == camTele)) ||
1409                 ((currentMaster == camTele) && (camMasterHint == camWide))){
1410             ret = true;
1411         } else {
1412             ret = false;
1413         }
1414     } else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_QTI) {
1415         if (mFovControlData.spatialAlignResult.readyStatus) {
1416             ret = true;
1417         } else {
1418             ret = false;
1419         }
1420     }
1421 
1422     char prop[PROPERTY_VALUE_MAX];
1423     int override = 0;
1424     property_get("persist.camera.fovc.override", prop, "0");
1425     override = atoi(prop);
1426     if(override) {
1427         ret = true;
1428     }
1429 
1430     return ret;
1431 }
1432 
1433 
1434 /*===========================================================================
1435  * FUNCTION    : validateAndExtractParameters
1436  *
1437  * DESCRIPTION : Validates a subset of parameters from capabilities and
1438  *               saves those parameters for decision making.
1439  *
1440  * PARAMETERS  :
1441  *  @capsMain  : The capabilities for the main camera
1442  *  @capsAux   : The capabilities for the aux camera
1443  *
1444  * RETURN      :
1445  * true        : Success
1446  * false       : Failure
1447  *
1448  *==========================================================================*/
validateAndExtractParameters(cam_capability_t * capsMainCam,cam_capability_t * capsAuxCam)1449 bool QCameraFOVControl::validateAndExtractParameters(
1450         cam_capability_t  *capsMainCam,
1451         cam_capability_t  *capsAuxCam)
1452 {
1453     bool rc = false;
1454     if (capsMainCam && capsAuxCam) {
1455 
1456         mFovControlConfig.percentMarginHysterisis  = 5;
1457         mFovControlConfig.percentMarginMain        = 25;
1458         mFovControlConfig.percentMarginAux         = 15;
1459         mFovControlConfig.waitTimeForHandoffMs     = 1000;
1460 
1461         mDualCamParams.paramsMain.sensorStreamWidth =
1462                 capsMainCam->related_cam_calibration.main_cam_specific_calibration.\
1463                 native_sensor_resolution_width;
1464         mDualCamParams.paramsMain.sensorStreamHeight =
1465                 capsMainCam->related_cam_calibration.main_cam_specific_calibration.\
1466                 native_sensor_resolution_height;
1467 
1468         mDualCamParams.paramsAux.sensorStreamWidth   =
1469                 capsMainCam->related_cam_calibration.aux_cam_specific_calibration.\
1470                 native_sensor_resolution_width;
1471         mDualCamParams.paramsAux.sensorStreamHeight  =
1472                 capsMainCam->related_cam_calibration.aux_cam_specific_calibration.\
1473                 native_sensor_resolution_height;
1474 
1475         mDualCamParams.paramsMain.focalLengthMm = capsMainCam->focal_length;
1476         mDualCamParams.paramsAux.focalLengthMm  = capsAuxCam->focal_length;
1477 
1478         mDualCamParams.paramsMain.pixelPitchUm = capsMainCam->pixel_pitch_um;
1479         mDualCamParams.paramsAux.pixelPitchUm  = capsAuxCam->pixel_pitch_um;
1480 
1481         if ((capsMainCam->min_focus_distance > 0) &&
1482                 (capsAuxCam->min_focus_distance > 0)) {
1483             // Convert the min focus distance from diopters to cm
1484             // and choose the max of both sensors.
1485             uint32_t minFocusDistCmMain = (100.0f / capsMainCam->min_focus_distance);
1486             uint32_t minFocusDistCmAux  = (100.0f / capsAuxCam->min_focus_distance);
1487             mDualCamParams.minFocusDistanceCm = (minFocusDistCmMain > minFocusDistCmAux) ?
1488                     minFocusDistCmMain : minFocusDistCmAux;
1489         }
1490 
1491         if (capsMainCam->related_cam_calibration.relative_position_flag == 0) {
1492             mDualCamParams.positionAux = CAM_POSITION_RIGHT;
1493         } else {
1494             mDualCamParams.positionAux = CAM_POSITION_LEFT;
1495         }
1496 
1497         if ((capsMainCam->avail_spatial_align_solns & CAM_SPATIAL_ALIGN_QTI) ||
1498                 (capsMainCam->avail_spatial_align_solns & CAM_SPATIAL_ALIGN_OEM)) {
1499             mFovControlData.availableSpatialAlignSolns =
1500                     capsMainCam->avail_spatial_align_solns;
1501         } else {
1502             LOGW("Spatial alignment not supported");
1503         }
1504 
1505         if (capsMainCam->zoom_supported > 0) {
1506             mFovControlData.zoomRatioTable      = capsMainCam->zoom_ratio_tbl;
1507             mFovControlData.zoomRatioTableCount = capsMainCam->zoom_ratio_tbl_cnt;
1508         } else {
1509             LOGE("zoom feature not supported");
1510             return false;
1511         }
1512         rc = true;
1513     }
1514 
1515     return rc;
1516 }
1517 
1518 /*===========================================================================
1519  * FUNCTION   : calculateBasicFovRatio
1520  *
1521  * DESCRIPTION: Calculate the FOV ratio between main and aux cameras
1522  *
1523  * PARAMETERS : None
1524  *
1525  * RETURN     :
1526  * true       : Success
1527  * false      : Failure
1528  *
1529  *==========================================================================*/
calculateBasicFovRatio()1530 bool QCameraFOVControl::calculateBasicFovRatio()
1531 {
1532     float fovWide = 0.0f;
1533     float fovTele = 0.0f;
1534     bool rc = false;
1535 
1536     if ((mDualCamParams.paramsMain.focalLengthMm > 0.0f) &&
1537          (mDualCamParams.paramsAux.focalLengthMm > 0.0f)) {
1538         if (mDualCamParams.paramsMain.focalLengthMm <
1539             mDualCamParams.paramsAux.focalLengthMm) {
1540             fovWide = (mDualCamParams.paramsMain.sensorStreamWidth *
1541                         mDualCamParams.paramsMain.pixelPitchUm) /
1542                         mDualCamParams.paramsMain.focalLengthMm;
1543 
1544             fovTele = (mDualCamParams.paramsAux.sensorStreamWidth *
1545                         mDualCamParams.paramsAux.pixelPitchUm) /
1546                         mDualCamParams.paramsAux.focalLengthMm;
1547         } else {
1548             fovWide = (mDualCamParams.paramsAux.sensorStreamWidth *
1549                         mDualCamParams.paramsAux.pixelPitchUm) /
1550                         mDualCamParams.paramsAux.focalLengthMm;
1551 
1552             fovTele = (mDualCamParams.paramsMain.sensorStreamWidth *
1553                         mDualCamParams.paramsMain.pixelPitchUm) /
1554                         mDualCamParams.paramsMain.focalLengthMm;
1555         }
1556         if (fovTele > 0.0f) {
1557             mFovControlData.basicFovRatio = (fovWide / fovTele);
1558             rc = true;
1559         }
1560     }
1561 
1562     LOGD("Main cam focalLengthMm : %f", mDualCamParams.paramsMain.focalLengthMm);
1563     LOGD("Aux  cam focalLengthMm : %f", mDualCamParams.paramsAux.focalLengthMm);
1564     LOGD("Main cam sensorStreamWidth : %u", mDualCamParams.paramsMain.sensorStreamWidth);
1565     LOGD("Main cam sensorStreamHeight: %u", mDualCamParams.paramsMain.sensorStreamHeight);
1566     LOGD("Main cam pixelPitchUm      : %f", mDualCamParams.paramsMain.pixelPitchUm);
1567     LOGD("Main cam focalLengthMm     : %f", mDualCamParams.paramsMain.focalLengthMm);
1568     LOGD("Aux cam sensorStreamWidth  : %u", mDualCamParams.paramsAux.sensorStreamWidth);
1569     LOGD("Aux cam sensorStreamHeight : %u", mDualCamParams.paramsAux.sensorStreamHeight);
1570     LOGD("Aux cam pixelPitchUm       : %f", mDualCamParams.paramsAux.pixelPitchUm);
1571     LOGD("Aux cam focalLengthMm      : %f", mDualCamParams.paramsAux.focalLengthMm);
1572     LOGD("fov wide : %f", fovWide);
1573     LOGD("fov tele : %f", fovTele);
1574     LOGD("BasicFovRatio : %f", mFovControlData.basicFovRatio);
1575 
1576     return rc;
1577 }
1578 
1579 
1580 /*===========================================================================
1581  * FUNCTION   : combineFovAdjustment
1582  *
1583  * DESCRIPTION: Calculate the final FOV adjustment by combining basic FOV ratio
1584  *              with the margin info
1585  *
1586  * PARAMETERS : None
1587  *
1588  * RETURN     :
1589  * true       : Success
1590  * false      : Failure
1591  *
1592  *==========================================================================*/
combineFovAdjustment()1593 bool QCameraFOVControl::combineFovAdjustment()
1594 {
1595     float ratioMarginWidth;
1596     float ratioMarginHeight;
1597     float adjustedRatio;
1598     bool rc = false;
1599 
1600     ratioMarginWidth = (1.0 + (mFovControlData.camMainWidthMargin)) /
1601             (1.0 + (mFovControlData.camAuxWidthMargin));
1602     ratioMarginHeight = (1.0 + (mFovControlData.camMainHeightMargin)) /
1603             (1.0 + (mFovControlData.camAuxHeightMargin));
1604 
1605     adjustedRatio = (ratioMarginHeight < ratioMarginWidth) ? ratioMarginHeight : ratioMarginWidth;
1606 
1607     if (adjustedRatio > 0.0f) {
1608         mFovControlData.transitionParams.cutOverFactor =
1609                 (mFovControlData.basicFovRatio / adjustedRatio);
1610         rc = true;
1611     }
1612 
1613     LOGD("Main cam margin for width  : %f", mFovControlData.camMainWidthMargin);
1614     LOGD("Main cam margin for height : %f", mFovControlData.camMainHeightMargin);
1615     LOGD("Aux  cam margin for width  : %f", mFovControlData.camAuxWidthMargin);
1616     LOGD("Aux  cam margin for height : %f", mFovControlData.camAuxHeightMargin);
1617     LOGD("Width  margin ratio : %f", ratioMarginWidth);
1618     LOGD("Height margin ratio : %f", ratioMarginHeight);
1619 
1620     return rc;
1621 }
1622 
1623 
1624 /*===========================================================================
1625  * FUNCTION   : calculateDualCamTransitionParams
1626  *
1627  * DESCRIPTION: Calculate the transition parameters needed to switch the camera
1628  *              between main and aux
1629  *
1630  * PARAMETERS :
1631  * @fovAdjustBasic       : basic FOV ratio
1632  * @zoomTranslationFactor: translation factor for main, aux zoom
1633  *
1634  * RETURN     : none
1635  *
1636  *==========================================================================*/
calculateDualCamTransitionParams()1637 void QCameraFOVControl::calculateDualCamTransitionParams()
1638 {
1639     float percentMarginWide;
1640     float percentMarginTele;
1641 
1642     if (isMainCamFovWider()) {
1643         percentMarginWide = mFovControlConfig.percentMarginMain;
1644         percentMarginTele = mFovControlConfig.percentMarginAux;
1645     } else {
1646         percentMarginWide = mFovControlConfig.percentMarginAux;
1647         percentMarginTele = mFovControlConfig.percentMarginMain;
1648     }
1649 
1650     mFovControlData.transitionParams.cropRatio = mFovControlData.basicFovRatio;
1651 
1652     mFovControlData.transitionParams.cutOverWideToTele =
1653             mFovControlData.transitionParams.cutOverFactor +
1654             (mFovControlConfig.percentMarginHysterisis / 100.0) * mFovControlData.basicFovRatio;
1655 
1656     mFovControlData.transitionParams.cutOverTeleToWide =
1657             mFovControlData.transitionParams.cutOverFactor;
1658 
1659     mFovControlData.transitionParams.transitionHigh =
1660             mFovControlData.transitionParams.cutOverWideToTele +
1661             (percentMarginWide / 100.0) * mFovControlData.basicFovRatio;
1662 
1663     mFovControlData.transitionParams.transitionLow =
1664             mFovControlData.transitionParams.cutOverTeleToWide -
1665             (percentMarginTele / 100.0) * mFovControlData.basicFovRatio;
1666 
1667     if (mFovControlConfig.snapshotPPConfig.enablePostProcess) {
1668         // Expand the transition zone if necessary to account for
1669         // the snapshot post-process settings
1670         if (mFovControlConfig.snapshotPPConfig.zoomMax >
1671                 mFovControlData.transitionParams.transitionHigh) {
1672             mFovControlData.transitionParams.transitionHigh =
1673                 mFovControlConfig.snapshotPPConfig.zoomMax;
1674         }
1675         if (mFovControlConfig.snapshotPPConfig.zoomMin <
1676                 mFovControlData.transitionParams.transitionLow) {
1677             mFovControlData.transitionParams.transitionLow =
1678                 mFovControlConfig.snapshotPPConfig.zoomMin;
1679         }
1680 
1681         // Set aux switch brightness threshold as the lower of aux switch and
1682         // snapshot post-process thresholds
1683         if (mFovControlConfig.snapshotPPConfig.luxMin < mFovControlConfig.auxSwitchBrightnessMin) {
1684             mFovControlConfig.auxSwitchBrightnessMin = mFovControlConfig.snapshotPPConfig.luxMin;
1685         }
1686     }
1687 
1688     LOGD("transition param: TransitionLow  %f", mFovControlData.transitionParams.transitionLow);
1689     LOGD("transition param: TeleToWide     %f", mFovControlData.transitionParams.cutOverTeleToWide);
1690     LOGD("transition param: WideToTele     %f", mFovControlData.transitionParams.cutOverWideToTele);
1691     LOGD("transition param: TransitionHigh %f", mFovControlData.transitionParams.transitionHigh);
1692 }
1693 
1694 
1695 /*===========================================================================
1696  * FUNCTION   : findZoomValue
1697  *
1698  * DESCRIPTION: For the input zoom ratio, find the zoom value.
1699  *              Zoom table contains zoom ratios where the indices
1700  *              in the zoom table indicate the corresponding zoom values.
1701  * PARAMETERS :
1702  * @zoomRatio : Zoom ratio
1703  *
1704  * RETURN     : Zoom value
1705  *
1706  *==========================================================================*/
findZoomValue(uint32_t zoomRatio)1707 uint32_t QCameraFOVControl::findZoomValue(
1708         uint32_t zoomRatio)
1709 {
1710     uint32_t zoom = 0;
1711     for (uint32_t i = 0; i < mFovControlData.zoomRatioTableCount; ++i) {
1712         if (zoomRatio <= mFovControlData.zoomRatioTable[i]) {
1713             zoom = i;
1714             break;
1715         }
1716     }
1717     return zoom;
1718 }
1719 
1720 
1721 /*===========================================================================
1722  * FUNCTION   : findZoomRatio
1723  *
1724  * DESCRIPTION: For the input zoom value, find the zoom ratio.
1725  *              Zoom table contains zoom ratios where the indices
1726  *              in the zoom table indicate the corresponding zoom values.
1727  * PARAMETERS :
1728  * @zoom      : zoom value
1729  *
1730  * RETURN     : zoom ratio
1731  *
1732  *==========================================================================*/
findZoomRatio(uint32_t zoom)1733 uint32_t QCameraFOVControl::findZoomRatio(
1734         uint32_t zoom)
1735 {
1736     return mFovControlData.zoomRatioTable[zoom];
1737 }
1738 
1739 
1740 /*===========================================================================
1741  * FUNCTION   : readjustZoomForTele
1742  *
1743  * DESCRIPTION: Calculate the zoom value for the tele camera based on zoom value
1744  *              for the wide camera
1745  *
1746  * PARAMETERS :
1747  * @zoomWide  : Zoom value for wide camera
1748  *
1749  * RETURN     : Zoom value for tele camera
1750  *
1751  *==========================================================================*/
readjustZoomForTele(uint32_t zoomWide)1752 uint32_t QCameraFOVControl::readjustZoomForTele(
1753         uint32_t zoomWide)
1754 {
1755     uint32_t zoomRatioWide;
1756     uint32_t zoomRatioTele;
1757 
1758     zoomRatioWide = findZoomRatio(zoomWide);
1759     zoomRatioTele  = zoomRatioWide / mFovControlData.transitionParams.cutOverFactor;
1760 
1761     return(findZoomValue(zoomRatioTele));
1762 }
1763 
1764 
1765 /*===========================================================================
1766  * FUNCTION   : readjustZoomForWide
1767  *
1768  * DESCRIPTION: Calculate the zoom value for the wide camera based on zoom value
1769  *              for the tele camera
1770  *
1771  * PARAMETERS :
1772  * @zoomTele  : Zoom value for tele camera
1773  *
1774  * RETURN     : Zoom value for wide camera
1775  *
1776  *==========================================================================*/
readjustZoomForWide(uint32_t zoomTele)1777 uint32_t QCameraFOVControl::readjustZoomForWide(
1778         uint32_t zoomTele)
1779 {
1780     uint32_t zoomRatioWide;
1781     uint32_t zoomRatioTele;
1782 
1783     zoomRatioTele = findZoomRatio(zoomTele);
1784     zoomRatioWide = zoomRatioTele * mFovControlData.transitionParams.cutOverFactor;
1785 
1786     return(findZoomValue(zoomRatioWide));
1787 }
1788 
1789 
1790 /*===========================================================================
1791  * FUNCTION   : convertUserZoomToWideAndTele
1792  *
1793  * DESCRIPTION: Calculate the zoom value for the wide and tele cameras
1794  *              based on the input user zoom value
1795  *
1796  * PARAMETERS :
1797  * @zoom      : User zoom value
1798  *
1799  * RETURN     : none
1800  *
1801  *==========================================================================*/
convertUserZoomToWideAndTele(uint32_t zoom)1802 void QCameraFOVControl::convertUserZoomToWideAndTele(
1803         uint32_t zoom)
1804 {
1805     Mutex::Autolock lock(mMutex);
1806 
1807     // If the zoom translation library is present and initialized,
1808     // use it to get wide and tele zoom values
1809     if (mZoomTranslator && mZoomTranslator->isInitialized()) {
1810         uint32_t zoomWide = 0;
1811         uint32_t zoomTele = 0;
1812         if (mZoomTranslator->getZoomValues(zoom, &zoomWide, &zoomTele) != NO_ERROR) {
1813             LOGE("getZoomValues failed from zoom translation lib");
1814             // Use zoom translation logic from FOV-control
1815             mFovControlData.zoomWide = zoom;
1816             mFovControlData.zoomTele = readjustZoomForTele(mFovControlData.zoomWide);
1817         } else {
1818             // Use the zoom values provided by zoom translation lib
1819             mFovControlData.zoomWide = zoomWide;
1820             mFovControlData.zoomTele = zoomTele;
1821         }
1822     } else {
1823         mFovControlData.zoomWide = zoom;
1824         mFovControlData.zoomTele = readjustZoomForTele(mFovControlData.zoomWide);
1825     }
1826 }
1827 
1828 
1829 /*===========================================================================
1830  * FUNCTION   : translateFocusAreas
1831  *
1832  * DESCRIPTION: Translate the focus areas from main to aux camera.
1833  *
1834  * PARAMETERS :
1835  * @roiAfMain : Focus area ROI for main camera
1836  * @cam       : Cam type
1837  *
1838  * RETURN     : Translated focus area ROI for aux camera
1839  *
1840  *==========================================================================*/
translateFocusAreas(cam_roi_info_t roiAfMain,cam_sync_type_t cam)1841 cam_roi_info_t QCameraFOVControl::translateFocusAreas(
1842         cam_roi_info_t  roiAfMain,
1843         cam_sync_type_t cam)
1844 {
1845     float fovRatio;
1846     float zoomWide;
1847     float zoomTele;
1848     float AuxDiffRoiLeft;
1849     float AuxDiffRoiTop;
1850     float AuxRoiLeft;
1851     float AuxRoiTop;
1852     cam_roi_info_t roiAfTrans = roiAfMain;
1853     int32_t shiftHorzAdjusted;
1854     int32_t shiftVertAdjusted;
1855     float zoom = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
1856 
1857     zoomWide = findZoomRatio(mFovControlData.zoomWide);
1858     zoomTele = findZoomRatio(mFovControlData.zoomTele);
1859 
1860     if (cam == mFovControlData.camWide) {
1861         fovRatio = 1.0f;
1862     } else {
1863         fovRatio = (zoomTele / zoomWide) * mFovControlData.transitionParams.cropRatio;
1864     }
1865 
1866     // Acquire the mutex in order to read the spatial alignment result which is written
1867     // by another thread
1868     mMutex.lock();
1869     if (cam == mFovControlData.camWide) {
1870         shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz;
1871         shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert;
1872     } else {
1873         shiftHorzAdjusted = (mFovControlData.transitionParams.cropRatio / zoom) *
1874                 mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz;
1875         shiftVertAdjusted = (mFovControlData.transitionParams.cropRatio / zoom) *
1876                 mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert;
1877     }
1878     mMutex.unlock();
1879 
1880     for (int i = 0; i < roiAfMain.num_roi; ++i) {
1881         roiAfTrans.roi[i].width  = roiAfMain.roi[i].width * fovRatio;
1882         roiAfTrans.roi[i].height = roiAfMain.roi[i].height * fovRatio;
1883 
1884         AuxDiffRoiLeft = (roiAfTrans.roi[i].width - roiAfMain.roi[i].width) / 2.0f;
1885         AuxRoiLeft = roiAfMain.roi[i].left - AuxDiffRoiLeft;
1886         AuxDiffRoiTop = (roiAfTrans.roi[i].height - roiAfMain.roi[i].height) / 2.0f;
1887         AuxRoiTop = roiAfMain.roi[i].top - AuxDiffRoiTop;
1888 
1889         roiAfTrans.roi[i].left = AuxRoiLeft - shiftHorzAdjusted;
1890         roiAfTrans.roi[i].top  = AuxRoiTop - shiftVertAdjusted;
1891 
1892         // Check the ROI bounds and correct if necessory
1893         // If ROI is out of bounds, revert to default ROI
1894         if ((roiAfTrans.roi[i].left >= mFovControlData.previewSize.width) ||
1895             (roiAfTrans.roi[i].top >= mFovControlData.previewSize.height) ||
1896             (roiAfTrans.roi[i].width >= mFovControlData.previewSize.width) ||
1897             (roiAfTrans.roi[i].height >= mFovControlData.previewSize.height)) {
1898             // TODO : use default ROI when available from AF. This part of the code
1899             // is still being worked upon. WA - set it to main cam ROI
1900             roiAfTrans = roiAfMain;
1901             LOGW("AF ROI translation failed, reverting to the default ROI");
1902         } else {
1903             if (roiAfTrans.roi[i].left < 0) {
1904                 roiAfTrans.roi[i].left = 0;
1905                 LOGW("AF ROI translation failed");
1906             }
1907             if (roiAfTrans.roi[i].top < 0) {
1908                 roiAfTrans.roi[i].top = 0;
1909                 LOGW("AF ROI translation failed");
1910             }
1911             if ((roiAfTrans.roi[i].left + roiAfTrans.roi[i].width) >=
1912                         mFovControlData.previewSize.width) {
1913                 roiAfTrans.roi[i].width =
1914                         mFovControlData.previewSize.width - roiAfTrans.roi[i].left;
1915                 LOGW("AF ROI translation failed");
1916             }
1917             if ((roiAfTrans.roi[i].top + roiAfTrans.roi[i].height) >=
1918                         mFovControlData.previewSize.height) {
1919                 roiAfTrans.roi[i].height =
1920                         mFovControlData.previewSize.height - roiAfTrans.roi[i].top;
1921                 LOGW("AF ROI translation failed");
1922             }
1923         }
1924 
1925         LOGD("Translated AF ROI-%d %s: L:%d, T:%d, W:%d, H:%d", i,
1926                 (cam == CAM_TYPE_MAIN) ? "main cam" : "aux  cam", roiAfTrans.roi[i].left,
1927                 roiAfTrans.roi[i].top, roiAfTrans.roi[i].width, roiAfTrans.roi[i].height);
1928     }
1929     return roiAfTrans;
1930 }
1931 
1932 
1933 /*===========================================================================
1934  * FUNCTION   : translateMeteringAreas
1935  *
1936  * DESCRIPTION: Translate the AEC metering areas from main to aux camera.
1937  *
1938  * PARAMETERS :
1939  * @roiAfMain : AEC ROI for main camera
1940  * @cam       : Cam type
1941  *
1942  * RETURN     : Translated AEC ROI for aux camera
1943  *
1944  *==========================================================================*/
translateMeteringAreas(cam_set_aec_roi_t roiAecMain,cam_sync_type_t cam)1945 cam_set_aec_roi_t QCameraFOVControl::translateMeteringAreas(
1946         cam_set_aec_roi_t roiAecMain,
1947         cam_sync_type_t cam)
1948 {
1949     float fovRatio;
1950     float zoomWide;
1951     float zoomTele;
1952     float AuxDiffRoiX;
1953     float AuxDiffRoiY;
1954     float AuxRoiX;
1955     float AuxRoiY;
1956     cam_set_aec_roi_t roiAecTrans = roiAecMain;
1957     int32_t shiftHorzAdjusted;
1958     int32_t shiftVertAdjusted;
1959     float zoom = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
1960 
1961     zoomWide = findZoomRatio(mFovControlData.zoomWide);
1962     zoomTele = findZoomRatio(mFovControlData.zoomTele);
1963 
1964     if (cam == mFovControlData.camWide) {
1965         fovRatio = 1.0f;
1966     } else {
1967         fovRatio = (zoomTele / zoomWide) * mFovControlData.transitionParams.cropRatio;
1968     }
1969 
1970     // Acquire the mutex in order to read the spatial alignment result which is written
1971     // by another thread
1972     mMutex.lock();
1973     if (cam == mFovControlData.camWide) {
1974         shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz;
1975         shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert;
1976     } else {
1977         shiftHorzAdjusted = (mFovControlData.transitionParams.cropRatio / zoom) *
1978                 mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz;
1979         shiftVertAdjusted = (mFovControlData.transitionParams.cropRatio / zoom) *
1980                 mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert;
1981     }
1982     mMutex.unlock();
1983 
1984     for (int i = 0; i < roiAecMain.num_roi; ++i) {
1985         AuxDiffRoiX = fovRatio * ((float)roiAecMain.cam_aec_roi_position.coordinate[i].x -
1986                           (mFovControlData.previewSize.width / 2));
1987         AuxRoiX = (mFovControlData.previewSize.width / 2) + AuxDiffRoiX;
1988 
1989         AuxDiffRoiY = fovRatio * ((float)roiAecMain.cam_aec_roi_position.coordinate[i].y -
1990                           (mFovControlData.previewSize.height / 2));
1991         AuxRoiY = (mFovControlData.previewSize.height / 2) + AuxDiffRoiY;
1992 
1993         roiAecTrans.cam_aec_roi_position.coordinate[i].x = AuxRoiX - shiftHorzAdjusted;
1994         roiAecTrans.cam_aec_roi_position.coordinate[i].y = AuxRoiY - shiftVertAdjusted;
1995 
1996         // Check the ROI bounds and correct if necessory
1997         if ((AuxRoiX < 0) ||
1998             (AuxRoiY < 0)) {
1999             roiAecTrans.cam_aec_roi_position.coordinate[i].x = 0;
2000             roiAecTrans.cam_aec_roi_position.coordinate[i].y = 0;
2001             LOGW("AEC ROI translation failed");
2002         } else if ((AuxRoiX >= mFovControlData.previewSize.width) ||
2003             (AuxRoiY >= mFovControlData.previewSize.height)) {
2004             // Clamp the Aux AEC ROI co-ordinates to max possible value
2005             if (AuxRoiX >= mFovControlData.previewSize.width) {
2006                 roiAecTrans.cam_aec_roi_position.coordinate[i].x =
2007                         mFovControlData.previewSize.width - 1;
2008             }
2009             if (AuxRoiY >= mFovControlData.previewSize.height) {
2010                 roiAecTrans.cam_aec_roi_position.coordinate[i].y =
2011                         mFovControlData.previewSize.height - 1;
2012             }
2013             LOGW("AEC ROI translation failed");
2014         }
2015 
2016         LOGD("Translated AEC ROI-%d %s: x:%d, y:%d", i,
2017                 (cam == CAM_TYPE_MAIN) ? "main cam" : "aux  cam",
2018                 roiAecTrans.cam_aec_roi_position.coordinate[i].x,
2019                 roiAecTrans.cam_aec_roi_position.coordinate[i].y);
2020     }
2021     return roiAecTrans;
2022 }
2023 
2024 
2025 /*===========================================================================
2026  * FUNCTION   : translateRoiFD
2027  *
2028  * DESCRIPTION: Translate face detection ROI from aux metadata to main
2029  *
2030  * PARAMETERS :
2031  * @faceDetectionInfo  : face detection data from aux metadata. This face
2032  *                       detection data is overwritten with the translated
2033  *                       FD ROI.
2034  * @cam                : Cam type
2035  *
2036  * RETURN     : none
2037  *
2038  *==========================================================================*/
translateRoiFD(cam_face_detection_data_t metaFD,cam_sync_type_t cam)2039 cam_face_detection_data_t QCameraFOVControl::translateRoiFD(
2040         cam_face_detection_data_t metaFD,
2041         cam_sync_type_t cam)
2042 {
2043     cam_face_detection_data_t metaFDTranslated = metaFD;
2044     int32_t shiftHorz = 0;
2045     int32_t shiftVert = 0;
2046 
2047     if (cam == mFovControlData.camWide) {
2048         shiftHorz = mFovControlData.spatialAlignResult.shiftWide.shiftHorz;
2049         shiftVert = mFovControlData.spatialAlignResult.shiftWide.shiftVert;
2050     } else {
2051         shiftHorz = mFovControlData.spatialAlignResult.shiftTele.shiftHorz;
2052         shiftVert = mFovControlData.spatialAlignResult.shiftTele.shiftVert;
2053     }
2054 
2055     for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
2056         metaFDTranslated.faces[i].face_boundary.left += shiftHorz;
2057         metaFDTranslated.faces[i].face_boundary.top  += shiftVert;
2058     }
2059 
2060     // If ROI is out of bounds, remove that FD ROI from the list
2061     for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
2062         if ((metaFDTranslated.faces[i].face_boundary.left < 0) ||
2063             (metaFDTranslated.faces[i].face_boundary.left >= mFovControlData.previewSize.width) ||
2064             (metaFDTranslated.faces[i].face_boundary.top < 0) ||
2065             (metaFDTranslated.faces[i].face_boundary.top >= mFovControlData.previewSize.height) ||
2066             ((metaFDTranslated.faces[i].face_boundary.left +
2067                     metaFDTranslated.faces[i].face_boundary.width) >=
2068                     mFovControlData.previewSize.width) ||
2069             ((metaFDTranslated.faces[i].face_boundary.top +
2070                     metaFDTranslated.faces[i].face_boundary.height) >=
2071                     mFovControlData.previewSize.height)) {
2072             // Invalid FD ROI detected
2073             LOGD("Failed translating FD ROI %s: L:%d, T:%d, W:%d, H:%d",
2074                     (cam == CAM_TYPE_MAIN) ? "main cam" : "aux  cam",
2075                     metaFDTranslated.faces[i].face_boundary.left,
2076                     metaFDTranslated.faces[i].face_boundary.top,
2077                     metaFDTranslated.faces[i].face_boundary.width,
2078                     metaFDTranslated.faces[i].face_boundary.height);
2079 
2080             // Remove it by copying the last FD ROI at this index
2081             if (i < (metaFDTranslated.num_faces_detected - 1)) {
2082                 metaFDTranslated.faces[i] =
2083                         metaFDTranslated.faces[metaFDTranslated.num_faces_detected - 1];
2084                 // Decrement the current index to process the newly copied FD ROI.
2085                 --i;
2086             }
2087             --metaFDTranslated.num_faces_detected;
2088         }
2089         else {
2090             LOGD("Translated FD ROI-%d %s: L:%d, T:%d, W:%d, H:%d", i,
2091                     (cam == CAM_TYPE_MAIN) ? "main cam" : "aux  cam",
2092                     metaFDTranslated.faces[i].face_boundary.left,
2093                     metaFDTranslated.faces[i].face_boundary.top,
2094                     metaFDTranslated.faces[i].face_boundary.width,
2095                     metaFDTranslated.faces[i].face_boundary.height);
2096         }
2097     }
2098     return metaFDTranslated;
2099 }
2100 
2101 
2102 /*===========================================================================
2103  * FUNCTION      : getFrameMargins
2104  *
2105  * DESCRIPTION   : Return frame margin data for the requested camera
2106  *
2107  * PARAMETERS    :
2108  * @masterCamera : Master camera id
2109  *
2110  * RETURN        : Frame margins
2111  *
2112  *==========================================================================*/
getFrameMargins(int8_t masterCamera)2113 cam_frame_margins_t QCameraFOVControl::getFrameMargins(
2114         int8_t masterCamera)
2115 {
2116     cam_frame_margins_t frameMargins;
2117     memset(&frameMargins, 0, sizeof(cam_frame_margins_t));
2118 
2119     if (masterCamera == CAM_TYPE_MAIN) {
2120         frameMargins.widthMargins  = mFovControlData.camMainWidthMargin;
2121         frameMargins.heightMargins = mFovControlData.camMainHeightMargin;
2122     } else if (masterCamera == CAM_TYPE_AUX) {
2123         frameMargins.widthMargins  = mFovControlData.camAuxWidthMargin;
2124         frameMargins.heightMargins = mFovControlData.camAuxHeightMargin;
2125     }
2126 
2127     return frameMargins;
2128 }
2129 }; // namespace qcamera
2130