blob: b70bcb9733e50e5327777d5da428f0cb613db4b7 [file] [log] [blame]
/*
**
** Copyright 2016, 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 "ExynosCameraPipeSync"
#include <log/log.h>
#include "ExynosCameraPipeSync.h"
namespace android {
status_t ExynosCameraPipeSync::create(int32_t *sensorIds)
{
status_t ret = NO_ERROR;
ret = ExynosCameraSWPipe::create(sensorIds);
if (ret != NO_ERROR) {
CLOGE("SWPipe creation fail!");
return ret;
}
m_masterFrameQ = new frame_queue_t;
m_slaveFrameQ = new frame_queue_t;
m_inputFrameQ->setWaitTime(100000000);
if (m_reprocessing) {
/* Actually, it sync any frame if there's a pair frame */
m_syncType = SYNC_TYPE_FIFO;
} else {
m_syncType = SYNC_TYPE_TIMESTAMP;
}
m_syncTimestampMinCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
m_syncTimestampMaxCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
CLOGI("create() is succeed (%d)", getPipeId());
return NO_ERROR;
}
status_t ExynosCameraPipeSync::start(void)
{
CLOGD("");
status_t ret = NO_ERROR;
uint32_t minFps = 30;
uint32_t maxFps = 30;
ret = ExynosCameraSWPipe::start();
if (ret != NO_ERROR) {
CLOGE("SWPipe start fail!");
return ret;
}
m_cleanFrameByMinCount(m_slaveFrameQ, 0);
m_cleanFrameByMinCount(m_masterFrameQ, 0);
m_lastTimeStamp = 0;
m_lastFrameCount = 0;
/* find out current preview fps */
m_configurations->getPreviewFpsRange(&minFps, &maxFps);
m_syncTimestampMinCalbTime = (1000 / maxFps / 2) + SYNC_TIMESTAMP_CALB_TIME_MARGIN;
m_syncTimestampMaxCalbTime = (1000 / minFps / 2) + SYNC_TIMESTAMP_CALB_TIME_MARGIN;
m_syncCalbTimeThreshold = 1000 / maxFps + SYNC_TIMESTAMP_CALB_TIME_MARGIN;
/* init each camera's lastTimeStamp info for sync */
for (int i = 0; i < CAMERA_ID_MAX; i++) {
m_syncLastTimeStamp[i] = 0;
m_needMaxCalbTime[i] = false;
}
CLOGD("calbTime(%d/%d ms), fps(%d, %d)",
m_syncTimestampMinCalbTime, m_syncTimestampMaxCalbTime, minFps, maxFps);
return NO_ERROR;
}
status_t ExynosCameraPipeSync::stop(void)
{
CLOGD("");
status_t ret = NO_ERROR;
ret = ExynosCameraSWPipe::stop();
if (ret != NO_ERROR) {
CLOGE("SWPipe stop fail!");
return ret;
}
m_cleanFrameByMinCount(m_slaveFrameQ, 0);
m_cleanFrameByMinCount(m_masterFrameQ, 0);
m_lastTimeStamp = 0;
m_lastFrameCount = 0;
m_syncTimestampMinCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
m_syncTimestampMaxCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
return NO_ERROR;
}
status_t ExynosCameraPipeSync::m_destroy(void)
{
status_t ret = NO_ERROR;
ret = ExynosCameraSWPipe::m_destroy();
if (ret != NO_ERROR)
CLOGE("Destroy fail!");
if (m_masterFrameQ != NULL) {
m_masterFrameQ->release();
delete m_masterFrameQ;
m_masterFrameQ = NULL;
}
if (m_slaveFrameQ != NULL) {
m_slaveFrameQ->release();
delete m_slaveFrameQ;
m_slaveFrameQ = NULL;
}
return ret;
}
status_t ExynosCameraPipeSync::m_run(void)
{
status_t ret = NO_ERROR;
uint64_t curMs = 0;
int cameraId = -1;
static int internalLogCount[CAMERA_ID_MAX];
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraFrameSP_sptr_t syncFrame = NULL;
ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame);
if (ret != NO_ERROR) {
/* TODO: We need to make timeout duration depends on FPS */
if (ret == TIMED_OUT) {
enum DUAL_OPERATION_MODE dualOperationMode =
m_configurations->getDualOperationMode();
if (dualOperationMode == DUAL_OPERATION_MODE_SYNC) {
CLOGW("wait timeout");
return ret;
}
if (m_reprocessing) {
CLOGW("wait timeout for reprocessing(%d)",
m_configurations->getDualOperationModeReprocessing());
return ret;
}
m_cleanFrameByMinCount(m_slaveFrameQ, 0);
m_cleanFrameByMinCount(m_masterFrameQ, 0);
} else {
CLOGE("wait and pop fail, ret(%d)", ret);
/* TODO: doing exception handling */
}
return ret;
}
if (newFrame == NULL) {
CLOGE("new frame is NULL");
return BAD_VALUE;
}
cameraId = newFrame->getCameraId();
if (cameraId < 0 || cameraId >= CAMERA_ID_MAX) {
CLOGE("new frame is inavlid cameraId(%d)", cameraId);
return BAD_VALUE;
}
/*
* Calculate this camera's current frameduration.
* This information would be used to select min/max calbTime.
*/
curMs = (uint64_t)ns2ms(newFrame->getTimeStampBoot());
if (m_syncType == SYNC_TYPE_TIMESTAMP &&
m_configurations->getDualHwSyncOn() == false) {
bool needMaxCalbTime = false;
uint64_t lastMs = m_syncLastTimeStamp[cameraId];
int64_t diffMs = curMs - lastMs;
/* for abs */
if (diffMs < 0)
diffMs = -diffMs;
if (diffMs > m_syncCalbTimeThreshold)
needMaxCalbTime = true;
m_needMaxCalbTime[cameraId] = needMaxCalbTime;
}
#if 0
CLOGD("input frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d)",
newFrame->getCameraId(),
newFrame->getFrameCount(),
newFrame->getMetaFrameCount(),
newFrame->getFrameType(),
newFrame->getTimeStampBoot() / 1000000LL,
newFrame->getFrameState());
#endif
/* remove under this timestamp in master, slaveQ */
uint64_t removeTimeStamp = (uint64_t)ns2ms(newFrame->getTimeStampBoot());
if (removeTimeStamp > SYNC_REMOVE_TIMESTAMP_DIFF)
removeTimeStamp -= SYNC_REMOVE_TIMESTAMP_DIFF;
else
removeTimeStamp = 0;
/* check the frame state */
switch (newFrame->getFrameState()) {
case FRAME_STATE_INVALID:
case FRAME_STATE_SKIPPED:
CLOGE("[F%d,T%d] This frame's state is invalid(%d)",
newFrame->getFrameCount(), newFrame->getFrameType(), newFrame->getFrameState());
newFrame->setFrameState(FRAME_STATE_SKIPPED);
m_cleanFrameBySyncType(m_slaveFrameQ, newFrame, m_syncType, false);
m_cleanFrameBySyncType(m_masterFrameQ, newFrame, m_syncType, false);
m_pushFrameToOutputQ(newFrame);
goto p_exit;
break;
default:
break;
}
/* check the frame type */
switch (newFrame->getFrameType()) {
case FRAME_TYPE_INTERNAL:
case FRAME_TYPE_INTERNAL_SLAVE:
if ((internalLogCount[m_cameraId]++ % 100) == 0) {
CLOGI("[INTERNAL_FRAME] frame(%d) type(%d), (%d)",
newFrame->getFrameCount(), newFrame->getFrameType(), internalLogCount[m_cameraId]);
}
newFrame->setFrameState(FRAME_STATE_SKIPPED);
m_cleanFrameBySyncType(m_slaveFrameQ, newFrame, m_syncType, false);
m_cleanFrameBySyncType(m_masterFrameQ, newFrame, m_syncType, false);
break;
/*
* Case 1. FRAME_TYPE_PREVIEW
* => save all masterFrameQ ( > m_lastFrameCount ) and clean slaveFrameQ
* Case 2. FRAME_TYPE_PREVIEW_SLAVE
* => save all slaveFrameQ ( > m_lastFrameCount ) and clean masterFrameQ
* Case 3. FRAME_TYPE_INTERNAL
* => clean masterFrameQ and clean slaveFrameQ ( <= slaveFrameCount )
* Case 4. FRAME_TYPE_INTERNAL_SLAVE
* => clean slaveFrameQ and clean masterFrameQ ( <= masterFrameCount )
* Case 5. Other
* => just push master or slaveFrameQ
*/
case FRAME_TYPE_PREVIEW:
case FRAME_TYPE_PREVIEW_SLAVE:
case FRAME_TYPE_REPROCESSING:
case FRAME_TYPE_REPROCESSING_SLAVE:
if (newFrame->getFrameType() == FRAME_TYPE_PREVIEW ||
newFrame->getFrameType() == FRAME_TYPE_REPROCESSING) {
/* I can save master frame */
m_cleanFrameBySyncType(m_masterFrameQ, newFrame, m_syncType, true);
m_cleanFrameBySyncType(m_slaveFrameQ, newFrame, m_syncType, false);
} else {
/* I can't save slave frame cause of no service buffer */
m_cleanFrameBySyncType(m_slaveFrameQ, newFrame, m_syncType, false);
m_cleanFrameBySyncType(m_masterFrameQ, newFrame, m_syncType, false);
}
m_pushFrameToOutputQ(newFrame);
break;
case FRAME_TYPE_PREVIEW_DUAL_MASTER:
case FRAME_TYPE_REPROCESSING_DUAL_MASTER:
case FRAME_TYPE_PREVIEW_DUAL_SLAVE:
case FRAME_TYPE_REPROCESSING_DUAL_SLAVE:
ret = m_syncFrame(newFrame, m_syncType, syncFrame);
if (syncFrame != NULL)
m_pushFrameToOutputQ(syncFrame);
break;
case FRAME_TYPE_JPEG_REPROCESSING:
goto p_exit;
default:
CLOGE("[F%d] invalid frameType(%d)", newFrame->getFrameCount(), newFrame->getFrameType());
break;
}
if (!(newFrame->getFrameType() == FRAME_TYPE_INTERNAL || newFrame->getFrameType() == FRAME_TYPE_INTERNAL_SLAVE))
internalLogCount[m_cameraId] = 0;
p_exit:
/* If frameQ have frame over expected count, clean Q */
#ifdef SAMSUNG_DUAL_PORTRAIT_LLS_CAPTURE
if ((m_configurations->getScenario() == SCENARIO_DUAL_REAR_PORTRAIT
|| m_configurations->getScenario() == SCENARIO_DUAL_FRONT_PORTRAIT)
&& m_reprocessing == true) {
int LDCaptureTotalCount = m_configurations->getModeValue(CONFIGURATION_LD_CAPTURE_COUNT);
if (LDCaptureTotalCount > 0) {
m_cleanFrameByMinCount(m_slaveFrameQ, LDCaptureTotalCount + 1);
m_cleanFrameByMinCount(m_masterFrameQ, LDCaptureTotalCount + 1);
} else {
m_cleanFrameByMinCount(m_slaveFrameQ, SYNC_WAITING_COUNT);
m_cleanFrameByMinCount(m_masterFrameQ, SYNC_WAITING_COUNT);
}
} else
#endif
{
m_cleanFrameByMinCount(m_slaveFrameQ, SYNC_WAITING_COUNT);
m_cleanFrameByMinCount(m_masterFrameQ, SYNC_WAITING_COUNT);
}
/*
* Clean old frame in both FrameQ.
* Because service might stop request and wait remained frames
* in each FrameQ that wait for sync.
*/
if (m_syncType != SYNC_TYPE_FIFO) {
m_cleanFrameByTimeStamp(m_slaveFrameQ, removeTimeStamp);
m_cleanFrameByTimeStamp(m_masterFrameQ, removeTimeStamp);
}
/* save the last timestamp for sync */
m_syncLastTimeStamp[cameraId] = curMs;
return NO_ERROR;
}
void ExynosCameraPipeSync::m_init(void)
{
m_lastTimeStamp = 0;
m_lastFrameCount = 0;
m_syncTimestampMinCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
m_syncTimestampMaxCalbTime = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
m_lastFrameType = FRAME_TYPE_BASE;
m_masterFrameQ = NULL;
m_slaveFrameQ = NULL;
m_syncType = SYNC_TYPE_INIT;
m_syncCalbTimeThreshold = SYNC_TIMESTAMP_CALB_TIME_DEFAULT;
}
void ExynosCameraPipeSync::m_pushFrameToOutputQ(ExynosCameraFrameSP_sptr_t frame)
{
status_t ret;
uint32_t currentFrameCount = frame->getFrameCount();
uint64_t currentTimeStamp = (uint64_t)frame->getTimeStampBoot();
#if 0
CLOGD("output frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d) last(%d, %d, %d)",
frame->getCameraId(),
frame->getFrameCount(),
frame->getMetaFrameCount(),
frame->getFrameType(),
frame->getTimeStampBoot() / 1000000LL,
frame->getFrameState(),
m_lastFrameCount,
m_lastTimeStamp / 1000000LL,
m_lastFrameType);
#endif
switch (frame->getFrameState()) {
case FRAME_STATE_SKIPPED:
case FRAME_STATE_INVALID:
CLOGV("drop this frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d) last(%d, %d, %d)",
frame->getCameraId(),
frame->getFrameCount(),
frame->getMetaFrameCount(),
frame->getFrameType(),
frame->getTimeStampBoot() / 1000000LL,
frame->getFrameState(),
m_lastFrameCount,
m_lastTimeStamp / 1000000LL,
m_lastFrameType);
break;
default:
if (!(frame->getFrameType() == FRAME_TYPE_PREVIEW_DUAL_SLAVE ||
frame->getFrameType() == FRAME_TYPE_REPROCESSING_DUAL_SLAVE)) {
if (m_lastTimeStamp > currentTimeStamp) {
CLOGE("detected reversed frame!! (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d) last(%d, %d, %d)",
frame->getCameraId(),
frame->getFrameCount(),
frame->getMetaFrameCount(),
frame->getFrameType(),
frame->getTimeStampBoot() / 1000000LL,
frame->getFrameState(),
m_lastFrameCount,
m_lastTimeStamp / 1000000LL,
m_lastFrameType);
frame->setFrameState(FRAME_STATE_SKIPPED);
} else {
m_lastFrameCount = currentFrameCount;
m_lastTimeStamp = currentTimeStamp;
m_lastFrameType = frame->getFrameType();
}
}
break;
}
ret = frame->setEntityState(getPipeId(), ENTITY_STATE_FRAME_DONE);
if (ret != NO_ERROR) {
CLOGE("setEntityState(%d, ENTITY_STATE_FRAME_DONE) frameCount%d fail", getPipeId(), frame->getFrameCount());
}
m_outputFrameQ->pushProcessQ(&frame);
}
/*
* clean frameQ
* @frameQ : Target FrameQ
* @frame : Base Frame
* If caller specified this frame is not NULL, this function clean all frames older than base frame.
* If caller specified this frame is NULL, this function clean all frames.
* @syncType : method to compare which frame is older than base frame
* (SYNC_TYPE_TIMESTAMP, SYNC_TYPE_FRAMECOUNT)
* @flagSaveFrame : If it's true, older frames will be saved by changing frameType.
*/
status_t ExynosCameraPipeSync::m_cleanFrameBySyncType(frame_queue_t *frameQ, ExynosCameraFrameSP_sptr_t baseFrame,
sync_type_t syncType, bool flagSaveFrame)
{
if (frameQ == NULL) {
CLOGE("frameQ is null");
return INVALID_OPERATION;
}
status_t ret;
int numOfProcessQ = frameQ->getSizeOfProcessQ();
ExynosCameraFrameSP_sptr_t tempFrame = NULL;
bool flagHasBaseFrame = false;
bool flagClean = false;
uint64_t baseTime, tempTime;
/* clean all frames */
if (baseFrame != NULL)
flagHasBaseFrame = true;
for (int i = 0; i < numOfProcessQ; i++) {
tempFrame = NULL;
ret = frameQ->popProcessQ(&tempFrame);
if (ret != NO_ERROR) {
CLOGE("popProcessQ fail!, ret(%d)", ret);
}
if (flagHasBaseFrame) {
switch (syncType) {
case SYNC_TYPE_FIFO:
/* don't remove */
break;
case SYNC_TYPE_FRAMECOUNT:
if (tempFrame->getFrameCount() < baseFrame->getFrameCount())
flagClean = true;
else
flagClean = false;
break;
case SYNC_TYPE_TIMESTAMP:
baseTime = (uint64_t)ns2ms(baseFrame->getTimeStampBoot());
tempTime = (uint64_t)ns2ms(tempFrame->getTimeStampBoot());
if (tempTime < baseTime)
flagClean = true;
else
flagClean = false;
break;
default:
CLOGE("invalid syncType(%d)", syncType);
flagClean = true;
break;
}
} else {
/* all clean */
flagClean = true;
}
if (flagClean) {
/* save the frame by changing frameType */
if (flagSaveFrame) {
switch (tempFrame->getFrameType()) {
case FRAME_TYPE_PREVIEW_DUAL_MASTER:
tempFrame->setFrameType(FRAME_TYPE_PREVIEW);
break;
case FRAME_TYPE_PREVIEW_DUAL_SLAVE:
tempFrame->setFrameType(FRAME_TYPE_PREVIEW_SLAVE);
break;
case FRAME_TYPE_REPROCESSING_DUAL_MASTER:
tempFrame->setFrameType(FRAME_TYPE_REPROCESSING);
break;
case FRAME_TYPE_REPROCESSING_DUAL_SLAVE:
tempFrame->setFrameType(FRAME_TYPE_REPROCESSING_SLAVE);
break;
default:
CLOGE("[F%d] invalid frameType(%d)",
tempFrame->getFrameCount(), tempFrame->getFrameType());
break;
}
} else {
tempFrame->setFrameState(FRAME_STATE_SKIPPED);
}
#if 0
CLOGD("clean frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d)",
tempFrame->getCameraId(),
tempFrame->getFrameCount(),
tempFrame->getMetaFrameCount(),
tempFrame->getFrameType(),
tempFrame->getTimeStampBoot() / 1000000LL,
tempFrame->getFrameState());
#endif
m_pushFrameToOutputQ(tempFrame);
} else {
frameQ->pushProcessQ(&tempFrame);
}
}
return NO_ERROR;
}
/*
* clean frameQ
* @frameQ : Target FrameQ
* @minCount : minimum count to keep in this frameQ
* if this value is 0, clean all frameQ
*/
status_t ExynosCameraPipeSync::m_cleanFrameByMinCount(frame_queue_t *frameQ, int minCount)
{
if (frameQ == NULL) {
CLOGE("frameQ is null");
return INVALID_OPERATION;
}
if (minCount < 0) {
CLOGE("invalid minCount(%d)", minCount);
return INVALID_OPERATION;
}
/* clean all frames */
status_t ret;
ExynosCameraFrameSP_sptr_t tempFrame = NULL;
int numOfProcessQ = frameQ->getSizeOfProcessQ();
if (minCount >= numOfProcessQ)
return NO_ERROR;
for (int i = 0; i < (numOfProcessQ - minCount); i++) {
tempFrame = NULL;
ret = frameQ->popProcessQ(&tempFrame);
if (ret != NO_ERROR) {
CLOGE("popProcessQ fail!, ret(%d)", ret);
}
tempFrame->setFrameState(FRAME_STATE_SKIPPED);
#if 0
CLOGD("clean frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d)",
tempFrame->getCameraId(),
tempFrame->getFrameCount(),
tempFrame->getMetaFrameCount(),
tempFrame->getFrameType(),
tempFrame->getTimeStampBoot() / 1000000LL,
tempFrame->getFrameState());
#endif
m_pushFrameToOutputQ(tempFrame);
}
return NO_ERROR;
}
/*
* clean frameQ
* @removeTimeStamp : baseline of timestamp (ms)
*/
status_t ExynosCameraPipeSync::m_cleanFrameByTimeStamp(frame_queue_t *frameQ, uint64_t removeTimeStamp)
{
if (frameQ == NULL) {
CLOGE("frameQ is null");
return INVALID_OPERATION;
}
status_t ret;
int numOfProcessQ = frameQ->getSizeOfProcessQ();
ExynosCameraFrameSP_sptr_t tempFrame = NULL;
uint64_t tempTime;
bool flagClean;
for (int i = 0; i < numOfProcessQ; i++) {
tempFrame = NULL;
ret = frameQ->popProcessQ(&tempFrame);
if (ret != NO_ERROR) {
CLOGE("popProcessQ fail!, ret(%d)", ret);
}
tempTime = (uint64_t)ns2ms(tempFrame->getTimeStampBoot());
if (tempTime <= removeTimeStamp)
flagClean = true;
else
flagClean = false;
if (flagClean) {
CLOGV("clean frame (Cam:%d, Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld, State:%d)",
tempFrame->getCameraId(),
tempFrame->getFrameCount(),
tempFrame->getMetaFrameCount(),
tempFrame->getFrameType(),
tempFrame->getTimeStampBoot() / 1000000LL,
tempFrame->getFrameState());
tempFrame->setFrameState(FRAME_STATE_SKIPPED);
m_pushFrameToOutputQ(tempFrame);
} else {
frameQ->pushProcessQ(&tempFrame);
}
}
return NO_ERROR;
}
/* This function return unified frame (master frame which have slave buffer) */
status_t ExynosCameraPipeSync::m_syncFrame(ExynosCameraFrameSP_sptr_t newFrame, sync_type_t syncType,
ExynosCameraFrameSP_dptr_t finalFrame)
{
bool iamFound = false;
bool iamMasterFrame = false;
uint64_t myTime, pairTime;
int64_t diffTimeMs;
int64_t syncCalbTime;
frame_queue_t *myFrameQ = NULL;
frame_queue_t *pairFrameQ = NULL;
ExynosCameraFrameSP_sptr_t pairFrame = NULL;
switch (newFrame->getFrameType()) {
case FRAME_TYPE_PREVIEW_DUAL_MASTER:
case FRAME_TYPE_REPROCESSING_DUAL_MASTER:
iamMasterFrame = true;
myFrameQ = m_masterFrameQ;
pairFrameQ = m_slaveFrameQ;
break;
case FRAME_TYPE_PREVIEW_DUAL_SLAVE:
case FRAME_TYPE_REPROCESSING_DUAL_SLAVE:
myFrameQ = m_slaveFrameQ;
pairFrameQ = m_masterFrameQ;
break;
default:
CLOG_ASSERT("[F%d] invalid frameType(%d)", newFrame->getFrameCount(), newFrame->getFrameType());
break;
}
/* let's find my pair frame by syncType */
raw_frame_queue_t *rawPairFrameQ = pairFrameQ->getRawProcessList();
pairFrameQ->rawLockProcessList(); /* lock */
for (raw_frame_queue_t::iterator r = rawPairFrameQ->begin(); r != rawPairFrameQ->end(); ++r) {
pairFrame = *r;
switch (syncType) {
case SYNC_TYPE_FIFO:
iamFound = true;
break;
case SYNC_TYPE_FRAMECOUNT:
if (pairFrame->getFrameCount() == newFrame->getFrameCount())
iamFound = true;
break;
case SYNC_TYPE_TIMESTAMP:
myTime = (uint64_t)ns2ms(newFrame->getTimeStampBoot());
pairTime = (uint64_t)ns2ms(pairFrame->getTimeStampBoot());
diffTimeMs = myTime - pairTime;
/* for abs */
if (diffTimeMs < 0) {
diffTimeMs = -diffTimeMs;
}
syncCalbTime = m_syncTimestampMinCalbTime;
/* The case to be able to support hw sync exactly (in variable fps in sync mode) */
if (m_configurations->getDualHwSyncOn() == false) {
if (m_needMaxCalbTime[newFrame->getCameraId()] == true &&
m_needMaxCalbTime[pairFrame->getCameraId()] == true) {
/* need maximum calbTime (both are low fps) */
CLOGV("dynamic calbTime change [min:%d -> max:%d]",
m_syncTimestampMinCalbTime, m_syncTimestampMaxCalbTime);
syncCalbTime = m_syncTimestampMaxCalbTime;
}
}
if (diffTimeMs <= syncCalbTime)
iamFound = true;
#if 0
CLOGD("compare diff(%lldms) calbTime(%lldms) new [Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld]"
"vs pair [Fcount:%d, MetaFrameCount:%d, Type:%d, Time:%lld]",
diffTimeMs,
syncCalbTime,
newFrame->getFrameCount(),
newFrame->getMetaFrameCount(),
newFrame->getFrameType(),
myTime,
pairFrame->getFrameCount(),
pairFrame->getMetaFrameCount(),
pairFrame->getFrameType(),
pairTime);
#endif
break;
default:
CLOG_ASSERT("invalid syncType(%d)", syncType);
break;
}
if (iamFound) {
/* remove */
rawPairFrameQ->erase(r);
break;
}
}
pairFrameQ->rawUnLockProcessList(); /* unlock */
if (iamFound) {
bool saveNotSyncedMyFrame = false;
bool saveNotSyncedPairFrame = false;
/* can save master frame only cause of service buffer */
if (m_lastFrameType == FRAME_TYPE_PREVIEW) {
if (iamMasterFrame)
saveNotSyncedMyFrame = true;
else
saveNotSyncedPairFrame = true;
}
/* clear old frames */
m_cleanFrameBySyncType(myFrameQ, newFrame, syncType, saveNotSyncedMyFrame);
m_cleanFrameBySyncType(pairFrameQ, pairFrame, syncType, saveNotSyncedPairFrame);
if (iamMasterFrame) {
m_makeOneMasterFrame(newFrame, pairFrame);
/* return useless slave frame */
m_pushFrameToOutputQ(pairFrame);
finalFrame = newFrame;
} else {
m_makeOneMasterFrame(pairFrame, newFrame);
/* return useless slave frame */
m_pushFrameToOutputQ(newFrame);
finalFrame = pairFrame;
}
} else {
myFrameQ->pushProcessQ(&newFrame);
}
return NO_ERROR;
}
void ExynosCameraPipeSync::m_makeOneMasterFrame(ExynosCameraFrameSP_sptr_t masterFrame, ExynosCameraFrameSP_sptr_t slaveFrame)
{
status_t ret;
ExynosCameraBuffer buffer;
ret = slaveFrame->getSrcBuffer(getPipeId(), &buffer);
if (ret != NO_ERROR) {
CLOGE("getDstBuffer fail, pipeId(%d), ret(%d)",
getPipeId(), ret);
}
/* TODO: Check timestamp and skip frame */
if (buffer.index < 0) {
CLOGE("Invalid buffer index(%d), framecount(%d), pipeId(%d)",
buffer.index, slaveFrame->getFrameCount(), getPipeId());
masterFrame->setFrameState(FRAME_STATE_SKIPPED);
slaveFrame->setFrameState(FRAME_STATE_SKIPPED);
} else {
ret = masterFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_REQUESTED);
if (ret != NO_ERROR) {
CLOGE("[F%d B%d]Failed to setDstBufferState. ret %d",
masterFrame->getFrameCount(), buffer.index, ret);
} else {
struct camera2_shot_ext *slave_shot_ext = NULL;
ret = masterFrame->setDstBuffer(getPipeId(), buffer);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer fail, pipeId(%d), ret(%d)",
getPipeId(), ret);
}
/* set Zoom Ratio */
masterFrame->setZoomRatio(slaveFrame->getZoomRatio(), OUTPUT_NODE_2);
/* set Active Zoom Ratio */
masterFrame->setActiveZoomRatio(slaveFrame->getActiveZoomRatio(), OUTPUT_NODE_2);
/* set Active Zoom Rect */
ExynosRect viewZoomRect = {0, };
slaveFrame->getZoomRect(&viewZoomRect);
masterFrame->setZoomRect(&viewZoomRect, OUTPUT_NODE_2);
/* set Active Zoom Rect */
ExynosRect slaveActiveZoomRect = {0, };
slaveFrame->getActiveZoomRect(&slaveActiveZoomRect);
masterFrame->setActiveZoomRect(slaveActiveZoomRect, OUTPUT_NODE_2);
/* set ActiveZoomMargin */
masterFrame->setActiveZoomMargin(slaveFrame->getActiveZoomMargin(), OUTPUT_NODE_2);
/* shot_ext */
slave_shot_ext = (struct camera2_shot_ext *)(buffer.addr[buffer.getMetaPlaneIndex()]);
masterFrame->setMetaData(slave_shot_ext, OUTPUT_NODE_2);
}
}
if (m_reprocessing == true && slaveFrame->getRequest(PIPE_HWFC_JPEG_DST_REPROCESSING)) {
ret = slaveFrame->getSrcBuffer(getPipeId(), &buffer, OUTPUT_NODE_2);
if (ret != NO_ERROR) {
CLOGE("getDstBuffer fail, pipeId(%d), ret(%d)", getPipeId(), ret);
}
if (buffer.index < 0) {
CLOGE("Invalid buffer index(%d), framecount(%d), pipeId(%d)",
buffer.index, slaveFrame->getFrameCount(), getPipeId());
} else {
ret = masterFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_REQUESTED, CAPTURE_NODE_2);
if (ret != NO_ERROR) {
CLOGE("[F%d B%d]Failed to setDstBufferState. ret %d",
masterFrame->getFrameCount(), buffer.index, ret);
} else {
ret = masterFrame->setDstBuffer(getPipeId(), buffer, CAPTURE_NODE_2);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer fail, pipeId(%d), ret(%d)", getPipeId(), ret);
}
}
}
}
}
}; /* namespace android */