blob: 55c91ecc9804b6db4c169c10e6faa4e08339aede [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 "ExynosCameraPipePP"
#include "ExynosCameraPipePP.h"
namespace android {
status_t ExynosCameraPipePP::start(void)
{
CLOGD("");
m_flagTryStop = false;
return NO_ERROR;
}
status_t ExynosCameraPipePP::stop(void)
{
CLOGD("");
m_flagTryStop = true;
m_mainThread->requestExitAndWait();
CLOGD(" thead exited");
m_inputFrameQ->release();
m_flagTryStop = false;
return NO_ERROR;
}
status_t ExynosCameraPipePP::startThread(void)
{
CLOGV("");
if (m_outputFrameQ == NULL) {
CLOGE("outputFrameQ is NULL, cannot start");
return INVALID_OPERATION;
}
m_mainThread->run(m_name);
CLOGI("startThread is succeed (%d)", getPipeId());
return NO_ERROR;
}
status_t ExynosCameraPipePP::stopThread(void)
{
m_flagTryStop = true;
m_mainThread->requestExit();
m_inputFrameQ->sendCmd(WAKE_UP);
m_dumpRunningFrameList();
return NO_ERROR;
}
bool ExynosCameraPipePP::m_checkThreadLoop()
{
Mutex::Autolock lock(m_pipeframeLock);
bool loop = false;
if (m_oneShotMode == false)
loop = true;
if (m_inputFrameQ->getSizeOfProcessQ() > 0)
loop = true;
if (m_flagTryStop == true)
loop = false;
return loop;
}
bool ExynosCameraPipePP::m_mainThreadFunc(void)
{
status_t ret = NO_ERROR;
ret = m_run();
if (ret != NO_ERROR) {
if (ret != TIMED_OUT) {
CLOGE("m_putBuffer fail");
}
}
return m_checkThreadLoop();
}
status_t ExynosCameraPipePP::m_run(void)
{
status_t ret = NO_ERROR;
ExynosCameraFrameSP_sptr_t newFrame = NULL;
ExynosCameraFrameEntity *entity = NULL;
int pipeId = getPipeId();
ExynosCameraParameters *params = NULL;
ExynosCameraImage srcImage[ExynosCameraImageCapacity::MAX_NUM_OF_IMAGE_MAX];
ExynosCameraImage dstImage[ExynosCameraImageCapacity::MAX_NUM_OF_IMAGE_MAX];
int numOfSrcImage = 0;
int numOfDstImage = 0;
int rotation = 0;
int flipHorizontal = 0;
int flipVertical = 0;
int multiShotCount = 0;
ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame);
if (ret != NO_ERROR) {
/* TODO: We need to make timeout duration depends on FPS */
if (ret == TIMED_OUT) {
CLOGV("wait timeout");
} else {
CLOGE("wait and pop fail, ret(%d)", ret);
/* TODO: doing exception handling */
}
return ret;
}
if (newFrame == NULL) {
CLOGE("new frame is NULL");
return NO_ERROR;
}
entity = newFrame->searchEntityByPipeId(pipeId);
if (entity == NULL
|| entity->getSrcBufState() == ENTITY_BUFFER_STATE_ERROR) {
CLOGE("frame(%d) entityState(ENTITY_BUFFER_STATE_ERROR), skip msc", newFrame->getFrameCount());
goto func_exit;
}
params = newFrame->getParameters();
//////////////////////////////
//// This is core drawing part
if (m_pp == NULL) {
CLOGE("m_pp == NULL. so, fail, frameCount(%d)", newFrame->getFrameCount());
goto func_exit;
}
numOfSrcImage = m_pp->getNumOfSrcImage();
numOfDstImage = m_pp->getNumOfDstImage();
// SRC
multiShotCount = newFrame->getFrameSpecialCaptureStep();
if (numOfSrcImage < 1) {
CLOGE("Invalid numOfSrcImage(%d). it must be bigger than 1",
numOfDstImage);
goto func_exit;
}
for (int i = 0; i < numOfSrcImage; i++) {
int nodeType = (int)OUTPUT_NODE + i;
ret = newFrame->getSrcBuffer(pipeId, &(srcImage[i].buf), i);
if (ret != NO_ERROR) {
CLOGE("newFrame->getSrcBuffer(pipeId(%d), nodeType : %d)", pipeId, nodeType);
goto func_exit;
}
ret = newFrame->getSrcRect(pipeId, &(srcImage[i].rect), i);
if (ret != NO_ERROR) {
CLOGE("newFrame->getSrcRect(pipeId(%d), nodeType : %d)", pipeId, nodeType);
goto func_exit;
}
srcImage[i].rotation = 0;
srcImage[i].flipH = false;
srcImage[i].flipV = false;
srcImage[i].multiShotCount = multiShotCount;
}
// DST
rotation = newFrame->getRotation(pipeId);
CLOGV(" getPipeId(%d), rotation(%d)", pipeId, rotation);
flipHorizontal = newFrame->getFlipHorizontal(pipeId);
flipVertical = newFrame->getFlipVertical(pipeId);
if (numOfDstImage < 1) {
CLOGE("Invalid numOfDstImage(%d). it must be bigger than 1",
numOfDstImage);
goto func_exit;
}
for (int i = 0; i < numOfDstImage; i++) {
int nodeType = (int)OUTPUT_NODE + i;
ret = newFrame->getDstBuffer(pipeId, &(dstImage[i].buf), nodeType);
if (ret != NO_ERROR) {
CLOGE("newFrame->getDstBuffer(pipeId(%d), nodeType : %d)", pipeId, nodeType);
goto func_exit;
}
ret = newFrame->getDstRect(pipeId, &(dstImage[i].rect));
if (ret != NO_ERROR) {
CLOGE("newFrame->getDstRect(pipeId(%d), nodeType : %d)", pipeId, nodeType);
goto func_exit;
}
dstImage[i].rotation = rotation;
dstImage[i].flipH = (flipHorizontal == 1) ? true : false;
dstImage[i].flipV = (flipVertical == 1) ? true : false;
}
/*
* HACK: libacryl(G2D) cannot handle YV12(V4L2_PIX_FMT_YVU420).
* so, it will have nextPP(PPLibcsc).
*/
if (m_nodeNum == 222) {
if (m_pp->isSupportedSrcImage(srcImage[0].rect.colorFormat, srcImage[0].rect.fullW) == false
|| m_pp->isSupportedDstImage(dstImage[0].rect.colorFormat, dstImage[0].rect.fullW) == false) {
ExynosCameraPP *nextPP = m_pp->getNextPP();
if (nextPP == NULL) {
nextPP = ExynosCameraPPFactory::newPP(m_cameraId, m_configurations, m_parameters, PICTURE_GSC_NODE_NUM);
CLOGD("m_pp(%s) can't support [SRC]%c%c%c%c, fullW(%d) / [DST]%c%c%c%c, fullW(%d). make nextPP(nodeNum : %d)",
m_pp->getName(), nextPP->getNodeNum(),
v4l2Format2Char(srcImage[0].rect.colorFormat, 0),
v4l2Format2Char(srcImage[0].rect.colorFormat, 1),
v4l2Format2Char(srcImage[0].rect.colorFormat, 2),
v4l2Format2Char(srcImage[0].rect.colorFormat, 3),
srcImage[0].rect.fullW,
v4l2Format2Char(dstImage[0].rect.colorFormat, 0),
v4l2Format2Char(dstImage[0].rect.colorFormat, 1),
v4l2Format2Char(dstImage[0].rect.colorFormat, 2),
v4l2Format2Char(dstImage[0].rect.colorFormat, 3),
dstImage[0].rect.fullW);
ret = m_pp->setNextPP(nextPP);
if (ret != NO_ERROR) {
CLOGE("m_pp(%s)->setNextPP(%s) fail",
m_pp->getName(), nextPP->getName());
goto func_exit;
}
}
}
}
ret = m_pp->draw(srcImage, dstImage, params);
if (dstImage[0].bufferDondeIndex >= 0) {
newFrame->setBufferDondeIndex(dstImage[0].bufferDondeIndex);
}
newFrame->setBvOffset(dstImage[0].bvOffset);
if (ret != NO_ERROR) {
goto func_exit;
}
//////////////////////////////
newFrame->setStreamTimestamp(dstImage[0].streamTimeStamp);
ret = newFrame->setDstBufferState(pipeId, ENTITY_BUFFER_STATE_COMPLETE);
if (ret != NO_ERROR) {
CLOGE("newFrame->setDstBufferState(%s, ENTITY_BUFFER_STATE_COMPLETE) fail, frameCount(%d)",
this->getName(), newFrame->getFrameCount());
goto func_exit;
}
ret = newFrame->setEntityState(pipeId, ENTITY_STATE_FRAME_DONE);
if (ret != NO_ERROR) {
CLOGE("newFrame->setEntityState(%s, ENTITY_STATE_FRAME_DONE) fail, frameCount(%d)",
this->getName(), newFrame->getFrameCount());
goto func_exit;
}
m_outputFrameQ->pushProcessQ(&newFrame);
return NO_ERROR;
func_exit:
ret = newFrame->setDstBufferState(pipeId, ENTITY_BUFFER_STATE_ERROR);
if (ret != NO_ERROR) {
CLOGE("newFrame->setDstBufferState(%s, ENTITY_BUFFER_STATE_COMPLETE) fail, frameCount(%d)",
this->getName(), newFrame->getFrameCount());
}
ret = newFrame->setEntityState(pipeId, ENTITY_STATE_FRAME_DONE);
if (ret != NO_ERROR) {
CLOGE("newFrame->setEntityState(%s, ENTITY_STATE_FRAME_DONE) fail, frameCount(%d)",
this->getName(), newFrame->getFrameCount());
}
m_outputFrameQ->pushProcessQ(&newFrame);
return NO_ERROR;
}
}; /* namespace android */