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