blob: f3c9f9dbd59b289bf92ae219323806a51713e84d [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 "ExynosCameraMCPipe"
#define INTERNAL_FRAME_LOG_DURATION (33 * 5) /* about 5s */
#include "ExynosCameraMCPipe.h"
namespace android {
#ifdef USE_MCPIPE_SERIALIZATION_MODE
Mutex ExynosCameraMCPipe::g_serializationLock[ExynosCameraParameters::CRITICAL_SECTION_TYPE_END];
#endif
ExynosCameraMCPipe::~ExynosCameraMCPipe()
{
this->destroy();
}
status_t ExynosCameraMCPipe::create(int32_t *sensorIds)
{
CLOGV("");
status_t ret = NO_ERROR;
ret = m_createSensorNode(sensorIds);
if (ret < 0) {
CLOGE("m_createSensorNode() fail");
return ret;
}
ret = m_preCreate();
if (ret != NO_ERROR) {
CLOGE("m_preCreate() fail, ret(%d)", ret);
return ret;
}
ret = m_postCreate();
if (ret != NO_ERROR) {
CLOGE("m_postCreate() fail, ret(%d)", ret);
return ret;
}
return ret;
}
status_t ExynosCameraMCPipe::precreate(__unused int32_t *sensorIds)
{
CLOGV("");
status_t ret = NO_ERROR;
ret = m_createSensorNode(sensorIds);
if (ret < 0) {
CLOGE("m_createSensorNode() fail");
return ret;
}
ret = m_preCreate();
if (ret != NO_ERROR) {
CLOGE("m_preCreate() fail, ret(%d)", ret);
return ret;
}
return ret;
}
status_t ExynosCameraMCPipe::postcreate(int32_t *sensorIds)
{
CLOGV("");
status_t ret = NO_ERROR;
ret = m_postCreate(sensorIds);
if (ret != NO_ERROR) {
CLOGE("m_postCreate() fail, ret(%d)", ret);
return ret;
}
CLOGV("postcreate() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::destroy(void)
{
CLOGI("");
status_t ret = NO_ERROR;
for (int i = (MAX_NODE - 1); i >= OUTPUT_NODE; i--) {
if (m_node[i] != NULL) {
if (i == m_sensorNodeIndex) {
m_destroyNode(m_cameraId, m_node[i]);
m_node[i] = NULL;
continue;
}
#ifdef SUPPORT_DEPTH_MAP
if (i == m_depthVcNodeIndex) {
m_destroyVcNode(m_cameraId, m_node[i]);
m_node[i] = NULL;
continue;
}
#endif // SUPPORT_DEPTH_MAP
if (OUTPUT_NODE < i
&& m_node[OUTPUT_NODE] != NULL
&& m_deviceInfo->nodeNum[OUTPUT_NODE] == m_deviceInfo->nodeNum[i]) {
/* In this case(3AA of 54xx), 3AA, 3AP node is same.
* So, should close one node. Skip 3AP node.
*/
} else {
ret = m_node[i]->close();
if (ret != NO_ERROR) {
CLOGE("Main node(%s) close fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
}
SAFE_DELETE(m_node[i]);
CLOGD("Main node(%s, sensorIds:%d) closed",
m_deviceInfo->nodeName[i], m_sensorIds[i]);
}
}
CLOGD("Node destroyed");
if (m_inputFrameQ != NULL) {
m_inputFrameQ->release();
SAFE_DELETE(m_inputFrameQ);
}
if (m_requestFrameQ != NULL) {
m_requestFrameQ->release();
SAFE_DELETE(m_requestFrameQ);
}
CLOGI("destroy() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::setupPipe(camera_pipe_info_t *pipeInfos, int32_t *sensorIds)
{
CLOGD("");
status_t ret = NO_ERROR;
uint32_t pipeId = 0;
int result = 0;
ExynosCameraNode *setFileSettingNode = NULL;
/* TODO: check node state */
/* set new sensorId to m_sensorIds */
if (sensorIds != NULL) {
CLOGD("set new sensorIds");
for (int i = OUTPUT_NODE; i < MAX_NODE; i++)
m_sensorIds[i] = sensorIds[i];
}
ret = m_setInput(m_node, m_deviceInfo->nodeNum, m_sensorIds);
if (ret != NO_ERROR) {
CLOGE("m_setInput(Main) fail, ret(%d)", ret);
return ret;
}
if (pipeInfos != NULL) {
ret = m_setPipeInfo(pipeInfos);
if (ret != NO_ERROR) {
CLOGE("m_setPipeInfo() fail, ret(%d)", ret);
return ret;
}
} else {
CLOGE("pipeInfos is NULL");
return BAD_VALUE;
}
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
result = getPipeId((enum NODE_TYPE)i);
if (0 <= result) {
if (m_node[i] != NULL)
setFileSettingNode = m_node[i];
else
continue;
pipeId = (uint32_t)result;
ret = m_setSetfile(setFileSettingNode, pipeId);
if (ret != NO_ERROR) {
CLOGE("m_setSetfile() fail, ret(%d)", ret);
return ret;
}
}
for (uint32_t j = 0; j < m_numBuffers[i]; j++) {
m_runningFrameList[i][j] = NULL;
}
m_numOfRunningFrame[i] = 0;
}
m_prepareBufferCount = m_exynosconfig->current->pipeInfo.prepare[getPipeId()];
if (getPipeId() == PIPE_3AA || getPipeId() == PIPE_FLITE) {
m_prepareBufferCount += m_parameters->getSensorControlDelay();
}
CLOGI("setupPipe() is succeed, Pipe(%d), prepare(%d)", getPipeId(), m_prepareBufferCount);
return ret;
}
status_t ExynosCameraMCPipe::prepare(void)
{
/* need modify */
CLOGD("");
status_t ret = NO_ERROR;
int32_t prepareCount = m_prepareBufferCount;
if (prepareCount > m_inputFrameQ->getSizeOfProcessQ()) {
CLOGE("m_putBufferThreadFunc no Frame(count = %d), running(%d)",
m_inputFrameQ->getSizeOfProcessQ(),
m_putBufferThread->isRunning());
prepareCount = m_inputFrameQ->getSizeOfProcessQ();
}
/*
* prepare on only capture node
* output node doesn't need prepare
*/
for (int32_t i = 0; i < prepareCount; i++)
m_putBufferThreadFunc();
CLOGI("prepare() is succeed, Pipe(%d), prepare(%d/%d)",
getPipeId(), prepareCount, m_prepareBufferCount);
return ret;
}
status_t ExynosCameraMCPipe::start(void)
{
CLOGV("");
status_t ret = NO_ERROR;
/* TODO: check state ready for start */
ret = m_startNode();
if (ret != NO_ERROR) {
CLOGE("m_startNode() fail, ret(%d)", ret);
return ret;
}
m_threadState = 0;
m_threadRenew = 0;
m_lastFrameCount = 0;
m_lastMetaFrameCount = 0;
m_flagStartPipe = true;
m_flagTryStop = false;
#ifdef DEBUG_DUMP_IMAGE
m_dumpBufferCount = 0;
#endif
CLOGI("start() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::stop(void)
{
CLOGV("");
status_t ret = NO_ERROR;
status_t funcRet = NO_ERROR;
ret = m_stopNode();
if (ret != NO_ERROR) {
CLOGE("m_stopNode() fail, ret(%d)", ret);
/* If stop() is error, driver will recover */
funcRet |= ret;
}
m_putBufferThread->requestExitAndWait();
m_getBufferThread->requestExitAndWait();
CLOGD("Thread exited");
m_inputFrameQ->release();
m_requestFrameQ->release();
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_unlockSerializeOperation((enum pipeline)getPipeId());
#endif
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
for (uint32_t j = 0; j < m_numBuffers[i]; j++) {
m_runningFrameList[i][j] = NULL;
}
m_numOfRunningFrame[i] = 0;
m_skipBuffer[i].index = -2;
m_skipPutBuffer[i] = false;
if (m_node[i] != NULL)
m_node[i]->removeItemBufferQ();
}
m_sensorStandbyLock.lock();
m_flagSensorStandby = SENSOR_STANDBY_OFF;
m_sensorStandbyLock.unlock();
m_flagStartPipe = false;
m_flagTryStop = false;
#ifdef DEBUG_DUMP_IMAGE
m_dumpBufferThread->requestExitAndWait();
m_dumpFrameQ->release();
#endif
CLOGI("stop() is succeed, Pipe(%d)", getPipeId());
return funcRet;
}
bool ExynosCameraMCPipe::flagStart(void)
{
return m_flagStartPipe;
}
status_t ExynosCameraMCPipe::startThread(void)
{
CLOGD("");
status_t ret = NO_ERROR;
if (m_outputFrameQ == NULL) {
CLOGE("outputFrameQ is NULL, cannot start");
return INVALID_OPERATION;
}
/* init the internal frame log count */
m_putInternalFrameLogCnt = 0;
m_getInternalFrameLogCnt = 0;
if (m_flagSensorStandby != SENSOR_STANDBY_ON) {
m_putBufferThread->run(PRIORITY_URGENT_DISPLAY);
m_getBufferThread->run(PRIORITY_URGENT_DISPLAY);
}
CLOGI("startThread is succeed, Pipe(%d), standby(%d)", getPipeId(), m_flagSensorStandby);
return ret;
}
status_t ExynosCameraMCPipe::stopThread(void)
{
CLOGD("");
status_t ret = NO_ERROR;
m_putBufferThread->requestExit();
m_getBufferThread->requestExit();
m_inputFrameQ->sendCmd(WAKE_UP);
m_requestFrameQ->sendCmd(WAKE_UP);
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_unlockSerializeOperation((enum pipeline)getPipeId());
#endif
m_dumpRunningFrameList();
#ifdef DEBUG_DUMP_IMAGE
m_dumpBufferThread->requestExit();
m_dumpFrameQ->sendCmd(WAKE_UP);
#endif
CLOGI("stopThread is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::stopThreadAndWait(int sleep, int times)
{
CLOGD(" IN");
status_t status = NO_ERROR;
int i = 0;
for (i = 0; i < times ; i++) {
if (m_putBufferThread->isRunning() == false && m_getBufferThread->isRunning() == false) {
break;
}
usleep(sleep * 1000);
}
if (i >= times) {
status = TIMED_OUT;
CLOGE(" stopThreadAndWait failed, waitTime(%d)ms", sleep*times);
}
CLOGV(" OUT");
return status;
}
bool ExynosCameraMCPipe::flagStartThread(void)
{
return m_putBufferThread->isRunning();
}
status_t ExynosCameraMCPipe::sensorStream(bool on)
{
Mutex::Autolock lock(m_sensorStandbyLock);
CLOGD("");
status_t ret = NO_ERROR;
int value = on ? IS_ENABLE_STREAM : IS_DISABLE_STREAM;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->setControl(V4L2_CID_IS_S_STREAM, value);
if (ret != NO_ERROR)
CLOGE("sensorStream failed, %s node, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
}
/* Set flag for prevent to duplication setting */
if (on == false) {
m_flagSensorStandby = SENSOR_STANDBY_ON;
}
CLOGE("All Nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::sensorStandby(bool on)
{
Mutex::Autolock lock(m_sensorStandbyLock);
CLOGD("%s(on:%d, standby:%d, start:%d)",
(on ? "On" : "Off"), on, m_flagSensorStandby, m_flagStartPipe);
status_t ret = NO_ERROR;
if (on == false) {
if (m_flagSensorStandby == SENSOR_STANDBY_ON
&& m_flagStartPipe == true) {
/* stop Thread */
ret = stopThread();
if (ret != NO_ERROR) {
CLOGE("Stop Thread fail! ret(%d)", ret);
}
CLOGI("Wait for putBufferThread Exit!!(%d)", m_inputFrameQ->getSizeOfProcessQ());
m_putBufferThread->requestExitAndWait();
CLOGI("Wait Done for putBufferThread Exit!!");
CLOGI("Wait for getBufferThread Exit!!(%d)", m_requestFrameQ->getSizeOfProcessQ());
m_getBufferThread->requestExitAndWait();
CLOGI("Wait Done for getBufferThread Exit!!");
ret = prepare();
if (ret != NO_ERROR) {
CLOGE("Prepare fail! ret(%d)", ret);
}
ret = m_sensorStandby(on);
if (ret != NO_ERROR) {
CLOGE("Sensor standby(%s) fail! ret(%d)",
(on?"On":"Off"), ret);
}
}
m_flagSensorStandby = SENSOR_STANDBY_OFF;
if (m_flagStartPipe == true) {
ret = startThread();
if (ret != NO_ERROR) {
CLOGE("Stop Thread fail! ret(%d)", ret);
}
}
}
if (on == true
&& m_flagSensorStandby == SENSOR_STANDBY_OFF) {
if (m_flagStartPipe == false) {
m_flagSensorStandby = SENSOR_STANDBY_ON;
} else {
m_flagSensorStandby = SENSOR_STANDBY_ON_READY;
}
m_inputFrameQ->sendCmd(WAKE_UP);
m_requestFrameQ->sendCmd(WAKE_UP);
}
return ret;
}
enum SENSOR_STANDBY_STATE ExynosCameraMCPipe::getSensorStandbyState(void)
{
Mutex::Autolock lock(m_sensorStandbyLock);
return m_flagSensorStandby;
}
status_t ExynosCameraMCPipe::forceDone(unsigned int cid, int value)
{
CLOGV("");
status_t ret = NO_ERROR;
if (m_node[OUTPUT_NODE] == NULL) {
CLOGE("m_node[OUTPUT_NODE] is NULL");
return INVALID_OPERATION;
}
ret = m_forceDone(m_node[OUTPUT_NODE], cid, value);
if (ret != NO_ERROR) {
CLOGE("m_forceDone() is failed, ret");
return ret;
}
CLOGI("forceDone() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::setControl(int cid, int value)
{
CLOGV("cdi %d value %d", cid, value);
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->setControl(cid, value);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->setControl failed, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("setControl() is succeed, Pipe(%d)", getPipeId((enum NODE_TYPE)i));
return ret;
}
}
CLOGE("All nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::setControl(int cid, int value, enum NODE_TYPE nodeType)
{
CLOGV("cid %d value %d nodeType %d", cid, value, nodeType);
status_t ret = NO_ERROR;
if (m_node[nodeType] == NULL) {
CLOGE("m_node[%d] == NULL. so, fail", nodeType);
return INVALID_OPERATION;
}
ret = m_node[nodeType]->setControl(cid, value);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->setControl failed, ret(%d)",
m_deviceInfo->nodeName[nodeType], ret);
return ret;
}
CLOGV("setControl() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::getControl(int cid, int *value)
{
CLOGV("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->getControl(cid, value);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->getControl failed, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("getControl() is succeed, Pipe(%d)", getPipeId((enum NODE_TYPE)i));
return ret;
}
}
CLOGE("All nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::getControl(int cid, int *value, enum NODE_TYPE nodeType)
{
CLOGV("");
status_t ret = NO_ERROR;
if (m_node[nodeType] == NULL) {
CLOGE("m_node[%d] == NULL. so, fail", nodeType);
return INVALID_OPERATION;
}
ret = m_node[nodeType]->getControl(cid, value);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->getControl failed, ret(%d)",
m_deviceInfo->nodeName[nodeType], ret);
return ret;
}
CLOGV("getControl() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::setExtControl(struct v4l2_ext_controls *ctrl)
{
CLOGV("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->setExtControl(ctrl);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->setControl failed, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("setControl() is succeed, Pipe(%d)",
getPipeId((enum NODE_TYPE)i));
return ret;
}
}
CLOGE("All nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::setExtControl(struct v4l2_ext_controls *ctrl, enum NODE_TYPE nodeType)
{
CLOGV("");
status_t ret = NO_ERROR;
if (m_node[nodeType] == NULL) {
CLOGE("m_node[%d] == NULL. so, fail",
nodeType);
return INVALID_OPERATION;
}
ret = m_node[nodeType]->setExtControl(ctrl);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->setControl failed, ret(%d)",
m_deviceInfo->nodeName[nodeType], ret);
return ret;
}
CLOGV("setControl() is succeed, Pipe(%d)",
getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::setParam(struct v4l2_streamparm streamParam)
{
CLOGV("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->setParam(&streamParam);
if (ret != NO_ERROR) {
CLOGE("m_node(%s)->setParam failed, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("setParam() is succeed, Pipe(%d)", getPipeId((enum NODE_TYPE)i));
return ret;
}
}
CLOGE("All nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::pushFrame(ExynosCameraFrameSP_dptr_t newFrame)
{
Mutex::Autolock lock(m_pipeframeLock);
if (newFrame == NULL) {
CLOGE("newFrame is NULL");
return BAD_VALUE;
}
m_inputFrameQ->pushProcessQ(&newFrame);
return NO_ERROR;
}
status_t ExynosCameraMCPipe::instantOn(int32_t numFrames)
{
CLOGD("");
status_t ret = NO_ERROR;
uint32_t nodeCount = 0;
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraBuffer newBuffer;
if (m_inputFrameQ->getSizeOfProcessQ() != numFrames) {
CLOGE("instantOn need %d Frames, but %d Frames are queued",
numFrames, m_inputFrameQ->getSizeOfProcessQ());
return BAD_VALUE;
}
for (int i = (MAX_CAPTURE_NODE - 1); i >= OUTPUT_NODE; i--) {
if (m_node[i] != NULL) {
#ifdef SUPPORT_DEPTH_MAP
if (i == m_depthVcNodeIndex) {
continue;
}
#endif // SUPPORT_DEPTH_MAP
ret = m_node[i]->start();
if (ret != NO_ERROR) {
CLOGE("node(%s) instantOn fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
nodeCount++;
}
}
if (nodeCount == 0) {
CLOGE("All nodes is NULL");
return INVALID_OPERATION;
}
for (int i = 0; i < numFrames; i++) {
ret = m_inputFrameQ->popProcessQ(&newFrame);
if (ret != NO_ERROR) {
CLOGE("Wait and pop fail, ret(%d)", ret);
return ret;
}
if (newFrame == NULL) {
CLOGE("newFrame is NULL");
return INVALID_OPERATION;
}
ret = newFrame->getSrcBuffer(getPipeId(), &newBuffer);
if (ret != NO_ERROR) {
CLOGE("Frame get buffer fail, ret(%d)", ret);
return ret;
}
if (m_node[OUTPUT_NODE] != NULL) {
CLOGD("Put instantOn Buffer (index %d)", newBuffer.index);
ret = m_node[OUTPUT_NODE]->putBuffer(&newBuffer);
if (ret != NO_ERROR) {
CLOGE("putBuffer() fail, ret(%d)", ret);
return ret;
/* TODO: doing exception handling */
}
} else {
CLOGE("m_node[OUTPUT_NODE] is NULL");
return INVALID_OPERATION;
}
}
CLOGI("instantOn() is succeed, Pipe(%d), Frames(%d)",
getPipeId(), numFrames);
return ret;
}
status_t ExynosCameraMCPipe::instantOff(void)
{
CLOGD("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++) {
if (m_node[i] != NULL) {
#ifdef SUPPORT_DEPTH_MAP
if (i == m_depthVcNodeIndex) {
continue;
}
#endif // SUPPORT_DEPTH_MAP
ret = m_node[i]->stop();
if (ret != NO_ERROR) {
CLOGE("node(%s) stop fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
ret = m_node[i]->clrBuffers();
if (ret != NO_ERROR) {
CLOGE("node(%s) clrBuffers fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
}
}
CLOGI("instantOff() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::getPipeInfo(int *fullW, int *fullH, int *colorFormat, int pipePosition)
{
CLOGV("");
status_t ret = NO_ERROR;
int planeCount = 0;
if (pipePosition == DST_PIPE) {
if (m_node[OUTPUT_NODE] == NULL) {
CLOGE("m_node[OUTPUT_NODE] is NULL");
return INVALID_OPERATION;
}
ret = m_node[OUTPUT_NODE]->getSize(fullW, fullH);
if (ret != NO_ERROR) {
CLOGE("node(%s) getSize fail, ret(%d)",
m_deviceInfo->nodeName[OUTPUT_NODE], ret);
return ret;
}
ret = m_node[OUTPUT_NODE]->getColorFormat(colorFormat, &planeCount);
if (ret != NO_ERROR) {
CLOGE("node(%s) getColorFormat fail, ret(%d)",
m_deviceInfo->nodeName[OUTPUT_NODE], ret);
return ret;
}
} else if (pipePosition == SRC_PIPE) {
for (int i = (MAX_CAPTURE_NODE - 1); i > OUTPUT_NODE; i--) {
if (m_node[i] != NULL) {
ret = m_node[i]->getSize(fullW, fullH);
if (ret != NO_ERROR) {
CLOGE("node(%s) getSize fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
ret = m_node[i]->getColorFormat(colorFormat, &planeCount);
if (ret != NO_ERROR) {
CLOGE("node(%s) getColorFormat fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("getPipeInfo() is succeed, Pipe(%d)", getPipeId((enum NODE_TYPE)i));
return ret;
}
}
CLOGE("all capture m_node is NULL");
return INVALID_OPERATION;
} else {
CLOGE("Pipe position is Invalid, position(%d)", pipePosition);
return BAD_VALUE;
}
CLOGV("getPipeInfo() is succeed, Pipe(%d)", getPipeId());
return ret;
}
status_t ExynosCameraMCPipe::setPipeId(uint32_t id)
{
return this->setPipeId(OUTPUT_NODE, id);
}
uint32_t ExynosCameraMCPipe::getPipeId(void)
{
return (uint32_t)this->getPipeId(OUTPUT_NODE);
}
status_t ExynosCameraMCPipe::setPipeId(enum NODE_TYPE nodeType, uint32_t id)
{
if (nodeType < OUTPUT_NODE || MAX_NODE <= nodeType) {
CLOGE("Invalid nodeType(%d). so, fail", nodeType);
return BAD_VALUE;
}
CLOGD("nodeType(%d), id(%d)", nodeType, id);
m_pipeIdArr[nodeType] = id;
if (nodeType == OUTPUT_NODE)
m_pipeId = id;
return NO_ERROR;
}
int ExynosCameraMCPipe::getPipeId(enum NODE_TYPE nodeType)
{
if (nodeType < OUTPUT_NODE || MAX_NODE <= nodeType) {
CLOGE("Invalid nodeType(%d). so, fail", nodeType);
return -1;
}
return m_pipeIdArr[nodeType];
}
status_t ExynosCameraMCPipe::setPipeName(const char *pipeName)
{
CLOGD("");
strncpy(m_name, pipeName, (EXYNOS_CAMERA_NAME_STR_SIZE - 1));
return NO_ERROR;
}
char *ExynosCameraMCPipe::getPipeName(void)
{
return m_name;
}
status_t ExynosCameraMCPipe::setBufferSupplier(ExynosCameraBufferSupplier *bufferSupplier)
{
CLOGD("");
m_bufferSupplier = bufferSupplier;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setBufferManager(ExynosCameraBufferManager **bufferManager)
{
CLOGD("");
for (int i = OUTPUT_NODE; i < MAX_NODE; i++)
m_bufferManager[i] = bufferManager[i];
return NO_ERROR;
}
status_t ExynosCameraMCPipe::clearInputFrameQ(void)
{
CLOGD("");
if (m_inputFrameQ != NULL)
m_inputFrameQ->release();
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getInputFrameQ(frame_queue_t **inputFrameQ)
{
*inputFrameQ = m_inputFrameQ;
if (*inputFrameQ == NULL)
CLOGE("inputFrameQ is NULL");
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setOutputFrameQ(frame_queue_t *outputFrameQ)
{
CLOGV("");
m_outputFrameQ = outputFrameQ;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getOutputFrameQ(frame_queue_t **outputFrameQ)
{
*outputFrameQ = m_outputFrameQ;
if (*outputFrameQ == NULL)
CLOGE("outputFrameQ is NULL");
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setFrameDoneQ(frame_queue_t *frameDoneQ)
{
CLOGV("");
m_frameDoneQ = frameDoneQ;
m_flagFrameDoneQ = true;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getFrameDoneQ(frame_queue_t **frameDoneQ)
{
*frameDoneQ = m_frameDoneQ;
if (*frameDoneQ == NULL)
CLOGE("frameDoneQ is NULL");
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setNodeInfos(camera_node_objects_t *nodeObjects, bool flagReset)
{
CLOGD("setNodeInfos flagReset(%s)",
(flagReset) ? "True" : "False");
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
m_node[i] = nodeObjects->node[i];
if (flagReset == true) {
if (m_node[i] != NULL)
m_node[i]->resetInput();
}
}
if (flagReset == true) {
m_frameDoneQ = NULL;
m_flagFrameDoneQ = false;
m_outputFrameQ = NULL;
}
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getNodeInfos(camera_node_objects_t *nodeObjects)
{
CLOGD("getNodeInfos");
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
nodeObjects->node[i] = m_node[i];
}
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setMapBuffer(__unused ExynosCameraBuffer *srcBuf, __unused ExynosCameraBuffer *dstBuf)
{
status_t ret = NO_ERROR;
/* Output Node */
for (int i = OUTPUT_NODE; i < MAX_OUTPUT_NODE; i++) {
if (m_node[i] != NULL &&
m_bufferManager[i] != NULL)
ret |= m_setMapBuffer(i);
}
/* Capture Node */
for (int i = CAPTURE_NODE; i < MAX_CAPTURE_NODE; i++) {
if (m_deviceInfo->connectionMode[i] == HW_CONNECTION_MODE_M2M_BUFFER_HIDING
&& m_node[i] != NULL
&& m_bufferManager[i] != NULL)
ret |= m_setMapBuffer(i);
}
return ret;
}
status_t ExynosCameraMCPipe::setBoosting(bool isBoosting)
{
CLOGD("");
m_isBoosting = isBoosting;
return NO_ERROR;
}
bool ExynosCameraMCPipe::isThreadRunning(void)
{
if (m_putBufferThread->isRunning() || m_getBufferThread->isRunning())
return true;
return false;
}
status_t ExynosCameraMCPipe::getThreadState(int **threadState)
{
*threadState = &m_threadState;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getThreadInterval(uint64_t **timeInterval)
{
*timeInterval = &m_timeInterval;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::getThreadRenew(int **timeRenew)
{
*timeRenew = &m_threadRenew;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::incThreadRenew(void)
{
m_threadRenew ++;
return NO_ERROR;
}
status_t ExynosCameraMCPipe::setStopFlag(void)
{
CLOGD("");
m_flagTryStop = true;
return NO_ERROR;
}
int ExynosCameraMCPipe::getRunningFrameCount(void)
{
int runningFrameCount = 0;
for (uint32_t i = 0; i < m_numBuffers[OUTPUT_NODE]; i++) {
if (m_runningFrameList[OUTPUT_NODE][i] != NULL) {
runningFrameCount++;
}
}
return runningFrameCount;
}
#ifdef USE_MCPIPE_SERIALIZATION_MODE
void ExynosCameraMCPipe::needSerialization(bool enable)
{
CLOGI("%s serialized operation %s",
m_name,
(enable == true)? "enabled" : "disabled");
m_serializeOperation = enable;
}
#endif
void ExynosCameraMCPipe::dump(void)
{
CLOGI("last fcount(HAL:%d, DRV:%d)", m_lastFrameCount, m_lastMetaFrameCount);
m_dumpRunningFrameList();
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
m_node[i]->dump();
}
if (m_bufferManager[i] != NULL) {
m_bufferManager[i]->dump();
}
}
return;
}
status_t ExynosCameraMCPipe::dumpFimcIsInfo(bool bugOn)
{
CLOGD("");
status_t ret = NO_ERROR;
ret = m_node[OUTPUT_NODE]->setControl(V4L2_CID_IS_DEBUG_DUMP, bugOn);
if (ret != NO_ERROR)
CLOGE("m_node[OUTPUT_NODE]->setControl failed");
return ret;
}
//#ifdef MONITOR_LOG_SYNC
status_t ExynosCameraMCPipe::syncLog(uint32_t syncId)
{
CLOGD("");
status_t ret = NO_ERROR;
ret = m_node[OUTPUT_NODE]->setControl(V4L2_CID_IS_DEBUG_SYNC_LOG, syncId);
if (ret != NO_ERROR)
CLOGE("m_node[OUTPUT_NODE]->setControl failed");
return ret;
}
//#endif
status_t ExynosCameraMCPipe::m_preCreate(void)
{
CLOGD("");
status_t ret = NO_ERROR;
ExynosCameraNode *jpegNode = NULL;
/* Create & open output/capture nodes */
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
// sensor's open happen in m_createSensorNode, for performance
if (i == m_sensorNodeIndex) {
continue;
}
#ifdef SUPPORT_DEPTH_MAP
if (i == m_depthVcNodeIndex) {
continue;
}
#endif // SUPPORT_DEPTH_MAP
void *module = NULL;
enum EXYNOS_CAMERA_NODE_LOCATION location = NODE_LOCATION_DST;
if (m_flagValidInt(m_deviceInfo->nodeNum[i]) == true) {
switch (m_deviceInfo->nodeNum[i]) {
case FIMC_IS_VIDEO_HWFC_JPEG_NUM:
case FIMC_IS_VIDEO_HWFC_THUMB_NUM:
if (m_deviceInfo->pipeId[i] == PIPE_HWFC_JPEG_SRC_REPROCESSING
|| m_deviceInfo->pipeId[i] == PIPE_HWFC_THUMB_SRC_REPROCESSING) {
location = NODE_LOCATION_SRC;
}
/* JpegHAL Node case */
m_node[i] = (ExynosCameraNode*)new ExynosCameraNodeJpegHAL();
if (jpegNode == NULL) {
jpegNode = m_node[i];
} else {
ret = jpegNode->getInternalModule(&module);
if (ret != NO_ERROR) {
CLOGE("jpegNode->getInternalModule failed");
return ret;
}
}
ret = m_node[i]->create(m_deviceInfo->nodeName[i], m_cameraId, location, module);
if (ret != NO_ERROR) {
CLOGE("Create node fail(Node:%s), ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
ret = m_node[i]->open(m_deviceInfo->nodeNum[i], (int)m_parameters->isUseThumbnailHWFC());
if (ret != NO_ERROR) {
CLOGE("Open node fail(Node:%s), ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGD("JpegHAL Node(%d) opened", m_deviceInfo->nodeNum[i]);
break;
default:
/* Normal case */
m_node[i] = new ExynosCameraNode();
ret = m_node[i]->create(m_deviceInfo->nodeName[i], m_cameraId);
if (ret != NO_ERROR) {
CLOGE("Create node fail(Node:%s), ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
ret = m_node[i]->open(m_deviceInfo->nodeNum[i]);
if (ret != NO_ERROR) {
CLOGE("Open node fail(Node:%s), ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
CLOGV("Node(%d) opened", m_deviceInfo->nodeNum[i]);
break;
}
}
}
m_putBufferThreadName.clear();
m_getBufferThreadName.clear();
m_putBufferThreadName.appendFormat("putBuf%d-%d", getPipeId(), m_cameraId);
m_getBufferThreadName.appendFormat("getBuf%d-%d", getPipeId(), m_cameraId);
m_putBufferThread = new MCPipeThread(this,
&ExynosCameraMCPipe::m_putBufferThreadFunc, m_putBufferThreadName.c_str(), PRIORITY_URGENT_DISPLAY);
m_getBufferThread = new MCPipeThread(this,
&ExynosCameraMCPipe::m_getBufferThreadFunc, m_getBufferThreadName.c_str(), PRIORITY_URGENT_DISPLAY);
#ifdef DEBUG_DUMP_IMAGE
m_dumpBufferThread = new MCPipeThread(this,
&ExynosCameraMCPipe::m_dumpBufferThreadFunc, "dumpBufferThread", PRIORITY_URGENT_DISPLAY);
#endif
if (m_reprocessing == true) {
m_inputFrameQ = new frame_queue_t(m_putBufferThread);
m_requestFrameQ = new frame_queue_t(m_getBufferThread);
} else {
m_inputFrameQ = new frame_queue_t;
m_requestFrameQ = new frame_queue_t;
}
#ifdef DEBUG_DUMP_IMAGE
m_dumpFrameQ = new frame_queue_t(m_dumpBufferThread);
#endif
/* Set wait time 0.55 sec. Because, it support 2fps */
m_inputFrameQ->setWaitTime(550000000); /* .55 sec */
m_requestFrameQ->setWaitTime(550000000); /* .55 sec */
#ifdef DEBUG_DUMP_IMAGE
m_dumpFrameQ->setWaitTime(5500000000); /* 5.5 sec */
#endif
CLOGI("m_preCreate() is succeed, Pipe(%d), prepare(%d)",
getPipeId(), m_prepareBufferCount);
return ret;
}
status_t ExynosCameraMCPipe::m_postCreate(int32_t *sensorIds)
{
CLOGD("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (sensorIds != NULL) {
CLOGD("Set new sensorIds[%d] : %d", i, sensorIds[i]);
m_sensorIds[i] = sensorIds[i];
} else {
m_sensorIds[i] = -1;
}
}
ret = m_setInput(m_node, m_deviceInfo->nodeNum, m_sensorIds);
if (ret != NO_ERROR) {
CLOGE("m_setInput(Main) fail, ret(%d)", ret);
return ret;
}
CLOGI("m_postCreate() is succeed, Pipe(%d)", getPipeId());
return ret;
}
#ifdef DEBUG_DUMP_IMAGE
bool ExynosCameraMCPipe::m_dumpBufferThreadFunc(void)
{
int pipeId;
status_t ret = NO_ERROR;
ExynosCameraBuffer buffer;
ExynosCameraFrameSP_sptr_t newFrame = NULL;
if (m_flagTryStop == true)
return true;
ret = m_dumpFrameQ->waitAndPopProcessQ(&newFrame);
if (ret == TIMED_OUT) {
return ret;
} else if (ret != NO_ERROR) {
/* TODO: doing exception handling */
return ret;
}
if (newFrame != NULL) {
uint32_t frameCount = newFrame->getFrameCount();
if (m_dumpBufferCount >= DEBUG_DUMP_MAX ||
(m_dumpBufferCount % DEBUG_DUMP_INTERVAL) > 0)
goto p_err;
/* output node dump */
for (int i = OUTPUT_NODE; i < MAX_OUTPUT_NODE; i++) {
pipeId = getPipeId((enum NODE_TYPE)i);
if (m_node[i] != NULL && DEBUG_DUMP_CONDITION(pipeId)) {
ret = newFrame->getSrcBuffer(getPipeId(), &buffer, i);
if (ret != NO_ERROR) {
CLOGE("%d's Frame get buffer fail, frameCount(%d), ret(%d)",
i, frameCount, ret);
} else {
CLOGI("start frame(%d) dump(pipeId:%d)", frameCount, i);
directDumpToFile(&buffer, m_cameraId, frameCount);
}
}
}
/* capture node dump */
for (int i = CAPTURE_NODE; i < MAX_CAPTURE_NODE; i++) {
pipeId = getPipeId((enum NODE_TYPE)i);
if (m_node[i] != NULL &&
newFrame->getRequest(pipeId) == true &&
DEBUG_DUMP_CONDITION(pipeId)) {
ret = newFrame->getDstBuffer(getPipeId(), &buffer, i);
if (ret != NO_ERROR) {
CLOGE("%d's Frame get buffer fail, frameCount(%d), ret(%d)",
i, frameCount, ret);
} else {
CLOGI("start frame(%d) dump(pipeId:%d)", frameCount, i);
directDumpToFile(&buffer, m_cameraId, frameCount);
}
}
}
}
p_err:
m_dumpBufferCount++;
return m_checkThreadLoop(m_dumpFrameQ);
}
#endif
bool ExynosCameraMCPipe::m_putBufferThreadFunc(void)
{
status_t ret = NO_ERROR;
#ifdef TEST_WATCHDOG_THREAD
testErrorDetect++;
if (testErrorDetect == 100)
m_threadState = ERROR_POLLING_DETECTED;
#endif
if (m_flagTryStop == true) {
usleep(5000);
return true;
}
ret = m_putBuffer();
if (ret != NO_ERROR)
CLOGW("m_putbuffer fail, ret(%d)", ret);
return m_checkThreadLoop(m_inputFrameQ);
}
bool ExynosCameraMCPipe::m_getBufferThreadFunc(void)
{
status_t ret = NO_ERROR;
if (m_flagTryStop == true) {
usleep(5000);
return true;
}
ret = m_getBuffer();
if (ret != NO_ERROR && m_putInternalFrameLogCnt == 0
#ifdef USE_DUAL_CAMERA
&& ret != BAD_TYPE
#endif
) {
CLOGW("m_getBuffer fail, ret(%d)", ret);
}
m_timer.stop();
m_timeInterval = m_timer.durationMsecs();
m_timer.start();
/*
* update renew count
* The m_threadRenew is the count checked the getBuffer(DQbuffer) block.
* Therefore, the time out of the getBuffer thread is unconnected with the getBuffer(DQbuffer) block.
*/
if (ret >= 0 || ret == TIMED_OUT
#ifdef USE_DUAL_CAMERA
|| ret == BAD_TYPE
#endif
) {
m_threadRenew = 0;
}
m_sensorStandbyLock.lock();
if (m_flagSensorStandby == SENSOR_STANDBY_ON_READY
&& m_flagStartPipe == true
&& m_requestFrameQ->getSizeOfProcessQ() == 0) {
ret = m_sensorStandby(true);
if (ret != NO_ERROR) {
CLOGE("Sensor standby(%s) fail! ret(%d)",
(m_flagSensorStandby?"On":"Off"), ret);
}
m_flagSensorStandby = SENSOR_STANDBY_ON;
}
m_sensorStandbyLock.unlock();
return m_checkThreadLoop(m_requestFrameQ);
}
status_t ExynosCameraMCPipe::m_putBuffer(void)
{
CLOGV("-IN-");
status_t ret = NO_ERROR;
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraBuffer buffer[OTF_NODE_BASE];
int pipeId = 0;
int bufferIndex[OTF_NODE_BASE];
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++)
bufferIndex[i] = -2;
uint32_t captureNodeCount = 0;
ExynosCameraDurationTimer blockingTimer[4];
#ifdef USE_DUAL_CAMERA
enum DUAL_OPERATION_MODE dualOperationMode = m_configurations->getDualOperationMode();
#endif
/* 1. Pop from input frame queue */
blockingTimer[0].start();
blockingTimer[1].start();
ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame);
if (ret == TIMED_OUT) {
#ifdef USE_DUAL_CAMERA
if ((m_cameraId == CAMERA_ID_BACK && dualOperationMode == DUAL_OPERATION_MODE_SLAVE) ||
(m_cameraId == CAMERA_ID_BACK_1 && dualOperationMode == DUAL_OPERATION_MODE_MASTER)) {
CLOGV("not pair. cameraId(%d), dualOperationMode(%d)", m_cameraId, dualOperationMode);
return NO_ERROR;
} else
#endif
{
CLOGW("inputFrameQ wait timeout");
return ret;
}
} else if (ret != NO_ERROR) {
CLOGE("inputFrameQ wait and pop fail, ret(%d)", ret);
/* TODO: doing exception handling */
return ret;
}
blockingTimer[1].stop();
if (newFrame == NULL) {
CLOGE("New frame is NULL");
return BAD_VALUE;
}
CLOG_PERFRAME(PATH, m_cameraId, m_name, newFrame.get(), nullptr, newFrame->getRequestKey(), "");
if (newFrame->getFrameType() == FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
|| newFrame->getFrameType() == FRAME_TYPE_INTERNAL_SLAVE
#endif
) {
if ((m_putInternalFrameLogCnt++ % INTERNAL_FRAME_LOG_DURATION) == 0) {
CLOGI("Internal Frame(%d), frameCount(%d), (%d)",
newFrame->getFrameType(), newFrame->getFrameCount(),
m_putInternalFrameLogCnt);
}
} else {
m_putInternalFrameLogCnt = 0;
}
if (newFrame->getFrameState() == FRAME_STATE_SKIPPED
|| newFrame->getFrameState() == FRAME_STATE_INVALID) {
if (newFrame->getFrameType() != FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
&& newFrame->getFrameType() != FRAME_TYPE_INTERNAL_SLAVE
#endif
) {
CLOGE("New frame is INVALID, frameCount(%d)",
newFrame->getFrameCount());
}
goto CLEAN_FRAME;
}
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_lockSerializeOperation((enum pipeline)getPipeId());
#endif
blockingTimer[2].start();
for (int i = (MAX_CAPTURE_NODE - 1); i >= CAPTURE_NODE; i--) {
if (m_node[i] == NULL)
continue;
pipeId = getPipeId((enum NODE_TYPE)i);
if (pipeId < 0) {
CLOGE("getPipeId(%d) fail", i);
return BAD_VALUE;
}
/* 2. Get capture node buffer(DstBuffer) from buffer manager */
if (m_node[i] != NULL
&& newFrame->getRequest(pipeId) == true
&& m_skipPutBuffer[i] == false) {
if (m_bufferSupplier == NULL) {
CLOGE("[F%d]BufferSupplier is NULL, i(%d), piepId(%d)",
newFrame->getFrameCount(), i, pipeId);
continue;
}
ret = newFrame->getDstBuffer(getPipeId(), &buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("getDstBuffer fail. pipeId(%d), frameCount(%d), ret(%d)",
pipeId, newFrame->getFrameCount(), ret);
continue;
}
if (buffer[i].index < 0) {
buffer_manager_tag_t bufTag;
bufTag.pipeId[0] = pipeId;
bufTag.managerType = m_deviceInfo->bufferManagerType[i];
ret = m_bufferSupplier->getBuffer(bufTag, &(buffer[i]));
if (ret != NO_ERROR) {
CLOGE("[%s][F%d]Failed to getBuffer from BufferSupplier. ret %d",
m_node[i]->getName(), newFrame->getFrameCount(), ret);
newFrame->dump();
newFrame->setRequest(pipeId, false);
continue;
}
bufferIndex[i] = buffer[i].index;
} else {
CLOGV("Skip to get buffer from bufferMgr.\
pipeId(%d), frameCount(%d) bufferIndex %d)",
pipeId, newFrame->getFrameCount(), buffer[i].index);
bufferIndex[i] = buffer[i].index;
}
if (bufferIndex[i] < 0
|| m_runningFrameList[i][(bufferIndex[i])] != NULL) {
CLOGE("%d's New buffer is invalid, we already get buffer, index(%d), frameCount(%d)",
i, bufferIndex[i], newFrame->getFrameCount());
newFrame->setRequest(pipeId, false);
/* dump(); */
continue;
}
/* 3. Put capture buffer(DstBuffer) to node */
if (bufferIndex[i] >= 0
&& newFrame->getRequest(pipeId) == true) {
switch(m_deviceInfo->pipeId[i]) {
case PIPE_HWFC_JPEG_SRC_REPROCESSING:
case PIPE_HWFC_JPEG_DST_REPROCESSING:
case PIPE_HWFC_THUMB_SRC_REPROCESSING:
ret = m_setJpegInfo(i, newFrame);
if (ret != NO_ERROR) {
CLOGE("Failed to setJpegInfo, pipeId %s buffer.index %d",
(m_deviceInfo->pipeId[i] == PIPE_HWFC_JPEG_SRC_REPROCESSING)?
"PIPE_HWFC_JPEG_SRC_REPROCESSING":"PIPE_HWFC_THUMB_SRC_REPROCESSING",
buffer[i].index);
continue;
}
break;
default:
break;
}
ret = m_node[i]->putBuffer(&(buffer[i]));
if (ret != NO_ERROR) {
CLOGE("node(%s)->putBuffer() fail, frameCount(%d), ret(%d)",
m_deviceInfo->nodeName[i], newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
if (m_bufferSupplier != NULL) {
ret = m_bufferSupplier->putBuffer(buffer[i]);
if (ret != NO_ERROR) {
CLOGE("[%s][F%d B%d]Failed to putBuffer. ret %d",
m_deviceInfo->nodeName[i],
newFrame->getFrameCount(),
buffer[i].index,
ret);
}
}
newFrame->setRequest(pipeId, false);
} else {
m_skipPutBuffer[i] = true;
m_skipBuffer[i] = buffer[i];
}
}
} else if (m_skipPutBuffer[i] == true) {
CLOGD("%s:Skip putBuffer. framecount %d bufferIndex %d",
m_deviceInfo->nodeName[i], newFrame->getFrameCount(), m_skipBuffer[i].index);
}
if (m_skipPutBuffer[i] == true)
captureNodeCount++;
}
blockingTimer[2].stop();
if (captureNodeCount == 0) {
if (newFrame->getFrameType() != FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
&& newFrame->getFrameType() != FRAME_TYPE_INTERNAL_SLAVE
&& newFrame->getFrameType() != FRAME_TYPE_TRANSITION
#endif
) {
CLOGW("Capture node putbuffer is Zero, frameCount(%d)",
newFrame->getFrameCount());
/* Comment out: 3AA and ISP must running, because it save stat and refered next frame.
* So, put SRC buffer to output node when DST buffers all empty(zero).
*/
/* goto CLEAN_FRAME; */
}
}
TIME_LOGGER_UPDATE(m_cameraId, newFrame->getFrameCount(), getPipeId(), INTERVAL, QBUF, 0);
/* 4. Get output node(SrcBuffer) buffer from frame */
blockingTimer[3].start();
for (int i = (MAX_OUTPUT_NODE - 1); i >= OUTPUT_NODE; i--) {
if (m_node[i] == NULL)
continue;
ret = newFrame->getSrcBuffer(getPipeId(), &(buffer[i]), i);
if (ret != NO_ERROR) {
CLOGE("Frame get src(%d) buffer fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
goto CLEAN_FRAME;
}
if (i == OUTPUT_NODE) {
/* Output Node(Can be group video node) */
if (m_runningFrameList[i][(buffer[i].index)] != NULL) {
if ( (m_parameters->isReprocessing() == true)
&& (m_parameters->getUsePureBayerReprocessing() == false) /* if Dirty bayer reprocessing */
&& (newFrame->getFrameType() == FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
|| newFrame->getFrameType() == FRAME_TYPE_INTERNAL_SLAVE
#endif
)
&& (getPipeId() == PIPE_ISP) ) { /* if internal frame at ISP pipe */
/* In dirty bayer mode, Internal frame would not have valid
output buffer on ISP pipe. So suppress error message */
CLOGI("Internal frame will raises an error here, but it's normal operation, index(%d), frameCount(%d)",
buffer[i].index, newFrame->getFrameCount());
} else {
CLOGE("New buffer is invalid, we already get buffer, index(%d), frameCount(%d)",
buffer[i].index, newFrame->getFrameCount());
}
/* dump(); */
goto CLEAN_FRAME;
}
/* 5. Update control metadata for request, Zoom, ... */
ret = m_updateMetadataFromFrame(newFrame, &(buffer[i]), m_perframeMainNodeGroupInfo[OUTPUT_NODE].perFrameLeaderInfo.perframeInfoIndex);
if (ret != NO_ERROR) {
CLOGW("Update metadata fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
}
}
/* 6. Put output buffer(SrcBuffer) to node */
ret = m_node[i]->putBuffer(&(buffer[i]));
if (ret != NO_ERROR) {
CLOGE("node(%s)->putBuffer() fail, frameCount(%d), ret(%d)",
m_deviceInfo->nodeName[i], newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
goto CLEAN_FRAME;
}
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_PROCESSING, i);
if (ret != NO_ERROR) {
CLOGE("setSrcBuffer(%d) state fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
m_runningFrameList[i][(buffer[i].index)] = newFrame;
m_numOfRunningFrame[i]++;
}
/* 7. Link capture node buffer(DstBuffer) to frame */
for (int i = (MAX_CAPTURE_NODE - 1); i >= CAPTURE_NODE; i--) {
if (m_node[i] == NULL)
continue;
pipeId = getPipeId((enum NODE_TYPE)i);
if (pipeId < 0) {
CLOGE("getPipeId(%d) fail", i);
return BAD_VALUE;
}
if (m_node[i] != NULL
&& newFrame->getRequest(pipeId) == true) {
/* HACK: Should change ExynosCamera, Frame */
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_REQUESTED, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
pipeId, newFrame->getFrameCount(), ret);
}
if (m_skipPutBuffer[i] == true) {
buffer[i] = m_skipBuffer[i];
bufferIndex[i] = buffer[i].index;
}
ret = newFrame->setDstBuffer(getPipeId(), buffer[i], i, INDEX(pipeId));
if (ret != NO_ERROR) {
CLOGE("Frame set dst buffer fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
if (m_bufferManager[i] != NULL)
ret = m_bufferManager[i]->putBuffer(buffer[i].index, EXYNOS_CAMERA_BUFFER_POSITION_NONE);
if (ret != NO_ERROR) {
CLOGE("Buffer manager putBuffer fail, manager(%d), frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
newFrame->setRequest(pipeId, false);
}
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_PROCESSING, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
getPipeId(), newFrame->getFrameCount(), ret);
}
m_runningFrameList[i][(bufferIndex[i])] = newFrame;
m_numOfRunningFrame[i]++;
m_skipPutBuffer[i] = false;
m_skipBuffer[i].index = -2;
}
}
blockingTimer[3].stop();
blockingTimer[0].stop();
/* 8. Push frame to getBufferThread */
m_requestFrameQ->pushProcessQ(&newFrame);
if ((int) blockingTimer[0].durationMsecs() > 1000) { /* Over 1 sec */
CLOGW("[F%d]putBuffer is delayed!! total %d waitInputFrameQ %d captureQ %d OutputQ %d",
newFrame->getFrameCount(),
(int) blockingTimer[0].durationMsecs(),
(int) blockingTimer[1].durationMsecs(),
(int) blockingTimer[2].durationMsecs(),
(int) blockingTimer[3].durationMsecs());
}
CLOGV("OUT-");
return NO_ERROR;
/* Error handling for SrcBuffer and Frame */
CLEAN_FRAME:
if (newFrame->getFrameType() != FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
&& newFrame->getFrameType() != FRAME_TYPE_INTERNAL_SLAVE
#endif
) {
CLOGD("clean frame, frameCount(%d)",
newFrame->getFrameCount());
}
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_unlockSerializeOperation((enum pipeline)getPipeId());
#endif
for (int i = OUTPUT_NODE; i < MAX_OUTPUT_NODE; i++) {
if (m_node[i] == NULL)
continue;
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("%d's setSrcBuffer state fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
}
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
getPipeId(), newFrame->getFrameCount(), ret);
}
for (int i = (MAX_CAPTURE_NODE - 1); i >= CAPTURE_NODE; i--) {
if (m_node[i] != NULL
&& newFrame->getRequest(getPipeId((enum NODE_TYPE)i)) == true)
newFrame->setRequest(getPipeId((enum NODE_TYPE)i), false);
}
if (newFrame->getFrameState() != FRAME_STATE_SKIPPED
&& newFrame->getFrameState() != FRAME_STATE_INVALID) {
newFrame->setFrameState(FRAME_STATE_SKIPPED);
if (ret != NO_ERROR) {
CLOGE("setFrameState fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
}
}
ret = m_completeFrame(newFrame, false);
if (ret != NO_ERROR) {
CLOGE("Complete frame fail, frameCount(%d), ret(%d)", newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
}
if (m_frameDoneQ != NULL && m_flagFrameDoneQ == true)
m_frameDoneQ->pushProcessQ(&newFrame);
m_outputFrameQ->pushProcessQ(&newFrame);
if (newFrame->getFrameType() != FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
&& newFrame->getFrameType() != FRAME_TYPE_INTERNAL_SLAVE
#endif
) {
return INVALID_OPERATION;
} else {
return ret;
}
}
status_t ExynosCameraMCPipe::m_getBuffer(void)
{
CLOGV("-IN-");
status_t ret = NO_ERROR;
status_t nodeDqRet[OTF_NODE_BASE];
status_t checkRet = NO_ERROR;
#ifdef USE_DUAL_CAMERA
enum DUAL_OPERATION_MODE dualOperationMode = m_configurations->getDualOperationMode();
#endif
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraBuffer buffer[OTF_NODE_BASE];
int pipeId = 0;
int v4l2Colorformat = 0;
int planeCount[OTF_NODE_BASE] = {0};
int bufferIndex[OTF_NODE_BASE];
int32_t captureNodeFrameCount[OTF_NODE_BASE];
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++) {
bufferIndex[i] = -2;
captureNodeFrameCount[i] = -1;
nodeDqRet[i] = NO_ERROR;
}
uint32_t captureNodeCount = 0;
uint32_t checkPollingCount = 0;
/* 1. Pop from request frame queue */
ret = m_requestFrameQ->waitAndPopProcessQ(&newFrame);
if (ret == TIMED_OUT) {
#ifdef USE_DUAL_CAMERA
if ((m_cameraId == CAMERA_ID_BACK && dualOperationMode == DUAL_OPERATION_MODE_SLAVE) ||
(m_cameraId == CAMERA_ID_BACK_1 && dualOperationMode == DUAL_OPERATION_MODE_MASTER)) {
CLOGV("not pair. cameraId(%d), dualOperationMode(%d)", m_cameraId, dualOperationMode);
return BAD_TYPE;
} else
#endif
{
if (m_putInternalFrameLogCnt == 0) {
CLOGW("requestFrameQ wait timeout");
}
return ret;
}
} else if (ret != NO_ERROR) {
CLOGE("requestFrameQ wait and pop fail, ret(%d)", ret);
/* TODO: doing exception handling */
return ret;
}
if (newFrame == NULL) {
CLOGE("New frame is NULL");
return BAD_VALUE;
}
/* 2. Get output buffer(SrcBuffer) from node */
for (int i = OUTPUT_NODE; i < MAX_OUTPUT_NODE; i++) {
if (m_node[i] == NULL)
continue;
ret = m_node[i]->getBuffer(&(buffer[i]), &(bufferIndex[i]));
nodeDqRet[i] = ret;
if (ret != NO_ERROR) {
CLOGE("node(%s)->getBuffer() fail, index(%d), frameCount(%d), ret(%d)",
m_deviceInfo->nodeName[i],
bufferIndex[i], newFrame->getFrameCount(), ret);
if (buffer[i].index < 0 && bufferIndex[i] >= 0) {
CLOGW("mismatching bufferIndex(%d) vs buffer[%d].index(%d)",
bufferIndex[i], i, buffer[i].index);
bufferIndex[i] = buffer[i].index;
}
/* TODO: doing exception handling */
/* Comment out : dqblock case was disappeared */
/*
for (int i = (MAX_NODE - 1); i > OUTPUT_NODE; i--) {
if (newFrame->getRequest(getPipeId() + i) == true)
m_skipPutBuffer[i] = true;
}
ret = m_completeFrame(newFrame, false);
if (ret != NO_ERROR) {
CLOGE("Complete frame fail, ret(%d)", ret);
}
goto CLEAN;
*/
if (bufferIndex[i] >= 0) {
newFrame = m_runningFrameList[i][bufferIndex[i]];
} else {
ret = newFrame->getSrcBuffer(getPipeId(), &buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("%d's Frame get buffer fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
} else {
buffer[i].index = -2;
ret = newFrame->setSrcBuffer(getPipeId(), buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("%d's setSrcBuffer fail, fCount(%d), pipe(%d), ret(%d)",
i, newFrame->getFrameCount(), getPipeId(), ret);
}
}
}
if (newFrame == NULL) {
CLOGE("%d's Invalid DQ buffer index(%d)", i, bufferIndex[i]);
ret = BAD_VALUE;
goto EXIT;
}
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("%d's setSrcBuffer state fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
} else {
if (bufferIndex[i] < 0) {
CLOGE("%d's Invalid DQ buffer index(%d)", i, bufferIndex[i]);
ret = BAD_VALUE;
goto EXIT;
}
/*
prevent the frame null pointer exception, get the frame from m_runningFrameList
1. in case of NDONE, dq order was reversed.
2. always use the m_runningFrameList instead of m_requestFrameQ
*/
newFrame = m_runningFrameList[i][bufferIndex[i]];
ret = newFrame->getSrcBuffer(getPipeId(), &buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("%d's Frame get buffer fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
} else {
if (bufferIndex[i] != buffer[i].index) {
ret = newFrame->getSrcBuffer(getPipeId(), &buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("%d's Frame get buffer fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
}
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_COMPLETE, i);
if (ret != NO_ERROR) {
CLOGE("%d's setSrcBuffer state fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
if (i == OUTPUT_NODE && m_reprocessing == false)
m_activityControl->activityAfterExecFunc(getPipeId(), (void *)&buffer[OUTPUT_NODE]);
}
}
TIME_LOGGER_UPDATE(m_cameraId, newFrame->getFrameCount(), getPipeId(), INTERVAL, DQBUF, 0);
if (bufferIndex[i] >= 0) {
/* 3. Update frame from dynamic metadata of output node buffer(SrcBuffer) for request, ... */
if (i == OUTPUT_NODE) {
ret = m_updateMetadataToFrame(buffer[i].addr[buffer[i].getMetaPlaneIndex()],
buffer[i].index, newFrame, (enum NODE_TYPE)i);
if (ret != NO_ERROR) {
CLOGE("%d's Update metadata fail, frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
}
m_runningFrameList[i][bufferIndex[i]] = NULL;
m_numOfRunningFrame[i]--;
}
}
CLOG_PERFRAME(PATH, m_cameraId, m_name, newFrame.get(), nullptr, newFrame->getRequestKey(), "");
if (m_parameters->isUseEarlyFrameReturn() == true
&& m_reprocessing == false
&& m_frameDoneQ != NULL\
&& m_flagFrameDoneQ == true) {
m_frameDoneQ->pushProcessQ(&newFrame);
}
/* 4. Get capture buffer(DstBuffer) from node */
for (int i = (MAX_CAPTURE_NODE - 1); i >= CAPTURE_NODE; i--) {
ret = NO_ERROR;
if (m_node[i] == NULL)
continue;
pipeId = getPipeId((enum NODE_TYPE)i);
if (pipeId < 0) {
CLOGE("getPipeId(%d) fail", i);
ret = BAD_VALUE;
goto EXIT;
}
if (m_node[i] != NULL
&& newFrame->getRequest(pipeId) == true) {
#ifndef SKIP_SCHECK_POLLING
if ((m_parameters->isPreviewPortId(m_parameters->getYuvOutPortId((enum pipeline)INDEX(pipeId))) == true)
&& (checkPollingCount == 0)) {
ret = m_checkPolling(m_node[i]);
if (ret != NO_ERROR) {
CLOGE("[F%d]m_checkPolling fail. ret %d",
newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
// HACK: for panorama shot
//return false;
}
checkPollingCount++;
}
#endif
ret = m_node[i]->getBuffer(&(buffer[i]), &(bufferIndex[i]));
nodeDqRet[i] = ret;
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_unlockSerializeOperation((enum pipeline)pipeId);
#endif
captureNodeFrameCount[i] = (bufferIndex[i] >= 0) ?
(m_runningFrameList[i][bufferIndex[i]]->getFrameCount()) : (newFrame->getFrameCount());
if (ret != NO_ERROR) {
CLOGE("node(%s)->getBuffer() fail, index(%d), frameCount(%d), ret(%d)",
m_deviceInfo->nodeName[i],
bufferIndex[i], newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
if (bufferIndex[i] >= 0) {
if ((int32_t)newFrame->getFrameCount() != captureNodeFrameCount[i]) {
CLOGW("output and capture node frame count do not match. (expect: %d != current: %d), pipeID(%d)",
newFrame->getFrameCount(), captureNodeFrameCount[i], pipeId);
} else {
newFrame = m_runningFrameList[i][bufferIndex[i]];
}
} else {
ret = newFrame->getDstBuffer(getPipeId(), &buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("Frame get buffer fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
} else {
bufferIndex[i] = buffer[i].index = -2;
ret = newFrame->setDstBuffer(getPipeId(), buffer[i], i);
if (ret != NO_ERROR) {
CLOGE("%d's setDstBuffer fail, fCount(%d), pipe(%d), ret(%d)",
i, newFrame->getFrameCount(), getPipeId(), ret);
}
}
newFrame->setRequest(pipeId, false);
}
if (newFrame == NULL) {
CLOGE("Invalid DQ buffer index(%d)", bufferIndex[i]);
ret = BAD_VALUE;
goto EXIT;
}
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
getPipeId(), newFrame->getFrameCount(), ret);
}
}
if (bufferIndex[i] >= 0) {
m_runningFrameList[i][bufferIndex[i]] = NULL;
m_numOfRunningFrame[i]--;
}
/* 5. Link capture node buffer(DstBuffer) to frame */
if (bufferIndex[i] >= 0 && nodeDqRet[i] == NO_ERROR) {
if (bufferIndex[i] != buffer[i].index) {
CLOGW("[F%d -> F%d] bufferIndex[i](%d) != buffer[i].index(%d)",
newFrame->getFrameCount(), m_runningFrameList[i][bufferIndex[i]]->getFrameCount(),
bufferIndex[i], buffer[i].index);
newFrame = m_runningFrameList[i][bufferIndex[i]];
}
/* HACK: Should change ExynosCamera, Frame */
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_REQUESTED, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
pipeId, newFrame->getFrameCount(), ret);
}
ret = newFrame->setDstBuffer(getPipeId(), buffer[i], i, INDEX(pipeId));
if (ret != NO_ERROR) {
CLOGE("Frame set dst buffer fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
if (m_bufferManager[i] != NULL)
ret = m_bufferManager[i]->putBuffer(buffer[i].index, EXYNOS_CAMERA_BUFFER_POSITION_NONE);
if (ret != NO_ERROR) {
CLOGE("Buffer manager putBuffer fail, manager(%d), frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
newFrame->setRequest(pipeId, false);
}
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_COMPLETE, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
getPipeId(), newFrame->getFrameCount(), ret);
}
captureNodeCount++;
/* 6. Update metadata of capture node buffer(DstBuffer) from output node buffer(SrcBuffer) */
if (m_node[OUTPUT_NODE] != NULL
&& m_deviceInfo->nodeNum[i] != FIMC_IS_VIDEO_HWFC_JPEG_NUM
&& m_deviceInfo->nodeNum[i] != FIMC_IS_VIDEO_HWFC_THUMB_NUM) {
m_node[OUTPUT_NODE]->getColorFormat(&v4l2Colorformat, &planeCount[OUTPUT_NODE]);
m_node[i]->getColorFormat(&v4l2Colorformat, &planeCount[i]);
camera2_shot_ext *shot_ext_src = (camera2_shot_ext *)buffer[OUTPUT_NODE].addr[buffer[OUTPUT_NODE].getMetaPlaneIndex()];
camera2_shot_ext *shot_ext_dst = (camera2_shot_ext *)buffer[i].addr[buffer[i].getMetaPlaneIndex()];
if (shot_ext_src != NULL && shot_ext_dst != NULL) {
memcpy(&shot_ext_dst->shot.ctl, &shot_ext_src->shot.ctl, sizeof(struct camera2_ctl) - sizeof(struct camera2_entry_ctl));
memcpy(&shot_ext_dst->shot.uctl, &shot_ext_src->shot.uctl, sizeof(struct camera2_uctl));
memcpy(&shot_ext_dst->shot.udm, &shot_ext_src->shot.udm, sizeof(struct camera2_udm));
memcpy(&shot_ext_dst->shot.dm, &shot_ext_src->shot.dm, sizeof(struct camera2_dm));
memcpy(&shot_ext_dst->tuning_info, &shot_ext_src->tuning_info, sizeof(struct camera2_tuning_info));
shot_ext_dst->setfile = shot_ext_src->setfile;
shot_ext_dst->drc_bypass = shot_ext_src->drc_bypass;
shot_ext_dst->dis_bypass = shot_ext_src->dis_bypass;
shot_ext_dst->dnr_bypass = shot_ext_src->dnr_bypass;
shot_ext_dst->fd_bypass = shot_ext_src->fd_bypass;
shot_ext_dst->shot.dm.request.frameCount = shot_ext_src->shot.dm.request.frameCount;
shot_ext_dst->shot.magicNumber= shot_ext_src->shot.magicNumber;
shot_ext_dst->shot.uctl.isModeUd.wdr_mode = shot_ext_src->shot.uctl.isModeUd.wdr_mode;
} else {
CLOGE("metadata address fail, frameCount(%d) shot_ext src(%p) dst(%p) ",
newFrame->getFrameCount(), shot_ext_src, shot_ext_dst);
}
/* Comment out : It was not useful for metadate fully update, I want know reasons for the existence. */
/* memcpy(buffer[i].addr[(planeCount[i] - 1)], buffer[OUTPUT_NODE].addr[(planeCount[OUTPUT_NODE] - 1)], sizeof(struct camera2_shot_ext)); */
}
}
}
}
/*
* skip condition :
* 1 : all capture nodes are not valid.
* 2 : one of capture nodes is not valid.
*/
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++) {
checkRet |= nodeDqRet[i];
}
if (captureNodeCount == 0 || checkRet != NO_ERROR) {
if (newFrame->getFrameType() == FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
|| newFrame->getFrameType() == FRAME_TYPE_INTERNAL_SLAVE
|| newFrame->getFrameType() == FRAME_TYPE_TRANSITION
|| newFrame->getFrameType() == FRAME_TYPE_TRANSITION_SLAVE
#endif
) {
if ((m_getInternalFrameLogCnt++ % INTERNAL_FRAME_LOG_DURATION) == 0) {
CLOGI("InternalFrame(%d) frameCount(%d)\
: captureNodeCount == %d || checkRet(%d) != NO_ERROR.\
so, setFrameState(FRAME_STATE_SKIPPED), (%d)",
newFrame->getFrameType(), newFrame->getFrameCount(), captureNodeCount, checkRet, m_getInternalFrameLogCnt);
}
} else {
CLOGE("frameCount(%d)\
: captureNodeCount == %d || checkRet(%d) != NO_ERROR.\
so, setFrameState(FRAME_STATE_SKIPPED)",
newFrame->getFrameCount(), captureNodeCount, checkRet);
}
/* set err on frame */
newFrame->setFrameState(FRAME_STATE_SKIPPED);
/* set err on src */
for (int i = OUTPUT_NODE; i < MAX_OUTPUT_NODE; i++) {
if (m_node[i] == NULL)
continue;
ret = newFrame->setSrcBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("%d's setSrcBufferState(%d, ENTITY_BUFFER_STATE_ERROR) fail, frameCount(%d), ret(%d)",
i, getPipeId(), newFrame->getFrameCount(), ret);
}
}
/* set err on dst */
for (int i = CAPTURE_NODE; i < MAX_CAPTURE_NODE; i++) {
int dstPipeId = getPipeId((enum NODE_TYPE)i);
if (dstPipeId < 0)
continue;
if (newFrame->getRequest(dstPipeId) == true) {
if ((int32_t)newFrame->getFrameCount() != captureNodeFrameCount[i]) {
if (captureNodeFrameCount[i] < 0) {
CLOGE("invalid captureNodeFrameCount, Pipe Id(%d), frameCount(%d)",
dstPipeId, newFrame->getFrameCount());
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("setDstBufferState(Pipe ID(%d), ENTITY_BUFFER_STATE_ERROR, %d) fail,"
" frameCount(%d), ret(%d)",
getPipeId(), i, newFrame->getFrameCount(), ret);
}
continue;
}
CLOGW("reset DstBuffer. frame for dst buffer(F%d) is different from frame of src buffer(F%d),"
" pipeId(%d), node(%d), bufferIndex(%d)",
captureNodeFrameCount[i], newFrame->getFrameCount(),
getPipeId(), i, bufferIndex[i]);
/* HACK: Should change ExynosCamera, Frame */
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_REQUESTED, i);
if (ret != NO_ERROR) {
CLOGE("setDstBuffer state fail, pipeID(%d), frameCount(%d), ret(%d)",
getPipeId(), newFrame->getFrameCount(), ret);
}
ret = newFrame->setDstBuffer(getPipeId(), buffer[i], i, INDEX(dstPipeId));
if (ret != NO_ERROR) {
CLOGE("Frame set dst buffer fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
if (m_bufferManager[i] != NULL) {
ret = m_bufferManager[i]->putBuffer(buffer[i].index, EXYNOS_CAMERA_BUFFER_POSITION_NONE);
if (ret != NO_ERROR) {
CLOGE("Buffer manager putBuffer fail, manager(%d), frameCount(%d), ret(%d)",
i, newFrame->getFrameCount(), ret);
}
}
newFrame->setRequest(dstPipeId, false);
}
}
ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_ERROR, i);
if (ret != NO_ERROR) {
CLOGE("setDstBufferState(Pipe ID(%d),\
ENTITY_BUFFER_STATE_ERROR, %d) fail, \
frameCount(%d), ret(%d)",
getPipeId(), i, newFrame->getFrameCount(), ret);
}
}
}
} else {
m_getInternalFrameLogCnt = 0;
#ifdef DEBUG_DUMP_IMAGE
m_dumpFrameQ->pushProcessQ(&newFrame);
#endif
}
/* for debuging */
m_lastFrameCount = newFrame->getFrameCount();
m_lastMetaFrameCount = newFrame->getMetaFrameCount();
/* 7. Complete frame */
ret = m_completeFrame(newFrame);
if (ret != NO_ERROR) {
CLOGE("Complete frame fail, frameCount(%d), ret(%d)",
newFrame->getFrameCount(), ret);
/* TODO: doing exception handling */
}
/* 8. Push frame to out of Pipe */
/* TODO: doing exception handling
CLEAN:
*/
m_outputFrameQ->pushProcessQ(&newFrame);
if ((m_parameters->isUseEarlyFrameReturn() == false
|| m_reprocessing == true)
&& m_frameDoneQ != NULL
&& m_flagFrameDoneQ == true)
m_frameDoneQ->pushProcessQ(&newFrame);
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++)
ret |= nodeDqRet[i];
CLOGV("OUT-");
EXIT:
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_unlockSerializeOperation((enum pipeline)getPipeId());
#endif
return ret;
}
status_t ExynosCameraMCPipe::m_checkShotDone(struct camera2_shot_ext *shot_ext)
{
CLOGD("");
if (shot_ext == NULL) {
CLOGE("shot_ext is NULL");
return BAD_VALUE;
}
if (shot_ext->node_group.leader.request != 1) {
CLOGW("3a1 NOT DONE, frameCount(%d)",
getMetaDmRequestFrameCount(shot_ext));
/* TODO: doing exception handling */
return INVALID_OPERATION;
}
return OK;
}
status_t ExynosCameraMCPipe::m_updateMetadataFromFrame(ExynosCameraFrameSP_sptr_t frame, ExynosCameraBuffer *buffer, int perframeInfoIndex)
{
CLOGV("");
status_t ret = NO_ERROR;
if (perframeInfoIndex < 0) {
CLOGE("Invalid perframeInfoIndex(%d), fail!", perframeInfoIndex);
return BAD_VALUE;
}
camera2_shot_ext *shot_ext = (struct camera2_shot_ext *)(buffer->addr[buffer->getMetaPlaneIndex()]);
if (shot_ext != NULL) {
int perframePosition = 0;
ExynosRect sensorSize;
ExynosRect bnsSize;
ExynosRect previewBayerCropSize;
ExynosRect pictureBayerCropSize;
ExynosRect bdsSize;
camera2_node_group node_group_info;
char captureNodeName[MAX_CAPTURE_NODE][EXYNOS_CAMERA_NAME_STR_SIZE];
for (int i = 0; i < MAX_CAPTURE_NODE; i++)
memset(captureNodeName[i], 0, EXYNOS_CAMERA_NAME_STR_SIZE);
frame->getMetaData(shot_ext);
if (m_reprocessing == false)
m_activityControl->activityBeforeExecFunc(getPipeId(), (void *)buffer);
CLOGV("frameCount(%d), rCount(%d)",
frame->getFrameCount(), getMetaDmRequestFrameCount(shot_ext));
frame->getNodeGroupInfo(&node_group_info, perframeInfoIndex);
/* Update node's size & request */
memset(&shot_ext->node_group, 0x0, sizeof(camera2_node_group));
if (node_group_info.leader.request == 1) {
if (m_checkNodeGroupInfo(frame, m_deviceInfo->nodeName[OUTPUT_NODE], &m_curNodeGroupInfo[perframeInfoIndex].leader, &node_group_info.leader) != NO_ERROR)
CLOGW(" m_checkNodeGroupInfo(leader) fail");
setMetaNodeLeaderInputSize(shot_ext,
node_group_info.leader.input.cropRegion[0],
node_group_info.leader.input.cropRegion[1],
node_group_info.leader.input.cropRegion[2],
node_group_info.leader.input.cropRegion[3]);
setMetaNodeLeaderOutputSize(shot_ext,
node_group_info.leader.output.cropRegion[0],
node_group_info.leader.output.cropRegion[1],
node_group_info.leader.output.cropRegion[2],
node_group_info.leader.output.cropRegion[3]);
setMetaNodeLeaderRequest(shot_ext, node_group_info.leader.request);
setMetaNodeLeaderVideoID(shot_ext,
m_perframeMainNodeGroupInfo[OUTPUT_NODE].perFrameLeaderInfo.perFrameVideoID);
setMetaNodeLeaderPixFormat(shot_ext, node_group_info.leader.pixelformat);
}
if (CAPTURE_NODE_MAX < m_perframeMainNodeGroupInfo[OUTPUT_NODE].perframeSupportNodeNum) {
android_printAssert(NULL, LOG_TAG, "ASSERT(%s[%d]):PipeId(%d) has Invalid perframeSupportNodeNum:CAPTURE_NODE_MAX(%d) < m_perframeMainNodeGroupInfo[OUTPUT_NODE].perframeSupportNodeNum(%d), assert!!!!",
__FUNCTION__, __LINE__, getPipeId(), CAPTURE_NODE_MAX, m_perframeMainNodeGroupInfo[OUTPUT_NODE].perframeSupportNodeNum);
}
/* Update capture node request from Frame */
for (int i = CAPTURE_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
uint32_t videoId = m_deviceInfo->nodeNum[i] - FIMC_IS_VIDEO_BAS_NUM;
for (perframePosition = 0; perframePosition < CAPTURE_NODE_MAX; perframePosition++) {
if (node_group_info.capture[perframePosition].vid == videoId) {
node_group_info.capture[perframePosition].request = frame->getRequest(getPipeId((enum NODE_TYPE)i));
strncpy(captureNodeName[perframePosition], m_deviceInfo->nodeName[i], EXYNOS_CAMERA_NAME_STR_SIZE - 1);
break;
}
}
}
}
for (int i = 0; i < m_perframeMainNodeGroupInfo[OUTPUT_NODE].perframeSupportNodeNum; i ++) {
/*
* To set 3AP BDS size on full OTF,
* We need to set perframeSize.
* set size when request is 0. so, no side effect.
*/
/* if (node_group_info.capture[i].request == 1) { */
if ((int)node_group_info.capture[i].vid + FIMC_IS_VIDEO_BAS_NUM < 0) {
CLOGW("invalid video ID(%d)", node_group_info.capture[i].vid);
continue;
}
if (m_checkNodeGroupInfo(frame, captureNodeName[i], &m_curNodeGroupInfo[perframeInfoIndex].capture[i], &node_group_info.capture[i]) != NO_ERROR)
CLOGW(" m_checkNodeGroupInfo(%d) fail", i);
setMetaNodeCaptureInputSize(shot_ext, i,
node_group_info.capture[i].input.cropRegion[0],
node_group_info.capture[i].input.cropRegion[1],
node_group_info.capture[i].input.cropRegion[2],
node_group_info.capture[i].input.cropRegion[3]);
setMetaNodeCaptureOutputSize(shot_ext, i,
node_group_info.capture[i].output.cropRegion[0],
node_group_info.capture[i].output.cropRegion[1],
node_group_info.capture[i].output.cropRegion[2],
node_group_info.capture[i].output.cropRegion[3]);
setMetaNodeCaptureRequest(shot_ext, i, node_group_info.capture[i].request);
setMetaNodeCaptureVideoID(shot_ext, i, node_group_info.capture[i].vid);
setMetaNodeCapturePixFormat(shot_ext, i, node_group_info.capture[i].pixelformat);
}
/*
CLOGI("frameCount(%d)", shot_ext->shot.dm.request.frameCount);
frame->dumpNodeGroupInfo(m_deviceInfo->nodeName[OUTPUT_NODE]);
m_dumpPerframeNodeGroupInfo("m_perframeMainNodeGroupInfo", m_perframeMainNodeGroupInfo[OUTPUT_NODE]);
for (int i = (OUTPUT_NODE + 1); i < m_perframeMainNodeGroupInfo[OUTPUT_NODE].perframeSupportNodeNum; i++)
m_dumpPerframeNodeGroupInfo("m_perframeCaptureNodeGroupInfo", m_perframeMainNodeGroupInfo[i]);
*/
/* dump info on shot_ext, just before qbuf */
/* m_dumpPerframeShotInfo(m_deviceInfo->nodeName[OUTPUT_NODE], frame->getFrameCount(), shot_ext); */
CLOG_PERFRAME(META, m_cameraId, m_name, frame.get(), &shot_ext->shot, frame->getRequestKey(), "");
}
return ret;
}
status_t ExynosCameraMCPipe::m_updateMetadataToFrame(void *metadata, int index, ExynosCameraFrameSP_sptr_t frame, enum NODE_TYPE nodeLocation)
{
CLOGV("");
status_t ret = NO_ERROR;
ExynosCameraFrameSP_sptr_t curFrame = NULL;
camera2_shot_ext *shot_ext;
shot_ext = (struct camera2_shot_ext *)metadata;
if (shot_ext == NULL) {
CLOGE("Meta buffer is null");
return BAD_VALUE;
}
if (index < 0) {
CLOGE("Invalid index(%d)", index);
return BAD_VALUE;
}
if (frame == NULL) {
CLOGE("frame is Null");
return BAD_VALUE;
}
if (nodeLocation < OUTPUT_NODE) {
CLOGE("Invalid node location(%d)", nodeLocation);
return BAD_VALUE;
}
if (m_metadataTypeShot == false) {
CLOGV("Stream type do not need update metadata");
return NO_ERROR;
}
/*
ret = m_getFrameByIndex(&curFrame, index, nodeLocation);
if (ret != NO_ERROR) {
CLOGE("m_getFrameByIndex() fail, node(%s), index(%d), ret(%d)",
m_deviceInfo->nodeName[nodeLocation], index, ret);
return ret;
}
*/
ret = frame->storeDynamicMeta(shot_ext);
if (ret != NO_ERROR) {
CLOGE("storeDynamicMeta() fail, ret(%d)", ret);
return ret;
}
ret = frame->storeUserDynamicMeta(shot_ext);
if (ret != NO_ERROR) {
CLOGE("storeUserDynamicMeta() fail, ret(%d)", ret);
return ret;
}
if (shot_ext->shot.dm.request.frameCount != 0)
ret = frame->setMetaDataEnable(true);
CLOG_PERFRAME(META, m_cameraId, m_name, frame.get(), &shot_ext->shot, frame->getRequestKey(), "");
return ret;
}
status_t ExynosCameraMCPipe::m_getFrameByIndex(ExynosCameraFrameSP_dptr_t frame, int index, enum NODE_TYPE nodeLocation)
{
CLOGV("");
if (nodeLocation < OUTPUT_NODE) {
CLOGE("Invalid node location(%d)", nodeLocation);
return BAD_VALUE;
}
if (index < 0) {
CLOGE("Invalid index(%d)", index);
return BAD_VALUE;
}
frame = m_runningFrameList[nodeLocation][index];
if (frame == NULL) {
CLOGE("Unknown buffer, index %d frame is NULL", index);
dump();
return BAD_VALUE;
}
return NO_ERROR;
}
status_t ExynosCameraMCPipe::m_completeFrame(
ExynosCameraFrameSP_sptr_t frame,
bool isValid)
{
CLOGV("");
status_t ret = NO_ERROR;
if (frame == NULL) {
CLOGE("Frame is NULL");
dump();
return BAD_VALUE;
}
if (frame->getFrameType() != FRAME_TYPE_INTERNAL
#ifdef USE_DUAL_CAMERA
&& frame->getFrameType() != FRAME_TYPE_INTERNAL_SLAVE
#endif
) {
if (isValid == false) {
CLOGD("NOT DONE frameCount(%d)",
frame->getFrameCount());
}
}
ret = frame->setEntityState(getPipeId(), ENTITY_STATE_FRAME_DONE);
if (ret != NO_ERROR) {
CLOGE("Set entity state fail, ret(%d)", ret);
/* TODO: doing exception handling */
return ret;
}
CLOGV("Entity pipeId(%d), frameCount(%d)",
getPipeId(), frame->getFrameCount());
return ret;
}
status_t ExynosCameraMCPipe::m_setInput(ExynosCameraNode *nodes[], int32_t *nodeNums, int32_t *sensorIds)
{
status_t ret = NO_ERROR;
int currentSensorId[MAX_NODE] = {0};
if (nodes == NULL || nodeNums == NULL || sensorIds == NULL) {
CLOGE(" nodes == %p || nodeNum == %p || sensorId == %p",
nodes, nodeNums, sensorIds);
return INVALID_OPERATION;
}
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
// sensor's setInput happen in m_createSensorNode, for performance
if (i == m_sensorNodeIndex) {
continue;
}
#ifdef SUPPORT_DEPTH_MAP
if (i == m_depthVcNodeIndex) {
continue;
}
#endif // SUPPORT_DEPTH_MAP
if (m_flagValidInt(nodeNums[i]) == false)
continue;
if (m_flagValidInt(sensorIds[i]) == false)
continue;
if (nodes[i] == NULL)
continue;
currentSensorId[i] = nodes[i]->getInput();
if (m_flagValidInt(currentSensorId[i]) == false ||
currentSensorId[i] != sensorIds[i]) {
#ifdef INPUT_STREAM_MASK
CLOGD(" setInput(sensorIds : %d) [src nodeNum : %d][nodeNums : %d][otf : %d][leader : %d][reprocessing : %d][unique sensorId : %d]",
sensorIds[i],
((sensorIds[i] & INPUT_VINDEX_MASK) >> INPUT_VINDEX_SHIFT) + FIMC_IS_VIDEO_BAS_NUM,
nodeNums[i],
((sensorIds[i] & INPUT_MEMORY_MASK) >> INPUT_MEMORY_SHIFT),
((sensorIds[i] & INPUT_LEADER_MASK) >> INPUT_LEADER_SHIFT),
((sensorIds[i] & INPUT_STREAM_MASK) >> INPUT_STREAM_SHIFT),
((sensorIds[i] & INPUT_MODULE_MASK) >> INPUT_MODULE_SHIFT));
#else
CLOGD(" setInput(sensorIds : %d)",
sensorIds[i]);
#endif
ret = nodes[i]->setInput(sensorIds[i]);
if (ret < 0) {
CLOGE(" nodeNums[%d] : %d, setInput(sensorIds : %d fail, ret(%d)",
i, nodeNums[i], sensorIds[i],
ret);
return ret;
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_setPipeInfo(camera_pipe_info_t *pipeInfos)
{
CLOGD("");
status_t ret = NO_ERROR;
uint32_t planeCount = 2;
enum YUV_RANGE yuvRange = YUV_FULL_RANGE;
if (pipeInfos == NULL) {
CLOGE("pipeInfos is NULL");
return BAD_VALUE;
}
for (int i = OUTPUT_NODE; i < OTF_NODE_BASE; i++) {
if (m_node[i] != NULL) {
m_numBuffers[i] = pipeInfos[i].bufInfo.count;
m_perframeMainNodeGroupInfo[i] = pipeInfos[i].perFrameNodeGroupInfo;
/*
* If node size is 0, node info is skipped.
* But the buffer number and per frame node group info of the node must be set.
*/
if ((0 >= pipeInfos[i].rectInfo.fullW)
|| (0 >= pipeInfos[i].rectInfo.fullH)) {
CLOGD("skip %s setNodeInfo, setFormat(%d, %d)",
m_node[i]->getName(),
pipeInfos[i].rectInfo.fullW, pipeInfos[i].rectInfo.fullH);
continue;
}
/* check about OUTPUT_NODE */
if (i == OUTPUT_NODE
&& pipeInfos[i].bufInfo.type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
CLOGE("pipeInfos[%d].bufInfo.type is not Valid(type:%d)",
i, pipeInfos[i].bufInfo.type);
return BAD_VALUE;
}
uint32_t bytePerPlane = 0;
int colorFormat = pipeInfos[i].rectInfo.colorFormat;
if (m_deviceInfo->nodeNum[i] <= FIMC_IS_VIDEO_I0S_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_I1S_NUM
|| m_deviceInfo->nodeNum[i] >= FIMC_IS_VIDEO_SS0VC0_NUM) {
planeCount = 1;
} else {
getV4l2FormatInfo(colorFormat, &bytePerPlane, &planeCount);
}
/* Add medadata plane count */
planeCount++;
if (m_reprocessing == false
&& (m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_SCP_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M0P_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M1P_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M2P_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M3P_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M4P_NUM
|| m_deviceInfo->nodeNum[i] == FIMC_IS_VIDEO_M5P_NUM)) {
int setfile = 0;
int previewYuvRange = 0;
/* MC scaler can set different format with preview */
/*
int colorFormat = m_parameters->getHwPreviewFormat();
if (colorFormat != pipeInfos[i].rectInfo.colorFormat) {
CLOGE("SCP colorformat is not Valid(%d)",
pipeInfos[i].rectInfo.colorFormat);
return BAD_VALUE;
}
*/
m_parameters->getSetfileYuvRange(m_reprocessing, &setfile, &previewYuvRange);
yuvRange = (enum YUV_RANGE)previewYuvRange;
} else {
yuvRange = YUV_FULL_RANGE;
}
ret = m_setNodeInfo(m_node[i], &pipeInfos[i], planeCount, yuvRange);
if (ret != NO_ERROR) {
CLOGE("m_setNodeInfo(W:%d, H:%d, buffer count:%d) fail(Node:%s), ret(%d)",
pipeInfos[i].rectInfo.fullW, pipeInfos[i].rectInfo.fullH,
pipeInfos[i].bufInfo.count, m_deviceInfo->nodeName[i], ret);
return ret;
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_setNodeInfo(ExynosCameraNode *node, camera_pipe_info_t *pipeInfos,
uint32_t planeCount, enum YUV_RANGE yuvRange,
__unused bool flagBayer)
{
CLOGD("");
status_t ret = NO_ERROR;
bool flagSetRequest = false;
unsigned int requestBufCount = 0;
int currentW = 0;
int currentH = 0;
int currentV4l2Colorformat = 0;
int currentPlanesCount = 0;
enum YUV_RANGE currentYuvRange = YUV_FULL_RANGE;
int currentBufferCount = 0;
enum v4l2_buf_type currentBufType;
enum v4l2_memory currentMemType;
if (node == NULL) {
CLOGE("node is NULL");
return BAD_VALUE;
}
if (pipeInfos == NULL) {
CLOGE("pipeInfos is NULL");
return BAD_VALUE;
}
requestBufCount = node->reqBuffersCount();
/* If it already set */
if (0 < requestBufCount) {
node->getSize(&currentW, &currentH);
node->getColorFormat(&currentV4l2Colorformat, &currentPlanesCount, &currentYuvRange);
node->getBufferType(&currentBufferCount, &currentBufType, &currentMemType);
if (/* setSize */
currentW != pipeInfos->rectInfo.fullW ||
currentH != pipeInfos->rectInfo.fullH ||
/* setColorFormat */
currentV4l2Colorformat != pipeInfos->rectInfo.colorFormat ||
currentPlanesCount != (int)planeCount ||
currentYuvRange != yuvRange ||
/* setBufferType */
currentBufferCount != (int)pipeInfos->bufInfo.count ||
currentBufType != (enum v4l2_buf_type)pipeInfos->bufInfo.type ||
currentMemType != (enum v4l2_memory)pipeInfos->bufInfo.memory) {
flagSetRequest = true;
CLOGW("Node is already requested. call clrBuffers()");
CLOGW("W(%d -> %d), H(%d -> %d)",
currentW, pipeInfos->rectInfo.fullW,
currentH, pipeInfos->rectInfo.fullH);
CLOGW("colorFormat(%d -> %d), planeCount(%d -> %d), yuvRange(%d -> %d)",
currentV4l2Colorformat, pipeInfos->rectInfo.colorFormat,
currentPlanesCount, planeCount,
currentYuvRange, yuvRange);
CLOGW("bufferCount(%d -> %d), bufType(%d -> %d), memType(%d -> %d)",
currentBufferCount, pipeInfos->bufInfo.count,
currentBufType, pipeInfos->bufInfo.type,
currentMemType, pipeInfos->bufInfo.memory);
ret = node->clrBuffers();
if (ret != NO_ERROR) {
CLOGE(" node->clrBuffers() fail");
return ret;
}
}
} else {
flagSetRequest = true;
}
if (flagSetRequest == true) {
CLOGD("set pipeInfos on %s, setFormat(%d, %d) and reqBuffers(%d)",
node->getName(), pipeInfos->rectInfo.fullW,
pipeInfos->rectInfo.fullH, pipeInfos->bufInfo.count);
bool flagValidSetFormatInfo = true;
if (pipeInfos->rectInfo.fullW == 0 || pipeInfos->rectInfo.fullH == 0) {
CLOGW("Invalid size(%d x %d), skip setSize()",
pipeInfos->rectInfo.fullW, pipeInfos->rectInfo.fullH);
flagValidSetFormatInfo = false;
}
node->setSize(pipeInfos->rectInfo.fullW, pipeInfos->rectInfo.fullH);
if (pipeInfos->rectInfo.colorFormat == 0 || planeCount == 0) {
CLOGW("invalid colorFormat(%d), planeCount(%d), skip setColorFormat()",
pipeInfos->rectInfo.colorFormat, planeCount);
flagValidSetFormatInfo = false;
}
node->setColorFormat(pipeInfos->rectInfo.colorFormat, planeCount, yuvRange, pipeInfos->pixelSize);
if ((int)pipeInfos->bufInfo.type == 0 || pipeInfos->bufInfo.memory == 0) {
CLOGW("Invalid bufInfo.type(%d), bufInfo.memory(%d), skip setBufferType()",
(int)pipeInfos->bufInfo.type, (int)pipeInfos->bufInfo.memory);
flagValidSetFormatInfo = false;
}
node->setBufferType(pipeInfos->bufInfo.count,
(enum v4l2_buf_type)pipeInfos->bufInfo.type,
(enum v4l2_memory)pipeInfos->bufInfo.memory);
if (flagValidSetFormatInfo == true) {
#ifdef SAMSUNG_DNG
if (m_parameters->getDNGCaptureModeOn() && strcmp(node->getName(), "BAYER") == 0) {
CLOGV(" DNG flite node->setFormat() getPipeId()(%d)", getPipeId());
if (node->setFormat() != NO_ERROR) {
CLOGE(" node->setFormat() fail");
return INVALID_OPERATION;
}
} else
#endif // SAMSUNG_DNG
{
ret = node->setFormat(pipeInfos->bytesPerPlane);
if (ret != NO_ERROR) {
CLOGE("node->setFormat() fail");
return ret;
}
}
}
node->getBufferType(&currentBufferCount, &currentBufType, &currentMemType);
} else {
CLOGD("Skip set pipeInfos setFormat(%d, %d) and reqBuffers(%d).",
pipeInfos->rectInfo.fullW, pipeInfos->rectInfo.fullH, pipeInfos->bufInfo.count);
}
if (currentBufferCount <= 0) {
CLOGW("Invalid currentBufferCount(%d), skip reqBuffers()",
currentBufferCount);
} else {
ret = node->reqBuffers();
if (ret != NO_ERROR) {
CLOGE("node->reqBuffers() fail");
return ret;
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_getPerframePosition(int *perframePosition, uint32_t pipeId)
{
status_t ret = NO_ERROR;
if (perframePosition == NULL) {
CLOGE("perframePosition is NULL");
return BAD_VALUE;
}
switch(pipeId) {
case PIPE_VC0:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_VC0_POS : PERFRAME_FRONT_VC0_POS;
break;
case PIPE_3AC:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_3AC_POS : PERFRAME_FRONT_3AC_POS;
break;
case PIPE_3AP:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_3AP_POS : PERFRAME_FRONT_3AP_POS;
break;
case PIPE_ISPC:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_ISPC_POS : PERFRAME_FRONT_ISPC_POS;
break;
case PIPE_ISPP:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_ISPP_POS : PERFRAME_FRONT_ISPP_POS;
break;
case PIPE_SCC:
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_SCC_POS : PERFRAME_FRONT_SCC_POS;
break;
case PIPE_SCP: /* Same as case of PIPE_MCSC0 */
*perframePosition = (m_cameraId == CAMERA_ID_BACK) ? PERFRAME_BACK_SCP_POS : PERFRAME_FRONT_SCP_POS;
break;
case PIPE_MCSC1:
*perframePosition = PERFRAME_BACK_MCSC1_POS;
break;
case PIPE_MCSC2:
*perframePosition = PERFRAME_BACK_MCSC2_POS;
break;
case PIPE_3AC_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_3AC_POS;
break;
case PIPE_3AP_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_3AP_POS;
break;
case PIPE_ISPC_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_ISPC_POS;
break;
case PIPE_ISPP_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_ISPP_POS;
break;
case PIPE_MCSC0_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_MCSC0_POS;
break;
case PIPE_MCSC1_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_MCSC1_POS;
break;
case PIPE_MCSC2_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_MCSC2_POS;
break;
case PIPE_MCSC3_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_MCSC3_POS;
break;
case PIPE_MCSC4_REPROCESSING:
*perframePosition = PERFRAME_REPROCESSING_MCSC4_POS;
break;
default:
CLOGV("Invalid pipeID(%d)", pipeId);
ret = BAD_VALUE;
break;
}
return ret;
}
status_t ExynosCameraMCPipe::m_setSetfile(ExynosCameraNode *node, uint32_t pipeId)
{
CLOGV("");
status_t ret = NO_ERROR;
int yuvRange = 0;
int setfile = 0;
m_parameters->getSetfileYuvRange(m_reprocessing, &setfile, &yuvRange);
if (m_parameters->getSetFileCtlMode() == true) {
if (m_parameters->getSetFileCtl3AA() == true
&& (pipeId == PIPE_3AA || pipeId == PIPE_3AA_REPROCESSING)) {
ret = node->setControl(V4L2_CID_IS_SET_SETFILE, setfile);
if (ret != NO_ERROR) {
CLOGE("setControl(%d) fail(ret = %d)", setfile, ret);
return ret;
}
} else if (m_parameters->getSetFileCtlISP() == true
&& (pipeId == PIPE_ISP || pipeId == PIPE_ISP_REPROCESSING)) {
ret = node->setControl(V4L2_CID_IS_SET_SETFILE, setfile);
if (ret != NO_ERROR) {
CLOGE("setControl(%d) fail(ret = %d)", setfile, ret);
return ret;
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_forceDone(ExynosCameraNode *node, unsigned int cid, int value)
{
CLOGD("");
status_t ret = NO_ERROR;
if (node == NULL) {
CLOGE("node is NULL");
return BAD_VALUE;
}
if (cid != V4L2_CID_IS_FORCE_DONE) {
CLOGW("cid != V4L2_CID_IS_FORCE_DONE");
}
/* "value" is not meaningful */
ret = node->setControl(V4L2_CID_IS_FORCE_DONE, value);
if (ret != NO_ERROR) {
CLOGE("node V4L2_CID_IS_FORCE_DONE failed");
node->dump();
return ret;
}
return ret;
}
status_t ExynosCameraMCPipe::m_sensorStandby(bool on)
{
status_t ret = NO_ERROR;
int value = (!on | (1 << SENSOR_USE_STANDBY_SHIFT));
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->setControl(V4L2_CID_IS_S_STREAM, value);
if (ret != NO_ERROR) {
CLOGE("sensorStandby failed, %s node, ret(%d)",
m_deviceInfo->nodeName[i], ret);
} else {
CLOGI("sensorStandby(%s) success!", (on?"On":"Off"));
}
return ret;
}
}
CLOGE("All Nodes is NULL");
return INVALID_OPERATION;
}
status_t ExynosCameraMCPipe::m_setMapBuffer(int nodeIndex)
{
status_t ret = NO_ERROR;
int bufferIndex[VIDEO_MAX_FRAME];
for (int i = 0; i < VIDEO_MAX_FRAME; i++)
bufferIndex[i] = -2;
ExynosCameraBuffer buffer;
if (m_bufferManager[nodeIndex]->getAllocatedBufferCount() > 0) {
int index = 0;
while (m_bufferManager[nodeIndex]->getNumOfAvailableBuffer() > 0) {
ret |= m_bufferManager[nodeIndex]->getBuffer(&(bufferIndex[index]), EXYNOS_CAMERA_BUFFER_POSITION_IN_HAL, &buffer);
if (ret != NO_ERROR) {
CLOGE("Buffer manager getBuffer fail, manager(%d), ret(%d)",
nodeIndex, ret);
}
ret |= m_node[nodeIndex]->prepareBuffer(&buffer);
if (ret != NO_ERROR) {
CLOGE("node(%s)->putBuffer() fail, ret(%d)",
m_deviceInfo->nodeName[nodeIndex], ret);
}
index++;
}
while (index > 0) {
index--;
/* TODO: doing exception handling */
ret |= m_bufferManager[nodeIndex]->putBuffer(bufferIndex[index], EXYNOS_CAMERA_BUFFER_POSITION_NONE);
if (ret != NO_ERROR) {
CLOGE("Buffer manager putBuffer fail, manager(%d), ret(%d)",
nodeIndex, ret);
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_setMapBuffer(ExynosCameraNode *node, ExynosCameraBuffer *buffer)
{
status_t ret = NO_ERROR;
if (buffer == NULL) {
CLOGE("Buffer is NULL");
return BAD_VALUE;
}
if (node == NULL) {
CLOGE("Node is NULL");
return BAD_VALUE;
}
/* Require code sync release-git to Repo */
#if 0
ret = node->mapBuffer(buffer);
if (ret != NO_ERROR)
CLOGE("mapBuffer() fail, ret(%d)", ret);
#endif
return ret;
}
status_t ExynosCameraMCPipe::m_setJpegInfo(int nodeType, ExynosCameraFrameSP_sptr_t frame)
{
status_t ret = NO_ERROR;
int pipeId = MAX_PIPE_NUM;
ExynosRect pictureRect;
ExynosRect thumbnailRect;
int jpegQuality = -1;
int thumbnailQuality = -1;
exif_attribute_t exifInfo;
debug_attribute_t *debugInfo;
camera2_shot_ext shot_ext;
/* 1. Check the invalid parameters */
if (nodeType < 0) {
CLOGE("Invalid nodeType %d", nodeType);
return BAD_VALUE;
}
if (frame == NULL) {
CLOGE("frame is NULL!");
return BAD_VALUE;
}
/* 2. Get control informations from parameter & metadata */
ret = frame->getMetaData(&shot_ext);
if (ret != NO_ERROR) {
CLOGE("Failed to getMetadata, Fcount(%d), ret %d",
frame->getFrameCount(), ret);
}
m_configurations->getSize(CONFIGURATION_PICTURE_SIZE, (uint32_t *)&pictureRect.w, (uint32_t *)&pictureRect.h);
jpegQuality = m_configurations->getModeValue(CONFIGURATION_JPEG_QUALITY);
thumbnailRect.w = shot_ext.shot.ctl.jpeg.thumbnailSize[0];
thumbnailRect.h = shot_ext.shot.ctl.jpeg.thumbnailSize[1];
thumbnailQuality = shot_ext.shot.ctl.jpeg.thumbnailQuality;
debugInfo = m_parameters->getDebugAttribute();
/* 3. Set JPEG node perframe control information for each node */
pipeId = m_deviceInfo->pipeId[nodeType];
CLOGD("pipeId-%d thumbnailRect[%d %d] thumbnailQuality %d", pipeId, thumbnailRect.w, thumbnailRect.h, thumbnailQuality);
switch (pipeId) {
case PIPE_HWFC_JPEG_DST_REPROCESSING:
/* Create EXIF info */
ret = m_parameters->getFixedExifInfo(&exifInfo);
if (ret != NO_ERROR) {
CLOGE("Failed to get Fixed Exif Info, ret %d", ret);
}
if (thumbnailRect.w > 0 && thumbnailRect.h > 0) {
exifInfo.enableThumb = true;
} else {
exifInfo.enableThumb = false;
}
m_parameters->setExifChangedAttribute(&exifInfo, &pictureRect, &thumbnailRect, &(shot_ext.shot));
/* JPEG HAL setExifInfo */
ret = m_node[nodeType]->setExifInfo(&exifInfo);
if (ret != NO_ERROR)
CLOGE("Failed to set EXIF info into %s, ret %d",
m_deviceInfo->nodeName[nodeType], ret);
/* JPEG HAL setDebugInfo */
debugInfo = m_parameters->getDebugAttribute();
ret = m_node[nodeType]->setDebugInfo(debugInfo);
if (ret != NO_ERROR)
CLOGE("Failed to set DEBUG Info into %s, ret %d",
m_deviceInfo->nodeName[nodeType], ret);
/* continue to setSize & setQuality */
case PIPE_HWFC_JPEG_SRC_REPROCESSING:
/* JPEG HAL setSize */
ret = m_node[nodeType]->setSize(pictureRect.w, pictureRect.h);
if (ret != NO_ERROR)
CLOGE("Failed to set size %dx%d into %s, ret %d",
pictureRect.w, pictureRect.h,
m_deviceInfo->nodeName[nodeType], ret);
#ifdef SAMSUNG_JQ
if (m_parameters->getJpegQtableOn() == true && m_parameters->getJpegQtableStatus() != JPEG_QTABLE_DEINIT) {
if (m_parameters->getJpegQtableStatus() == JPEG_QTABLE_UPDATED) {
CLOGD("[JQ]:Get JPEG Q-table");
m_parameters->setJpegQtableStatus(JPEG_QTABLE_RETRIEVED);
m_parameters->getJpegQtable(m_qtable);
}
CLOGD("[JQ]:Set JPEG Q-table");
ret = m_node[nodeType]->setQuality(m_qtable);
if (ret != NO_ERROR)
CLOGE("[JQ]:m_node[nodeType]->setQuality(qtable[]) fail");
} else
#endif
{
/* JPEG HAL setQuality */
CLOGV("m_node[nodeType]->setQuality(int)");
ret = m_node[nodeType]->setQuality(jpegQuality);
if (ret != NO_ERROR)
CLOGE("Failed to set jpeg quality %d into %s, ret %d",
jpegQuality,
m_deviceInfo->nodeName[nodeType], ret);
}
break;
case PIPE_HWFC_THUMB_SRC_REPROCESSING:
/* JPEG HAL setSize */
if (thumbnailRect.w > 0 && thumbnailRect.h > 0) {
ret = m_node[nodeType]->setSize(thumbnailRect.w, thumbnailRect.h);
if (ret != NO_ERROR)
CLOGE("Failed to set thumbnail size %dx%d into %s, ret %d",
thumbnailRect.w, thumbnailRect.h,
m_deviceInfo->nodeName[nodeType], ret);
}
/* JPEG HAL setQuality */
m_node[nodeType]->setQuality(thumbnailQuality);
if (ret != NO_ERROR)
CLOGE("Failed to setQuality %d into %s, ret %d",
thumbnailQuality,
m_deviceInfo->nodeName[nodeType], ret);
break;
default:
CLOGE("Invalid pipeId %d", pipeId);
ret = BAD_VALUE;
break;
}
return ret;
}
status_t ExynosCameraMCPipe::m_startNode(void)
{
CLOGD("");
status_t ret = NO_ERROR;
for (int i = (MAX_CAPTURE_NODE - 1); i >= OUTPUT_NODE; i--) {
/* only M2M mode need stream on/off */
/* TODO : flite has different sensorId bit */
if (m_node[i] != NULL) {
ret = m_node[i]->start();
if (ret != NO_ERROR) {
CLOGE("node(%s)->start fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_stopNode(void)
{
CLOGD("");
status_t ret = NO_ERROR;
status_t funcRet = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_CAPTURE_NODE; i++) {
/* only M2M mode need stream on/off */
/* TODO : flite has different sensorId bit */
if (m_node[i] != NULL) {
ret = m_node[i]->stop();
if (ret != NO_ERROR) {
CLOGE("node(%s)->stop fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
/* If stop() is error, driver will recover */
funcRet |= ret;
}
ret = m_node[i]->clrBuffers();
if (ret != NO_ERROR) {
CLOGE("node(%s)->clrBuffers fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
/* If clrBuffers() is error, driver will recover */
funcRet |= ret;
}
m_node[i]->removeItemBufferQ();
}
}
return funcRet;
}
status_t ExynosCameraMCPipe::m_clearNode(void)
{
CLOGD("");
status_t ret = NO_ERROR;
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
ret = m_node[i]->clrBuffers();
if (ret != NO_ERROR) {
CLOGE("node(%s)->clrBuffers fail, ret(%d)",
m_deviceInfo->nodeName[i], ret);
return ret;
}
}
}
return ret;
}
status_t ExynosCameraMCPipe::m_checkNodeGroupInfo(ExynosCameraFrameSP_dptr_t frame, char *name, camera2_node *oldNode, camera2_node *newNode)
{
if (oldNode == NULL || newNode == NULL) {
CLOGE(" oldNode(%p) == NULL || newNode(%p) == NULL", oldNode, newNode);
return INVALID_OPERATION;
}
for (int i = 0; i < 4; i++) {
if (m_configurations->getModeValue(CONFIGURATION_HIGHSPEED_MODE) <= CONFIG_MODE::HIGHSPEED_60
&& (oldNode->input.cropRegion[i] != newNode->input.cropRegion[i] ||
oldNode->output.cropRegion[i] != newNode->output.cropRegion[i] ||
oldNode->request != newNode->request)) {
CLOGD("[REQ:%d,F:%d,DRV:%d,T:%d] (%s):vid(%d), request(%d -> %d), oldCropSize(%d, %d, %d, %d / %d, %d, %d, %d) -> newCropSize(%d, %d, %d, %d / %d, %d, %d, %d)",
frame->getRequestKey(),
frame->getFrameCount(),
frame->getMetaFrameCount(),
frame->getFrameType(),
name,
newNode->vid,
oldNode->request, newNode->request,
oldNode->input. cropRegion[0], oldNode->input. cropRegion[1], oldNode->input. cropRegion[2], oldNode->input. cropRegion[3],
oldNode->output.cropRegion[0], oldNode->output.cropRegion[1], oldNode->output.cropRegion[2], oldNode->output.cropRegion[3],
newNode->input. cropRegion[0], newNode->input. cropRegion[1], newNode->input. cropRegion[2], newNode->input. cropRegion[3],
newNode->output.cropRegion[0], newNode->output.cropRegion[1], newNode->output.cropRegion[2], newNode->output.cropRegion[3]);
break;
}
}
for (int i = 0; i < 4; i++) {
oldNode->request = newNode->request;
oldNode->input. cropRegion[i] = newNode->input. cropRegion[i];
oldNode->output.cropRegion[i] = newNode->output.cropRegion[i];
}
return NO_ERROR;
}
status_t ExynosCameraMCPipe::m_checkNodeGroupInfo(ExynosCameraFrameSP_dptr_t frame, char *name, int index, camera2_node *oldNode, camera2_node *newNode)
{
if (oldNode == NULL || newNode == NULL) {
CLOGE(" oldNode(%p) == NULL || newNode(%p) == NULL", oldNode, newNode);
return INVALID_OPERATION;
}
for (int i = 0; i < 4; i++) {
if (oldNode->input.cropRegion[i] != newNode->input.cropRegion[i] ||
oldNode->output.cropRegion[i] != newNode->output.cropRegion[i] ||
oldNode->request != newNode->request) {
CLOGD("[REQ:%d,F:%d,DRV:%d,T:%d] name %s : index %d: PerFrame oldCropSize (%d, %d, %d, %d / %d, %d, %d, %d) -> newCropSize (%d, %d, %d, %d / %d, %d, %d, %d)",
frame->getRequestKey(),
frame->getFrameCount(),
frame->getMetaFrameCount(),
frame->getFrameType(),
name,
index,
oldNode->input. cropRegion[0], oldNode->input. cropRegion[1], oldNode->input. cropRegion[2], oldNode->input. cropRegion[3],
oldNode->output.cropRegion[0], oldNode->output.cropRegion[1], oldNode->output.cropRegion[2], oldNode->output.cropRegion[3],
newNode->input. cropRegion[0], newNode->input. cropRegion[1], newNode->input. cropRegion[2], newNode->input. cropRegion[3],
newNode->output.cropRegion[0], newNode->output.cropRegion[1], newNode->output.cropRegion[2], newNode->output.cropRegion[3]);
break;
}
}
for (int i = 0; i < 4; i++) {
oldNode->request = newNode->request;
oldNode->input. cropRegion[i] = newNode->input. cropRegion[i];
oldNode->output.cropRegion[i] = newNode->output.cropRegion[i];
}
return NO_ERROR;
}
status_t ExynosCameraMCPipe::m_checkNodeGroupInfo(ExynosCameraFrameSP_dptr_t frame, int index, camera2_node *oldNode, camera2_node *newNode)
{
return m_checkNodeGroupInfo(frame, m_deviceInfo->nodeName[index], oldNode, newNode);
}
void ExynosCameraMCPipe::m_dumpRunningFrameList(void)
{
CLOGV("*********runningFrameList dump***********");
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_node[i] != NULL) {
CLOGV("[%s] m_numBuffers[%d] : %d", m_deviceInfo->nodeName[i], i, m_numBuffers[i]);
for (uint32_t j = 0; j < m_numBuffers[i]; j++) {
if (m_runningFrameList[i][j] == NULL) {
CLOGV("[%s] runningFrameList[%d][%d] is NULL", m_deviceInfo->nodeName[i], i, j);
} else {
CLOGD("[%s] runningFrameList[%d][%d]: fcount = %d",
m_deviceInfo->nodeName[i], i, j, m_runningFrameList[i][j]->getFrameCount());
}
}
}
}
return;
}
void ExynosCameraMCPipe::m_dumpPerframeNodeGroupInfo(const char *name, camera_pipe_perframe_node_group_info_t nodeInfo)
{
if (name != NULL)
CLOGI("(%s) ++++++++++++++++++++", name);
CLOGI("\t\t perframeSupportNodeNum : %d", nodeInfo.perframeSupportNodeNum);
CLOGI("\t\t perFrameLeaderInfo.perframeInfoIndex : %d", nodeInfo.perFrameLeaderInfo.perframeInfoIndex);
CLOGI("\t\t perFrameLeaderInfo.perFrameVideoID : %d", nodeInfo.perFrameLeaderInfo.perFrameVideoID);
for (int i = 0; i < CAPTURE_NODE_MAX; i++)
CLOGI("\t\t perFrameCaptureInfo[%d].perFrameVideoID : %d", i, nodeInfo.perFrameCaptureInfo[i].perFrameVideoID);
if (name != NULL)
CLOGI("(%s) ------------------------------", name);
return;
}
void ExynosCameraMCPipe::m_dumpPerframeShotInfo(const char *name, int frameCount, camera2_shot_ext *shot_ext)
{
if (name != NULL)
CLOGI("(%s) frameCount(%d) ++++++++++++++++++++", name, frameCount);
if (shot_ext != NULL) {
for (int i = 0; i < CAPTURE_NODE_MAX; i++) {
CLOGI("\t\t index(%d), vid(%d) request(%d) input (%d, %d, %d, %d) output (%d, %d, %d, %d)",
i,
shot_ext->node_group.capture[i].vid,
shot_ext->node_group.capture[i].request,
shot_ext->node_group.capture[i].input.cropRegion[0],
shot_ext->node_group.capture[i].input.cropRegion[1],
shot_ext->node_group.capture[i].input.cropRegion[2],
shot_ext->node_group.capture[i].input.cropRegion[3],
shot_ext->node_group.capture[i].output.cropRegion[0],
shot_ext->node_group.capture[i].output.cropRegion[1],
shot_ext->node_group.capture[i].output.cropRegion[2],
shot_ext->node_group.capture[i].output.cropRegion[3]);
}
} else {
CLOGI("\t\t shot_ext == NULL");
}
if (name != NULL)
CLOGI("(%s) ------------------------------", name);
}
void ExynosCameraMCPipe::m_configDvfs(void)
{
CLOGD("");
bool newDvfs = m_configurations->getMode(CONFIGURATION_DVFS_LOCK_MODE);
if (newDvfs != m_dvfsLocked) {
setControl(V4L2_CID_IS_DVFS_LOCK, 533000);
m_dvfsLocked = newDvfs;
}
}
bool ExynosCameraMCPipe::m_flagValidInt(int num)
{
bool ret = false;
if (num < 0)
ret = false;
else
ret = true;
return ret;
}
bool ExynosCameraMCPipe::m_checkThreadLoop(frame_queue_t *frameQ)
{
Mutex::Autolock lock(m_pipeframeLock);
bool loop = false;
if (m_reprocessing == false)
loop = true;
if (m_oneShotMode == false)
loop = true;
if (frameQ->getSizeOfProcessQ() > 0)
loop = true;
if (m_flagSensorStandby >= SENSOR_STANDBY_ON_READY
&& frameQ->getSizeOfProcessQ() <= 0) {
loop = false;
}
if (m_flagTryStop == true)
loop = false;
return loop;
}
status_t ExynosCameraMCPipe::m_checkPolling(ExynosCameraNode *node)
{
int ret = 0;
ret = node->polling();
if (ret < 0) {
CLOGE("polling fail, ret(%d)", ret);
/* TODO: doing exception handling */
m_threadState = ERROR_POLLING_DETECTED;
return ERROR_POLLING_DETECTED;
}
return NO_ERROR;
}
void ExynosCameraMCPipe::m_init(camera_device_info_t *deviceInfo)
{
if (deviceInfo != NULL)
m_deviceInfo = deviceInfo;
else
m_deviceInfo = NULL;
/*
* For replace old pipe, MCPipe have all variables.
* but, if exist old pipe, same variable not declared by MCPipe.
*/
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
m_numOfRunningFrame[i] = 0;
m_skipPutBuffer[i] = false;
m_numBuffers[i] = 0;
for (int j = 0; j < MAX_BUFFERS; j++)
m_runningFrameList[i][j] = NULL;
memset(&m_perframeMainNodeGroupInfo[i], 0x00, sizeof(camera_pipe_perframe_node_group_info_t));
if (m_deviceInfo != NULL)
m_pipeIdArr[i] = m_deviceInfo->pipeId[i];
else
m_pipeIdArr[i] = 0;
}
m_requestFrameQ = NULL;
m_flagSensorStandby = SENSOR_STANDBY_OFF;
#ifdef USE_MCPIPE_SERIALIZATION_MODE
m_serializeOperation = false;
#endif
#ifdef TEST_WATCHDOG_THREAD
int testErrorDetect = 0;
#endif
m_sensorNodeIndex = -1;
#ifdef SUPPORT_DEPTH_MAP
m_depthVcNodeIndex = -1;
#endif // SUPPORT_DEPTH_MAP
m_putInternalFrameLogCnt = 0;
m_getInternalFrameLogCnt = 0;
m_lastFrameCount = 0;
m_lastMetaFrameCount = 0;
}
status_t ExynosCameraMCPipe::m_createSensorNode(int32_t *sensorIds)
{
status_t ret = NO_ERROR;
if (m_reprocessing == true)
return NO_ERROR;
int fliteNodeNum = getFliteNodenum(m_cameraId);
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_deviceInfo->nodeNum[i] == fliteNodeNum) {
m_sensorNodeIndex = i;
break;
}
}
if (m_sensorNodeIndex < 0) {
CLOGV("m_sensorNodeIndex(%d)", m_sensorNodeIndex);
return NO_ERROR;
}
if (m_node[m_sensorNodeIndex] != NULL) {
CLOGE("m_node[%d](%p) != NULL. so, fail", m_sensorNodeIndex, m_node[m_sensorNodeIndex]);
return INVALID_OPERATION;
}
if (sensorIds == NULL) {
CLOGE("sensorIds == NULL. so, fail");
return INVALID_OPERATION;
}
if (sensorIds[m_sensorNodeIndex] <= 0) {
CLOGE("sensorIds[%d](%d) <= 0. so, fail", m_sensorNodeIndex, sensorIds[m_sensorNodeIndex]);
return INVALID_OPERATION;
}
m_node[m_sensorNodeIndex] = m_createNode(m_cameraId, m_deviceInfo->nodeNum[m_sensorNodeIndex]);
if (m_node[m_sensorNodeIndex] == NULL) {
CLOGE("sensor open failed sensorNodeIndex(%d) sensorIds[%d]=%d m_node[%d]=NULL",
m_sensorNodeIndex, m_sensorNodeIndex, sensorIds[m_sensorNodeIndex], m_sensorNodeIndex);
return INVALID_OPERATION;
}
// setInput here for performance.
#ifdef INPUT_STREAM_MASK
CLOGD(" i(%2d) \t setInput(sensorIds : %d) [src nodeNum : %d][nodeNums : %d][otf : %d][leader : %d][reprocessing : %d][unique sensorId : %d]",
m_sensorNodeIndex,
sensorIds[m_sensorNodeIndex],
((sensorIds[m_sensorNodeIndex] & INPUT_VINDEX_MASK) >> INPUT_VINDEX_SHIFT) + FIMC_IS_VIDEO_BAS_NUM,
m_deviceInfo->nodeNum[m_sensorNodeIndex],
((sensorIds[m_sensorNodeIndex] & INPUT_MEMORY_MASK) >> INPUT_MEMORY_SHIFT),
((sensorIds[m_sensorNodeIndex] & INPUT_LEADER_MASK) >> INPUT_LEADER_SHIFT),
((sensorIds[m_sensorNodeIndex] & INPUT_STREAM_MASK) >> INPUT_STREAM_SHIFT),
((sensorIds[m_sensorNodeIndex] & INPUT_MODULE_MASK) >> INPUT_MODULE_SHIFT));
#else
CLOGD("setInput(sensorIds : %d)", sensorIds[m_sensorNodeIndex]);
#endif
ret = m_node[m_sensorNodeIndex]->setInput(sensorIds[m_sensorNodeIndex]);
if (ret < 0) {
CLOGE("nodeNums[%d] : %p, setInput(sensorIds : %d fail, ret(%d)",
m_sensorNodeIndex, m_node[m_sensorNodeIndex], m_sensorIds[m_sensorNodeIndex], ret);
m_destroyNode(m_cameraId, m_node[m_sensorNodeIndex]);
m_node[m_sensorNodeIndex] = NULL;
return ret;
}
m_sensorIds[m_sensorNodeIndex] = sensorIds[m_sensorNodeIndex];
#ifdef SUPPORT_DEPTH_MAP
if (m_parameters->isDepthMapSupported()) {
int depthMapNodeNum = getDepthVcNodeNum(m_cameraId);
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_deviceInfo->nodeNum[i] == depthMapNodeNum) {
m_depthVcNodeIndex = i;
break;
}
}
if (m_depthVcNodeIndex < 0) {
CLOGV("m_depthVcNodeIndex(%d)", m_depthVcNodeIndex);
return NO_ERROR;
}
if (m_node[m_depthVcNodeIndex] != NULL) {
CLOGE("m_node[%d](%p) != NULL. so, fail", m_depthVcNodeIndex, m_node[m_depthVcNodeIndex]);
return INVALID_OPERATION;
}
m_node[m_depthVcNodeIndex] = m_createVcNode(m_cameraId, m_deviceInfo->nodeNum[m_depthVcNodeIndex]);
}
#endif // SUPPORT_DEPTH_MAP
return ret;
}
status_t ExynosCameraMCPipe::setDeviceInfo(camera_device_info_t *deviceInfo)
{
if (deviceInfo != NULL) {
m_deviceInfo = deviceInfo;
} else {
m_deviceInfo = NULL;
}
for (int i = OUTPUT_NODE; i < MAX_NODE; i++) {
if (m_deviceInfo != NULL)
m_pipeIdArr[i] = m_deviceInfo->pipeId[i];
else
m_pipeIdArr[i] = 0;
}
return NO_ERROR;
}
#ifdef USE_MCPIPE_SERIALIZATION_MODE
void ExynosCameraMCPipe::m_lockSerializeOperation(enum pipeline pipeId)
{
if (m_serializeOperation == false) {
return;
}
for (int i = ExynosCameraParameters::CRITICAL_SECTION_TYPE_START;
i < ExynosCameraParameters::CRITICAL_SECTION_TYPE_END; i++) {
if (m_parameters->isCriticalSection(pipeId,
(enum ExynosCameraParameters::critical_section_type)i) == true) {
CLOGD("Critical Section %d WAIT", i);
ExynosCameraMCPipe::g_serializationLock[i].lock();
CLOGD("Critical Section %d START", i);
}
}
}
void ExynosCameraMCPipe::m_unlockSerializeOperation(enum pipeline pipeId)
{
if (m_serializeOperation == false) {
return;
}
for (int i = ExynosCameraParameters::CRITICAL_SECTION_TYPE_END - 1;
i >= ExynosCameraParameters::CRITICAL_SECTION_TYPE_START; i--) {
if (m_parameters->isCriticalSection(pipeId,
(enum ExynosCameraParameters::critical_section_type)i) == true) {
ExynosCameraMCPipe::g_serializationLock[i].unlock();
CLOGD("Critical Section %d END", i);
}
}
}
#endif
}; /* namespace android */