android_device_xiaomi_clover/camera/QCamera2/util/QCameraFOVControl.cpp

3005 lines
130 KiB
C++
Raw Permalink Normal View History

/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define LOG_TAG "QCameraFOVControl"
#include <stdlib.h>
#include <cutils/properties.h>
#include <utils/Timers.h>
#include <utils/Errors.h>
#include "QCameraFOVControl.h"
#include "QCameraDualCamSettings.h"
extern "C" {
#define CAM_MODULE CAM_HAL_MODULE
#include "mm_camera_dbg.h"
#include "mm_camera_interface.h"
}
namespace qcamera {
/*===========================================================================
* FUNCTION : QCameraFOVControl constructor
*
* DESCRIPTION: class constructor
*
* PARAMETERS : none
*
* RETURN : void
*
*==========================================================================*/
QCameraFOVControl::QCameraFOVControl(uint8_t isHAL3)
:mZoomTranslator(NULL),
mHalPPType(CAM_HAL_PP_TYPE_NONE),
mDualCamType(DUAL_CAM_WIDE_TELE),
mbIsHAL3(isHAL3)
{
memset(&mDualCamParams, 0, sizeof(dual_cam_params_t));
memset(&mFovControlConfig, 0, sizeof(fov_control_config_t));
memset(&mFovControlData, 0, sizeof(fov_control_data_t));
memset(&mFovControlResult, 0, sizeof(fov_control_result_t));
memset(&mFovControlParm, 0, sizeof(mFovControlParm));
memset(&mFovControlResultCachedCopy, 0, sizeof(fov_control_result_t));
}
/*===========================================================================
* FUNCTION : QCameraFOVControl destructor
*
* DESCRIPTION: class destructor
*
* PARAMETERS : none
*
* RETURN : void
*
*==========================================================================*/
QCameraFOVControl::~QCameraFOVControl()
{
// De-initialize zoom translator lib
if (mZoomTranslator && mZoomTranslator->isInitialized()) {
mZoomTranslator->deInit();
}
}
/*===========================================================================
* FUNCTION : create
*
* DESCRIPTION: This is a static method to create FOV-control object. It calls
* private constructor of the class and only returns a valid object
* if it can successfully initialize the FOV-control.
*
* PARAMETERS :
* @capsMain : The capabilities for the main camera
* @capsAux : The capabilities for the aux camera
*
* RETURN : Valid object pointer if succeeds
* NULL if fails
*
*==========================================================================*/
QCameraFOVControl* QCameraFOVControl::create(
cam_capability_t *capsMainCam,
cam_capability_t *capsAuxCam,
uint8_t isHAL3)
{
QCameraFOVControl *pFovControl = NULL;
if (capsMainCam && capsAuxCam) {
// Create FOV control object
pFovControl = new QCameraFOVControl(isHAL3);
if (pFovControl) {
bool success = false;
if (pFovControl->validateAndExtractParameters(capsMainCam, capsAuxCam)) {
// Based on focal lengths, map main and aux camera to wide and tele
if (pFovControl->mDualCamParams.paramsMain.focalLengthMm <
pFovControl->mDualCamParams.paramsAux.focalLengthMm) {
pFovControl->mFovControlData.camWide = CAM_TYPE_MAIN;
pFovControl->mFovControlData.camTele = CAM_TYPE_AUX;
pFovControl->mFovControlData.camState = STATE_WIDE;
} else {
pFovControl->mFovControlData.camWide = CAM_TYPE_AUX;
pFovControl->mFovControlData.camTele = CAM_TYPE_MAIN;
pFovControl->mFovControlData.camState = STATE_TELE;
}
// Initialize the master info to main camera
pFovControl->mFovControlResult.camMasterPreview = CAM_TYPE_MAIN;
pFovControl->mFovControlResult.camMaster3A = CAM_TYPE_MAIN;
// Check if LPM is enabled
char prop[PROPERTY_VALUE_MAX];
int lpmEnable = 1;
property_get("persist.vendor.dualcam.lpm.enable", prop, "1");
lpmEnable = atoi(prop);
if ((lpmEnable == 0) || (DUALCAM_LPM_ENABLE == 0)) {
pFovControl->mFovControlData.lpmEnabled = false;
} else {
pFovControl->mFovControlData.lpmEnabled = true;
}
// Open the external zoom translation library if requested
if (FOVC_USE_EXTERNAL_ZOOM_TRANSLATOR) {
pFovControl->mZoomTranslator =
QCameraExtZoomTranslator::create();
if (!pFovControl->mZoomTranslator) {
LOGE("Unable to open zoom translation lib");
}
}
success = true;
}
if (!success) {
LOGE("FOV-control: Failed to create an object");
delete pFovControl;
pFovControl = NULL;
}
} else {
LOGE("FOV-control: Failed to allocate memory for FOV-control object");
}
}
return pFovControl;
}
/*===========================================================================
* FUNCTION : consolidateCapabilities
*
* DESCRIPTION : Combine the capabilities from main and aux cameras to return
* the consolidated capabilities.
*
* PARAMETERS :
* @capsMainCam: Capabilities for the main camera
* @capsAuxCam : Capabilities for the aux camera
*
* RETURN : Consolidated capabilities
*
*==========================================================================*/
cam_capability_t QCameraFOVControl::consolidateCapabilities(
cam_capability_t *capsMainCam,
cam_capability_t *capsAuxCam)
{
cam_capability_t capsConsolidated;
memset(&capsConsolidated, 0, sizeof(cam_capability_t));
if ((capsMainCam != NULL) &&
(capsAuxCam != NULL)) {
memcpy(&capsConsolidated, capsMainCam, sizeof(cam_capability_t));
// Consolidate preview sizes
uint32_t previewSizesTblCntMain = capsMainCam->preview_sizes_tbl_cnt;
uint32_t previewSizesTblCntAux = capsAuxCam->preview_sizes_tbl_cnt;
uint32_t previewSizesTblCntFinal = 0;
for (uint32_t i = 0; i < previewSizesTblCntMain; ++i) {
for (uint32_t j = 0; j < previewSizesTblCntAux; ++j) {
if ((capsMainCam->preview_sizes_tbl[i].width ==
capsAuxCam->preview_sizes_tbl[j].width) &&
(capsMainCam->preview_sizes_tbl[i].height ==
capsAuxCam->preview_sizes_tbl[j].height)) {
if (previewSizesTblCntFinal != i) {
capsConsolidated.preview_sizes_tbl[previewSizesTblCntFinal].width =
capsAuxCam->preview_sizes_tbl[j].width;
capsConsolidated.preview_sizes_tbl[previewSizesTblCntFinal].height =
capsAuxCam->preview_sizes_tbl[j].height;
}
++previewSizesTblCntFinal;
break;
}
}
}
capsConsolidated.preview_sizes_tbl_cnt = previewSizesTblCntFinal;
// Consolidate video sizes
uint32_t videoSizesTblCntMain = capsMainCam->video_sizes_tbl_cnt;
uint32_t videoSizesTblCntAux = capsAuxCam->video_sizes_tbl_cnt;
uint32_t videoSizesTblCntFinal = 0;
for (uint32_t i = 0; i < videoSizesTblCntMain; ++i) {
for (uint32_t j = 0; j < videoSizesTblCntAux; ++j) {
if ((capsMainCam->video_sizes_tbl[i].width ==
capsAuxCam->video_sizes_tbl[j].width) &&
(capsMainCam->video_sizes_tbl[i].height ==
capsAuxCam->video_sizes_tbl[j].height)) {
if (videoSizesTblCntFinal != i) {
capsConsolidated.video_sizes_tbl[videoSizesTblCntFinal].width =
capsAuxCam->video_sizes_tbl[j].width;
capsConsolidated.video_sizes_tbl[videoSizesTblCntFinal].height =
capsAuxCam->video_sizes_tbl[j].height;
}
++videoSizesTblCntFinal;
break;
}
}
}
capsConsolidated.video_sizes_tbl_cnt = videoSizesTblCntFinal;
// Consolidate livesnapshot sizes
uint32_t livesnapshotSizesTblCntMain = capsMainCam->livesnapshot_sizes_tbl_cnt;
uint32_t livesnapshotSizesTblCntAux = capsAuxCam->livesnapshot_sizes_tbl_cnt;
uint32_t livesnapshotSizesTblCntFinal = 0;
for (uint32_t i = 0; i < livesnapshotSizesTblCntMain; ++i) {
for (uint32_t j = 0; j < livesnapshotSizesTblCntAux; ++j) {
if ((capsMainCam->livesnapshot_sizes_tbl[i].width ==
capsAuxCam->livesnapshot_sizes_tbl[j].width) &&
(capsMainCam->livesnapshot_sizes_tbl[i].height ==
capsAuxCam->livesnapshot_sizes_tbl[j].height)) {
if (livesnapshotSizesTblCntFinal != i) {
capsConsolidated.livesnapshot_sizes_tbl[livesnapshotSizesTblCntFinal].width=
capsAuxCam->livesnapshot_sizes_tbl[j].width;
capsConsolidated.livesnapshot_sizes_tbl[livesnapshotSizesTblCntFinal].height=
capsAuxCam->livesnapshot_sizes_tbl[j].height;
}
++livesnapshotSizesTblCntFinal;
break;
}
}
}
capsConsolidated.livesnapshot_sizes_tbl_cnt = livesnapshotSizesTblCntFinal;
// Consolidate picture size
// Find max picture dimension for main camera
cam_dimension_t maxPicDimMain;
maxPicDimMain.width = 0;
maxPicDimMain.height = 0;
for(uint32_t i = 0; i < (capsMainCam->picture_sizes_tbl_cnt - 1); ++i) {
if ((maxPicDimMain.width * maxPicDimMain.height) <
(capsMainCam->picture_sizes_tbl[i].width *
capsMainCam->picture_sizes_tbl[i].height)) {
maxPicDimMain.width = capsMainCam->picture_sizes_tbl[i].width;
maxPicDimMain.height = capsMainCam->picture_sizes_tbl[i].height;
}
}
// Find max picture dimension for aux camera
cam_dimension_t maxPicDimAux;
maxPicDimAux.width = 0;
maxPicDimAux.height = 0;
for(uint32_t i = 0; i < (capsAuxCam->picture_sizes_tbl_cnt - 1); ++i) {
if ((maxPicDimAux.width * maxPicDimAux.height) <
(capsAuxCam->picture_sizes_tbl[i].width *
capsAuxCam->picture_sizes_tbl[i].height)) {
maxPicDimAux.width = capsAuxCam->picture_sizes_tbl[i].width;
maxPicDimAux.height = capsAuxCam->picture_sizes_tbl[i].height;
}
}
LOGH("MAIN Max picture wxh %dx%d", maxPicDimMain.width, maxPicDimMain.height);
LOGH("AUX Max picture wxh %dx%d", maxPicDimAux.width, maxPicDimAux.height);
// Choose the larger of the two max picture dimensions
if ((maxPicDimAux.width * maxPicDimAux.height) >
(maxPicDimMain.width * maxPicDimMain.height)) {
capsConsolidated.picture_sizes_tbl_cnt = capsAuxCam->picture_sizes_tbl_cnt;
memcpy(capsConsolidated.picture_sizes_tbl, capsAuxCam->picture_sizes_tbl,
(capsAuxCam->picture_sizes_tbl_cnt * sizeof(cam_dimension_t)));
}
LOGH("Consolidated Max picture wxh %dx%d", capsConsolidated.picture_sizes_tbl[0].width,
capsConsolidated.picture_sizes_tbl[0].height);
// Consolidate raw size
cam_dimension_t maxRawDimMain;
maxRawDimMain.width = 0;
maxRawDimMain.height = 0;
//Find max raw dimension for main camera
for(uint32_t i=0; i < (capsMainCam->supported_raw_dim_cnt); i++)
{
if((maxRawDimMain.width * maxRawDimMain.height) <
(capsMainCam->raw_dim[i].width * capsMainCam->raw_dim[i].height))
{
maxRawDimMain.width = capsMainCam->raw_dim[i].width;
maxRawDimMain.height = capsMainCam->raw_dim[i].height;
}
}
cam_dimension_t maxRawDimAux;
maxRawDimAux.width = 0;
maxRawDimAux.height = 0;
//Find max raw dimention for aux camera
for(uint32_t i = 0; i < (capsAuxCam->supported_raw_dim_cnt ); i++)
{
if((maxRawDimAux.width * maxRawDimAux.height) <
(capsAuxCam->raw_dim[i].width * capsAuxCam->raw_dim[i].height))
{
maxRawDimAux.width = capsAuxCam->raw_dim[i].width;
maxRawDimAux.height = capsAuxCam->raw_dim[i].height;
}
}
//Choose the larger of the two max raw dimensions
if ((maxRawDimAux.width * maxRawDimAux.height) >
(maxRawDimMain.width * maxRawDimMain.height)) {
capsConsolidated.supported_raw_dim_cnt= capsAuxCam->supported_raw_dim_cnt;
memcpy(capsConsolidated.raw_dim, capsAuxCam->raw_dim,
(capsAuxCam->supported_raw_dim_cnt * sizeof(cam_dimension_t)));
}
LOGH("Consolidated Raw picture wxh %dx%d", capsConsolidated.raw_dim[0].width,
capsConsolidated.raw_dim[0].height);
// Consolidate supported preview formats
uint32_t supportedPreviewFmtCntMain = capsMainCam->supported_preview_fmt_cnt;
uint32_t supportedPreviewFmtCntAux = capsAuxCam->supported_preview_fmt_cnt;
uint32_t supportedPreviewFmtCntFinal = 0;
for (uint32_t i = 0; i < supportedPreviewFmtCntMain; ++i) {
for (uint32_t j = 0; j < supportedPreviewFmtCntAux; ++j) {
if (capsMainCam->supported_preview_fmts[i] ==
capsAuxCam->supported_preview_fmts[j]) {
if (supportedPreviewFmtCntFinal != i) {
capsConsolidated.supported_preview_fmts[supportedPreviewFmtCntFinal] =
capsAuxCam->supported_preview_fmts[j];
}
++supportedPreviewFmtCntFinal;
break;
}
}
}
capsConsolidated.supported_preview_fmt_cnt = supportedPreviewFmtCntFinal;
// Consolidate supported picture formats
uint32_t supportedPictureFmtCntMain = capsMainCam->supported_picture_fmt_cnt;
uint32_t supportedPictureFmtCntAux = capsAuxCam->supported_picture_fmt_cnt;
uint32_t supportedPictureFmtCntFinal = 0;
for (uint32_t i = 0; i < supportedPictureFmtCntMain; ++i) {
for (uint32_t j = 0; j < supportedPictureFmtCntAux; ++j) {
if (capsMainCam->supported_picture_fmts[i] ==
capsAuxCam->supported_picture_fmts[j]) {
if (supportedPictureFmtCntFinal != i) {
capsConsolidated.supported_picture_fmts[supportedPictureFmtCntFinal] =
capsAuxCam->supported_picture_fmts[j];
}
++supportedPictureFmtCntFinal;
break;
}
}
}
capsConsolidated.supported_picture_fmt_cnt = supportedPictureFmtCntFinal;
//consolidate focus modes, to handle FF + AF case
if (capsMainCam->supported_focus_modes_cnt <= 1) {
capsConsolidated.supported_focus_modes_cnt = capsAuxCam->supported_focus_modes_cnt;
memcpy(capsConsolidated.supported_focus_modes, capsAuxCam->supported_focus_modes,
(capsAuxCam->supported_focus_modes_cnt * sizeof(cam_focus_mode_type)));
}
if (mZoomTranslator) {
// Copy the opaque calibration data pointer and size
mFovControlData.zoomTransInitData.calibData =
capsConsolidated.related_cam_calibration.dc_otp_params;
mFovControlData.zoomTransInitData.calibDataSize =
capsConsolidated.related_cam_calibration.dc_otp_size;
}
}
return capsConsolidated;
}
/*===========================================================================
* FUNCTION : resetVars
*
* DESCRIPTION : Reset the variables used in FOV-control.
*
* PARAMETERS : None
*
* RETURN : None
*
*==========================================================================*/
void QCameraFOVControl::resetVars()
{
// Copy the FOV-control settings for camera/camcorder from QCameraFOVControlSettings.h
if (mFovControlData.camcorderMode) {
// Disable snapshot post-processing if two cameras have no sync mechanism.
mFovControlConfig.snapshotPPConfig.enablePostProcess =
(DUALCAM_SYNC_MECHANISM == CAM_SYNC_NO_SYNC) ?
0 : FOVC_CAMCORDER_SNAPSHOT_PP_ENABLE;
} else {
// Disable snapshot post-processing if two cameras have no sync mechanism.
mFovControlConfig.snapshotPPConfig.enablePostProcess =
(DUALCAM_SYNC_MECHANISM == CAM_SYNC_NO_SYNC) ? 0 : FOVC_CAM_SNAPSHOT_PP_ENABLE;
mFovControlConfig.snapshotPPConfig.zoomMin = FOVC_CAM_SNAPSHOT_PP_ZOOM_MIN;
mFovControlConfig.snapshotPPConfig.zoomMax = FOVC_CAM_SNAPSHOT_PP_ZOOM_MAX;
mFovControlConfig.snapshotPPConfig.LuxIdxMax = FOVC_CAM_SNAPSHOT_PP_LUX_IDX_MAX;
mFovControlConfig.snapshotPPConfig.focusDistanceMin =
FOVC_CAM_SNAPSHOT_PP_FOCUS_DIST_CM_MIN;
}
mFovControlConfig.auxSwitchLuxIdxMax = FOVC_AUXCAM_SWITCH_LUX_IDX_MAX;
mFovControlConfig.auxSwitchFocusDistCmMin = FOVC_AUXCAM_SWITCH_FOCUS_DIST_CM_MIN;
mFovControlData.fallbackEnabled = FOVC_MAIN_CAM_FALLBACK_MECHANISM;
mFovControlConfig.fallbackTimeout = FOVC_LOWLIGHT_MACROSCENE_FALLBACK_TIMEOUT_MS;
mFovControlConfig.constZoomTimeout = FOVC_CONSTZOOM_TIMEOUT_MS;
mFovControlConfig.constZoomTimeoutSnapshotPPRange = FOVC_CONSTZOOM_SNAPSHOT_PP_RANGE_TIMEOUT_MS;
// Reset variables
mFovControlData.zoomDirection = ZOOM_STABLE;
mFovControlData.fallbackToWide = false;
mFovControlData.afStatusMain = CAM_AF_STATE_INACTIVE;
mFovControlData.afStatusAux = CAM_AF_STATE_INACTIVE;
mFovControlData.wideCamStreaming = false;
mFovControlData.teleCamStreaming = false;
mFovControlData.frameCountWide = 0;
mFovControlData.frameCountTele = 0;
mFovControlData.spatialAlignResult.readyStatus = 0;
mFovControlData.spatialAlignResult.activeCameras = 0;
mFovControlData.spatialAlignResult.camMasterHint = 0;
mFovControlData.spatialAlignResult.shiftWide.shiftHorz = 0;
mFovControlData.spatialAlignResult.shiftWide.shiftVert = 0;
mFovControlData.spatialAlignResult.shiftTele.shiftHorz = 0;
mFovControlData.spatialAlignResult.shiftTele.shiftVert = 0;
mFovControlData.updateResultState = true;
// WA for now until the QTI solution is in place writing the spatial alignment ready status
mFovControlData.spatialAlignResult.readyStatus = 1;
// Inactivate the timers
inactivateTimer(&mFovControlData.timerLowLitMacroScene);
inactivateTimer(&mFovControlData.timerWellLitNonMacroScene);
inactivateTimer(&mFovControlData.timerConstZoom);
}
/*===========================================================================
* FUNCTION : updateConfigSettings
*
* DESCRIPTION : Update the config settings such as margins and preview size
* and recalculate the transition parameters.
*
* PARAMETERS :
* @capsMainCam: Capabilities for the main camera
* @capsAuxCam : Capabilities for the aux camera
*
* RETURN :
* NO_ERROR : Success
* INVALID_OPERATION : Failure
*
*==========================================================================*/
int32_t QCameraFOVControl::updateConfigSettings(
parm_buffer_t* paramsMainCam,
parm_buffer_t* paramsAuxCam)
{
int32_t rc = INVALID_OPERATION;
if (paramsMainCam &&
paramsAuxCam &&
paramsMainCam->is_valid[CAM_INTF_META_STREAM_INFO] &&
paramsAuxCam->is_valid[CAM_INTF_META_STREAM_INFO]) {
cam_stream_size_info_t camMainStreamInfo;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_META_STREAM_INFO, camMainStreamInfo);
mFovControlData.camcorderMode = false;
mFovControlData.camStreamInfo = camMainStreamInfo;
// Identify if in camera or camcorder mode
for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
mFovControlData.camcorderMode = true;
}
}
// Get the margins for the main camera. If video stream is present, the margins correspond
// to video stream. Otherwise, margins are copied from preview stream.
for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
mFovControlData.camMainWidthMargin = camMainStreamInfo.margins[i].widthMargins;
mFovControlData.camMainHeightMargin = camMainStreamInfo.margins[i].heightMargins;
}
if (camMainStreamInfo.type[i] == CAM_STREAM_TYPE_PREVIEW) {
// Update the preview dimension and ISP output size
mFovControlData.previewSize = camMainStreamInfo.stream_sizes[i];
mFovControlData.ispOutSize = camMainStreamInfo.stream_sz_plus_margin[i];
if (!mFovControlData.camcorderMode) {
mFovControlData.camMainWidthMargin =
camMainStreamInfo.margins[i].widthMargins;
mFovControlData.camMainHeightMargin =
camMainStreamInfo.margins[i].heightMargins;
break;
}
}
}
// Get the margins for the aux camera. If video stream is present, the margins correspond
// to the video stream. Otherwise, margins are copied from preview stream.
cam_stream_size_info_t camAuxStreamInfo;
READ_PARAM_ENTRY(paramsAuxCam, CAM_INTF_META_STREAM_INFO, camAuxStreamInfo);
for (int i = 0; i < MAX_NUM_STREAMS; ++i) {
if (camAuxStreamInfo.type[i] == CAM_STREAM_TYPE_VIDEO) {
mFovControlData.camAuxWidthMargin = camAuxStreamInfo.margins[i].widthMargins;
mFovControlData.camAuxHeightMargin = camAuxStreamInfo.margins[i].heightMargins;
}
if (camAuxStreamInfo.type[i] == CAM_STREAM_TYPE_PREVIEW) {
// Update the preview dimension
mFovControlData.previewSize = camAuxStreamInfo.stream_sizes[i];
if (!mFovControlData.camcorderMode) {
mFovControlData.camAuxWidthMargin = camAuxStreamInfo.margins[i].widthMargins;
mFovControlData.camAuxHeightMargin = camAuxStreamInfo.margins[i].heightMargins;
break;
}
}
}
// Get the sensor out dimensions
cam_dimension_t sensorDimMain = {0,0};
cam_dimension_t sensorDimAux = {0,0};
if (paramsMainCam->is_valid[CAM_INTF_PARM_RAW_DIMENSION]) {
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_RAW_DIMENSION, sensorDimMain);
mDualCamParams.paramsMain.sensorStreamWidth = sensorDimMain.width;
mDualCamParams.paramsMain.sensorStreamHeight = sensorDimMain.height;
}
if (paramsAuxCam->is_valid[CAM_INTF_PARM_RAW_DIMENSION]) {
READ_PARAM_ENTRY(paramsAuxCam, CAM_INTF_PARM_RAW_DIMENSION, sensorDimAux);
mDualCamParams.paramsAux.sensorStreamWidth = sensorDimAux.width;
mDualCamParams.paramsAux.sensorStreamHeight = sensorDimAux.height;
}
// Reset the internal variables
resetVars();
if (isBayerMono()) {
// Bayer is primary camera
mFovControlResult.isValid = true;
mFovControlResult.camMasterPreview = CAM_TYPE_MAIN;
mFovControlResult.camMaster3A = CAM_TYPE_MAIN;
mFovControlResult.activeCameras = MM_CAMERA_DUAL_CAM;
mFovControlData.configCompleted = true;
mFovControlResult.snapshotPostProcess = true;
memcpy(&mFovControlResultCachedCopy, &mFovControlResult,
sizeof(fov_control_result_t));
LOGH("Configure FOVC for Bayer+Mono");
return NO_ERROR;
}
// Recalculate the transition parameters
if (calculateBasicFovRatio() && combineFovAdjustment()) {
calculateDualCamTransitionParams();
if (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) {
// Tele is primary camera
mFovControlResult.isValid = true;
mFovControlResult.camMasterPreview = mFovControlData.camTele;
mFovControlResult.camMaster3A = mFovControlData.camTele;
mFovControlResult.activeCameras =
(uint32_t)(mFovControlData.camTele | mFovControlData.camWide);
mFovControlResult.snapshotPostProcess = true;
mFovControlResult.oisMode = OIS_MODE_HOLD;
mFovControlData.configCompleted = true;
memcpy(&mFovControlResultCachedCopy, &mFovControlResult,
sizeof(fov_control_result_t));
LOGH("Bokeh : start camera state for Bokeh Mode: TELE");
return NO_ERROR;
}
// Initialize the result OIS mode as HOLD
mFovControlResult.oisMode = OIS_MODE_HOLD;
// Update OIS setting / scheme
if (mFovControlData.camcorderMode) {
mFovControlData.oisSetting = DUALCAM_OIS_MODE_CAMCORDER;
} else {
mFovControlData.oisSetting = DUALCAM_OIS_MODE_CAM;
}
// Set initial camera state
float zoom = findZoomRatio(mFovControlData.zoomUser) /
(float)mFovControlData.zoomRatioTable[0];
if (zoom > mFovControlData.transitionParams.cutOverWideToTele) {
mFovControlResult.camMasterPreview = mFovControlData.camTele;
mFovControlResult.camMaster3A = mFovControlData.camTele;
mFovControlResult.activeCameras = (uint32_t)mFovControlData.camTele;
mFovControlData.camState = STATE_TELE;
LOGH("start camera state: TELE");
} else {
mFovControlResult.camMasterPreview = mFovControlData.camWide;
mFovControlResult.camMaster3A = mFovControlData.camWide;
mFovControlResult.activeCameras = (uint32_t)mFovControlData.camWide;
mFovControlData.camState = STATE_WIDE;
LOGH("start camera state: WIDE");
}
mFovControlResult.snapshotPostProcess = false;
// Deinit zoom translation lib if needed
if (mZoomTranslator && mZoomTranslator->isInitialized()) {
if (mZoomTranslator->deInit() != NO_ERROR) {
ALOGW("deinit failed for zoom translation lib");
}
}
// Initialize the zoom translation lib
if (mZoomTranslator) {
// Set the initialization data
mFovControlData.zoomTransInitData.previewDimension.width =
mFovControlData.previewSize.width;
mFovControlData.zoomTransInitData.previewDimension.height =
mFovControlData.previewSize.height;
mFovControlData.zoomTransInitData.ispOutDimension.width =
mFovControlData.ispOutSize.width;
mFovControlData.zoomTransInitData.ispOutDimension.height =
mFovControlData.ispOutSize.height;
mFovControlData.zoomTransInitData.sensorOutDimensionMain.width =
sensorDimMain.width;
mFovControlData.zoomTransInitData.sensorOutDimensionMain.height =
sensorDimMain.height;
mFovControlData.zoomTransInitData.sensorOutDimensionAux.width =
sensorDimAux.width;
mFovControlData.zoomTransInitData.sensorOutDimensionAux.height =
sensorDimAux.height;
mFovControlData.zoomTransInitData.zoomRatioTable =
mFovControlData.zoomRatioTable;
mFovControlData.zoomTransInitData.zoomRatioTableCount =
mFovControlData.zoomRatioTableCount;
mFovControlData.zoomTransInitData.mode = mFovControlData.camcorderMode ?
MODE_CAMCORDER : MODE_CAMERA;
if(mZoomTranslator->init(mFovControlData.zoomTransInitData) != NO_ERROR) {
LOGE("init failed for zoom translation lib");
// deinitialize the zoom translator and set to NULL
mZoomTranslator->deInit();
mZoomTranslator = NULL;
}
}
// FOV-control config is complete for the current use case
mFovControlData.configCompleted = true;
rc = NO_ERROR;
memcpy(&mFovControlResultCachedCopy, &mFovControlResult, sizeof(fov_control_result_t));
rc = translateInputParams(paramsMainCam, paramsAuxCam);
if (rc != NO_ERROR) {
LOGE("FOV-control: Failed to translate");
return rc;
}
}
}
return rc;
}
/*===========================================================================
* FUNCTION : translateInputParams
*
* DESCRIPTION: Translate a subset of input parameters from main camera. As main
* and aux cameras have different properties/params, this translation
* is needed before the input parameters are sent to the aux camera.
*
* PARAMETERS :
* @paramsMainCam : Input parameters for main camera
* @paramsAuxCam : Input parameters for aux camera
*
* RETURN :
* NO_ERROR : Success
* INVALID_OPERATION : Failure
*
*==========================================================================*/
int32_t QCameraFOVControl::translateInputParams(
parm_buffer_t* paramsMainCam,
parm_buffer_t* paramsAuxCam)
{
int32_t rc = INVALID_OPERATION;
if (paramsMainCam && paramsAuxCam) {
bool useCropRegion = false;
cam_crop_region_t scalerCropRegion;
// First copy all the parameters from main to aux and then translate the subset
memcpy(paramsAuxCam, paramsMainCam, sizeof(parm_buffer_t));
if (isBayerMono()) {
//skip translation for B+M
return NO_ERROR;
}
//Translate zoom in HAL3
if (paramsMainCam->is_valid[CAM_INTF_META_SCALER_CROP_REGION]) {
READ_PARAM_ENTRY(paramsMainCam,
CAM_INTF_META_SCALER_CROP_REGION, scalerCropRegion);
float ratio = (float)mDualCamParams.paramsMain.sensorStreamWidth / scalerCropRegion.width;
uint32_t userZoomRatio = ratio * 100;
uint32_t userZoom = findZoomValue(userZoomRatio);
mFovControlParm.zoom_valid = 1;
mFovControlParm.zoom_value = userZoom;
useCropRegion = true;
LOGH("user zoomRatio: %f", ratio);
}
// Translate zoom in HAL1
if (paramsMainCam->is_valid[CAM_INTF_PARM_USERZOOM]) {
//Cache user zoom
cam_zoom_info_t zoomInfo;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_USERZOOM, zoomInfo);
mFovControlParm.zoom_valid = 1;
mFovControlParm.zoom_value = zoomInfo.user_zoom;
}
// Translate zoom
if (mFovControlParm.zoom_valid) {
uint32_t userZoom = mFovControlParm.zoom_value;
convertUserZoomToWideAndTele(userZoom);
// Update zoom values in the param buffers
cam_zoom_info_t zoomInfo;
memset(&zoomInfo, 0, sizeof(cam_zoom_info_t));
zoomInfo.num_streams = mFovControlData.camStreamInfo.num_streams;
if (zoomInfo.num_streams) {
zoomInfo.is_stream_zoom_info_valid = 1;
}
zoomInfo.user_zoom = userZoom;
LOGD("user zoom: %d", userZoom);
// Read the snapshot postprocess flag
mMutex.lock();
bool snapshotPostProcess = mFovControlResult.snapshotPostProcess;
mMutex.unlock();
// Update zoom value for main camera param buffer
uint32_t zoomTotal = isMainCamFovWider() ?
mFovControlData.zoomWide : mFovControlData.zoomTele;
uint32_t zoomIsp = isMainCamFovWider() ?
mFovControlData.zoomWideIsp : mFovControlData.zoomTeleIsp;
uint32_t zoomStep = isMainCamFovWider() ?
mFovControlData.zoomRatioWide : mFovControlData.zoomRatioTele;
if (useCropRegion) {
setCropParam(CAM_TYPE_MAIN, zoomStep, paramsMainCam);
} else {
setZoomParam(CAM_TYPE_MAIN, zoomInfo, zoomTotal, zoomIsp,
snapshotPostProcess, paramsMainCam);
}
// Update zoom value for aux camera param buffer
zoomTotal = isMainCamFovWider() ?
mFovControlData.zoomTele : mFovControlData.zoomWide;
zoomIsp = isMainCamFovWider() ?
mFovControlData.zoomTeleIsp : mFovControlData.zoomWideIsp;
zoomStep = isMainCamFovWider() ?
mFovControlData.zoomRatioTele : mFovControlData.zoomRatioWide;
if (useCropRegion) {
setCropParam(CAM_TYPE_AUX, zoomStep, paramsAuxCam);
} else {
setZoomParam(CAM_TYPE_AUX, zoomInfo, zoomTotal, zoomIsp,
snapshotPostProcess, paramsAuxCam);
}
// Generate FOV-control result
generateFovControlResult();
if (mFovControlData.configCompleted) {
mFovControlParm.zoom_valid = 0;
}
}
// Translate focus areas
if (paramsMainCam->is_valid[CAM_INTF_PARM_AF_ROI]) {
cam_roi_info_t roiAfMain;
cam_roi_info_t roiAfAux;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_AF_ROI, roiAfMain);
if (roiAfMain.num_roi > 0) {
roiAfAux = translateFocusAreas(roiAfMain, CAM_TYPE_AUX);
roiAfMain = translateFocusAreas(roiAfMain, CAM_TYPE_MAIN);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_AF_ROI, roiAfAux);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_AF_ROI, roiAfMain);
}
} else if (paramsMainCam->is_valid[CAM_INTF_META_AF_ROI]) {
cam_area_t roiAfMain;
cam_area_t roiAfAux;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_META_AF_ROI, roiAfMain);
roiAfAux = translateRoi(roiAfMain, CAM_TYPE_AUX);
roiAfMain = translateRoi(roiAfMain, CAM_TYPE_MAIN);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_META_AF_ROI, roiAfAux);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_META_AF_ROI, roiAfMain);
}
// Translate metering areas
if (paramsMainCam->is_valid[CAM_INTF_PARM_AEC_ROI]) {
cam_set_aec_roi_t roiAecMain;
cam_set_aec_roi_t roiAecAux;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_AEC_ROI, roiAecMain);
if (roiAecMain.aec_roi_enable == CAM_AEC_ROI_ON) {
roiAecAux = translateMeteringAreas(roiAecMain, CAM_TYPE_AUX);
roiAecMain = translateMeteringAreas(roiAecMain, CAM_TYPE_MAIN);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_PARM_AEC_ROI, roiAecAux);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_PARM_AEC_ROI, roiAecMain);
}
} else if (paramsMainCam->is_valid[CAM_INTF_META_AEC_ROI]) {
cam_area_t roiAecMain;
cam_area_t roiAecAux;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_META_AEC_ROI, roiAecMain);
roiAecAux = translateRoi(roiAecMain, CAM_TYPE_AUX);
roiAecMain = translateRoi(roiAecMain, CAM_TYPE_MAIN);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsAuxCam, CAM_INTF_META_AEC_ROI, roiAecAux);
ADD_SET_PARAM_ENTRY_TO_BATCH(paramsMainCam, CAM_INTF_META_AEC_ROI, roiAecMain);
}
/*Set torch param only in the active session.With present LPM logic in MCT, if the session
which has been put to LPM wakes up, MCT will start applying all the previous settings at
one go. This can lead to a sudden unwanted flash sometimes. To avoid this, added WA
in HAL to set torch mode only in the active session.*/
if (paramsMainCam->is_valid[CAM_INTF_PARM_LED_MODE]) {
int32_t flashMode = CAM_FLASH_MODE_OFF;
READ_PARAM_ENTRY(paramsMainCam, CAM_INTF_PARM_LED_MODE, flashMode);
if (CAM_FLASH_MODE_TORCH == flashMode) {
if (isMaster(mFovControlData.camWide)) {
paramsAuxCam->is_valid[CAM_INTF_PARM_LED_MODE] = 0;
} else {
paramsMainCam->is_valid[CAM_INTF_PARM_LED_MODE] = 0;
}
}
}
rc = NO_ERROR;
}
return rc;
}
/*===========================================================================
* FUNCTION : processResultMetadata
*
* DESCRIPTION: Process the metadata from main and aux cameras to generate the
* result metadata. The result metadata should be the metadata
* coming from the master camera. If aux camera is master, the
* subset of the metadata needs to be translated to main as that's
* the only camera seen by the application.
*
* PARAMETERS :
* @metaMain : metadata for main camera
* @metaAux : metadata for aux camera
*
* RETURN :
* Result metadata for the logical camera. After successfully processing main
* and aux metadata, the result metadata points to either main or aux metadata
* based on which one was the master. In case of failure, it returns NULL.
*==========================================================================*/
metadata_buffer_t* QCameraFOVControl::processResultMetadata(
metadata_buffer_t* metaMain,
metadata_buffer_t* metaAux)
{
metadata_buffer_t* metaResult = NULL;
if (metaMain || metaAux) {
mMutex.lock();
metadata_buffer_t *meta = metaMain ? metaMain : metaAux;
cam_sync_type_t masterCam = mFovControlData.updateResultState ?
mFovControlResult.camMasterPreview : mFovControlResultCachedCopy.camMasterPreview;
// Book-keep the needed metadata from main camera and aux camera
IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
CAM_INTF_META_DC_SAC_OUTPUT_INFO, meta) {
// Get master camera hint
if (spatialAlignOutput->is_master_hint_valid) {
uint8_t master = spatialAlignOutput->master_hint;
mFovControlData.spatialAlignResult.fallbackComplete = 0;
if (master == CAM_ROLE_WIDE) {
mFovControlData.spatialAlignResult.camMasterHint = mFovControlData.camWide;
} else if (master == CAM_ROLE_TELE) {
mFovControlData.spatialAlignResult.camMasterHint = mFovControlData.camTele;
} else if (master == CAM_ROLE_WIDE_FALLBACK) {
// Confirmation on fallback complete
mFovControlData.spatialAlignResult.camMasterHint = 0;
mFovControlData.spatialAlignResult.fallbackComplete = 1;
}
}
// Get master camera used for the preview in the frame corresponding to this metadata
if (spatialAlignOutput->is_master_preview_valid) {
uint8_t master = spatialAlignOutput->master_preview;
if (master == CAM_ROLE_WIDE) {
masterCam = mFovControlData.camWide;
mFovControlData.spatialAlignResult.camMasterPreview = masterCam;
} else if (master == CAM_ROLE_TELE) {
masterCam = mFovControlData.camTele;
mFovControlData.spatialAlignResult.camMasterPreview = masterCam;
}
}
// Get master camera used for 3A in the frame corresponding to this metadata
if (spatialAlignOutput->is_master_3A_valid) {
uint8_t master = spatialAlignOutput->master_3A;
if (master == CAM_ROLE_WIDE) {
mFovControlData.spatialAlignResult.camMaster3A = mFovControlData.camWide;
} else if (master == CAM_ROLE_TELE) {
mFovControlData.spatialAlignResult.camMaster3A = mFovControlData.camTele;
}
}
// Get spatial alignment ready status
if (spatialAlignOutput->is_ready_status_valid) {
mFovControlData.spatialAlignResult.readyStatus = spatialAlignOutput->ready_status;
}
LOGD("master_hint_valid %d masterCam %d FBcomplete %d camMaster3A %d readyStatus %d",
mFovControlData.spatialAlignResult.camMasterHint,
mFovControlData.spatialAlignResult.camMasterPreview,
mFovControlData.spatialAlignResult.fallbackComplete,
mFovControlData.spatialAlignResult.camMaster3A,
mFovControlData.spatialAlignResult.readyStatus);
}
metadata_buffer_t *metaWide = isMainCamFovWider() ? metaMain : metaAux;
metadata_buffer_t *metaTele = isMainCamFovWider() ? metaAux : metaMain;
// Get spatial alignment output info for wide camera
if (metaWide) {
IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
CAM_INTF_META_DC_SAC_OUTPUT_INFO, metaWide) {
// Get spatial alignment output shift for wide camera
if (spatialAlignOutput->is_output_shift_valid) {
// Calculate the spatial alignment shift for the current stream dimensions based
// on the reference resolution used for the output shift.
float horzShiftFactor = (float)mFovControlData.previewSize.width /
spatialAlignOutput->reference_res_for_output_shift.width;
float vertShiftFactor = (float)mFovControlData.previewSize.height /
spatialAlignOutput->reference_res_for_output_shift.height;
mFovControlData.spatialAlignResult.shiftWide.shiftHorz =
spatialAlignOutput->output_shift.shift_horz * horzShiftFactor;
mFovControlData.spatialAlignResult.shiftWide.shiftVert =
spatialAlignOutput->output_shift.shift_vert * vertShiftFactor;
LOGD("SAC output shift for Wide: x:%d, y:%d",
mFovControlData.spatialAlignResult.shiftWide.shiftHorz,
mFovControlData.spatialAlignResult.shiftWide.shiftVert);
}
// Get the AF roi shift for wide camera
if (spatialAlignOutput->is_focus_roi_shift_valid) {
// Calculate the spatial alignment shift for the current stream dimensions based
// on the reference resolution used for the output shift.
float horzShiftFactor = (float)mFovControlData.previewSize.width /
spatialAlignOutput->reference_res_for_focus_roi_shift.width;
float vertShiftFactor = (float)mFovControlData.previewSize.height /
spatialAlignOutput->reference_res_for_focus_roi_shift.height;
mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz =
spatialAlignOutput->focus_roi_shift.shift_horz * horzShiftFactor;
mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert =
spatialAlignOutput->focus_roi_shift.shift_vert * vertShiftFactor;
LOGD("SAC AF ROI shift for Wide: x:%d, y:%d",
mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz,
mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert);
}
}
}
// Get spatial alignment output info for tele camera
if (metaTele) {
IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
CAM_INTF_META_DC_SAC_OUTPUT_INFO, metaTele) {
// Get spatial alignment output shift for tele camera
if (spatialAlignOutput->is_output_shift_valid) {
// Calculate the spatial alignment shift for the current stream dimensions based
// on the reference resolution used for the output shift.
float horzShiftFactor = (float)mFovControlData.previewSize.width /
spatialAlignOutput->reference_res_for_output_shift.width;
float vertShiftFactor = (float)mFovControlData.previewSize.height /
spatialAlignOutput->reference_res_for_output_shift.height;
mFovControlData.spatialAlignResult.shiftTele.shiftHorz =
spatialAlignOutput->output_shift.shift_horz * horzShiftFactor;
mFovControlData.spatialAlignResult.shiftTele.shiftVert =
spatialAlignOutput->output_shift.shift_vert * vertShiftFactor;
LOGD("SAC output shift for Tele: x:%d, y:%d",
mFovControlData.spatialAlignResult.shiftTele.shiftHorz,
mFovControlData.spatialAlignResult.shiftTele.shiftVert);
}
// Get the AF roi shift for tele camera
if (spatialAlignOutput->is_focus_roi_shift_valid) {
// Calculate the spatial alignment shift for the current stream dimensions based
// on the reference resolution used for the output shift.
float horzShiftFactor = (float)mFovControlData.previewSize.width /
spatialAlignOutput->reference_res_for_focus_roi_shift.width;
float vertShiftFactor = (float)mFovControlData.previewSize.height /
spatialAlignOutput->reference_res_for_focus_roi_shift.height;
mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz =
spatialAlignOutput->focus_roi_shift.shift_horz * horzShiftFactor;
mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert =
spatialAlignOutput->focus_roi_shift.shift_vert * vertShiftFactor;
LOGD("SAC AF ROI shift for Tele: x:%d, y:%d",
mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz,
mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert);
}
}
}
// Get the requested LPM
if (meta) {
IF_META_AVAILABLE(cam_sac_output_info_t, spatialAlignOutput,
CAM_INTF_META_DC_SAC_OUTPUT_INFO, meta) {
if (spatialAlignOutput->is_lpm_info_valid) {
// Update active cameras requested by spatial alignment
for (int i = 0; i < DUALCAM_CAMERA_CNT; ++i) {
if(spatialAlignOutput->lpm_info[i].camera_role == CAM_ROLE_WIDE) {
if (spatialAlignOutput->lpm_info[i].lpm_enable) {
mFovControlData.spatialAlignResult.activeCameras &=
~mFovControlData.camWide;
} else {
mFovControlData.spatialAlignResult.activeCameras |=
mFovControlData.camWide;
}
}
if(spatialAlignOutput->lpm_info[i].camera_role == CAM_ROLE_TELE) {
if (spatialAlignOutput->lpm_info[i].lpm_enable) {
mFovControlData.spatialAlignResult.activeCameras &=
~mFovControlData.camTele;
} else {
mFovControlData.spatialAlignResult.activeCameras |=
mFovControlData.camTele;
}
}
LOGD("SAC LPM info: cam role: %d, lpm: %d",
spatialAlignOutput->lpm_info[i].camera_role,
spatialAlignOutput->lpm_info[i].lpm_enable);
}
}
}
}
// Update the camera streaming status
if (metaWide) {
mFovControlData.wideCamStreaming = true;
++mFovControlData.frameCountWide;
IF_META_AVAILABLE(uint8_t, enableLPM, CAM_INTF_META_DC_LOW_POWER_ENABLE, metaWide) {
if (*enableLPM) {
// If LPM enabled is 1, this is probably the last metadata returned
// before going into LPM state
mFovControlData.wideCamStreaming = false;
mFovControlData.frameCountWide = 0;
}
}
}
if (metaTele) {
mFovControlData.teleCamStreaming = true;
++mFovControlData.frameCountTele;
IF_META_AVAILABLE(uint8_t, enableLPM, CAM_INTF_META_DC_LOW_POWER_ENABLE, metaTele) {
if (*enableLPM) {
// If LPM enabled is 1, this is probably the last metadata returned
// before going into LPM state
mFovControlData.teleCamStreaming = false;
mFovControlData.frameCountTele = 0;
}
}
}
LOGD("active cameras: SAC requested %d, current wide streaming %d, tele streaming %d",
mFovControlData.spatialAlignResult.activeCameras, mFovControlData.wideCamStreaming,
mFovControlData.teleCamStreaming);
// Get AF status
if (metaMain) {
IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaMain) {
mFovControlData.afStatusMain = *afState;
LOGD("AF state: Main cam: %d", mFovControlData.afStatusMain);
}
IF_META_AVAILABLE(float, luxIndex, CAM_INTF_META_AEC_LUX_INDEX, metaMain) {
mFovControlData.status3A.main.ae.luxIndex = *luxIndex;
LOGD("Lux Index: Main cam: %f", mFovControlData.status3A.main.ae.luxIndex);
}
IF_META_AVAILABLE(int32_t, objDist, CAM_INTF_META_AF_OBJ_DIST_CM, metaMain) {
mFovControlData.status3A.main.af.focusDistCm = (*objDist < 0) ? 0 : *objDist;
LOGD("Obj Dist: Main cam: %d", mFovControlData.status3A.main.af.focusDistCm);
}
}
if (metaAux) {
IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaAux) {
mFovControlData.afStatusAux = *afState;
LOGD("AF state: Aux cam: %d", mFovControlData.afStatusAux);
}
IF_META_AVAILABLE(float, luxIndex, CAM_INTF_META_AEC_LUX_INDEX, metaAux) {
mFovControlData.status3A.aux.ae.luxIndex = *luxIndex;
LOGD("Lux Index: Aux cam: %f", mFovControlData.status3A.aux.ae.luxIndex);
}
IF_META_AVAILABLE(int32_t, objDist, CAM_INTF_META_AF_OBJ_DIST_CM, metaAux) {
mFovControlData.status3A.aux.af.focusDistCm = (*objDist < 0) ? 0 : *objDist;
LOGD("Obj Dist: Aux cam: %d", mFovControlData.status3A.aux.af.focusDistCm);
}
}
if ((masterCam == CAM_TYPE_AUX) && metaAux) {
// Translate face detection ROI from aux camera
IF_META_AVAILABLE(cam_face_detection_data_t, metaFD,
CAM_INTF_META_FACE_DETECTION, metaAux) {
cam_face_detection_data_t metaFDTranslated;
metaFDTranslated = translateRoiFD(*metaFD, CAM_TYPE_AUX);
ADD_SET_PARAM_ENTRY_TO_BATCH(metaAux, CAM_INTF_META_FACE_DETECTION,
metaFDTranslated);
}
metaResult = metaAux;
}
else if ((masterCam == CAM_TYPE_MAIN) && metaMain) {
// Translate face detection ROI from main camera
IF_META_AVAILABLE(cam_face_detection_data_t, metaFD,
CAM_INTF_META_FACE_DETECTION, metaMain) {
cam_face_detection_data_t metaFDTranslated;
metaFDTranslated = translateRoiFD(*metaFD, CAM_TYPE_MAIN);
ADD_SET_PARAM_ENTRY_TO_BATCH(metaMain, CAM_INTF_META_FACE_DETECTION,
metaFDTranslated);
}
metaResult = metaMain;
} else {
// Metadata for the master camera was dropped
metaResult = NULL;
LOGD("Metadata Result is NULL")
}
// If snapshot postprocess is enabled, consolidate the AF status to be sent to the app
// when in the transition state.
// Only return focused if both are focused.
bool snapshotPostProcess = mFovControlData.updateResultState ?
mFovControlResult.snapshotPostProcess :
mFovControlResultCachedCopy.snapshotPostProcess;
uint32_t camState = mFovControlData.updateResultState ?
mFovControlResult.activeCameras : mFovControlResultCachedCopy.activeCameras;
if (snapshotPostProcess &&
(camState == (CAM_TYPE_MAIN | CAM_TYPE_AUX)) &&
metaResult) {
if (!mDualCamParams.paramsMain.isAFSupported)
mFovControlData.afStatusMain = mFovControlData.afStatusAux;
else if (!mDualCamParams.paramsAux.isAFSupported)
mFovControlData.afStatusAux = mFovControlData.afStatusMain;
if (((mFovControlData.afStatusMain == CAM_AF_STATE_FOCUSED_LOCKED) ||
(mFovControlData.afStatusMain == CAM_AF_STATE_NOT_FOCUSED_LOCKED)) &&
((mFovControlData.afStatusAux == CAM_AF_STATE_FOCUSED_LOCKED) ||
(mFovControlData.afStatusAux == CAM_AF_STATE_NOT_FOCUSED_LOCKED))) {
// If both indicate focused, return focused.
// If either one indicates 'not focused', return 'not focused'.
if ((mFovControlData.afStatusMain == CAM_AF_STATE_FOCUSED_LOCKED) &&
(mFovControlData.afStatusAux == CAM_AF_STATE_FOCUSED_LOCKED)) {
ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
CAM_AF_STATE_FOCUSED_LOCKED);
} else {
ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
CAM_AF_STATE_NOT_FOCUSED_LOCKED);
}
} else {
// If either one indicates passive state or active scan, return that state
if ((mFovControlData.afStatusMain != CAM_AF_STATE_FOCUSED_LOCKED) &&
(mFovControlData.afStatusMain != CAM_AF_STATE_NOT_FOCUSED_LOCKED)) {
ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
mFovControlData.afStatusMain);
} else {
ADD_SET_PARAM_ENTRY_TO_BATCH(metaResult, CAM_INTF_META_AF_STATE,
mFovControlData.afStatusAux);
}
}
IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, metaResult) {
LOGD("Result AF state: %d", *afState);
}
}
mMutex.unlock();
// Generate FOV-control result only if the result meta is valid
if (metaResult) {
generateFovControlResult();
}
}
return metaResult;
}
/*===========================================================================
* FUNCTION : generateFovControlResult
*
* DESCRIPTION: Generate FOV control result
*
* PARAMETERS : None
*
* RETURN : None
*
*==========================================================================*/
void QCameraFOVControl::generateFovControlResult()
{
Mutex::Autolock lock(mMutex);
if (isBayerMono()) {
// Bayer is primary camera
mFovControlResult.camMasterPreview = CAM_TYPE_MAIN;
mFovControlResult.camMaster3A = CAM_TYPE_MAIN;
mFovControlResult.activeCameras = MM_CAMERA_DUAL_CAM;
mFovControlData.configCompleted = true;
if(mHalPPType != CAM_HAL_PP_TYPE_NONE)
{
mFovControlResult.snapshotPostProcess = true;
} else {
mFovControlResult.snapshotPostProcess = false;
}
mFovControlResult.isValid = true;
return;
} else if (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) {
// Tele is primary camera
mFovControlResult.camMasterPreview = mFovControlData.camTele;
mFovControlResult.camMaster3A = mFovControlData.camTele;
mFovControlResult.activeCameras =
(uint32_t)(mFovControlData.camTele | mFovControlData.camWide);
mFovControlData.configCompleted = true;
mFovControlResult.snapshotPostProcess = true;
mFovControlResult.oisMode = OIS_MODE_HOLD;
mFovControlResult.isValid = true;
return;
}
float zoom = findZoomRatio(mFovControlData.zoomUser) / (float)mFovControlData.zoomRatioTable[0];
uint32_t zoomCur = mFovControlData.zoomUser;
uint32_t zoomPrev = mFovControlData.zoomUserPrev;
if (mFovControlData.configCompleted == false) {
// Return as invalid result if the FOV-control configuration is not yet complete
mFovControlResult.isValid = false;
return;
}
// Update previous zoom value
mFovControlData.zoomUserPrev = mFovControlData.zoomUser;
uint16_t currentLuxIdx = 0;
uint16_t currentFocusDist = 0;
if (isMaster(CAM_TYPE_MAIN)) {
currentLuxIdx = mFovControlData.status3A.main.ae.luxIndex;
currentFocusDist = mFovControlData.status3A.main.af.focusDistCm;
} else {
currentLuxIdx = mFovControlData.status3A.aux.ae.luxIndex;
currentFocusDist = mFovControlData.status3A.aux.af.focusDistCm;
}
cam_sync_type_t camWide = mFovControlData.camWide;
cam_sync_type_t camTele = mFovControlData.camTele;
uint16_t thresholdLuxIdx = mFovControlConfig.auxSwitchLuxIdxMax;
uint16_t thresholdFocusDist = mFovControlConfig.auxSwitchFocusDistCmMin;
LOGD("current LuxIdx: %d, threshold LuxIdx: %d", currentLuxIdx, thresholdLuxIdx);
LOGD("current focus dist: %d, threshold focus dist: %d", currentFocusDist, thresholdFocusDist);
dual_cam_state prevCamState = mFovControlData.camState;
if (zoomCur == zoomPrev) {
mFovControlData.zoomDirection = ZOOM_STABLE;
} else if (zoomCur > zoomPrev) {
mFovControlData.zoomDirection = ZOOM_IN;
} else {
mFovControlData.zoomDirection = ZOOM_OUT;
}
// Update snapshot post-process flags
if (mFovControlConfig.snapshotPPConfig.enablePostProcess &&
(zoom >= mFovControlConfig.snapshotPPConfig.zoomMin) &&
(zoom <= mFovControlConfig.snapshotPPConfig.zoomMax)) {
mFovControlResult.snapshotPostProcessZoomRange = true;
} else {
mFovControlResult.snapshotPostProcessZoomRange = false;
}
if (mFovControlResult.snapshotPostProcessZoomRange &&
(currentLuxIdx <= mFovControlConfig.snapshotPPConfig.LuxIdxMax) &&
(currentFocusDist >= mFovControlConfig.snapshotPPConfig.focusDistanceMin)) {
mFovControlResult.snapshotPostProcess = true;
} else {
mFovControlResult.snapshotPostProcess = false;
}
// Default the fallback to No fallback
mFovControlResult.fallback = CAM_NO_FALLBACK;
switch (mFovControlData.camState) {
case STATE_WIDE:
// Start timerWellLitNonMacroScene timer if the scene is bright and non-macro,
// otherwise inactivate.
if (mFovControlData.fallbackEnabled) {
if ((currentLuxIdx <= thresholdLuxIdx) &&
(currentFocusDist >= thresholdFocusDist)) {
if (!mFovControlData.timerWellLitNonMacroScene.active) {
startTimer(&mFovControlData.timerWellLitNonMacroScene,
mFovControlConfig.fallbackTimeout);
LOGD("state: wide: start timer for well lit, non-macro scene");
}
} else {
inactivateTimer(&mFovControlData.timerWellLitNonMacroScene);
}
}
// Reset fallback to main flag if zoom is less than cutover point
if (mFovControlData.fallbackEnabled &&
mFovControlData.fallbackToWide &&
!needDualZone()) {
// Reset fallback to wide flag
mFovControlData.fallbackToWide = false;
LOGD("state: wide: fallback complete. zoom less than tele-to-wide threshold");
}
// Check if the scene is good for aux (bright and far focused) if fallback is enabled
if (!mFovControlData.fallbackEnabled ||
((currentLuxIdx <= thresholdLuxIdx) &&
(currentFocusDist >= thresholdFocusDist))) {
/* Switch to transition state if -
1. Scene is bright and far focused
2. Force cameras to wakeup (Bundled snapshot / autofocus)
3. Zoom is above threshold with user zooming in
4. No low light / macro scene fallback triggered
5. Spatial alignment disabling LPM on both if FOVControl fallback is disabled
Lower constraint if zooming in
This path is taken for the normal behavior - there was no fallback to wide state
due to low light, macro-scene and user zooms in with zoom hitting the threshold */
if ((mFovControlData.forceCameraWakeup) ||
(!mFovControlData.fallbackEnabled &&
((mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) &&
(mFovControlData.spatialAlignResult.activeCameras == (camWide | camTele)))) ||
(needDualZone() &&
((mFovControlData.zoomDirection == ZOOM_IN) ||
(mFovControlData.fallbackEnabled &&
(zoom >= mFovControlData.transitionParams.cutOverTeleToWide))) &&
(mFovControlData.fallbackToWide == false))) {
mFovControlData.camState = STATE_TRANSITION;
mFovControlResult.activeCameras = (camWide | camTele);
if (mFovControlData.forceCameraWakeup) {
LOGD("state: wide: Forced camera wakeup (bundled snapshot/autofocus)."
" Switching to Transition state");
}
}
/* 6. Low light / macro scene fallback was triggered and completed
Higher constraint if not zooming in.
This path is taken if the state had transitioned to wide due to low light or
macro scene - check that using mFovControlData.fallbackToWide flag.
timerWellLitNonMacroScene will timeout if the scene continues to be bright and
non-macro for the duration specified as FOVC_FALLBACK_TIMEOUT_MS.
This indicates that the scene is bright and non-macro, as a result it's safe to
move back to transition state */
else if (mFovControlData.fallbackEnabled &&
mFovControlData.fallbackToWide &&
isTimedOut(mFovControlData.timerWellLitNonMacroScene)) {
// Enter the transition state
mFovControlData.camState = STATE_TRANSITION;
mFovControlResult.activeCameras = (camWide | camTele);
// Reset fallback to wide flag
mFovControlData.fallbackToWide = false;
LOGD("state: wide: fallback complete. Switching to Transition state");
}
} else {
LOGD("state: wide: low light / macro scene. Remain in Wide state.");
// Set the fallback to Wide
mFovControlResult.fallback = CAM_WIDE_FALLBACK;
}
break;
case STATE_TRANSITION:
// Start const-zoom timer if needed
if (mFovControlData.zoomDirection == ZOOM_STABLE) {
if (!mFovControlData.timerConstZoom.active ||
mFovControlData.forceCameraWakeup) {
/* Provide the timeout value based on whether zoom is in snapshot
postprocess range. */
startTimer(&mFovControlData.timerConstZoom,
(mFovControlResult.snapshotPostProcessZoomRange ?
mFovControlConfig.constZoomTimeoutSnapshotPPRange :
mFovControlConfig.constZoomTimeout));
LOGD("state: transition: start const zoom timer");
}
} else {
inactivateTimer(&mFovControlData.timerConstZoom);
}
if (mFovControlData.fallbackEnabled) {
if ((currentLuxIdx > thresholdLuxIdx) ||
(currentFocusDist < thresholdFocusDist)) {
/* Update timerLowLitMacroScene / fallback timer if the scene continues
to be dark or macro */
if (!mFovControlData.timerLowLitMacroScene.active) {
startTimer(&mFovControlData.timerLowLitMacroScene,
mFovControlConfig.fallbackTimeout);
inactivateTimer(&mFovControlData.timerWellLitNonMacroScene);
LOGD("state: transition: start fallback timer");
}
// If the fallback timer times out, set the fallback flag to true
if (isTimedOut(mFovControlData.timerLowLitMacroScene)) {
mFovControlData.fallbackToWide = true;
mFovControlData.fallbackInitedInTransition = true;
LOGD("state: transition: fallback timer timed out");
}
} else {
/* Update timerWellLitNonMacroScene timer to check if the scene is
bright and non-macro */
if (!mFovControlData.timerWellLitNonMacroScene.active) {
startTimer(&mFovControlData.timerWellLitNonMacroScene,
mFovControlConfig.fallbackTimeout);
inactivateTimer(&mFovControlData.timerLowLitMacroScene);
LOGD("state: transition: start timer for well lit, non-macro scene");
}
// If the fallback timer times out, set the fallback flag to true
if (isTimedOut(mFovControlData.timerWellLitNonMacroScene)) {
mFovControlData.fallbackToWide = false;
mFovControlData.fallbackInitedInTransition = false;
LOGD("state: transition: well lit, non-macro scene timer timed out");
}
}
}
// Set the master info
// Switch to wide
if (isMaster(camTele) &&
canSwitchMasterTo(CAM_ROLE_WIDE)) {
mFovControlResult.camMasterPreview = camWide;
mFovControlResult.camMaster3A = camWide;
LOGD("state: transition: Switching master to Wide");
}
// switch to tele
else if (isMaster(camWide) &&
canSwitchMasterTo(CAM_ROLE_TELE)) {
mFovControlResult.camMasterPreview = camTele;
mFovControlResult.camMaster3A = camTele;
LOGD("state: transition: Switching master to Tele");
}
/* Change the transition state if necessary.
Switch to wide state if -
1. The low light / macro scene detected */
if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
if (isMaster(camWide) &&
(!mFovControlData.availableSpatialAlignSolns ||
(mFovControlData.spatialAlignResult.camMasterPreview == camWide)) &&
(!mFovControlData.fallbackInitedInTransition ||
FOVC_TELE_LPM_IN_TRANSITION_WITH_FALLBACK)) {
// Put Tele to LPM only when Spatial alignment starts outputing Wide
mFovControlData.camState = STATE_WIDE;
mFovControlResult.activeCameras = camWide;
LOGD("state: transition: low light / Macro scene fallback triggered."
" Switching to Wide state");
}
// 2. Zoom is below threshold
} else if (!needDualZone() && isMaster(camWide)) {
mFovControlData.camState = STATE_WIDE;
mFovControlResult.activeCameras = camWide;
/* Switch to tele state if -
1. Zoom is above threshold */
} else if (!needDualZone() && isMaster(camTele)) {
mFovControlData.camState = STATE_TELE;
mFovControlResult.activeCameras = camTele;
} else if (isTimedOut(mFovControlData.timerConstZoom) &&
(mFovControlData.fallbackEnabled ||
((mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) &&
(mFovControlData.spatialAlignResult.activeCameras !=
(camWide | camTele))))) {
/* timerConstZoom will timeout if the zoom does not change for the duration
specified as FOVC_CONST_ZOOM_TIMEOUT_MS
If the zoom is stable put the non-master camera to LPM for power optimization */
if (isMaster(camWide)) {
mFovControlData.camState = STATE_WIDE;
mFovControlResult.activeCameras = camWide;
LOGD("state: transition: const zoom timer timed out. Switching to Wide state");
} else {
mFovControlData.camState = STATE_TELE;
mFovControlResult.activeCameras = camTele;
LOGD("state: transition: const zoom timer timed out. Switching to Tele state");
}
}
break;
case STATE_TELE:
/* Update the fallback timer if the scene continues to be dark or macro,
reset otherwise */
if (mFovControlData.fallbackEnabled) {
if ((currentLuxIdx > thresholdLuxIdx) ||
(currentFocusDist < thresholdFocusDist)) {
if (!mFovControlData.timerLowLitMacroScene.active) {
startTimer(&mFovControlData.timerLowLitMacroScene,
mFovControlConfig.fallbackTimeout);
LOGD("state: tele: start fallback timer");
}
/* timerLowLitMacroScene will timeout if the scene continues to be dark or macro
for the duration specified as FOVC_FALLBACK_TIMEOUT_MS
If the fallback timer times out, set the fallback flag to true */
if (isTimedOut(mFovControlData.timerLowLitMacroScene)) {
mFovControlData.fallbackToWide = true;
mFovControlData.fallbackInitedInTransition = false;
LOGD("state: tele: fallback timer timed out");
}
} else {
inactivateTimer(&mFovControlData.timerLowLitMacroScene);
}
}
/* Switch to transition state if -
1. Start fallback to wide if the low light / macro scene detected
2. Force cameras to wakeup (Bundled snapshot / autofocus) */
if ((mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) ||
(mFovControlData.forceCameraWakeup)) {
mFovControlData.camState = STATE_TRANSITION;
mFovControlResult.activeCameras = (camWide | camTele);
if (mFovControlData.forceCameraWakeup) {
LOGD("state: tele: Forced camera wakeup (bundled snapshot/autofocus)."
" Switching to Transition state");
} else if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
LOGD("state: tele: low light / Macro scene fallback triggered."
" Switching to Transition state");
}
}
/* 3. Zooming out and if the zoom value is less than the threshold
4. Spatial alignment disabling LPM on both if FOVControl fallback is disabled */
else if ((needDualZone() && (mFovControlData.zoomDirection == ZOOM_OUT)) ||
(!mFovControlData.fallbackEnabled &&
((mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) &&
(mFovControlData.spatialAlignResult.activeCameras ==(camWide | camTele))))||
(mFovControlData.fallbackEnabled &&
(zoom <= mFovControlData.transitionParams.cutOverWideToTele))) {
mFovControlData.camState = STATE_TRANSITION;
mFovControlResult.activeCameras = (camWide | camTele);
}
break;
}
// Inactivate the timers if the camera state changed
if (prevCamState != mFovControlData.camState) {
inactivateTimer(&mFovControlData.timerLowLitMacroScene);
inactivateTimer(&mFovControlData.timerWellLitNonMacroScene);
inactivateTimer(&mFovControlData.timerConstZoom);
LOGD("Active camera state changed. Reset timers");
}
// Only one active camera in case of thermal throttle and disable snapshot post-processing
if (mFovControlData.thermalThrottle) {
mFovControlResult.activeCameras = isMaster(camWide) ? camWide : camTele;
mFovControlResult.snapshotPostProcess = false;
}
// Update OIS mode in the result
if (mFovControlData.oisSetting == OIS_ACTIVE_IN_LPM) {
mFovControlResult.oisMode = (mFovControlData.camState == STATE_TRANSITION) ?
OIS_MODE_HOLD : OIS_MODE_ACTIVE;
} else if (mFovControlData.oisSetting == OIS_HOLD) {
mFovControlResult.oisMode = OIS_MODE_HOLD;
}
// Update fallback result if needed
if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
mFovControlResult.fallback = CAM_WIDE_FALLBACK;
}
mFovControlResult.isValid = true;
// Debug print for the FOV-control result
LOGD("Effective zoom: %f", zoom);
LOGD("zoom direction: %s", ((mFovControlData.zoomDirection == ZOOM_STABLE) ? "STABLE" :
((mFovControlData.zoomDirection == ZOOM_IN) ? "IN" : "OUT")));
LOGD("zoomWide: %d, zoomTele: %d", mFovControlData.zoomWide, mFovControlData.zoomTele);
LOGD("Snapshot postprocess: %d", mFovControlResult.snapshotPostProcess);
LOGD("Master camera : %s", (mFovControlResult.camMasterPreview == CAM_TYPE_MAIN) ?
"CAM_TYPE_MAIN" : "CAM_TYPE_AUX");
LOGD("Master camera for preview: %s",
(mFovControlResult.camMasterPreview == camWide ) ? "Wide" : "Tele");
LOGD("Master camera for 3A : %s",
(mFovControlResult.camMaster3A == camWide ) ? "Wide" : "Tele");
LOGD("Wide camera status : %s",
(mFovControlResult.activeCameras & camWide) ? "Active" : "LPM");
LOGD("Tele camera status : %s",
(mFovControlResult.activeCameras & camTele) ? "Active" : "LPM");
LOGH("transition state: %s", ((mFovControlData.camState == STATE_WIDE) ? "STATE_WIDE" :
((mFovControlData.camState == STATE_TELE) ? "STATE_TELE" : "STATE_TRANSITION" )));
LOGD("OIS mode: %s", ((mFovControlResult.oisMode == OIS_MODE_ACTIVE) ? "ACTIVE" :
((mFovControlResult.oisMode == OIS_MODE_HOLD) ? "HOLD" : "INACTIVE")));
LOGD("fallback : %d, thermal throttle: %d", mFovControlResult.fallback,
mFovControlData.thermalThrottle);
}
/*===========================================================================
* FUNCTION : getFovControlResult
*
* DESCRIPTION: Return FOV-control result
*
* PARAMETERS : None
*
* RETURN : FOV-control result
*
*==========================================================================*/
fov_control_result_t QCameraFOVControl::getFovControlResult()
{
Mutex::Autolock lock(mMutex);
/* Return either the latest result or the cached result based on the update flag
set by HAL */
fov_control_result_t fovControlResult = mFovControlData.updateResultState ?
mFovControlResult : mFovControlResultCachedCopy;
return fovControlResult;
}
/*===========================================================================
* FUNCTION : isMainCamFovWider
*
* DESCRIPTION : Check if the main camera FOV is wider than aux
*
* PARAMETERS : None
*
* RETURN :
* true : If main cam FOV is wider than tele
* false : If main cam FOV is narrower than tele
*
*==========================================================================*/
bool QCameraFOVControl::isMainCamFovWider()
{
if (mDualCamParams.paramsMain.focalLengthMm <
mDualCamParams.paramsAux.focalLengthMm) {
return true;
} else {
return false;
}
}
/*===========================================================================
* FUNCTION : needDualZone
*
* DESCRIPTION : Check if both the cameras need to be active.
*
* PARAMETERS : None
*
* RETURN :
* true : If dual zone is needed
* false : If dual zone is not needed
*
*==========================================================================*/
bool QCameraFOVControl::needDualZone()
{
bool ret = false;
cam_sync_type_t camWide = mFovControlData.camWide;
cam_sync_type_t camTele = mFovControlData.camTele;
float zoom = findZoomRatio(mFovControlData.zoomUser) / (float)mFovControlData.zoomRatioTable[0];
float transitionLow = mFovControlData.transitionParams.transitionLow;
float transitionHigh = mFovControlData.transitionParams.transitionHigh;
float cutoverWideToTele = mFovControlData.transitionParams.cutOverWideToTele;
float cutoverTeleToWide = mFovControlData.transitionParams.cutOverTeleToWide;
if (mFovControlResult.snapshotPostProcessZoomRange) {
ret = true;
}
// Return true if Spatial alignment block requested both the cameras to be active or
// if zoom level dictates so
else if (((mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) &&
(mFovControlData.spatialAlignResult.activeCameras == (camWide | camTele))) ||
((zoom >= transitionLow) && (zoom <= transitionHigh)) ||
(mFovControlData.fallbackEnabled &&
(((zoom >= cutoverWideToTele) && isMaster(camWide)) ||
((zoom <= cutoverTeleToWide) && isMaster(camTele))))) {
ret = true;
}
return ret;
}
/*===========================================================================
* FUNCTION : canSwitchMasterTo
*
* DESCRIPTION : Check if the master can be switched to the camera- cam.
*
* PARAMETERS :
* @cam : cam type
*
* RETURN :
* true : If master can be switched
* false : If master cannot be switched
*
*==========================================================================*/
bool QCameraFOVControl::canSwitchMasterTo(
uint32_t cam)
{
bool ret = false;
float zoom = findZoomRatio(mFovControlData.zoomUser) / (float)mFovControlData.zoomRatioTable[0];
float cutOverWideToTele = mFovControlData.transitionParams.cutOverWideToTele;
float cutOverTeleToWide = mFovControlData.transitionParams.cutOverTeleToWide;
uint16_t thresholdLuxIdx = mFovControlConfig.auxSwitchLuxIdxMax;
uint16_t thresholdFocusDist = mFovControlConfig.auxSwitchFocusDistCmMin;
uint16_t currentLuxIdxTele = 0;
uint16_t currentFocusDistTele = 0;
if (mFovControlData.camTele == CAM_TYPE_AUX) {
currentLuxIdxTele = mFovControlData.status3A.aux.ae.luxIndex;
currentFocusDistTele = mFovControlData.status3A.aux.af.focusDistCm;
} else {
currentLuxIdxTele = mFovControlData.status3A.main.ae.luxIndex;
currentFocusDistTele = mFovControlData.status3A.main.af.focusDistCm;
}
LOGD("Tele: current LuxIdx: %d, threshold LuxIdx: %d", currentLuxIdxTele, thresholdLuxIdx);
LOGD("Tele: current focus dist: %d, threshold focus dist: %d",
currentFocusDistTele, thresholdFocusDist);
LOGD("frameCountWide: %d, frameCountTele: %d",
mFovControlData.frameCountWide, mFovControlData.frameCountTele);
if (cam == CAM_ROLE_WIDE) {
// In case of thermal throttle, only check zoom value for master switch.
if (mFovControlData.thermalThrottle) {
if (zoom < cutOverTeleToWide) {
ret = true;
}
} else if (mFovControlData.wideCamStreaming &&
(mFovControlData.frameCountWide > FOVC_MIN_FRAME_WAIT_FOR_MASTER_SWITCH)) {
if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
/* If the fallback is initiated, only switch the master when the spatial alignment
confirms the completion of the fallback. */
if (!(mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) ||
((mFovControlData.spatialAlignResult.camMasterHint == 0) &&
mFovControlData.spatialAlignResult.fallbackComplete)) {
ret = true;
} else if (zoom < cutOverTeleToWide) {
// In case of QTI Spatial alignment solution and no spatial alignment solution,
// check the fallback flag or if the zoom level has crossed the threhold.
ret = true;
}
} else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
// In case of OEM Spatial alignment solution, check the spatial alignment ready
if (isSpatialAlignmentReady()) {
ret = true;
}
} else if (zoom < cutOverTeleToWide) {
// In case of QTI Spatial alignment solution and no spatial alignment solution,
// check the fallback flag or if the zoom level has crossed the threhold.
ret = true;
}
}
} else if (cam == CAM_ROLE_TELE) {
if (mFovControlData.fallbackEnabled && mFovControlData.fallbackToWide) {
// If the fallback to wide is initiated, don't switch the master to tele
ret = false;
} else if (mFovControlData.thermalThrottle) {
// In case of thermal throttle, only check zoom value for master switch.
if (zoom > cutOverWideToTele) {
ret = true;
}
} else if (mFovControlData.teleCamStreaming &&
(mFovControlData.frameCountTele > FOVC_MIN_FRAME_WAIT_FOR_MASTER_SWITCH)) {
bool teleWellLitNonMacroScene = !mFovControlData.fallbackEnabled ||
(currentLuxIdxTele <= thresholdLuxIdx);
if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
// In case of OEM Spatial alignment solution, check the spatial alignment ready
if (isSpatialAlignmentReady() &&
teleWellLitNonMacroScene) {
ret = true;
}
} else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_QTI) {
// In case of QTI Spatial alignment solution check the spatial alignment ready flag
// and if the zoom level has crossed the threhold.
if (isSpatialAlignmentReady() &&
(zoom > cutOverWideToTele) &&
teleWellLitNonMacroScene) {
ret = true;
}
} else {
// In case of no spatial alignment solution check if
// the zoom level has crossed the threhold.
if ((zoom > cutOverWideToTele) &&
teleWellLitNonMacroScene) {
ret = true;
}
}
}
} else {
LOGE("Request to switch to invalid cam type");
}
return ret;
}
/*===========================================================================
* FUNCTION : isSpatialAlignmentReady
*
* DESCRIPTION : Check if the spatial alignment is ready.
* For QTI solution, check ready_status flag
* For OEM solution, check camMasterHint
* If the spatial alignment solution is not needed, return true
*
* PARAMETERS : None
*
* RETURN :
* true : If spatial alignment is ready
* false : If spatial alignment is not yet ready
*
*==========================================================================*/
bool QCameraFOVControl::isSpatialAlignmentReady()
{
bool ret = true;
cam_sync_type_t camWide = mFovControlData.camWide;
cam_sync_type_t camTele = mFovControlData.camTele;
if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_OEM) {
uint8_t currentMaster = (uint8_t)mFovControlResult.camMasterPreview;
uint8_t camMasterHint = mFovControlData.spatialAlignResult.camMasterHint;
LOGD("current master: %d, recommended master: %d", currentMaster, camMasterHint);
if (((currentMaster == camWide) && (camMasterHint == camTele)) ||
((currentMaster == camTele) && (camMasterHint == camWide))){
ret = true;
} else {
ret = false;
}
} else if (mFovControlData.availableSpatialAlignSolns & CAM_SPATIAL_ALIGN_QTI) {
if (mFovControlData.spatialAlignResult.readyStatus) {
ret = true;
} else {
ret = false;
}
}
return ret;
}
/*===========================================================================
* FUNCTION : isMaster
*
* DESCRIPTION : Check if the given camera is master.
*
* PARAMETERS :
* @cam : input camera for master check
*
* RETURN : Boolean indicating if the given camera is master
*
*==========================================================================*/
inline bool QCameraFOVControl::isMaster(
cam_sync_type_t cam)
{
if ((mFovControlResult.camMasterPreview == cam) &&
(mFovControlResult.camMaster3A == cam)) {
return true;
} else {
return false;
}
}
/*===========================================================================
* FUNCTION : isTimedOut
*
* DESCRIPTION : Check if the timer is timed out.
*
* PARAMETERS :
* @timer : Timer to check the timeout.
*
* RETURN : Boolean indicating if timed out
*
*==========================================================================*/
bool QCameraFOVControl::isTimedOut(
timer_t timer)
{
if (timer.active && (systemTime() > timer.timeout)) {
return true;
}
return false;
}
/*===========================================================================
* FUNCTION : startTimer
*
* DESCRIPTION : Start the timer for the duration specified.
*
* PARAMETERS :
* @timer : Timer to start.
* @time : Time duration in ms.
*
* RETURN : void
*
*==========================================================================*/
void QCameraFOVControl::startTimer(
timer_t *timer,
uint32_t time)
{
if (time > 0) {
timer->timeout = systemTime() + ms2ns(time);
timer->active = true;
}
}
/*===========================================================================
* FUNCTION : inactivateTimer
*
* DESCRIPTION : Stop the timer and set the 'active' flag to false.
*
* PARAMETERS :
* @timer : Timer to stop.
*
* RETURN : void
*
*==========================================================================*/
void QCameraFOVControl::inactivateTimer(
timer_t *timer)
{
timer->active = false;
}
/*===========================================================================
* FUNCTION : validateAndExtractParameters
*
* DESCRIPTION : Validates a subset of parameters from capabilities and
* saves those parameters for decision making.
*
* PARAMETERS :
* @capsMain : The capabilities for the main camera
* @capsAux : The capabilities for the aux camera
*
* RETURN :
* true : Success
* false : Failure
*
*==========================================================================*/
bool QCameraFOVControl::validateAndExtractParameters(
cam_capability_t *capsMainCam,
cam_capability_t *capsAuxCam)
{
bool rc = false;
if (capsMainCam && capsAuxCam) {
char propSAC[PROPERTY_VALUE_MAX];
char propSAT[PROPERTY_VALUE_MAX];
property_get("persist.vendor.camera.sac.enable", propSAC, "0");
property_get("persist.vendor.camera.sat.enable", propSAT, "0");
mFovControlConfig.percentMarginHysterisis = 5;
mFovControlConfig.percentMarginMain = 25;
mFovControlConfig.percentMarginAux = 15;
mDualCamParams.paramsMain.focalLengthMm = capsMainCam->focal_length;
mDualCamParams.paramsAux.focalLengthMm = capsAuxCam->focal_length;
mDualCamParams.paramsMain.pixelPitchUm = capsMainCam->pixel_pitch_um;
mDualCamParams.paramsAux.pixelPitchUm = capsAuxCam->pixel_pitch_um;
if (capsMainCam->supported_focus_modes_cnt > 1)
mDualCamParams.paramsMain.isAFSupported = true;
if (capsAuxCam->supported_focus_modes_cnt > 1)
mDualCamParams.paramsAux.isAFSupported = true;
if (((capsMainCam->avail_spatial_align_solns & CAM_SPATIAL_ALIGN_QTI) && atoi(propSAC)) ||
((capsMainCam->avail_spatial_align_solns & CAM_SPATIAL_ALIGN_OEM) &&
atoi(propSAT))) {
mFovControlData.availableSpatialAlignSolns =
capsMainCam->avail_spatial_align_solns;
} else {
LOGW("Spatial alignment not supported");
}
if (capsMainCam->zoom_supported > 0) {
mFovControlData.zoomRatioTable = capsMainCam->zoom_ratio_tbl;
mFovControlData.zoomRatioTableCount = capsMainCam->zoom_ratio_tbl_cnt;
} else {
LOGE("zoom feature not supported");
return false;
}
rc = true;
}
return rc;
}
/*===========================================================================
* FUNCTION : calculateBasicFovRatio
*
* DESCRIPTION: Calculate the FOV ratio between main and aux cameras
*
* PARAMETERS : None
*
* RETURN :
* true : Success
* false : Failure
*
*==========================================================================*/
bool QCameraFOVControl::calculateBasicFovRatio()
{
float fovWide = 0.0f;
float fovTele = 0.0f;
bool rc = false;
if ((mDualCamParams.paramsMain.focalLengthMm > 0.0f) &&
(mDualCamParams.paramsAux.focalLengthMm > 0.0f)) {
if (mDualCamParams.paramsMain.focalLengthMm <
mDualCamParams.paramsAux.focalLengthMm) {
fovWide = (mDualCamParams.paramsMain.sensorStreamWidth *
mDualCamParams.paramsMain.pixelPitchUm) /
mDualCamParams.paramsMain.focalLengthMm;
fovTele = (mDualCamParams.paramsAux.sensorStreamWidth *
mDualCamParams.paramsAux.pixelPitchUm) /
mDualCamParams.paramsAux.focalLengthMm;
} else {
fovWide = (mDualCamParams.paramsAux.sensorStreamWidth *
mDualCamParams.paramsAux.pixelPitchUm) /
mDualCamParams.paramsAux.focalLengthMm;
fovTele = (mDualCamParams.paramsMain.sensorStreamWidth *
mDualCamParams.paramsMain.pixelPitchUm) /
mDualCamParams.paramsMain.focalLengthMm;
}
if (fovTele > 0.0f) {
mFovControlData.basicFovRatio = (fovWide / fovTele);
rc = true;
}
}
LOGD("Main cam focalLengthMm : %f", mDualCamParams.paramsMain.focalLengthMm);
LOGD("Aux cam focalLengthMm : %f", mDualCamParams.paramsAux.focalLengthMm);
LOGD("Main cam sensorStreamWidth : %u", mDualCamParams.paramsMain.sensorStreamWidth);
LOGD("Main cam sensorStreamHeight: %u", mDualCamParams.paramsMain.sensorStreamHeight);
LOGD("Aux cam sensorStreamWidth : %u", mDualCamParams.paramsAux.sensorStreamWidth);
LOGD("Aux cam sensorStreamHeight : %u", mDualCamParams.paramsAux.sensorStreamHeight);
LOGD("Main cam pixelPitchUm : %f", mDualCamParams.paramsMain.pixelPitchUm);
LOGD("Aux cam pixelPitchUm : %f", mDualCamParams.paramsAux.pixelPitchUm);
LOGD("fov wide : %f", fovWide);
LOGD("fov tele : %f", fovTele);
LOGD("BasicFovRatio : %f", mFovControlData.basicFovRatio);
return rc;
}
/*===========================================================================
* FUNCTION : combineFovAdjustment
*
* DESCRIPTION: Calculate the final FOV adjustment by combining basic FOV ratio
* with the margin info
*
* PARAMETERS : None
*
* RETURN :
* true : Success
* false : Failure
*
*==========================================================================*/
bool QCameraFOVControl::combineFovAdjustment()
{
float ratioMarginWidth;
float ratioMarginHeight;
float adjustedRatio;
bool rc = false;
ratioMarginWidth = (1.0 + (mFovControlData.camMainWidthMargin)) /
(1.0 + (mFovControlData.camAuxWidthMargin));
ratioMarginHeight = (1.0 + (mFovControlData.camMainHeightMargin)) /
(1.0 + (mFovControlData.camAuxHeightMargin));
adjustedRatio = (ratioMarginHeight < ratioMarginWidth) ? ratioMarginHeight : ratioMarginWidth;
if (adjustedRatio > 0.0f) {
mFovControlData.transitionParams.cutOverFactor =
(mFovControlData.basicFovRatio / adjustedRatio);
rc = true;
}
LOGD("Main cam margin for width : %f", mFovControlData.camMainWidthMargin);
LOGD("Main cam margin for height : %f", mFovControlData.camMainHeightMargin);
LOGD("Aux cam margin for width : %f", mFovControlData.camAuxWidthMargin);
LOGD("Aux cam margin for height : %f", mFovControlData.camAuxHeightMargin);
LOGD("Width margin ratio : %f", ratioMarginWidth);
LOGD("Height margin ratio : %f", ratioMarginHeight);
return rc;
}
/*===========================================================================
* FUNCTION : calculateDualCamTransitionParams
*
* DESCRIPTION: Calculate the transition parameters needed to switch the camera
* between main and aux
*
* PARAMETERS :
* @fovAdjustBasic : basic FOV ratio
* @zoomTranslationFactor: translation factor for main, aux zoom
*
* RETURN : none
*
*==========================================================================*/
void QCameraFOVControl::calculateDualCamTransitionParams()
{
float percentMarginWide;
float percentMarginTele;
if (isMainCamFovWider()) {
percentMarginWide = mFovControlConfig.percentMarginMain;
percentMarginTele = mFovControlConfig.percentMarginAux;
} else {
percentMarginWide = mFovControlConfig.percentMarginAux;
percentMarginTele = mFovControlConfig.percentMarginMain;
}
mFovControlData.transitionParams.cropRatio = mFovControlData.basicFovRatio;
mFovControlData.transitionParams.cutOverWideToTele =
mFovControlData.transitionParams.cutOverFactor +
(mFovControlConfig.percentMarginHysterisis / 100.0) * mFovControlData.basicFovRatio;
mFovControlData.transitionParams.cutOverTeleToWide =
mFovControlData.transitionParams.cutOverFactor;
mFovControlData.transitionParams.transitionHigh =
mFovControlData.transitionParams.cutOverWideToTele +
(percentMarginWide / 100.0) * mFovControlData.basicFovRatio;
mFovControlData.transitionParams.transitionLow =
mFovControlData.transitionParams.cutOverTeleToWide -
(percentMarginTele / 100.0) * mFovControlData.basicFovRatio;
if (mFovControlConfig.snapshotPPConfig.enablePostProcess) {
// Expand the transition zone if necessary to account for
// the snapshot post-process settings
if (mFovControlConfig.snapshotPPConfig.zoomMax >
mFovControlData.transitionParams.transitionHigh) {
mFovControlData.transitionParams.transitionHigh =
mFovControlConfig.snapshotPPConfig.zoomMax;
}
if (mFovControlConfig.snapshotPPConfig.zoomMin <
mFovControlData.transitionParams.transitionLow) {
mFovControlData.transitionParams.transitionLow =
mFovControlConfig.snapshotPPConfig.zoomMin;
}
}
LOGD("transition param: TransitionLow %f", mFovControlData.transitionParams.transitionLow);
LOGD("transition param: TeleToWide %f", mFovControlData.transitionParams.cutOverTeleToWide);
LOGD("transition param: WideToTele %f", mFovControlData.transitionParams.cutOverWideToTele);
LOGD("transition param: TransitionHigh %f", mFovControlData.transitionParams.transitionHigh);
}
/*===========================================================================
* FUNCTION : findZoomValue
*
* DESCRIPTION: For the input zoom ratio, find the zoom value.
* Zoom table contains zoom ratios where the indices
* in the zoom table indicate the corresponding zoom values.
* PARAMETERS :
* @zoomRatio : Zoom ratio
*
* RETURN : Zoom value
*
*==========================================================================*/
uint32_t QCameraFOVControl::findZoomValue(
uint32_t zoomRatio)
{
uint32_t zoom = 0;
for (uint32_t i = 0; i < mFovControlData.zoomRatioTableCount; ++i) {
if (zoomRatio <= mFovControlData.zoomRatioTable[i]) {
zoom = i;
break;
}
}
return zoom;
}
/*===========================================================================
* FUNCTION : findZoomRatio
*
* DESCRIPTION: For the input zoom value, find the zoom ratio.
* Zoom table contains zoom ratios where the indices
* in the zoom table indicate the corresponding zoom values.
* PARAMETERS :
* @zoom : zoom value
*
* RETURN : zoom ratio
*
*==========================================================================*/
uint32_t QCameraFOVControl::findZoomRatio(
uint32_t zoom)
{
return mFovControlData.zoomRatioTable[zoom];
}
/*===========================================================================
* FUNCTION : readjustZoomForTele
*
* DESCRIPTION: Calculate the zoom value for the tele camera based on zoom value
* for the wide camera
*
* PARAMETERS :
* @zoomWide : Zoom value for wide camera
*
* RETURN : Zoom value for tele camera
*
*==========================================================================*/
uint32_t QCameraFOVControl::readjustZoomForTele(
uint32_t zoomWide)
{
uint32_t zoomRatioWide;
uint32_t zoomRatioTele;
zoomRatioWide = findZoomRatio(zoomWide);
zoomRatioTele = zoomRatioWide / mFovControlData.transitionParams.cutOverFactor;
mFovControlData.zoomRatioWide = zoomRatioWide;
mFovControlData.zoomRatioTele = zoomRatioTele;
return(findZoomValue(zoomRatioTele));
}
/*===========================================================================
* FUNCTION : readjustZoomForWide
*
* DESCRIPTION: Calculate the zoom value for the wide camera based on zoom value
* for the tele camera
*
* PARAMETERS :
* @zoomTele : Zoom value for tele camera
*
* RETURN : Zoom value for wide camera
*
*==========================================================================*/
uint32_t QCameraFOVControl::readjustZoomForWide(
uint32_t zoomTele)
{
uint32_t zoomRatioWide;
uint32_t zoomRatioTele;
zoomRatioTele = findZoomRatio(zoomTele);
zoomRatioWide = zoomRatioTele * mFovControlData.transitionParams.cutOverFactor;
mFovControlData.zoomRatioWide = zoomRatioWide;
mFovControlData.zoomRatioTele = zoomRatioTele;
return(findZoomValue(zoomRatioWide));
}
/*===========================================================================
* FUNCTION : convertUserZoomToWideAndTele
*
* DESCRIPTION: Calculate the zoom value for the wide and tele cameras
* based on the input user zoom value
*
* PARAMETERS :
* @zoom : User zoom value
*
* RETURN : none
*
*==========================================================================*/
void QCameraFOVControl::convertUserZoomToWideAndTele(
uint32_t zoom)
{
Mutex::Autolock lock(mMutex);
mFovControlData.zoomUser = zoom;
// If the zoom translation library is present and initialized,
// use it to get wide and tele zoom values
if (mZoomTranslator && mZoomTranslator->isInitialized()) {
zoom_data zoomData;
if (mZoomTranslator->getZoomValues(zoom, &zoomData) != NO_ERROR) {
LOGE("getZoomValues failed from zoom translation lib");
// Use zoom translation logic from FOV-control
mFovControlData.zoomWide = zoom;
mFovControlData.zoomTele = readjustZoomForTele(mFovControlData.zoomWide);
} else {
// Use the zoom values provided by zoom translation lib
mFovControlData.zoomWideIsp = zoomData.zoomWideIsp;
mFovControlData.zoomTeleIsp = zoomData.zoomTeleIsp;
mFovControlData.zoomWide = zoomData.zoomWideTotal;
mFovControlData.zoomTele = zoomData.zoomTeleTotal;
}
} else {
if (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) {
mFovControlData.zoomTele = zoom;
mFovControlData.zoomWide = readjustZoomForWide(mFovControlData.zoomTele);
} else {
mFovControlData.zoomWide = zoom;
mFovControlData.zoomTele = readjustZoomForTele(mFovControlData.zoomWide);
}
mFovControlData.zoomWideIsp = mFovControlData.zoomWide;
mFovControlData.zoomTeleIsp = mFovControlData.zoomTele;
}
}
/*===========================================================================
* FUNCTION : translateFocusAreas
*
* DESCRIPTION: Translate the focus areas from main to aux camera.
*
* PARAMETERS :
* @roiAfMain : Focus area ROI for main camera
* @cam : Cam type
*
* RETURN : Translated focus area ROI for aux camera
*
*==========================================================================*/
cam_roi_info_t QCameraFOVControl::translateFocusAreas(
cam_roi_info_t roiAfMain,
cam_sync_type_t cam)
{
float fovRatio;
float zoomWide;
float zoomTele;
float AuxRoiLeft;
float AuxRoiTop;
cam_roi_info_t roiAfTrans = roiAfMain;
int32_t shiftHorzAdjusted;
int32_t shiftVertAdjusted;
zoomWide = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
zoomTele = findZoomRatio(mFovControlData.zoomTele) / (float)mFovControlData.zoomRatioTable[0];
if (cam == mFovControlData.camWide) {
fovRatio = (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) ?
(1.0f / mFovControlData.transitionParams.cropRatio) : 1.0f;
} else {
fovRatio = (zoomTele / zoomWide) * mFovControlData.transitionParams.cropRatio;
}
// Acquire the mutex in order to read the spatial alignment result which is written
// by another thread
mMutex.lock();
if (cam == mFovControlData.camWide) {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz * zoomWide;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert * zoomWide;
} else {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz * zoomTele;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert * zoomTele;
}
mMutex.unlock();
for (int i = 0; i < roiAfMain.num_roi; ++i) {
roiAfTrans.roi[i].width = roiAfMain.roi[i].width * fovRatio;
roiAfTrans.roi[i].height = roiAfMain.roi[i].height * fovRatio;
AuxRoiTop = ((roiAfMain.roi[i].top - mFovControlData.previewSize.height / 2.0f) * fovRatio)
+ (mFovControlData.previewSize.height / 2.0f);
roiAfTrans.roi[i].top = AuxRoiTop - shiftVertAdjusted;
AuxRoiLeft = ((roiAfMain.roi[i].left - mFovControlData.previewSize.width / 2.0f) * fovRatio)
+ (mFovControlData.previewSize.width / 2.0f);
roiAfTrans.roi[i].left = AuxRoiLeft - shiftHorzAdjusted;
// Check the ROI bounds and correct if necessory
if ((roiAfTrans.roi[i].width >= mFovControlData.previewSize.width) ||
(roiAfTrans.roi[i].height >= mFovControlData.previewSize.height)) {
roiAfTrans = roiAfMain;
LOGW("AF ROI translation failed, reverting to the pre-translation ROI");
} else {
bool error = false;
if (roiAfTrans.roi[i].left < 0) {
roiAfTrans.roi[i].left = 0;
error = true;
}
if (roiAfTrans.roi[i].top < 0) {
roiAfTrans.roi[i].top = 0;
error = true;
}
if ((roiAfTrans.roi[i].left >= mFovControlData.previewSize.width) ||
((roiAfTrans.roi[i].left + roiAfTrans.roi[i].width) >
mFovControlData.previewSize.width)) {
roiAfTrans.roi[i].left = mFovControlData.previewSize.width -
roiAfTrans.roi[i].width;
error = true;
}
if ((roiAfTrans.roi[i].top >= mFovControlData.previewSize.height) ||
((roiAfTrans.roi[i].top + roiAfTrans.roi[i].height) >
mFovControlData.previewSize.height)) {
roiAfTrans.roi[i].top = mFovControlData.previewSize.height -
roiAfTrans.roi[i].height;
error = true;
}
if (error) {
LOGW("Translated ROI - out of bounds. Clamping to the nearest valid ROI");
}
}
LOGD("Translated AF ROI-%d %s: L:%d, T:%d, W:%d, H:%d", i,
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam", roiAfTrans.roi[i].left,
roiAfTrans.roi[i].top, roiAfTrans.roi[i].width, roiAfTrans.roi[i].height);
}
return roiAfTrans;
}
/*===========================================================================
* FUNCTION : translateMeteringAreas
*
* DESCRIPTION: Translate the AEC metering areas from main to aux camera.
*
* PARAMETERS :
* @roiAfMain : AEC ROI for main camera
* @cam : Cam type
*
* RETURN : Translated AEC ROI for aux camera
*
*==========================================================================*/
cam_set_aec_roi_t QCameraFOVControl::translateMeteringAreas(
cam_set_aec_roi_t roiAecMain,
cam_sync_type_t cam)
{
float fovRatio;
float zoomWide;
float zoomTele;
float AuxDiffRoiX;
float AuxDiffRoiY;
float AuxRoiX;
float AuxRoiY;
cam_set_aec_roi_t roiAecTrans = roiAecMain;
int32_t shiftHorzAdjusted;
int32_t shiftVertAdjusted;
zoomWide = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
zoomTele = findZoomRatio(mFovControlData.zoomTele) / (float)mFovControlData.zoomRatioTable[0];
if (cam == mFovControlData.camWide) {
fovRatio = (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) ?
(1.0f / mFovControlData.transitionParams.cropRatio) : 1.0f;
} else {
fovRatio = (zoomTele / zoomWide) * mFovControlData.transitionParams.cropRatio;
}
// Acquire the mutex in order to read the spatial alignment result which is written
// by another thread
mMutex.lock();
if (cam == mFovControlData.camWide) {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz * zoomWide;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert * zoomWide;
} else {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz * zoomTele;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert * zoomTele;
}
mMutex.unlock();
for (int i = 0; i < roiAecMain.num_roi; ++i) {
AuxDiffRoiX = fovRatio * ((float)roiAecMain.cam_aec_roi_position.coordinate[i].x -
(mFovControlData.previewSize.width / 2));
AuxRoiX = (mFovControlData.previewSize.width / 2) + AuxDiffRoiX;
AuxDiffRoiY = fovRatio * ((float)roiAecMain.cam_aec_roi_position.coordinate[i].y -
(mFovControlData.previewSize.height / 2));
AuxRoiY = (mFovControlData.previewSize.height / 2) + AuxDiffRoiY;
roiAecTrans.cam_aec_roi_position.coordinate[i].x = AuxRoiX - shiftHorzAdjusted;
roiAecTrans.cam_aec_roi_position.coordinate[i].y = AuxRoiY - shiftVertAdjusted;
// Check the ROI bounds and correct if necessory
if ((AuxRoiX < 0) ||
(AuxRoiY < 0)) {
roiAecTrans.cam_aec_roi_position.coordinate[i].x = 0;
roiAecTrans.cam_aec_roi_position.coordinate[i].y = 0;
LOGW("AEC ROI translation failed");
} else if ((AuxRoiX >= mFovControlData.previewSize.width) ||
(AuxRoiY >= mFovControlData.previewSize.height)) {
// Clamp the Aux AEC ROI co-ordinates to max possible value
if (AuxRoiX >= mFovControlData.previewSize.width) {
roiAecTrans.cam_aec_roi_position.coordinate[i].x =
mFovControlData.previewSize.width - 1;
}
if (AuxRoiY >= mFovControlData.previewSize.height) {
roiAecTrans.cam_aec_roi_position.coordinate[i].y =
mFovControlData.previewSize.height - 1;
}
LOGW("AEC ROI translation failed");
}
LOGD("Translated AEC ROI-%d %s: x:%d, y:%d", i,
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam",
roiAecTrans.cam_aec_roi_position.coordinate[i].x,
roiAecTrans.cam_aec_roi_position.coordinate[i].y);
}
return roiAecTrans;
}
/*===========================================================================
* FUNCTION : translateRoiFD
*
* DESCRIPTION: Translate face detection ROI from aux metadata to main
*
* PARAMETERS :
* @faceDetectionInfo : face detection data from aux metadata. This face
* detection data is overwritten with the translated
* FD ROI.
* @cam : Cam type
*
* RETURN : none
*
*==========================================================================*/
cam_face_detection_data_t QCameraFOVControl::translateRoiFD(
cam_face_detection_data_t metaFD,
cam_sync_type_t cam)
{
if (mbIsHAL3) {
return translateHAL3FDRoi(metaFD, cam);
}
cam_face_detection_data_t metaFDTranslated = metaFD;
int32_t shiftHorz = 0;
int32_t shiftVert = 0;
float zoomWide = findZoomRatio(mFovControlData.zoomWide) /
(float)mFovControlData.zoomRatioTable[0];
float zoomTele = findZoomRatio(mFovControlData.zoomTele) /
(float)mFovControlData.zoomRatioTable[0];
if (cam == mFovControlData.camWide) {
shiftHorz = mFovControlData.spatialAlignResult.shiftWide.shiftHorz * zoomWide;
shiftVert = mFovControlData.spatialAlignResult.shiftWide.shiftVert * zoomWide;
} else {
shiftHorz = mFovControlData.spatialAlignResult.shiftTele.shiftHorz * zoomTele;
shiftVert = mFovControlData.spatialAlignResult.shiftTele.shiftVert * zoomTele;
}
for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
metaFDTranslated.faces[i].face_boundary.left += shiftHorz;
metaFDTranslated.faces[i].face_boundary.top += shiftVert;
}
// If ROI is out of bounds, remove that FD ROI from the list
for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
if ((metaFDTranslated.faces[i].face_boundary.left < 0) ||
(metaFDTranslated.faces[i].face_boundary.left >= mFovControlData.previewSize.width) ||
(metaFDTranslated.faces[i].face_boundary.top < 0) ||
(metaFDTranslated.faces[i].face_boundary.top >= mFovControlData.previewSize.height) ||
((metaFDTranslated.faces[i].face_boundary.left +
metaFDTranslated.faces[i].face_boundary.width) >=
mFovControlData.previewSize.width) ||
((metaFDTranslated.faces[i].face_boundary.top +
metaFDTranslated.faces[i].face_boundary.height) >=
mFovControlData.previewSize.height)) {
// Invalid FD ROI detected
LOGW("Failed translating FD ROI %s: L:%d, T:%d, W:%d, H:%d",
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam",
metaFDTranslated.faces[i].face_boundary.left,
metaFDTranslated.faces[i].face_boundary.top,
metaFDTranslated.faces[i].face_boundary.width,
metaFDTranslated.faces[i].face_boundary.height);
// Remove it by copying the last FD ROI at this index
if (i < (metaFDTranslated.num_faces_detected - 1)) {
metaFDTranslated.faces[i] =
metaFDTranslated.faces[metaFDTranslated.num_faces_detected - 1];
// Decrement the current index to process the newly copied FD ROI.
--i;
}
--metaFDTranslated.num_faces_detected;
}
else {
LOGD("Translated FD ROI-%d %s: L:%d, T:%d, W:%d, H:%d", i,
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam",
metaFDTranslated.faces[i].face_boundary.left,
metaFDTranslated.faces[i].face_boundary.top,
metaFDTranslated.faces[i].face_boundary.width,
metaFDTranslated.faces[i].face_boundary.height);
}
}
return metaFDTranslated;
}
/*===========================================================================
* FUNCTION : getFrameMargins
*
* DESCRIPTION : Return frame margin data for the requested camera
*
* PARAMETERS :
* @masterCamera : Master camera id
*
* RETURN : Frame margins
*
*==========================================================================*/
cam_frame_margins_t QCameraFOVControl::getFrameMargins(
int8_t masterCamera)
{
cam_frame_margins_t frameMargins;
memset(&frameMargins, 0, sizeof(cam_frame_margins_t));
if (masterCamera == CAM_TYPE_MAIN) {
frameMargins.widthMargins = mFovControlData.camMainWidthMargin;
frameMargins.heightMargins = mFovControlData.camMainHeightMargin;
} else if (masterCamera == CAM_TYPE_AUX) {
frameMargins.widthMargins = mFovControlData.camAuxWidthMargin;
frameMargins.heightMargins = mFovControlData.camAuxHeightMargin;
}
return frameMargins;
}
/*===========================================================================
* FUNCTION : setHalPPType
*
* DESCRIPTION : set the mode in which dual camera is performing
*
* PARAMETERS :
* @halPPType : HAL post processing type for current dual camera mode
*
* RETURN : NONE
*
*==========================================================================*/
void QCameraFOVControl::setHalPPType(cam_hal_pp_type_t halPPType)
{
mHalPPType = halPPType;
LOGH("halPPType: %d", halPPType);
return;
}
/*===========================================================================
* FUNCTION : UpdateFlag
*
* DESCRIPTION : Update FOV-control flag and run the state machine to reflect
* the effect of the flag
*
* PARAMETERS :
* @flag : Flag to update
* @value : value to update
*
* RETURN : void
*
*==========================================================================*/
void QCameraFOVControl::UpdateFlag(
fov_control_flag flag,
void *value)
{
if ((flag >= 0) && (flag < FOVCONTROL_FLAG_COUNT)) {
mMutex.lock();
switch (flag) {
case FOVCONTROL_FLAG_FORCE_CAMERA_WAKEUP: {
bool forceCameraWakeup = *(bool*)value;
if (forceCameraWakeup) {
mFovControlData.forceCameraWakeup = true;
} else {
mFovControlData.forceCameraWakeup = false;
}
break;
}
case FOVCONTROL_FLAG_THERMAL_THROTTLE:
mFovControlData.thermalThrottle = *(bool*)value;
break;
case FOVCONTROL_FLAG_UPDATE_RESULT_STATE:
if (mFovControlData.updateResultState == *(bool*)value) {
mMutex.unlock();
return;
} else {
mFovControlData.updateResultState = *(bool*)value;
// Cache the latest result if the update flag is set to false
if (mFovControlData.updateResultState == false) {
memcpy(&mFovControlResultCachedCopy, &mFovControlResult,
sizeof(fov_control_result_t));
}
}
break;
default:
LOGE("Invalid event to process");
break;
}
mMutex.unlock();
LOGH("FOV-Control received flag %d with value %d", flag, *(bool*)value);
generateFovControlResult();
}
}
/*===========================================================================
* FUNCTION : setDualCameraConfig
*
* DESCRIPTION: set dual camera configuration whether B+M/W+T
*
* PARAMETERS : input of type dual_cam_type
*
* RETURN : none
*==========================================================================*/
void QCameraFOVControl::setDualCameraConfig(uint8_t type)
{
mDualCamType = type;
}
void QCameraFOVControl::setZoomParam(uint8_t cam_type, cam_zoom_info_t zoomInfo, uint32_t zoomTotal,
uint32_t zoomIsp, bool snapshotPostProcess, parm_buffer_t* params)
{
for (uint32_t i = 0; i < zoomInfo.num_streams; ++i) {
zoomInfo.stream_zoom_info[i].stream_type = mFovControlData.camStreamInfo.type[i];
zoomInfo.stream_zoom_info[i].stream_zoom = zoomTotal;
zoomInfo.stream_zoom_info[i].isp_zoom = zoomIsp;
// If the snapshot post-processing is enabled, disable isp zoom
if (snapshotPostProcess &&
(zoomInfo.stream_zoom_info[i].stream_type == CAM_STREAM_TYPE_SNAPSHOT)) {
zoomInfo.stream_zoom_info[i].isp_zoom = 0;
}
LOGD("cam[%d]: stream_type: %d, stream_zoom: %d, isp_zoom: %d",
cam_type, zoomInfo.stream_zoom_info[i].stream_type,
zoomInfo.stream_zoom_info[i].stream_zoom,
zoomInfo.stream_zoom_info[i].isp_zoom);
}
ADD_SET_PARAM_ENTRY_TO_BATCH(params, CAM_INTF_PARM_USERZOOM, zoomInfo);
}
void QCameraFOVControl::setCropParam(uint8_t cam_type, uint32_t zoomStep, parm_buffer_t* params)
{
uint32_t sensorW, sensorH;
cam_crop_region_t scalerCropRegion;
float zoomRatio = zoomStep/100.0;
if (zoomRatio < 1.0) zoomRatio = 1.0;
// Adjust crop region from main sensor output coordinate system to aux
// array coordinate system.
if (cam_type == CAM_TYPE_MAIN) {
sensorW = mDualCamParams.paramsMain.sensorStreamWidth;
sensorH = mDualCamParams.paramsMain.sensorStreamHeight;
} else {
sensorW = mDualCamParams.paramsAux.sensorStreamWidth;
sensorH = mDualCamParams.paramsAux.sensorStreamHeight;
}
uint32_t xCenter = sensorW / 2;
uint32_t yCenter = sensorH / 2;
uint32_t xDelta = (uint32_t) (sensorW / (2 * zoomRatio));
uint32_t yDelta = (uint32_t) (sensorH / (2 * zoomRatio));
scalerCropRegion.left = xCenter - xDelta;
scalerCropRegion.top = yCenter - yDelta;
scalerCropRegion.width = (uint32_t)sensorW/zoomRatio;
scalerCropRegion.height = (uint32_t)sensorH/zoomRatio;
LOGD("Cam type %d : zoomRatio %f Crop [%d, %d, %d %d]",
cam_type, zoomRatio,
scalerCropRegion.left,
scalerCropRegion.top,
scalerCropRegion.width,
scalerCropRegion.height);
ADD_SET_PARAM_ENTRY_TO_BATCH(params, CAM_INTF_META_SCALER_CROP_REGION,
scalerCropRegion);
}
/*===========================================================================
* FUNCTION : translateRoi
*
* DESCRIPTION: Translate the focus areas from main to aux camera.
*
* PARAMETERS :
* @roiAfMain : Focus area ROI for main camera
* @cam : Cam type
*
* RETURN : Translated focus area ROI for aux camera
*
*==========================================================================*/
cam_area_t QCameraFOVControl::translateRoi(
cam_area_t roiMain,
cam_sync_type_t cam)
{
float fovRatio;
float zoomWide;
float zoomTele;
float AuxRoiLeft;
float AuxRoiTop;
cam_area_t roiTrans = roiMain;
int32_t shiftHorzAdjusted;
int32_t shiftVertAdjusted;
uint32_t maxW, maxH;
zoomWide = findZoomRatio(mFovControlData.zoomWide) / (float)mFovControlData.zoomRatioTable[0];
zoomTele = findZoomRatio(mFovControlData.zoomTele) / (float)mFovControlData.zoomRatioTable[0];
if (cam == mFovControlData.camWide) {
fovRatio = (mHalPPType == CAM_HAL_PP_TYPE_BOKEH) ?
(1.0f / mFovControlData.transitionParams.cropRatio) : 1.0f;
} else {
fovRatio = (zoomTele / zoomWide) * mFovControlData.transitionParams.cropRatio;
}
// Acquire the mutex in order to read the spatial alignment result which is written
// by another thread
mMutex.lock();
if (cam == mFovControlData.camWide) {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftHorz * zoomWide;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiWide.shiftVert * zoomWide;
} else {
shiftHorzAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftHorz * zoomTele;
shiftVertAdjusted = mFovControlData.spatialAlignResult.shiftAfRoiTele.shiftVert * zoomTele;
}
mMutex.unlock();
roiTrans.rect.width = roiMain.rect.width * fovRatio;
roiTrans.rect.height = roiMain.rect.height * fovRatio;
AuxRoiTop = ((roiMain.rect.top - mDualCamParams.paramsMain.sensorStreamHeight / 2.0f) * fovRatio)
+ (mDualCamParams.paramsMain.sensorStreamHeight / 2.0f);
roiTrans.rect.top = AuxRoiTop - shiftVertAdjusted;
AuxRoiLeft = ((roiMain.rect.left - mDualCamParams.paramsMain.sensorStreamWidth / 2.0f) * fovRatio)
+ (mDualCamParams.paramsMain.sensorStreamWidth / 2.0f);
roiTrans.rect.left = AuxRoiLeft - shiftHorzAdjusted;
if (CAM_TYPE_MAIN == cam) {
maxW = mDualCamParams.paramsMain.sensorStreamWidth;
maxH = mDualCamParams.paramsMain.sensorStreamHeight;
} else {
maxW = mDualCamParams.paramsAux.sensorStreamWidth;
maxH = mDualCamParams.paramsAux.sensorStreamHeight;
}
// Check the ROI bounds and correct if necessory
if ((roiTrans.rect.width >= (int32_t)maxW) ||
(roiTrans.rect.height >= (int32_t)maxH)) {
roiTrans = roiMain;
LOGW("ROI translation failed, reverting to the pre-translation ROI");
} else {
bool error = false;
if (roiTrans.rect.left < 0) {
roiTrans.rect.left = 0;
error = true;
}
if (roiTrans.rect.top < 0) {
roiTrans.rect.top = 0;
error = true;
}
if ((roiTrans.rect.left >= (int32_t)maxW) ||
((roiTrans.rect.left + roiTrans.rect.width) > (int32_t) maxW)) {
roiTrans.rect.left = maxW - roiTrans.rect.width;
error = true;
}
if ((roiTrans.rect.top >= (int32_t)maxH) ||
((roiTrans.rect.top + roiTrans.rect.height) > (int32_t)maxH)) {
roiTrans.rect.top = maxH - roiTrans.rect.height;
error = true;
}
if (error) {
LOGW("Translated ROI - out of bounds. Clamping to the nearest valid ROI");
}
}
LOGD("Translated ROI - %s: L:%d, T:%d, W:%d, H:%d",
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam", roiTrans.rect.left,
roiTrans.rect.top, roiTrans.rect.width, roiTrans.rect.height);
return roiTrans;
}
/*===========================================================================
* FUNCTION : translateHAL3FDRoi
*
* DESCRIPTION: Translate face detection ROI from aux metadata to main
*
* PARAMETERS :
* @faceDetectionInfo : face detection data from aux metadata. This face
* detection data is overwritten with the translated
* FD ROI.
* @cam : Cam type
*
* RETURN : none
*
*==========================================================================*/
cam_face_detection_data_t QCameraFOVControl::translateHAL3FDRoi(
cam_face_detection_data_t metaFD,
cam_sync_type_t cam)
{
cam_face_detection_data_t metaFDTranslated = metaFD;
int32_t shiftHorz = 0;
int32_t shiftVert = 0;
uint32_t maxW, maxH;
float zoomWide = findZoomRatio(mFovControlData.zoomWide) /
(float)mFovControlData.zoomRatioTable[0];
float zoomTele = findZoomRatio(mFovControlData.zoomTele) /
(float)mFovControlData.zoomRatioTable[0];
if (cam == mFovControlData.camWide) {
shiftHorz = mFovControlData.spatialAlignResult.shiftWide.shiftHorz * zoomWide;
shiftVert = mFovControlData.spatialAlignResult.shiftWide.shiftVert * zoomWide;
} else {
shiftHorz = mFovControlData.spatialAlignResult.shiftTele.shiftHorz * zoomTele;
shiftVert = mFovControlData.spatialAlignResult.shiftTele.shiftVert * zoomTele;
}
maxW = mDualCamParams.paramsMain.sensorStreamWidth;
maxH = mDualCamParams.paramsMain.sensorStreamHeight;
for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
metaFDTranslated.faces[i].face_boundary.left += shiftHorz;
metaFDTranslated.faces[i].face_boundary.top += shiftVert;
//maping AUX fd values to MAIN.
if(CAM_TYPE_AUX == cam && (mHalPPType != CAM_HAL_PP_TYPE_BOKEH))
{
float widthFactor = (float)(mDualCamParams.paramsMain.sensorStreamWidth/
(float)mDualCamParams.paramsAux.sensorStreamWidth);
float heightFactor = (float)(mDualCamParams.paramsMain.sensorStreamHeight/
(float)mDualCamParams.paramsAux.sensorStreamHeight);
float zoomFactor = (float)(zoomTele / (float)zoomWide);
cam_rect_t *face = &metaFDTranslated.faces[i].face_boundary;
face->left =
(((face->left - mDualCamParams.paramsAux.sensorStreamWidth/2.0f) * zoomFactor)
+ (mDualCamParams.paramsAux.sensorStreamWidth / 2.0f)) * widthFactor;
face->top =
(((face->top - mDualCamParams.paramsAux.sensorStreamHeight/2.0f) * zoomFactor)
+ (mDualCamParams.paramsAux.sensorStreamHeight/2.0f)) * heightFactor;
face->width *= zoomFactor;
face->height *= zoomFactor;
}
}
// If ROI is out of bounds, remove that FD ROI from the list
for (int i = 0; i < metaFDTranslated.num_faces_detected; ++i) {
if ((metaFDTranslated.faces[i].face_boundary.left < 0) ||
(metaFDTranslated.faces[i].face_boundary.left >= (int32_t)maxW) ||
(metaFDTranslated.faces[i].face_boundary.top < 0) ||
(metaFDTranslated.faces[i].face_boundary.top >= (int32_t)maxH) ||
((metaFDTranslated.faces[i].face_boundary.left +
metaFDTranslated.faces[i].face_boundary.width) >= (int32_t)maxW) ||
((metaFDTranslated.faces[i].face_boundary.top +
metaFDTranslated.faces[i].face_boundary.height) >= (int32_t)maxH)) {
// Invalid FD ROI detected
LOGW("Failed translating FD ROI %s: L:%d, T:%d, W:%d, H:%d",
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam",
metaFDTranslated.faces[i].face_boundary.left,
metaFDTranslated.faces[i].face_boundary.top,
metaFDTranslated.faces[i].face_boundary.width,
metaFDTranslated.faces[i].face_boundary.height);
// Remove it by copying the last FD ROI at this index
if (i < (metaFDTranslated.num_faces_detected - 1)) {
metaFDTranslated.faces[i] =
metaFDTranslated.faces[metaFDTranslated.num_faces_detected - 1];
// Decrement the current index to process the newly copied FD ROI.
--i;
}
--metaFDTranslated.num_faces_detected;
}
else {
LOGD("Translated FD ROI-%d %s: L:%d, T:%d, W:%d, H:%d", i,
(cam == CAM_TYPE_MAIN) ? "main cam" : "aux cam",
metaFDTranslated.faces[i].face_boundary.left,
metaFDTranslated.faces[i].face_boundary.top,
metaFDTranslated.faces[i].face_boundary.width,
metaFDTranslated.faces[i].face_boundary.height);
}
}
return metaFDTranslated;
}
}; // namespace qcamera