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
39extern "C" {
40#include "mm_camera_dbg.h"
41}
42
43namespace qcamera {
44
45/*===========================================================================
46 * FUNCTION   : QCameraFOVControl constructor
47 *
48 * DESCRIPTION: class constructor
49 *
50 * PARAMETERS : none
51 *
52 * RETURN     : void
53 *
54 *==========================================================================*/
55QCameraFOVControl::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 *==========================================================================*/
75QCameraFOVControl::~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 *==========================================================================*/
99QCameraFOVControl* 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 *==========================================================================*/
177cam_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 *==========================================================================*/
363void 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 *==========================================================================*/
427int32_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 *==========================================================================*/
598int32_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 *==========================================================================*/
685metadata_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 *==========================================================================*/
991void 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 *==========================================================================*/
1263inline 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 *==========================================================================*/
1287inline 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 *==========================================================================*/
1316bool 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 *==========================================================================*/
1398bool 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 *==========================================================================*/
1449bool 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 *==========================================================================*/
1530bool 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 *==========================================================================*/
1593bool 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 *==========================================================================*/
1637void 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 *==========================================================================*/
1707uint32_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 *==========================================================================*/
1733uint32_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 *==========================================================================*/
1752uint32_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 *==========================================================================*/
1777uint32_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 *==========================================================================*/
1802void 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 *==========================================================================*/
1841cam_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 *==========================================================================*/
1945cam_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 *==========================================================================*/
2039cam_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 *==========================================================================*/
2113cam_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