blob: 45029c1109098cda5dccbeca9026aae98fd4e8ba [file] [log] [blame]
/*
**
** Copyright 2017, 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_NDEBUG 0 */
#define LOG_TAG "ExynosCameraPipeGMV"
#include "ExynosCameraPipeGMV.h"
namespace android {
status_t ExynosCameraPipeGMV::create(__unused int32_t *sensorIds)
{
CLOGD("-IN-");
ExynosCameraAutoTimer autoTimer(__FUNCTION__);
if (m_checkState(PIPE_STATE_CREATE) == false) {
CLOGE("Invalid curState %d", m_state);
return INVALID_OPERATION;
}
char gmvLibPath[] = GMV_LIBRARY_PATH;
ExynosCameraSWPipe::create(sensorIds);
m_gmvDl = NULL;
getGlobalMotionEst = NULL;
m_gmvDl = dlopen(gmvLibPath, RTLD_NOW);
if (m_gmvDl == NULL) {
CLOGE("Failed to open GMV Library. path %s", gmvLibPath);
return INVALID_OPERATION;
}
getGlobalMotionEst = (void (*)(const uint8_t *,
const uint32_t *, const uint32_t *,
int *, int *))
dlsym(m_gmvDl, "getGlobalMotionEst");
void *error = dlerror();
if (error != NULL && getGlobalMotionEst == NULL) {
CLOGE("Failed to dlsym getGlobalMotionEst %p/%p", error, getGlobalMotionEst);
goto err_exit;
}
m_transitState(PIPE_STATE_CREATE);
return NO_ERROR;
err_exit:
if (m_gmvDl != NULL) {
dlclose(m_gmvDl);
}
return INVALID_OPERATION;
}
status_t ExynosCameraPipeGMV::start(void)
{
CLOGD("-IN-");
ExynosCameraAutoTimer autoTimer(__FUNCTION__);
if (m_checkState(PIPE_STATE_INIT) == false) {
CLOGE("Invalid curState %d", m_state);
return INVALID_OPERATION;
}
#ifdef DUMP_GMV_INPUT
char filePath[200];
/* Open File for prevVecList */
snprintf(filePath, sizeof(filePath), "%s/GMV_PreviousVectorList_CamID%d_%lld.csv",
DUMP_GMV_INPUT_PATH, m_cameraId, systemTime(SYSTEM_TIME_MONOTONIC));
prevVecListFd = fopen(filePath, "w+");
if (prevVecListFd == NULL) {
CLOGE("Failed to open file %s", filePath);
return INVALID_OPERATION;
}
CLOGD("Open %s", filePath);
/* Open FILE for currVecList */
memset(filePath, 0x00, sizeof(filePath));
snprintf(filePath, sizeof(filePath), "%s/GMV_CurrentVectorList_CamID%d_%lld.csv",
DUMP_GMV_INPUT_PATH, m_cameraId, systemTime(SYSTEM_TIME_MONOTONIC));
currVecListFd = fopen(filePath, "w+");
if (currVecListFd == NULL) {
CLOGE("Failed to open file %s", filePath);
return INVALID_OPERATION;
}
CLOGD("Open %s", filePath);
#endif
m_transitState(PIPE_STATE_INIT);
return NO_ERROR;
}
status_t ExynosCameraPipeGMV::stop(void)
{
CLOGD("-IN-");
ExynosCameraAutoTimer autoTimer(__FUNCTION__);
if (m_checkState(PIPE_STATE_CREATE) == false) {
CLOGE("Invalid curState %d", m_state);
return INVALID_OPERATION;
}
stopThreadAndInputQ(m_mainThread, 1, m_inputFrameQ);
CLOGD("thead exited");
#ifdef DUMP_GMV_INPUT
if (prevVecListFd != NULL) {
CLOGD("Close prevVecListFd");
fflush(prevVecListFd);
fclose(prevVecListFd);
prevVecListFd = NULL;
}
if (currVecListFd != NULL) {
CLOGD("Close currVecListFd");
fflush(currVecListFd);
fclose(currVecListFd);
currVecListFd = NULL;
}
#endif
m_transitState(PIPE_STATE_CREATE);
return NO_ERROR;
}
status_t ExynosCameraPipeGMV::m_destroy(void)
{
CLOGD("-IN-");
ExynosCameraAutoTimer autoTimer(__FUNCTION__);
status_t ret = NO_ERROR;
ExynosCameraSWPipe::m_destroy();
if (m_gmvDl != NULL) {
dlclose(m_gmvDl);
m_gmvDl = NULL;
}
m_transitState(PIPE_STATE_NONE);
return NO_ERROR;
}
status_t ExynosCameraPipeGMV::m_run(void)
{
status_t ret = NO_ERROR;
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraBuffer buffer;
struct camera2_shot_ext frameShotExt;
entity_buffer_state_t bufferState;
if (m_checkState(PIPE_STATE_RUN) == false) {
CLOGE("Invalid curState %d", m_state);
return INVALID_OPERATION;
}
if (m_state != PIPE_STATE_RUN) {
ret = m_transitState(PIPE_STATE_RUN);
if (ret != NO_ERROR) {
CLOGE("Failed to transitState into RUN. ret %d", ret);
return ret;
}
}
ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame);
if (ret != NO_ERROR) {
if (ret == TIMED_OUT) {
CLOGW("wait timeout");
} else {
CLOGE("wait and pop fail. ret %d", ret);
}
return ret;
} else if (newFrame == NULL) {
CLOGE("new frame is NULL");
return NO_ERROR;
}
ret = newFrame->getSrcBufferState(getPipeId(), &bufferState);
if (ret != NO_ERROR || bufferState == ENTITY_BUFFER_STATE_ERROR) {
CLOGE("[F%d]Invalid SrcBufferState %d. ret %d",
newFrame->getFrameCount(), bufferState, ret);
goto err_exit;
}
ret = newFrame->getSrcBuffer(getPipeId(), &buffer);
if (ret != NO_ERROR || buffer.index < 0) {
CLOGE("[F%d B%d]Failed to getSrcBuffer. ret %d",
newFrame->getFrameCount(), buffer.index, ret);
goto err_exit;
}
ret = newFrame->getMetaData(&frameShotExt);
if (ret != NO_ERROR) {
CLOGE("[F%d]Failed to getMetaData from frame. ret %d",
newFrame->getFrameCount(), ret);
}
#ifdef DUMP_GMV_INPUT
ret = m_dumpGmvInput(buffer.addr[0], &frameShotExt);
if (ret != NO_ERROR) {
CLOGE("[F%d(%d]Failed to dumpGmvInput. ret %d",
newFrame->getFrameCount(),
frameShotExt.shot.dm.request.frameCount,
ret);
/* continue */
}
#endif
CLOGV("[F%d(%d) B%d]GMV Processing start.",
newFrame->getFrameCount(),
frameShotExt.shot.dm.request.frameCount,
buffer.index);
m_timer.start();
getGlobalMotionEst((const uint8_t *) buffer.addr[0],
(const uint32_t *) frameShotExt.shot.udm.me.motion_vector,
(const uint32_t *) frameShotExt.shot.udm.me.current_patch,
(int *) &frameShotExt.shot.uctl.gmvUd.gmX,
(int *) &frameShotExt.shot.uctl.gmvUd.gmY);
m_timer.stop();
if ((int) m_timer.durationMsecs() > (int) (1000 / frameShotExt.shot.dm.aa.aeTargetFpsRange[0])) {
CLOGW("[F%d B%d]Too delayed to handleGMVFrame. %d msec",
newFrame->getFrameCount(), buffer.index,
(int) m_timer.durationMsecs());
}
CLOGV("[F%d(%d) B%d]GMV Processing done. gmv %d,%d duration %d msec",
newFrame->getFrameCount(), frameShotExt.shot.dm.request.frameCount,
buffer.index,
frameShotExt.shot.uctl.gmvUd.gmX, frameShotExt.shot.uctl.gmvUd.gmY,
(int) m_timer.durationMsecs());
ret = newFrame->storeDynamicMeta(&(frameShotExt.shot.dm));
if (ret != NO_ERROR) {
CLOGE("[F%d]Failed to storeDynamicMeta to frame. ret %d",
newFrame->getFrameCount(), ret);
}
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_COMPLETE);
if (ret != NO_ERROR) {
CLOGE("[F%d]setSrcBufferState failed. ret %d",
newFrame->getFrameCount(), ret);
return ret;
}
goto func_exit;
err_exit:
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR);
if (ret != NO_ERROR) {
CLOGE("[F%d]setSrcBufferState failed. ret %d",
newFrame->getFrameCount(), ret);
return ret;
}
func_exit:
ret = newFrame->setEntityState(getPipeId(), ENTITY_STATE_FRAME_DONE);
if (ret != NO_ERROR) {
CLOGE("[F%d]setEntityState failed. ret %d",
newFrame->getFrameCount(), ret);
return ret;
}
m_outputFrameQ->pushProcessQ(&newFrame);
return NO_ERROR;
}
void ExynosCameraPipeGMV::m_init(void)
{
#ifdef DUMP_GMV_INPUT
prevVecListFd = NULL;
currVecListFd = NULL;
#endif
}
#ifdef DUMP_GMV_INPUT
status_t ExynosCameraPipeGMV::m_dumpGmvInput(const char *pkdQvga, const struct camera2_shot_ext *shotExt)
{
if (pkdQvga == NULL || shotExt == NULL) {
CLOGE("Invalid parameters. pkdQvga %p shotExt %p",
pkdQvga, shotExt);
return BAD_VALUE;
} else if (prevVecListFd == NULL || currVecListFd == NULL) {
CLOGE("FDs are not opened. prevVecListFd %p currVecListFd %p",
prevVecListFd, currVecListFd);
return INVALID_OPERATION;
}
/* Print sensor frame count */
fprintf(prevVecListFd, "%d,", shotExt->shot.dm.request.frameCount);
fprintf(currVecListFd, "%d,", shotExt->shot.dm.request.frameCount);
/* Print vector list */
for (int i = 0; i < CAMERA2_MAX_ME_MV; i++) {
fprintf(prevVecListFd, "%d,", shotExt->shot.udm.me.motion_vector[i]);
fprintf(currVecListFd, "%d,", shotExt->shot.udm.me.motion_vector[i]);
}
/* Print new line */
fprintf(prevVecListFd, "\n");
fprintf(currVecListFd, "\n");
return NO_ERROR;
}
#endif
}; /* namespace android */