Home | History | Annotate | Download | only in util
      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  *==========================================================================*/
     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  *==========================================================================*/
     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  *==========================================================================*/
     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  *==========================================================================*/
    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  *==========================================================================*/
    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  *==========================================================================*/
    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  *==========================================================================*/
    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  *==========================================================================*/
    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  *==========================================================================*/
    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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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  *==========================================================================*/
   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