blob: bc4182a2aac431b23949c7504678112968e7e316 [file] [log] [blame]
/*
* Copyright@ Samsung Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "ExynosCameraFusionWrapper"
#include "ExynosCameraFusionWrapper.h"
ExynosCameraFusionWrapper::ExynosCameraFusionWrapper()
{
ALOGD("DEBUG(%s[%d]):new ExynosCameraFusionWrapper object allocated", __FUNCTION__, __LINE__);
for (int i = 0; i < CAMERA_ID_MAX; i++) {
m_flagCreated[i] = false;
m_width[i] = 0;
m_height[i] = 0;
m_stride[i] = 0;
}
}
ExynosCameraFusionWrapper::~ExynosCameraFusionWrapper()
{
status_t ret = NO_ERROR;
for (int i = 0; i < CAMERA_ID_MAX; i++) {
if (flagCreate(i) == true) {
ret = destroy(i);
if (ret != NO_ERROR) {
ALOGE("ERR(%s[%d]):destroy(%d) fail", __FUNCTION__, __LINE__, i);
}
}
}
}
status_t ExynosCameraFusionWrapper::create(int cameraId,
int srcWidth, int srcHeight,
int dstWidth, int dstHeight,
char *calData, int calDataSize)
{
// hack for CLOG
int m_cameraId = cameraId;
const char *m_name = "";
Mutex::Autolock lock(m_createLock);
status_t ret = NO_ERROR;
if (CAMERA_ID_MAX <= cameraId) {
CLOGE("ERR(%s[%d]):invalid cameraId(%d). so, fail", __FUNCTION__, __LINE__, cameraId);
return INVALID_OPERATION;
}
if (m_flagCreated[cameraId] == true) {
CLOGE("ERR(%s[%d]):cameraId(%d) is alread created. so, fail", __FUNCTION__, __LINE__, cameraId);
return INVALID_OPERATION;
}
if (srcWidth == 0 || srcWidth == 0 || dstWidth == 0 || dstHeight == 0) {
CLOGE("ERR(%s[%d]):srcWidth == %d || srcWidth == %d || dstWidth == %d || dstHeight == %d. so, fail",
__FUNCTION__, __LINE__, srcWidth, srcWidth, dstWidth, dstHeight);
return INVALID_OPERATION;
}
m_init(cameraId);
CLOGD("DEBUG(%s[%d]):create(calData(%p), calDataSize(%d), srcWidth(%d), srcHeight(%d), dstWidth(%d), dstHeight(%d)",
__FUNCTION__, __LINE__,
calData, calDataSize, srcWidth, srcHeight, dstWidth, dstHeight);
// set info int width, int height, int stride
m_width [cameraId] = srcWidth;
m_height [cameraId] = srcHeight;
m_stride [cameraId] = srcWidth;
// declare it created
m_flagCreated[cameraId] = true;
return NO_ERROR;
}
status_t ExynosCameraFusionWrapper::destroy(int cameraId)
{
// hack for CLOG
int m_cameraId = cameraId;
const char *m_name = "";
Mutex::Autolock lock(m_createLock);
status_t ret = NO_ERROR;
if (CAMERA_ID_MAX <= cameraId) {
CLOGE("ERR(%s[%d]):invalid cameraId(%d). so, fail", __FUNCTION__, __LINE__, cameraId);
return INVALID_OPERATION;
}
if (m_flagCreated[cameraId] == false) {
CLOGE("ERR(%s[%d]):cameraId(%d) is alread destroyed. so, fail", __FUNCTION__, __LINE__, cameraId);
return INVALID_OPERATION;
}
CLOGD("DEBUG(%s[%d]):destroy()", __FUNCTION__, __LINE__);
m_flagCreated[cameraId] = false;
return NO_ERROR;
}
bool ExynosCameraFusionWrapper::flagCreate(int cameraId)
{
Mutex::Autolock lock(m_createLock);
if (CAMERA_ID_MAX <= cameraId) {
android_printAssert(NULL, LOG_TAG, "ASSERT(%s[%d]):invalid cameraId(%d), assert!!!!",
__FUNCTION__, __LINE__, cameraId);
}
return m_flagCreated[cameraId];
}
bool ExynosCameraFusionWrapper::flagReady(int cameraId)
{
return m_flagCreated[cameraId];
}
status_t ExynosCameraFusionWrapper::execute(int cameraId,
__unused struct camera2_shot_ext *shot_ext[], __unused DOF *dof[],
ExynosCameraBuffer srcBuffer[], ExynosRect srcRect[], __unused ExynosCameraBufferManager *srcBufferManager[],
ExynosCameraBuffer dstBuffer, ExynosRect dstRect, __unused ExynosCameraBufferManager *dstBufferManager)
{
// hack for CLOG
int m_cameraId = cameraId;
const char *m_name = "";
status_t ret = NO_ERROR;
if (this->flagCreate(cameraId) == false) {
CLOGE("ERR(%s[%d]):flagCreate(%d) == false. so fail", __FUNCTION__, __LINE__, cameraId);
return INVALID_OPERATION;
}
m_emulationProcessTimer.start();
ret = m_execute(cameraId,
srcBuffer, srcRect,
dstBuffer, dstRect);
m_emulationProcessTimer.stop();
m_emulationProcessTime = (int)m_emulationProcessTimer.durationUsecs();
if (ret != NO_ERROR) {
CLOGE("ERR(%s[%d]):m_execute() fail", __FUNCTION__, __LINE__);
}
return ret;
}
status_t ExynosCameraFusionWrapper::m_execute(int cameraId,
ExynosCameraBuffer srcBuffer[], ExynosRect srcRect[],
ExynosCameraBuffer dstBuffer, ExynosRect dstRect)
{
// hack for CLOG
int m_cameraId = cameraId;
const char *m_name = "";
status_t ret = NO_ERROR;
char *srcYAddr = NULL;
char *srcCbcrAddr = NULL;
char *dstYAddr = NULL;
char *dstCbcrAddr = NULL;
unsigned int bpp = 0;
unsigned int planeCount = 1;
int srcPlaneSize = 0;
int srcHalfPlaneSize = 0;
int dstPlaneSize = 0;
int dstHalfPlaneSize = 0;
int copySize = 0;
/*
* if previous emulationProcessTime is slow than 33msec,
* we need change the next copy time
*
* ex :
* frame 0 :
* 1.0(copyRatio) = 33333 / 33333(previousFusionProcessTime : init value)
* 1.0 (copyRatio) = 1.0(copyRatio) * 1.0(m_emulationCopyRatio);
* m_emulationCopyRatio = 1.0
* m_emulationProcessTime = 66666
* frame 1 : because of frame0's low performance, shrink down copyRatio.
* 0.5(copyRatio) = 33333 / 66666(previousFusionProcessTime)
* 0.5(copyRatio) = 0.5(copyRatio) * 1.0(m_emulationCopyRatio);
* m_emulationCopyRatio = 0.5
* m_emulationProcessTime = 33333
* frame 2 : acquire the proper copy time
* 1.0(copyRatio) = 33333 / 33333(previousFusionProcessTime)
* 0.5(copyRatio) = 1.0(copyRatio) * 0.5(m_emulationCopyRatio);
* m_emulationCopyRatio = 0.5
* m_emulationProcessTime = 16666
* frame 3 : because of frame2's fast performance, increase copyRatio.
* 2.0(copyRatio) = 33333 / 16666(previousFusionProcessTime)
* 1.0(copyRatio) = 2.0(copyRatio) * 0.5(m_emulationCopyRatio);
* m_emulationCopyRatio = 1.0
* m_emulationProcessTime = 33333
*/
int previousFusionProcessTime = m_emulationProcessTime;
if (previousFusionProcessTime <= 0)
previousFusionProcessTime = 1;
float copyRatio = (float)FUSION_PROCESSTIME_STANDARD / (float)previousFusionProcessTime;
copyRatio = copyRatio * m_emulationCopyRatio;
if (1.0f <= copyRatio) {
copyRatio = 1.0f;
} else if (0.1f < copyRatio) {
copyRatio -= 0.05f; // threshold value : 5%
} else {
CLOGW("WARN(%s[%d]):copyRatio(%d) is too smaller than 0.1f. previousFusionProcessTime(%d), m_emulationCopyRatio(%f)",
__FUNCTION__, __LINE__, copyRatio, previousFusionProcessTime, m_emulationCopyRatio);
}
m_emulationCopyRatio = copyRatio;
for (int i = 0; i < CAMERA_ID_MAX; i++) {
if (m_flagValidCameraId[i] == false)
continue;
srcPlaneSize = srcRect[i].fullW * srcRect[i].fullH;
srcHalfPlaneSize = srcPlaneSize / 2;
dstPlaneSize = dstRect.fullW * dstRect.fullH;
dstHalfPlaneSize = dstPlaneSize / 2;
copySize = (srcHalfPlaneSize < dstHalfPlaneSize) ? srcHalfPlaneSize : dstHalfPlaneSize;
ret = getYuvFormatInfo(srcRect[i].colorFormat, &bpp, &planeCount);
if (ret < 0) {
CLOGE("ERR(%s[%d]):getYuvFormatInfo(srcRect[%d].colorFormat(%x)) fail", __FUNCTION__, __LINE__, i, srcRect[i].colorFormat);
}
srcYAddr = srcBuffer[i].addr[0];
dstYAddr = dstBuffer.addr[0];
switch (planeCount) {
case 1:
srcCbcrAddr = srcBuffer[i].addr[0] + srcRect[i].fullW * srcRect[i].fullH;
dstCbcrAddr = dstBuffer.addr[0] + dstRect.fullW * dstRect.fullH;
break;
case 2:
srcCbcrAddr = srcBuffer[i].addr[1];
dstCbcrAddr = dstBuffer.addr[1];
break;
default:
android_printAssert(NULL, LOG_TAG, "ASSERT(%s[%d]):Invalid planeCount(%d), assert!!!!",
__FUNCTION__, __LINE__, planeCount);
break;
}
EXYNOS_CAMERA_FUSION_WRAPPER_DEBUG_LOG("DEBUG(%s[%d]):fusion emulationn running ~~~ memcpy(%d, %d, %d) by src(%d, %d), dst(%d, %d), previousFusionProcessTime(%d) copyRatio(%f)",
__FUNCTION__, __LINE__,
dstBuffer.addr[0], srcBuffer[i].addr[0], copySize,
srcRect[i].fullW, srcRect[i].fullH,
dstRect.fullW, dstRect.fullH,
previousFusionProcessTime, copyRatio);
if (i == m_subCameraId) {
dstYAddr += dstHalfPlaneSize;
dstCbcrAddr += dstHalfPlaneSize / 2;
}
if (srcRect[i].fullW == dstRect.fullW &&
srcRect[i].fullH == dstRect.fullH) {
int oldCopySize = copySize;
copySize = (int)((float)copySize * copyRatio);
if (oldCopySize < copySize) {
CLOGW("WARN(%s[%d]):oldCopySize(%d) < copySize(%d). just adjust oldCopySize",
__FUNCTION__, __LINE__, oldCopySize, copySize);
copySize = oldCopySize;
}
memcpy(dstYAddr, srcYAddr, copySize);
memcpy(dstCbcrAddr, srcCbcrAddr, copySize / 2);
} else {
int width = (srcRect[i].fullW < dstRect.fullW) ? srcRect[i].fullW : dstRect.fullW;
int height = (srcRect[i].fullH < dstRect.fullH) ? srcRect[i].fullH : dstRect.fullH;
int oldHeight = height;
height = (int)((float)height * copyRatio);
if (oldHeight < height) {
CLOGW("WARN(%s[%d]):oldHeight(%d) < height(%d). just adjust oldHeight",
__FUNCTION__, __LINE__, oldHeight, height);
height = oldHeight;
}
for (int h = 0; h < height / 2; h++) {
memcpy(dstYAddr, srcYAddr, width);
srcYAddr += srcRect[i].fullW;
dstYAddr += dstRect.fullW;
}
for (int h = 0; h < height / 4; h++) {
memcpy(dstCbcrAddr, srcCbcrAddr, width);
srcCbcrAddr += srcRect[i].fullW;
dstCbcrAddr += dstRect.fullW;
}
}
}
return ret;
}
void ExynosCameraFusionWrapper::m_init(int cameraId)
{
// hack for CLOG
int m_cameraId = cameraId;
const char *m_name = "";
getDualCameraId(&m_mainCameraId, &m_subCameraId);
CLOGD("DEBUG(%s[%d]):m_mainCameraId(CAMERA_ID_%d), m_subCameraId(CAMERA_ID_%d)",
__FUNCTION__, __LINE__, m_mainCameraId, m_subCameraId);
for (int i = 0; i < CAMERA_ID_MAX; i++) {
m_flagValidCameraId[i] = false;
}
m_flagValidCameraId[m_mainCameraId] = true;
m_flagValidCameraId[m_subCameraId] = true;
m_emulationProcessTime = FUSION_PROCESSTIME_STANDARD;
m_emulationCopyRatio = 1.0f;
}