| /* |
| ** |
| ** Copyright 2013, 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 "ExynosCameraPipe" |
| #include <cutils/log.h> |
| |
| #include "ExynosCameraPipe.h" |
| |
| namespace android { |
| |
| ExynosCameraPipe::ExynosCameraPipe() |
| { |
| m_pipeId = 0; |
| m_cameraId = -1; |
| m_reprocessing = 0; |
| m_parameters = NULL; |
| m_prepareBufferCount = 0; |
| m_numBuffers = 0; |
| m_activityControl = NULL; |
| |
| m_inputFrameQ = NULL; |
| m_outputFrameQ = NULL; |
| |
| for (uint32_t i = 0; i < MAX_BUFFERS; i++) { |
| m_runningFrameList[i] = NULL; |
| } |
| m_numOfRunningFrame = 0; |
| |
| m_mainNode = NULL; |
| m_mainNodeNum = -1; |
| |
| m_threadCommand = 0; |
| m_timeInterval = 0; |
| m_threadState = 0; |
| m_threadRenew = 0; |
| memset(m_name, 0x00, sizeof(m_name)); |
| |
| m_exynosconfig = NULL; |
| |
| m_flagStartPipe = false; |
| m_flagTryStop = false; |
| |
| m_isBoosting = false; |
| |
| m_metadataTypeShot = true; |
| |
| m_dvfsLocked = false; |
| |
| memset(&m_perframeMainNodeGroupInfo, 0x00, sizeof(camera_pipe_perframe_node_group_info_t)); |
| |
| } |
| |
| ExynosCameraPipe::~ExynosCameraPipe() |
| { |
| } |
| |
| status_t ExynosCameraPipe::create(int32_t *sensorIds) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| if (sensorIds == NULL) { |
| ALOGE("ERR(%s[%d]): Pipe need sensorId", __FUNCTION__, __LINE__); |
| return BAD_VALUE; |
| } |
| |
| m_mainNode = new ExynosCameraNode(); |
| ret = m_mainNode->create("main", m_cameraId); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode create fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| |
| ret = m_mainNode->open(FIMC_IS_VIDEO_SS0_NUM); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode open fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| ALOGD("DEBUG(%s):Node(%d) opened", __FUNCTION__, FIMC_IS_VIDEO_SS0_NUM); |
| |
| ret = m_mainNode->setInput(sensorIds[OUTPUT_NODE]); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode setInput fail, sensorId(%d), ret(%d)", __FUNCTION__, __LINE__, sensorIds[0], ret); |
| return ret; |
| } |
| |
| m_mainThread = ExynosCameraThreadFactory::createThread(this, &ExynosCameraPipe::m_mainThreadFunc, "mainThread"); |
| |
| m_inputFrameQ = new frame_queue_t; |
| |
| m_prepareBufferCount = 0; |
| CLOGI("INFO(%s[%d]):create() is succeed (%d) prepare (%d)", __FUNCTION__, __LINE__, getPipeId(), m_prepareBufferCount); |
| |
| return NO_ERROR; |
| } |
| |
| #ifdef SAMSUNG_COMPANION |
| status_t ExynosCameraPipe::precreate(int32_t *sensorIds) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| if (sensorIds == NULL) { |
| ALOGE("ERR(%s[%d]): Pipe need sensorId", __FUNCTION__, __LINE__); |
| return BAD_VALUE; |
| } |
| |
| m_mainNode = new ExynosCameraNode(); |
| ret = m_mainNode->create("main", m_cameraId); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode create fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| |
| ret = m_mainNode->open(FIMC_IS_VIDEO_SS0_NUM); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode open fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| |
| CLOGI("INFO(%s[%d]):precreate() is succeed (%d) prepare (%d)", __FUNCTION__, __LINE__, getPipeId(), m_prepareBufferCount); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::postcreate(int32_t *sensorIds) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| if (sensorIds == NULL) { |
| ALOGE("ERR(%s[%d]): Pipe need sensorId", __FUNCTION__, __LINE__); |
| return BAD_VALUE; |
| } |
| |
| ret = m_mainNode->setInput(sensorIds[OUTPUT_NODE]); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): mainNode setInput fail, sensorId(%d), ret(%d)", __FUNCTION__, __LINE__, sensorIds[0], ret); |
| return ret; |
| } |
| |
| m_mainThread = ExynosCameraThreadFactory::createThread(this, &ExynosCameraPipe::m_mainThreadFunc, "mainThread"); |
| |
| m_inputFrameQ = new frame_queue_t; |
| |
| m_prepareBufferCount = 0; |
| CLOGI("INFO(%s[%d]):postcreate() is succeed (%d) prepare (%d)", __FUNCTION__, __LINE__, getPipeId(), m_prepareBufferCount); |
| |
| return NO_ERROR; |
| } |
| #endif |
| |
| status_t ExynosCameraPipe::destroy(void) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| if (m_mainNode != NULL) { |
| if (m_mainNode->close() != NO_ERROR) { |
| CLOGE("ERR(%s): close fail", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| delete m_mainNode; |
| m_mainNode = NULL; |
| ALOGD("DEBUG(%s):Node(%d) closed", __FUNCTION__, FIMC_IS_VIDEO_SS0_NUM); |
| } |
| |
| if (m_inputFrameQ != NULL) { |
| m_inputFrameQ->release(); |
| delete m_inputFrameQ; |
| m_inputFrameQ = NULL; |
| } |
| |
| CLOGI("INFO(%s[%d]):destroy() is succeed (%d)", __FUNCTION__, __LINE__, getPipeId()); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::m_setMapBuffer(ExynosCameraNode *node, ExynosCameraBuffer *buffer) |
| { |
| status_t ret = NO_ERROR; |
| |
| if (buffer == NULL) { |
| CLOGE("ERR(%s[%d]):Buffer is NULL", __FUNCTION__, __LINE__); |
| return INVALID_OPERATION; |
| } |
| if (node == NULL) { |
| CLOGE("ERR(%s[%d]):Node is NULL", __FUNCTION__, __LINE__); |
| return INVALID_OPERATION; |
| } |
| |
| ret = node->mapBuffer(buffer); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s[%d]):mapBuffer() fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::setupPipe(camera_pipe_info_t *pipeInfos) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| /* TODO: check node state */ |
| |
| /* initialize node */ |
| int maxW = pipeInfos[0].rectInfo.fullW; |
| int maxH = pipeInfos[0].rectInfo.fullH; |
| int colorFormat = pipeInfos[0].rectInfo.colorFormat; |
| enum v4l2_buf_type bufType = (enum v4l2_buf_type)pipeInfos[0].bufInfo.type; |
| enum v4l2_memory memType = (enum v4l2_memory)pipeInfos[0].bufInfo.memory; |
| m_numBuffers = pipeInfos[0].bufInfo.count; |
| |
| m_perframeMainNodeGroupInfo = pipeInfos[0].perFrameNodeGroupInfo; |
| |
| m_mainNode->setSize(maxW, maxH); |
| m_mainNode->setColorFormat(colorFormat, 2); |
| m_mainNode->setBufferType(m_numBuffers, bufType, memType); |
| |
| m_mainNode->setFormat(); |
| m_mainNode->reqBuffers(); |
| |
| for (uint32_t i = 0; i < m_numBuffers; i++) { |
| m_runningFrameList[i] = NULL; |
| } |
| m_numOfRunningFrame = 0; |
| |
| m_prepareBufferCount = 0; |
| CLOGI("INFO(%s[%d]):setupPipe() is succeed (%d) prepare (%d)", __FUNCTION__, __LINE__, getPipeId(), m_prepareBufferCount); |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::prepare(void) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| for (uint32_t i = 0; i < m_prepareBufferCount; i++) { |
| ret = m_putBuffer(); |
| if (ret < 0) { |
| CLOGE("ERR(%s): m_putBuffer fail, ret(%d)", __FUNCTION__, ret); |
| return ret; |
| } |
| } |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::start(void) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| /* TODO: check state ready for start */ |
| |
| int ret = 0; |
| |
| ret = m_mainNode->start(); |
| if (ret != NO_ERROR) { |
| ALOGE("ERR(%s): Starting Node Error!", __FUNCTION__); |
| return ret; |
| } |
| |
| m_threadState = 0; |
| m_threadRenew = 0; |
| m_threadCommand = 0; |
| m_timeInterval = 0; |
| |
| m_flagStartPipe = true; |
| m_flagTryStop = false; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::stop(void) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| m_flagStartPipe = false; |
| |
| ret = m_mainNode->stop(); |
| if (ret < 0) { |
| CLOGE("ERR(%s): node stop fail, ret(%d)", __FUNCTION__, ret); |
| return ret; |
| } |
| |
| m_mainThread->requestExitAndWait(); |
| |
| ret = m_mainNode->clrBuffers(); |
| if (ret < 0) { |
| CLOGE("ERR(%s): node clrBuffers fail, ret(%d)", __FUNCTION__, ret); |
| return ret; |
| } |
| |
| CLOGD("DEBUG(%s[%d]): thead exited", __FUNCTION__, __LINE__); |
| |
| m_inputFrameQ->release(); |
| |
| m_mainNode->removeItemBufferQ(); |
| |
| for (uint32_t i = 0; i < m_numBuffers; i++) |
| m_runningFrameList[i] = NULL; |
| |
| m_numOfRunningFrame = 0; |
| |
| m_threadState = 0; |
| m_threadRenew = 0; |
| m_threadCommand = 0; |
| m_timeInterval = 0; |
| m_flagTryStop= false; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::startThread(void) |
| { |
| if (m_outputFrameQ == NULL) { |
| CLOGE("ERR(%s): outputFrameQ is NULL, cannot start", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| m_timer.start(); |
| if (m_mainThread->isRunning() == false) { |
| m_mainThread->run(); |
| CLOGI("INFO(%s[%d]):startThread is succeed (%d)", __FUNCTION__, __LINE__, getPipeId()); |
| } else { |
| CLOGW("WRN(%s[%d]):startThread is already running (%d)", __FUNCTION__, __LINE__, getPipeId()); |
| } |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::stopThread(void) |
| { |
| m_mainThread->requestExit(); |
| m_inputFrameQ->sendCmd(WAKE_UP); |
| |
| m_dumpRunningFrameList(); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::sensorStream(bool on) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| int value = on ? IS_ENABLE_STREAM: IS_DISABLE_STREAM; |
| |
| ret = m_mainNode->setControl(V4L2_CID_IS_S_STREAM, value); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->sensorStream failed", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::setControl(int cid, int value) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| ret = m_mainNode->setControl(cid, value); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->setControl failed", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::getControl(int cid, int *value) |
| { |
| CLOGV("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| ret = m_mainNode->getControl(cid, value); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->getControl failed", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::setParam(struct v4l2_streamparm streamParam) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| ret = m_mainNode->setParam(&streamParam); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->setControl failed", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::setStopFlag(void) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| |
| m_flagTryStop = true; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::instantOn(int32_t numFrames) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| ExynosCameraFrame *newFrame = NULL; |
| ExynosCameraBuffer newBuffer; |
| |
| ret = m_mainNode->start(); |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]): mainNode instantOn fail", __FUNCTION__, __LINE__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::instantOnQbuf(ExynosCameraFrame **frame, BUFFER_POS::POS pos) |
| { |
| ExynosCameraFrame *newFrame = NULL; |
| ExynosCameraBuffer newBuffer; |
| int ret = 0; |
| ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame); |
| if (ret < 0) { |
| /* TODO: We need to make timeout duration depends on FPS */ |
| if (ret == TIMED_OUT) { |
| CLOGW("WARN(%s):wait timeout", __FUNCTION__); |
| m_mainNode->dumpState(); |
| } else { |
| CLOGE("ERR(%s):wait and pop fail, ret(%d)", __FUNCTION__, ret); |
| /* TODO: doing exception handling */ |
| } |
| return ret; |
| } |
| |
| if (newFrame == NULL) { |
| CLOGE("ERR(%s):newFrame is NULL", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| if(pos == BUFFER_POS::DST) |
| ret = newFrame->getDstBuffer(getPipeId(), &newBuffer); |
| else if(pos == BUFFER_POS::SRC) |
| ret = newFrame->getSrcBuffer(getPipeId(), &newBuffer); |
| |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]):frame get buffer fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| /* TODO: doing exception handling */ |
| return OK; |
| } |
| |
| if (m_runningFrameList[newBuffer.index] != NULL) { |
| CLOGE("ERR(%s):new buffer is invalid, we already get buffer index(%d), newFrame->frameCount(%d)", |
| __FUNCTION__, newBuffer.index, newFrame->getFrameCount()); |
| return BAD_VALUE; |
| } |
| |
| camera2_shot_ext *shot_ext = (struct camera2_shot_ext *)(newBuffer.addr[1]); |
| |
| if (shot_ext != NULL) { |
| newFrame->getMetaData(shot_ext); |
| m_parameters->duplicateCtrlMetadata((void *)shot_ext); |
| m_activityControl->activityBeforeExecFunc(getPipeId(), (void *)&newBuffer); |
| |
| /* set metadata for instant on */ |
| shot_ext->shot.ctl.scaler.cropRegion[0] = 0; |
| shot_ext->shot.ctl.scaler.cropRegion[1] = 0; |
| shot_ext->shot.ctl.scaler.cropRegion[2] = FASTEN_AE_WIDTH; |
| shot_ext->shot.ctl.scaler.cropRegion[3] = FASTEN_AE_HEIGHT; |
| |
| setMetaCtlAeTargetFpsRange(shot_ext, FASTEN_AE_FPS, FASTEN_AE_FPS); |
| setMetaCtlSensorFrameDuration(shot_ext, (uint64_t)((1000 * 1000 * 1000) / (uint64_t)FASTEN_AE_FPS)); |
| |
| shot_ext->shot.ctl.aa.afMode = AA_AFMODE_INFINITY; |
| |
| if (m_perframeMainNodeGroupInfo.perFrameLeaderInfo.perFrameNodeType == PERFRAME_NODE_TYPE_LEADER) { |
| camera2_node_group node_group_info; |
| memset(&shot_ext->node_group, 0x0, sizeof(camera2_node_group)); |
| newFrame->getNodeGroupInfo(&node_group_info, m_perframeMainNodeGroupInfo.perFrameLeaderInfo.perframeInfoIndex); |
| |
| /* Per - Leader */ |
| if (node_group_info.leader.request == 1) { |
| 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.perFrameLeaderInfo.perFrameVideoID); |
| } |
| |
| /* Per - Captures */ |
| for (int i = 0; i < m_perframeMainNodeGroupInfo.perframeSupportNodeNum - 1; i ++) { |
| if (node_group_info.capture[i].request == 1) { |
| 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, m_perframeMainNodeGroupInfo.perFrameCaptureInfo[i].perFrameVideoID); |
| } |
| } |
| } |
| } |
| ret = m_mainNode->putBuffer(&newBuffer); |
| if (ret < 0) { |
| CLOGE("ERR(%s):putBuffer fail", __FUNCTION__); |
| return ret; |
| /* TODO: doing exception handling */ |
| } |
| |
| ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_PROCESSING); |
| if (ret < 0) { |
| CLOGE("ERR(%s): setDstBuffer state fail", __FUNCTION__); |
| return ret; |
| } |
| |
| m_runningFrameList[newBuffer.index] = newFrame; |
| |
| m_numOfRunningFrame++; |
| |
| *frame = newFrame; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::instantOnDQbuf(ExynosCameraFrame **frame, BUFFER_POS::POS pos) |
| { |
| ExynosCameraFrame *curFrame = NULL; |
| ExynosCameraBuffer curBuffer; |
| int index = -1; |
| int ret = 0; |
| |
| if (m_numOfRunningFrame <= 0 ) { |
| ALOGD("DEBUG(%s[%d]): skip getBuffer, numOfRunningFrame = %d", __FUNCTION__, __LINE__, m_numOfRunningFrame); |
| return NO_ERROR; |
| } |
| |
| ret = m_mainNode->getBuffer(&curBuffer, &index); |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]):getBuffer fail", __FUNCTION__, __LINE__); |
| /* TODO: doing exception handling */ |
| return ret; |
| } |
| |
| if (index < 0) { |
| CLOGE("ERR(%s[%d]):Invalid index(%d) fail", __FUNCTION__, __LINE__, index); |
| return INVALID_OPERATION; |
| } |
| |
| m_activityControl->activityAfterExecFunc(getPipeId(), (void *)&curBuffer); |
| |
| ret = m_updateMetadataToFrame(curBuffer.addr[1], curBuffer.index); |
| if (ret < 0) |
| ALOGE("ERR(%s[%d]): updateMetadataToFrame fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| |
| |
| if (curBuffer.index < 0) { |
| CLOGE("ERR(%s):index(%d) is invalid", __FUNCTION__, curBuffer.index); |
| return BAD_VALUE; |
| } |
| |
| curFrame = m_runningFrameList[curBuffer.index]; |
| |
| if (curFrame == NULL) { |
| CLOGE("ERR(%s):Unknown buffer, frame is NULL", __FUNCTION__); |
| dump(); |
| return BAD_VALUE; |
| } |
| |
| *frame = curFrame; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::instantOff(void) |
| { |
| int ret = 0; |
| |
| ret = m_mainNode->stop(); |
| |
| ret = m_mainNode->clrBuffers(); |
| if (ret < 0) { |
| ALOGE("ERR(%s):3AA output node clrBuffers fail, ret(%d)", __FUNCTION__, ret); |
| return ret; |
| } |
| |
| for( int i = 0 ; i < MAX_BUFFERS ; i++ ) { |
| m_runningFrameList[i] = NULL; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::instantOnPushFrameQ(BUFFERQ_TYPE::TYPE type, ExynosCameraFrame **frame) |
| { |
| if( type == BUFFERQ_TYPE::OUTPUT ) |
| m_outputFrameQ->pushProcessQ(frame); |
| else |
| m_inputFrameQ->pushProcessQ(frame); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::pushFrame(ExynosCameraFrame **newFrame) |
| { |
| Mutex::Autolock lock(m_pipeframeLock); |
| if (newFrame == NULL) { |
| CLOGE("ERR(%s):newFrame is NULL", __FUNCTION__); |
| return BAD_VALUE; |
| } |
| |
| m_inputFrameQ->pushProcessQ(newFrame); |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosCameraPipe::getCameraId(void) |
| { |
| return this->m_cameraId; |
| } |
| |
| uint32_t ExynosCameraPipe::getPipeId(void) |
| { |
| return this->m_pipeId; |
| } |
| |
| status_t ExynosCameraPipe::setPipeId(uint32_t id) |
| { |
| this->m_pipeId = id; |
| |
| return NO_ERROR; |
| } |
| |
| int ExynosCameraPipe::getPipeId(enum NODE_TYPE nodeType) |
| { |
| android_printAssert(NULL, LOG_TAG, "ASSERT(%s[%d]):Not supported API. use MCPipe, assert!!!!", __FUNCTION__, __LINE__); |
| |
| return -1; |
| } |
| |
| status_t ExynosCameraPipe::setPipeId(enum NODE_TYPE nodeType, uint32_t id) |
| { |
| android_printAssert(NULL, LOG_TAG, "ASSERT(%s[%d]):Not supported API. use MCPipe, assert!!!!", __FUNCTION__, __LINE__); |
| |
| return INVALID_OPERATION; |
| } |
| |
| status_t ExynosCameraPipe::setPipeName(const char *pipeName) |
| { |
| strncpy(m_name, pipeName, EXYNOS_CAMERA_NAME_STR_SIZE - 1); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::getInputFrameQ(frame_queue_t **inputFrameQ) |
| { |
| *inputFrameQ = m_inputFrameQ; |
| |
| if (*inputFrameQ == NULL) |
| CLOGE("ERR(%s[%d])inputFrameQ is NULL", __FUNCTION__, __LINE__); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::getOutputFrameQ(frame_queue_t **outputFrameQ) |
| { |
| *outputFrameQ = m_outputFrameQ; |
| |
| if (*outputFrameQ == NULL) |
| CLOGE("ERR(%s[%d])outputFrameQ is NULL", __FUNCTION__, __LINE__); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::setOutputFrameQ(frame_queue_t *outputFrameQ) |
| { |
| m_outputFrameQ = outputFrameQ; |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::clearInputFrameQ(void) |
| { |
| if (m_inputFrameQ != NULL) |
| m_inputFrameQ->release(); |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::setBoosting(bool isBoosting) |
| { |
| m_isBoosting = isBoosting; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::setMapBuffer(ExynosCameraBuffer *srcBuf, ExynosCameraBuffer *dstBuf) |
| { |
| return m_setMapBuffer(m_mainNode, srcBuf); |
| } |
| |
| status_t ExynosCameraPipe::setMapBuffer(List<ExynosCameraBuffer> *srcBufList, List<ExynosCameraBuffer> *dstBufList) |
| { |
| status_t ret = NO_ERROR; |
| List<ExynosCameraBuffer>::iterator r; |
| ExynosCameraBuffer buffer; |
| List<ExynosCameraBuffer> *list = NULL; |
| |
| |
| list = srcBufList; |
| |
| if (list == NULL || list->empty()) { |
| CLOGD("DEBUG(%s[%d]):list is NULL or empty ", __FUNCTION__, __LINE__); |
| return NO_ERROR; |
| } |
| |
| r = list->begin()++; |
| |
| while(r != list->end()) |
| { |
| buffer = *r; |
| ret = m_setMapBuffer(m_mainNode, &buffer); |
| if( ret < 0 ) { |
| CLOGD("DEBUG(%s[%d]):m_setMapBuffer failed ", __FUNCTION__, __LINE__); |
| ret = NO_ERROR; |
| return ret; |
| } |
| r++; |
| } |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::getPipeInfo(int *fullW, int *fullH, int *colorFormat, int pipePosition) |
| { |
| int planeCount = 0; |
| int ret = NO_ERROR; |
| |
| ret = m_mainNode->getSize(fullW, fullH); |
| if (ret < 0) { |
| CLOGE("ERR(%s):getSize fail", __FUNCTION__); |
| return ret; |
| } |
| |
| ret = m_mainNode->getColorFormat(colorFormat, &planeCount); |
| if (ret < 0) { |
| CLOGE("ERR(%s):getColorFormat fail", __FUNCTION__); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| status_t ExynosCameraPipe::m_putBuffer(void) |
| { |
| ExynosCameraFrame *newFrame = NULL; |
| ExynosCameraBuffer newBuffer; |
| int ret = 0; |
| |
| ret = m_inputFrameQ->waitAndPopProcessQ(&newFrame); |
| if (m_flagTryStop == true) { |
| CLOGD("DEBUG(%s[%d]):m_flagTryStop(%d)", __FUNCTION__, __LINE__, m_flagTryStop); |
| return NO_ERROR; |
| } |
| if (ret < 0) { |
| /* TODO: We need to make timeout duration depends on FPS */ |
| if (ret == TIMED_OUT) { |
| CLOGW("WARN(%s):wait timeout", __FUNCTION__); |
| m_mainNode->dumpState(); |
| } else { |
| CLOGE("ERR(%s):wait and pop fail, ret(%d)", __FUNCTION__, ret); |
| /* TODO: doing exception handling */ |
| } |
| return ret; |
| } |
| |
| if (newFrame == NULL) { |
| CLOGE("ERR(%s):newFrame is NULL", __FUNCTION__); |
| return INVALID_OPERATION; |
| } |
| |
| ret = newFrame->getDstBuffer(getPipeId(), &newBuffer); |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]):frame get buffer fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| /* TODO: doing exception handling */ |
| return OK; |
| } |
| |
| if (m_runningFrameList[newBuffer.index] != NULL) { |
| CLOGE("ERR(%s):new buffer is invalid, we already get buffer index(%d), newFrame->frameCount(%d)", |
| __FUNCTION__, newBuffer.index, newFrame->getFrameCount()); |
| m_dumpRunningFrameList(); |
| |
| return BAD_VALUE; |
| } |
| |
| camera2_shot_ext *shot_ext = (struct camera2_shot_ext *)(newBuffer.addr[1]); |
| if (shot_ext != NULL) { |
| newFrame->getMetaData(shot_ext); |
| m_parameters->duplicateCtrlMetadata((void *)shot_ext); |
| m_activityControl->activityBeforeExecFunc(getPipeId(), (void *)&newBuffer); |
| |
| if (m_perframeMainNodeGroupInfo.perFrameLeaderInfo.perFrameNodeType == PERFRAME_NODE_TYPE_LEADER) { |
| camera2_node_group node_group_info; |
| memset(&shot_ext->node_group, 0x0, sizeof(camera2_node_group)); |
| newFrame->getNodeGroupInfo(&node_group_info, m_perframeMainNodeGroupInfo.perFrameLeaderInfo.perframeInfoIndex); |
| |
| /* Per - Leader */ |
| if (node_group_info.leader.request == 1) { |
| 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.perFrameLeaderInfo.perFrameVideoID); |
| } |
| |
| /* Per - Captures */ |
| for (int i = 0; i < m_perframeMainNodeGroupInfo.perframeSupportNodeNum - 1; i ++) { |
| if (node_group_info.capture[i].request == 1) { |
| 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, m_perframeMainNodeGroupInfo.perFrameCaptureInfo[i].perFrameVideoID); |
| } |
| } |
| } |
| } |
| |
| ret = m_mainNode->putBuffer(&newBuffer); |
| if (ret < 0) { |
| CLOGE("ERR(%s):putBuffer fail", __FUNCTION__); |
| return ret; |
| /* TODO: doing exception handling */ |
| } |
| |
| ret = newFrame->setDstBufferState(getPipeId(), ENTITY_BUFFER_STATE_PROCESSING); |
| if (ret < 0) { |
| CLOGE("ERR(%s): setDstBuffer state fail", __FUNCTION__); |
| return ret; |
| } |
| |
| m_runningFrameList[newBuffer.index] = newFrame; |
| m_numOfRunningFrame++; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::m_getBuffer(void) |
| { |
| ExynosCameraFrame *curFrame = NULL; |
| ExynosCameraBuffer curBuffer; |
| int index = -1; |
| int ret = 0; |
| |
| if (m_numOfRunningFrame <= 0 || m_flagStartPipe == false) { |
| ALOGD("DEBUG(%s[%d]): skip getBuffer, flagStartPipe(%d), numOfRunningFrame = %d", __FUNCTION__, __LINE__, m_flagStartPipe, m_numOfRunningFrame); |
| return NO_ERROR; |
| } |
| |
| ret = m_mainNode->getBuffer(&curBuffer, &index); |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]):getBuffer fail", __FUNCTION__, __LINE__); |
| /* TODO: doing exception handling */ |
| return ret; |
| } |
| |
| if (index < 0) { |
| CLOGE("ERR(%s[%d]):Invalid index(%d) fail", __FUNCTION__, __LINE__, index); |
| return INVALID_OPERATION; |
| } |
| |
| m_activityControl->activityAfterExecFunc(getPipeId(), (void *)&curBuffer); |
| |
| ret = m_updateMetadataToFrame(curBuffer.addr[1], curBuffer.index); |
| if (ret < 0) |
| ALOGE("ERR(%s[%d]): updateMetadataToFrame fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| |
| /* complete frame */ |
| ret = m_completeFrame(&curFrame, curBuffer); |
| if (ret < 0) { |
| CLOGE("ERR(%s):m_comleteFrame fail", __FUNCTION__); |
| /* TODO: doing exception handling */ |
| } |
| |
| if (curFrame == NULL) { |
| CLOGE("ERR(%s):curFrame is fail", __FUNCTION__); |
| } |
| |
| m_outputFrameQ->pushProcessQ(&curFrame); |
| |
| return NO_ERROR; |
| } |
| |
| bool ExynosCameraPipe::m_mainThreadFunc(void) |
| { |
| int ret = 0; |
| |
| /* TODO: check exit condition */ |
| /* running list != empty */ |
| |
| if (m_flagTryStop == true) { |
| usleep(5000); |
| return true; |
| } |
| |
| ret = m_getBuffer(); |
| if (ret < 0) { |
| CLOGE("ERR(%s):m_getBuffer fail", __FUNCTION__); |
| /* TODO: doing exception handling */ |
| return false; |
| } |
| |
| ret = m_putBuffer(); |
| if (ret < 0) { |
| if (ret == TIMED_OUT) |
| return true; |
| CLOGE("ERR(%s):m_putBuffer fail", __FUNCTION__); |
| /* TODO: doing exception handling */ |
| return false; |
| } |
| |
| return true; |
| } |
| |
| status_t ExynosCameraPipe::m_completeFrame( |
| ExynosCameraFrame **frame, |
| ExynosCameraBuffer buffer, |
| bool isValid) |
| { |
| int ret = 0; |
| |
| if (buffer.index < 0) { |
| CLOGE("ERR(%s):index(%d) is invalid", __FUNCTION__, buffer.index); |
| return BAD_VALUE; |
| } |
| |
| *frame = m_runningFrameList[buffer.index]; |
| |
| if (*frame == NULL) { |
| CLOGE("ERR(%s):Unknown buffer, frame is NULL", __FUNCTION__); |
| dump(); |
| return BAD_VALUE; |
| } |
| |
| if (isValid == false) { |
| ALOGD("DEBUG(%s[%d]):NOT DONE frameCount %d, buffer index(%d)", __FUNCTION__, __LINE__, |
| (*frame)->getFrameCount(), buffer.index); |
| } |
| |
| ret = (*frame)->setEntityState(getPipeId(), ENTITY_STATE_FRAME_DONE); |
| if (ret < 0) { |
| CLOGE("ERR(%s[%d]):set entity state fail, ret(%d)", __FUNCTION__, __LINE__, ret); |
| /* TODO: doing exception handling */ |
| return OK; |
| } |
| |
| CLOGV("DEBUG(%s):entity pipeId(%d), buffer index(%d), frameCount(%d)", |
| __FUNCTION__, buffer.index, getPipeId(), |
| m_runningFrameList[buffer.index]->getFrameCount()); |
| |
| m_runningFrameList[buffer.index] = NULL; |
| m_numOfRunningFrame--; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::m_getFrameByIndex(ExynosCameraFrame **frame, int index) |
| { |
| *frame = m_runningFrameList[index]; |
| if (*frame == NULL) { |
| CLOGE("ERR(%s[%d]):Unknown buffer, index %d frame is NULL", __FUNCTION__, __LINE__, index); |
| dump(); |
| return BAD_VALUE; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::m_updateMetadataToFrame(void *metadata, int index) |
| { |
| int ret = 0; |
| ExynosCameraFrame *curFrame = NULL; |
| camera2_shot_ext *shot_ext; |
| shot_ext = (struct camera2_shot_ext *)metadata; |
| if (shot_ext == NULL) { |
| ALOGE("ERR(%s[%d]): metabuffer is null", __FUNCTION__, __LINE__); |
| return BAD_VALUE; |
| } |
| if (index < 0) { |
| ALOGE("ERR(%s[%d]): Invalid index(%d)", __FUNCTION__, __LINE__, index); |
| return BAD_VALUE; |
| } |
| |
| if (m_metadataTypeShot == false) { |
| ALOGV("DEBUG(%s[%d]): stream type do not need update metadata", __FUNCTION__, __LINE__); |
| return NO_ERROR; |
| } |
| |
| ret = m_getFrameByIndex(&curFrame, index); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): m_getFrameByIndex fail, index(%d), ret(%d)", __FUNCTION__, __LINE__, index, ret); |
| return ret; |
| } |
| |
| ret = curFrame->storeDynamicMeta(shot_ext); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): storeDynamicMeta fail ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| |
| ret = curFrame->storeUserDynamicMeta(shot_ext); |
| if (ret < 0) { |
| ALOGE("ERR(%s[%d]): storeUserDynamicMeta fail ret(%d)", __FUNCTION__, __LINE__, ret); |
| return ret; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::getThreadState(int **threadState) |
| { |
| *threadState = &m_threadState; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::getThreadInterval(uint64_t **timeInterval) |
| { |
| *timeInterval = &m_timeInterval; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::getThreadRenew(int **timeRenew) |
| { |
| *timeRenew = &m_threadRenew; |
| |
| return NO_ERROR; |
| } |
| |
| status_t ExynosCameraPipe::incThreadRenew() |
| { |
| m_threadRenew ++; |
| |
| return NO_ERROR; |
| } |
| |
| void ExynosCameraPipe::dump() |
| { |
| ALOGI("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| |
| m_dumpRunningFrameList(); |
| |
| if (m_mainNode != NULL) |
| m_mainNode->dump(); |
| |
| return; |
| } |
| |
| bool ExynosCameraPipe::isThreadRunning() |
| { |
| return m_mainThread->isRunning(); |
| } |
| |
| status_t ExynosCameraPipe::dumpFimcIsInfo(bool bugOn) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| ret = m_mainNode->setControl(V4L2_CID_IS_DEBUG_DUMP, bugOn); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->setControl failed", __FUNCTION__); |
| |
| return ret; |
| } |
| |
| #ifdef MONITOR_LOG_SYNC |
| status_t ExynosCameraPipe::syncLog(uint32_t syncId) |
| { |
| CLOGD("DEBUG(%s[%d])", __FUNCTION__, __LINE__); |
| int ret = 0; |
| |
| ret = m_mainNode->setControl(V4L2_CID_IS_DEBUG_SYNC_LOG, syncId); |
| if (ret != NO_ERROR) |
| CLOGE("ERR(%s):m_mainNode->setControl failed", __FUNCTION__); |
| |
| return ret; |
| } |
| #endif |
| bool ExynosCameraPipe::m_isReprocessing(void) |
| { |
| return m_reprocessing == 1 ? true : false; |
| } |
| |
| bool ExynosCameraPipe::m_checkThreadLoop(void) |
| { |
| Mutex::Autolock lock(m_pipeframeLock); |
| bool loop = false; |
| |
| if (m_isReprocessing() == false) |
| loop = true; |
| |
| if (m_inputFrameQ->getSizeOfProcessQ() > 0) |
| loop = true; |
| |
| if (m_flagTryStop == true) |
| loop = false; |
| |
| return loop; |
| } |
| |
| void ExynosCameraPipe::m_dumpRunningFrameList(void) |
| { |
| CLOGI("DEBUG(%s[%d]):*********runningFrameList dump***********", __FUNCTION__, __LINE__); |
| CLOGI("DEBUG(%s[%d]):m_numBuffers : %d", __FUNCTION__, __LINE__, m_numBuffers); |
| for (uint32_t i = 0; i < m_numBuffers; i++) { |
| if (m_runningFrameList[i] == NULL) { |
| CLOGI("DEBUG:runningFrameList[%d] is NULL", i); |
| } else { |
| CLOGI("DEBUG:runningFrameList[%d]: fcount = %d", |
| i, m_runningFrameList[i]->getFrameCount()); |
| } |
| } |
| } |
| |
| void ExynosCameraPipe::m_dumpPerframeNodeGroupInfo(const char *name, camera_pipe_perframe_node_group_info_t nodeInfo) |
| { |
| if (name != NULL) |
| CLOGI("DEBUG(%s[%d]):(%s) ++++++++++++++++++++", __FUNCTION__, __LINE__, 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); |
| CLOGI("\t\t perFrameCaptureInfo[0].perFrameVideoID : %d", nodeInfo.perFrameCaptureInfo[0].perFrameVideoID); |
| CLOGI("\t\t perFrameCaptureInfo[1].perFrameVideoID : %d", nodeInfo.perFrameCaptureInfo[1].perFrameVideoID); |
| |
| if (name != NULL) |
| CLOGI("DEBUG(%s[%d]):(%s) ------------------------------", __FUNCTION__, __LINE__, name); |
| } |
| |
| void ExynosCameraPipe::m_configDvfs(void) { |
| bool newDvfs = m_parameters->getDvfsLock(); |
| |
| if (newDvfs != m_dvfsLocked) { |
| setControl(V4L2_CID_IS_DVFS_LOCK, 533000); |
| m_dvfsLocked = newDvfs; |
| } |
| } |
| |
| }; /* namespace android */ |