#define LOG_NDEBUG 0 #define LOG_TAG "EISDevice" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "EISDevice.h" #include "EISChannel.h" #include using namespace std; namespace EyeseeLinux{ // register proxy of other module to EIS status_t EISDevice::CameraProxyInfo::SetCameraChannelInfo(EIS_CameraChannelInfo *pCameraChnInfo) { if (mpCameraProxy != NULL) { delete mpCameraProxy; mpCameraProxy = NULL; } if(pCameraChnInfo->mpCameraRecordingProxy) { mpCameraProxy = pCameraChnInfo->mpCameraRecordingProxy; mnCameraChannel = pCameraChnInfo->mnCameraChannel; } else { aloge("fatal error! camera == NULL"); } return NO_ERROR; } // move frm node from used_frame_list to waiting_release_list // function calling will happen when the input frame sent to EIS component has been processed. status_t EISDevice::CameraProxyInfo::addReleaseFrame(VIDEO_FRAME_INFO_S *pVIFrame) { bool bFindFlag = false; int matchCount = 0; AutoMutex lock(mFrameBufListLock); std::list::iterator firstOne; for(std::list::iterator it=mUsedFrameBufList.begin(); it!=mUsedFrameBufList.end(); ++it) { if(it->mFrameBuf.mId == pVIFrame->mId) { matchCount++; if(!bFindFlag) { bFindFlag = true; firstOne = it; } } } if(0 == matchCount) { aloge("fatal error! not find frameId[0x%x]!", pVIFrame->mId); } else { if(firstOne != mUsedFrameBufList.begin()) { aloge("fatal error! MPP-EIS release frame is not first one of mUsedFrameBufList!"); } if(matchCount > 1) { aloge("fatal error! find [%d] matched frames in mUsedFrameBufList!", matchCount); } mWaitReleaseFrameBufList.splice(mWaitReleaseFrameBufList.end(), mUsedFrameBufList, firstOne); } return NO_ERROR; } EISDevice::CameraProxyInfo::CameraProxyInfo() { mpCameraProxy = NULL; mnCameraChannel = 0;; mIdleFrameBufList.resize(12); // add more nodes, since eis need 8 frm at least. } EISDevice::CameraProxyInfo::CameraProxyInfo(const CameraProxyInfo& ref) { mpCameraProxy = ref.mpCameraProxy; mnCameraChannel = ref.mnCameraChannel; mIdleFrameBufList = ref.mIdleFrameBufList; mReadyFrameBufList = ref.mReadyFrameBufList; mUsedFrameBufList = ref.mUsedFrameBufList; mWaitReleaseFrameBufList = ref.mWaitReleaseFrameBufList; mReleasingFrameBufList = ref.mReleasingFrameBufList; } EISDevice::CameraProxyInfo::~CameraProxyInfo() { if(mReadyFrameBufList.size()>0 || mUsedFrameBufList.size()>0 ||mWaitReleaseFrameBufList.size()>0 || mReleasingFrameBufList.size()>0) { aloge("fatal error! why cameraProxy[%p] vipp[%d] still has [%d][%d][%d][%d]frames?", mpCameraProxy, mnCameraChannel, mReadyFrameBufList.size(), mUsedFrameBufList.size(), mWaitReleaseFrameBufList.size(), mReleasingFrameBufList.size()); } if (mpCameraProxy != NULL) { delete mpCameraProxy; mpCameraProxy = NULL; } } /* EIS listener for proxy use */ EISDevice::CameraProxyListener::CameraProxyListener(EISDevice *pEis, int nCameraIndex) { mpEis = pEis; mCameraIndex = nCameraIndex; } void EISDevice::CameraProxyListener::dataCallbackTimestamp(const void *pdata) { mpEis->dataCallbackTimestamp(mCameraIndex, (const VIDEO_FRAME_BUFFER_S*)pdata); } /* Threads defined for input frame process */ //SendPicThread start ---> EISDevice::DoSendPicThread::DoSendPicThread(EISDevice *pEisDev) :mpEisDev(pEisDev) { mbWaitInputFrameBuf = false; mSendPicThreadState = EIS_SENDPIC_STATE_LOADED; mbThreadOK = true; if(NO_ERROR != run("EISSendPicThread")) { aloge("fatal error! create thread fail");; mbThreadOK = false; } } EISDevice::DoSendPicThread::~DoSendPicThread() { SendPicThreadReset(); EyeseeMessage msg; msg.mMsgType = MsgTypeSendPic_Exit; mSendPicMsgQueue.queueMessage(&msg); requestExitAndWait(); mSendPicMsgQueue.flushMessage(); } status_t EISDevice::DoSendPicThread::SendPicThreadStart() { AutoMutex autoLock(mLock); AutoMutex autoLock2(mStateLock); if(mSendPicThreadState == EIS_SENDPIC_STATE_STARTED) { alogd("already in started"); return NO_ERROR; } if(mSendPicThreadState != EIS_SENDPIC_STATE_LOADED && mSendPicThreadState != EIS_SENDPIC_STATE_PAUSED) { aloge("fatal error! can't call in state[0x%x]", mSendPicThreadState); return INVALID_OPERATION; } EyeseeMessage msg; msg.mMsgType = MsgTypeSendPic_SetState; msg.mPara0 = EIS_SENDPIC_STATE_STARTED; mSendPicMsgQueue.queueMessage(&msg); while(EIS_SENDPIC_STATE_STARTED != mSendPicThreadState) { mStartCompleteCond.wait(mStateLock); } return NO_ERROR; } status_t EISDevice::DoSendPicThread::SendPicThreadPause() { AutoMutex autoLock(mLock); AutoMutex autoLock2(mStateLock); if(mSendPicThreadState == EIS_SENDPIC_STATE_PAUSED) { alogd("already in paused"); return NO_ERROR; } if(mSendPicThreadState != EIS_SENDPIC_STATE_STARTED) { aloge("fatal error! can't call in state[0x%x]", mSendPicThreadState); return INVALID_OPERATION; } EyeseeMessage msg; msg.mMsgType = MsgTypeSendPic_SetState; msg.mPara0 = EIS_SENDPIC_STATE_PAUSED; mSendPicMsgQueue.queueMessage(&msg); while(EIS_SENDPIC_STATE_PAUSED != mSendPicThreadState) { mPauseCompleteCond.wait(mStateLock); } return NO_ERROR; } status_t EISDevice::DoSendPicThread::SendPicThreadReset() { AutoMutex autoLock(mLock); { AutoMutex autoLock2(mStateLock); if(mSendPicThreadState != EIS_SENDPIC_STATE_LOADED) { EyeseeMessage msg; msg.mMsgType = MsgTypeSendPic_SetState; msg.mPara0 = EIS_SENDPIC_STATE_LOADED; mSendPicMsgQueue.queueMessage(&msg); while(EIS_SENDPIC_STATE_LOADED != mSendPicThreadState) { mLoadedCompleteCond.wait(mStateLock); } } } mbWaitInputFrameBuf = false; return NO_ERROR; } status_t EISDevice::DoSendPicThread::SendMessage_InputFrameReady() { mbWaitInputFrameBuf = false; EyeseeMessage msg; msg.mMsgType = DoSendPicThread::MsgTypeSendPic_InputFrameAvailable; mSendPicMsgQueue.queueMessage(&msg); return NO_ERROR; } bool EISDevice::DoSendPicThread::threadLoop() { if(!exitPending()) { return sendPicThread(); } else { return false; } } bool EISDevice::DoSendPicThread::sendPicThread() // send,means send current frm got from ready list,to EIS component { bool bRunningFlag = true; status_t getMsgRet; ERRORTYPE ret; EyeseeMessage msg; while(1) { PROCESS_MESSAGE: getMsgRet = mSendPicMsgQueue.dequeueMessage(&msg); if(getMsgRet == NO_ERROR) { if(MsgTypeSendPic_SetState == msg.mMsgType) { AutoMutex autoLock(mStateLock); if(msg.mPara0 == mSendPicThreadState) { aloge("fatal error! same state[0x%x]", mSendPicThreadState); } else if(EIS_SENDPIC_STATE_LOADED == msg.mPara0) { alogd("sendPic thread state[0x%x]->loaded", mSendPicThreadState); mSendPicThreadState = EIS_SENDPIC_STATE_LOADED; mLoadedCompleteCond.signal(); } else if(EIS_SENDPIC_STATE_PAUSED == msg.mPara0) { alogd("sendPic thread state[0x%x]->paused", mSendPicThreadState); mSendPicThreadState = EIS_SENDPIC_STATE_PAUSED; mPauseCompleteCond.signal(); } else if(EIS_SENDPIC_STATE_STARTED == msg.mPara0) { alogd("sendPic thread state[0x%x]->started", mSendPicThreadState); mSendPicThreadState = EIS_SENDPIC_STATE_STARTED; mStartCompleteCond.signal(); } else { aloge("fatal error! check code!"); } } else if(MsgTypeSendPic_InputFrameAvailable == msg.mMsgType) { //alogv("input frame come"); } else if(MsgTypeSendPic_Exit == msg.mMsgType) { bRunningFlag = false; goto _exit0; } else { aloge("unknown msg[0x%x]!", msg.mMsgType); } goto PROCESS_MESSAGE; } if(EIS_SENDPIC_STATE_STARTED == mSendPicThreadState) { for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); } unsigned int minFrameNum = (unsigned int)-1; unsigned int maxFrameNum = 0; unsigned int sendFrameNum = 0; for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { if(it->mReadyFrameBufList.size() < minFrameNum) { minFrameNum = it->mReadyFrameBufList.size(); } if(it->mReadyFrameBufList.size() > maxFrameNum) { maxFrameNum = it->mReadyFrameBufList.size(); } sendFrameNum = maxFrameNum;//(EISMODE_ONE_FISHEYE == mpEisDev->mEisAttr.iseMode) ? maxFrameNum : minFrameNum; VIDEO_FRAME_INFO_S *pbuf0; VIDEO_FRAME_INFO_S *pbuf1; for(unsigned int i=0; imReadyFrameBufList.begin()->mFrameBuf; pbuf1 = NULL; ret = AW_MPI_EIS_SendPic(mpEisDev->mGroupId, pbuf0, -1); if (ret != SUCCESS) { // move to waitReleaseList directly it->mWaitReleaseFrameBufList.splice(it->mWaitReleaseFrameBufList.end(), it->mReadyFrameBufList, it->mReadyFrameBufList.begin()); aloge("fatal error! why MPP-EIS can't accept new frame! check code!"); } else { it->mUsedFrameBufList.splice(it->mUsedFrameBufList.end(), it->mReadyFrameBufList, it->mReadyFrameBufList.begin()); } } } mbWaitInputFrameBuf = true; for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.unlock(); } mSendPicMsgQueue.waitMessage(); } else { mSendPicMsgQueue.waitMessage(); } } return true; _exit0: return bRunningFlag; } // doSendPicThread end <--- // DoReturnPicThread start --> EISDevice::DoReturnPicThread::DoReturnPicThread(EISDevice *pEisDev) :mpEisDev(pEisDev) { mbWaitInputFrameBuf = false; mState = EIS_RETURNPIC_STATE_LOADED; mbThreadOK = true; if(NO_ERROR != run("EISReturnPic")) { aloge("fatal error! create thread fail"); mbThreadOK = false; } } EISDevice::DoReturnPicThread::~DoReturnPicThread() { Reset(); EyeseeMessage msg; msg.mMsgType = MsgTypeReturnPic_Exit; mMsgQueue.queueMessage(&msg); requestExitAndWait(); mMsgQueue.flushMessage(); } status_t EISDevice::DoReturnPicThread::Start() { AutoMutex autoLock(mLock); if(mState == EIS_RETURNPIC_STATE_STARTED) { alogd("already in started"); return NO_ERROR; } if(mState != EIS_RETURNPIC_STATE_LOADED) { aloge("fatal error! can't call in state[0x%x]", mState); return INVALID_OPERATION; } EyeseeMessage msg; msg.mMsgType = MsgTypeReturnPic_SetState; msg.mPara0 = EIS_RETURNPIC_STATE_STARTED; mMsgQueue.queueMessage(&msg); return NO_ERROR; } status_t EISDevice::DoReturnPicThread::Reset() { AutoMutex autoLock(mLock); EyeseeMessage msg; msg.mMsgType = MsgTypeReturnPic_ReturnAllFrames; mMsgQueue.queueMessage(&msg); msg.reset(); msg.mMsgType = MsgTypeReturnPic_SetState; msg.mPara0 = EIS_RETURNPIC_STATE_LOADED; mMsgQueue.queueMessage(&msg); AutoMutex autoLock2(mStateLock); while(mState != EIS_RETURNPIC_STATE_LOADED) { mStateCond.wait(mStateLock); } mbWaitInputFrameBuf = false; return NO_ERROR; } status_t EISDevice::DoReturnPicThread::notifyReturnPictureCome() { AutoMutex lock(mInputFrameLock); if(mbWaitInputFrameBuf) { mbWaitInputFrameBuf = false; EyeseeMessage msg; msg.mMsgType = MsgTypeReturnPic_InputFrameAvailable; mMsgQueue.queueMessage(&msg); } return NO_ERROR; } status_t EISDevice::DoReturnPicThread::SendCommand_ReturnAllFrames() { EyeseeMessage msg; msg.mMsgType = MsgTypeReturnPic_ReturnAllFrames; mMsgQueue.queueMessage(&msg); return NO_ERROR; } bool EISDevice::DoReturnPicThread::threadLoop() { if(!exitPending()) { return returnPicThread(); } else { return false; } } status_t EISDevice::DoReturnPicThread::returnAllFrames() { bool bHasFrame; // return all waitReleaseFrames while(1) { bHasFrame = false; for(std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); if(!it->mWaitReleaseFrameBufList.empty()) { bHasFrame = true; if(!it->mReleasingFrameBufList.empty()) { aloge("fatal error! check code!"); } it->mReleasingFrameBufList.splice(it->mReleasingFrameBufList.end(), it->mWaitReleaseFrameBufList, it->mWaitReleaseFrameBufList.begin()); it->mFrameBufListLock.unlock(); it->mpCameraProxy->releaseRecordingFrame(it->mnCameraChannel, it->mReleasingFrameBufList.begin()->mFrameBuf.mId); it->mFrameBufListLock.lock(); it->mIdleFrameBufList.splice(it->mIdleFrameBufList.end(), it->mReleasingFrameBufList); it->mFrameBufListLock.unlock(); } else { it->mFrameBufListLock.unlock(); } } if(!bHasFrame) { break; } } // return all readyFrames while(1) { bHasFrame = false; for(std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); if(!it->mReadyFrameBufList.empty()) { bHasFrame = true; if(!it->mReleasingFrameBufList.empty()) { aloge("fatal error! check code!"); } it->mReleasingFrameBufList.splice(it->mReleasingFrameBufList.end(), it->mReadyFrameBufList, it->mReadyFrameBufList.begin()); it->mFrameBufListLock.unlock(); it->mpCameraProxy->releaseRecordingFrame(it->mnCameraChannel, it->mReleasingFrameBufList.begin()->mFrameBuf.mId); it->mFrameBufListLock.lock(); it->mIdleFrameBufList.splice(it->mIdleFrameBufList.end(), it->mReleasingFrameBufList); it->mFrameBufListLock.unlock(); } else { it->mFrameBufListLock.unlock(); } } if(!bHasFrame) { break; } } // return all frm in mUsedFrameBufList while(1) { bHasFrame = false; for(std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); if(!it->mUsedFrameBufList.empty()) { bHasFrame = true; if(!it->mReleasingFrameBufList.empty()) { aloge("fatal error! check code!"); } it->mReleasingFrameBufList.splice(it->mReleasingFrameBufList.end(), it->mUsedFrameBufList, it->mUsedFrameBufList.begin()); it->mFrameBufListLock.unlock(); it->mpCameraProxy->releaseRecordingFrame(it->mnCameraChannel, it->mReleasingFrameBufList.begin()->mFrameBuf.mId); it->mFrameBufListLock.lock(); it->mIdleFrameBufList.splice(it->mIdleFrameBufList.end(), it->mReleasingFrameBufList); it->mFrameBufListLock.unlock(); } else { it->mFrameBufListLock.unlock(); } } if(!bHasFrame) { break; } } //check again int nCameraIndex = 0; for(std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); if(it->mReadyFrameBufList.size()>0 || it->mUsedFrameBufList.size()>0 || it->mWaitReleaseFrameBufList.size()>0 || it->mReleasingFrameBufList.size()>0) { aloge("fatal error! why cameraProxy[%p] camIdx[%d] vipp[%d] still has [%d][%d][%d][%d]frames?", it->mpCameraProxy, nCameraIndex, it->mnCameraChannel, it->mReadyFrameBufList.size(), it->mUsedFrameBufList.size(), it->mWaitReleaseFrameBufList.size(), it->mReleasingFrameBufList.size()); } it->mFrameBufListLock.unlock(); nCameraIndex++; } return NO_ERROR; } // this thread process waiting_release_frm_list ,releasingFrmList,and call function to release frm used done samuel.zhou bool EISDevice::DoReturnPicThread::returnPicThread() { bool bRunningFlag = true; EyeseeMessage msg; status_t getMsgRet; ERRORTYPE ret; while(1) { PROCESS_MESSAGE: getMsgRet = mMsgQueue.dequeueMessage(&msg); if(getMsgRet == NO_ERROR) { if(MsgTypeReturnPic_SetState == msg.mMsgType) { AutoMutex autoLock(mStateLock); if(msg.mPara0 == mState) { alogd("same state[0x%x]", mState); } else if(EIS_RETURNPIC_STATE_LOADED == msg.mPara0) { //returnAllFrames(); alogd("returnPic thread state[0x%x]->loaded", mState); mState = EIS_RETURNPIC_STATE_LOADED; } else if(EIS_RETURNPIC_STATE_STARTED == msg.mPara0) { alogd("returnPic thread state[0x%x]->started", mState); mState = EIS_RETURNPIC_STATE_STARTED; } else { aloge("fatal error! wrong state[0x%x]!", msg.mPara0); } mStateCond.signal(); } else if(MsgTypeReturnPic_InputFrameAvailable == msg.mMsgType) { //alogv("input frame come"); } else if(MsgTypeReturnPic_ReturnAllFrames == msg.mMsgType) { returnAllFrames(); } else if(MsgTypeReturnPic_Exit == msg.mMsgType) { returnAllFrames(); bRunningFlag = false; goto _exit0; } else { aloge("unknown msg[0x%x]!", msg.mMsgType); } goto PROCESS_MESSAGE; } if(EIS_RETURNPIC_STATE_STARTED == mState) { bool bHasFrame; while(1) { bHasFrame = false; for(std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); if(!it->mWaitReleaseFrameBufList.empty()) // frame has been moved to this mWaitReleaseFrameBufList samuel.zhou { bHasFrame = true; if(!it->mReleasingFrameBufList.empty()) { aloge("fatal error! check code!"); } it->mReleasingFrameBufList.splice(it->mReleasingFrameBufList.end(), it->mWaitReleaseFrameBufList, it->mWaitReleaseFrameBufList.begin()); it->mFrameBufListLock.unlock(); it->mpCameraProxy->releaseRecordingFrame(it->mnCameraChannel, it->mReleasingFrameBufList.begin()->mFrameBuf.mId); // releaseRecordingFrame() function of camara proxy samuel.zhou it->mFrameBufListLock.lock(); it->mIdleFrameBufList.splice(it->mIdleFrameBufList.end(), it->mReleasingFrameBufList); it->mFrameBufListLock.unlock(); } else { it->mFrameBufListLock.unlock(); } } if(!bHasFrame) { //if all cameraproxies has no frame, check them again! for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); } for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { if(!it->mWaitReleaseFrameBufList.empty()) { bHasFrame = true; break; } } if(!bHasFrame) { mInputFrameLock.lock(); mbWaitInputFrameBuf = true; mInputFrameLock.unlock(); } for (std::vector::iterator it = mpEisDev->mCameraProxies.begin(); it!=mpEisDev->mCameraProxies.end(); ++it) { it->mFrameBufListLock.unlock(); } if(!bHasFrame) { break; } } } mMsgQueue.waitMessage(); } else { mMsgQueue.waitMessage(); } } return true; _exit0: return bRunningFlag; } //DoReturnPicThread end <-- //DoCaptureThread start --> EISDevice::DoCaptureThread::DoCaptureThread(EISDevice *pEisDev) : mpEisDev(pEisDev) { mCapThreadState = EIS_CAPTURE_STATE_LOADED; mbThreadOK = true; if(NO_ERROR != run("EISCaptureThread")) { aloge("fatal error! create thread fail");; mbThreadOK = false; } } EISDevice::DoCaptureThread::~DoCaptureThread() { CaptureThreadReset(); EyeseeMessage msg; msg.mMsgType = MsgTypeCapture_Exit; mCaptureMsgQueue.queueMessage(&msg); requestExitAndWait(); mCaptureMsgQueue.flushMessage(); } status_t EISDevice::DoCaptureThread::CaptureThreadStart() { AutoMutex autoLock(mLock); AutoMutex autoLock2(mStateLock); if(mCapThreadState == EIS_CAPTURE_STATE_STARTED) { alogd("already in started"); return NO_ERROR; } if(mCapThreadState != EIS_CAPTURE_STATE_LOADED && mCapThreadState != EIS_CAPTURE_STATE_PAUSED) { aloge("fatal error! can't call in state[0x%x]", mCapThreadState); return INVALID_OPERATION; } EyeseeMessage msg; msg.mMsgType = MsgTypeCapture_SetState; msg.mPara0 = EIS_CAPTURE_STATE_STARTED; mCaptureMsgQueue.queueMessage(&msg); while(EIS_CAPTURE_STATE_STARTED != mCapThreadState) { mStartCompleteCond.wait(mStateLock); } return NO_ERROR; } status_t EISDevice::DoCaptureThread::CaptureThreadPause() { AutoMutex autoLock(mLock); AutoMutex autoLock2(mStateLock); if(mCapThreadState == EIS_CAPTURE_STATE_PAUSED) { alogd("already in paused"); return NO_ERROR; } if(mCapThreadState != EIS_CAPTURE_STATE_STARTED) { aloge("fatal error! can't call in state[0x%x]", mCapThreadState); return INVALID_OPERATION; } EyeseeMessage msg; msg.mMsgType = MsgTypeCapture_SetState; msg.mPara0 = EIS_CAPTURE_STATE_PAUSED; mCaptureMsgQueue.queueMessage(&msg); while(EIS_CAPTURE_STATE_PAUSED != mCapThreadState) { mPauseCompleteCond.wait(mStateLock); } return NO_ERROR; } status_t EISDevice::DoCaptureThread::CaptureThreadReset() { AutoMutex autoLock(mLock); AutoMutex autoLock2(mStateLock); if(mCapThreadState != EIS_CAPTURE_STATE_LOADED) { EyeseeMessage msg; msg.mMsgType = MsgTypeCapture_SetState; msg.mPara0 = EIS_CAPTURE_STATE_LOADED; mCaptureMsgQueue.queueMessage(&msg); while(EIS_CAPTURE_STATE_LOADED != mCapThreadState) { mLoadedCompleteCond.wait(mStateLock); } } return NO_ERROR; } bool EISDevice::DoCaptureThread::threadLoop() { if(!exitPending()) { return captureThread(); } else { return false; } } bool EISDevice::DoCaptureThread::captureThread() { bool bRunningFlag = true; status_t getMsgRet; int ret; EyeseeMessage msg; while(1) { PROCESS_MESSAGE: getMsgRet = mCaptureMsgQueue.dequeueMessage(&msg); if(getMsgRet == NO_ERROR) { if(MsgTypeCapture_SetState == msg.mMsgType) { AutoMutex autoLock(mStateLock); if(msg.mPara0 == mCapThreadState) { aloge("fatal error! same state[0x%x]", mCapThreadState); } else if(EIS_CAPTURE_STATE_LOADED == msg.mPara0) { alogd("capture thread state[0x%x]->loaded", mCapThreadState); mCapThreadState = EIS_CAPTURE_STATE_LOADED; mLoadedCompleteCond.signal(); } else if(EIS_CAPTURE_STATE_PAUSED == msg.mPara0) { alogd("capture thread state[0x%x]->paused", mCapThreadState); mCapThreadState = EIS_CAPTURE_STATE_PAUSED; mPauseCompleteCond.signal(); } else if(EIS_CAPTURE_STATE_STARTED == msg.mPara0) { alogd("capture thread state[0x%x]->started", mCapThreadState); mCapThreadState = EIS_CAPTURE_STATE_STARTED; mStartCompleteCond.signal(); } else { aloge("fatal error! check code!"); } } else if(MsgTypeCapture_Exit == msg.mMsgType) { bRunningFlag = false; goto _exit0; } else { aloge("unknown msg[0x%x]!", msg.mMsgType); } goto PROCESS_MESSAGE; } if(EIS_CAPTURE_STATE_STARTED == mCapThreadState) { //AutoMutex autoLock(mpEisDev->mEISChannelVectorLock); for (vector::iterator it = mpEisDev->mEISChannelVector.begin(); it != mpEisDev->mEISChannelVector.end(); ++it) { it->mpChannel->process(); } } else { mCaptureMsgQueue.waitMessage(); } } _exit0: return bRunningFlag; } // DoCaptureThread end <--- EISDevice::EISDevice(unsigned int nEISId) : mEISId(nEISId) , mDevState(EIS_STATE_CONSTRUCTED) , mpSendPicThread(NULL) , mpCapThread(NULL) { alogd("Construct"); // memset(&mIseAttr, 0, sizeof(mIseAttr)); mpSendPicThread = new DoSendPicThread(this); mpReturnPicThread = new DoReturnPicThread(this); mpCapThread = new DoCaptureThread(this); memset(&mEisChnAttr,0,sizeof(mEisChnAttr)); mColorSpace = V4L2_COLORSPACE_JPEG; //MPP components // mEISGroup.mModId = MOD_ID_EIS; // mEISGroup.mDevId = MM_INVALID_DEV; // mEISGroup.mChnId = MM_INVALID_CHN; mGroupId = MM_INVALID_DEV; } EISDevice::~EISDevice() { alogd("Destruct"); reset(); delete mpSendPicThread; delete mpReturnPicThread; delete mpCapThread; } EISChannel *EISDevice::searchEISChannel(int chnId) { AutoMutex lock(mEISChannelVectorLock); for (vector::iterator it = mEISChannelVector.begin(); it != mEISChannelVector.end(); ++it) { if (it->mChnId== chnId) { return it->mpChannel; } } return NULL; } status_t EISDevice::prepare(EIS_ATTR_S *pEisChnAttr) { AutoMutex lock(mLock); status_t result; if(mDevState != EIS_STATE_CONSTRUCTED) { aloge("prepare in error state %d", mDevState); return INVALID_OPERATION; } if(mCameraProxies.size()>0) { CameraParameters CameraChannelParam; mCameraProxies[0].mpCameraProxy->getParameters(mCameraProxies[0].mnCameraChannel, CameraChannelParam); mColorSpace = CameraChannelParam.getColorSpace(); } else { alogd("no camera set?"); } memcpy(&mEisChnAttr,pEisChnAttr,sizeof(EIS_ATTR_S)); ERRORTYPE ret; bool bSuccessFlag = false; //mISEGroup.mDevId = 0; mGroupId = 0; while(mGroupId < MAX_EIS_CHN_NUM) { ret = AW_MPI_EIS_CreateChn(mGroupId, &mEisChnAttr); if(SUCCESS == ret) { bSuccessFlag = true; alogd("create EIS chl[%d] success!", mGroupId); break; } else if(ERR_EIS_EXIST == ret) { alogd("EIS chl[%d] is exist, find next!", mGroupId); mGroupId++; } else { alogd("create EIS chl[%d] ret[0x%x], find next!", mGroupId, ret); mGroupId++; } } if(false == bSuccessFlag) { mGroupId = MM_INVALID_DEV; aloge("fatal error! create ISE chl fail!"); return UNKNOWN_ERROR; } MPPCallbackInfo cbInfo; cbInfo.cookie = (void*)this; cbInfo.callback = (MPPCallbackFuncType)&MPPCallbackWrapper; ret = AW_MPI_EIS_RegisterCallback(mGroupId, &cbInfo); if(SUCCESS != ret) { aloge("register callback to mpi_eis fail"); } mDevState = EIS_STATE_PREPARED; return NO_ERROR; } status_t EISDevice::release_l() { if (mDevState != EIS_STATE_PREPARED) { aloge("release in error state %d", mDevState); return INVALID_OPERATION; } mpSendPicThread->SendPicThreadReset(); mpReturnPicThread->Reset(); mpCapThread->CaptureThreadReset(); ERRORTYPE ret = AW_MPI_EIS_DestroyChn(mGroupId); if (ret != SUCCESS) { aloge("fatal error! AW_MPI_EIS_DestroyChn error!"); } mGroupId = MM_INVALID_DEV; mDevState = EIS_STATE_CONSTRUCTED; return NO_ERROR; } status_t EISDevice::release() { AutoMutex lock(mLock); return release_l(); } status_t EISDevice::start() { AutoMutex lock(mLock); if(mDevState == EIS_STATE_STARTED) { alogd("already in state started"); return NO_ERROR; } if (mDevState != EIS_STATE_PREPARED) { aloge("start in error state %d", mDevState); return INVALID_OPERATION; } //judge if camera is set successful. { bool bCameraOK = true; if(mCameraProxies.size() > 0) { for(std::vector::iterator it=mCameraProxies.begin(); it!=mCameraProxies.end(); ++it) { if(NULL == it->mpCameraProxy) { aloge("Camera is not set yet?"); bCameraOK = false; } } } else { aloge("no camera set?"); bCameraOK = false; } if(!bCameraOK) { return INVALID_OPERATION; } } ERRORTYPE ret = AW_MPI_EIS_StartChn(mGroupId); if (ret != SUCCESS) { aloge("AW_MPI_EIS_Start error!"); return UNKNOWN_ERROR; } mDevState = EIS_STATE_STARTED; //start sendPic_thread and capture_thread. mpSendPicThread->SendPicThreadStart(); mpReturnPicThread->Start(); mpCapThread->CaptureThreadStart(); for(unsigned int i=0; istartRecording( mCameraProxies[i].mnCameraChannel, new CameraProxyListener(this, i), (int)mEISId); } // CameraParameters camParam; // getParameters(0, camParam); return NO_ERROR; } status_t EISDevice::stop_l() { if (mDevState != EIS_STATE_STARTED) { aloge("stop in error state %d", mDevState); return INVALID_OPERATION; } //pause capture thread mpCapThread->CaptureThreadPause(); //stop camera sending frame here. for(unsigned int i=0; istopRecording(mCameraProxies[i].mnCameraChannel, (int)mEISId); } //pause sendPic thread mpSendPicThread->SendPicThreadPause(); { AutoMutex lock(mEISChannelVectorLock); for (vector::iterator it = mEISChannelVector.begin(); it != mEISChannelVector.end(); ++it) { #if 0 //by andy it->mpChannel->stopPreview(); it->mpChannel->releaseAllEISFrames(); #else it->mpChannel->stopChannel(); #endif } } //stop EIS AW_MPI_EIS_StopChn(mGroupId); //let return Pic thread return all frames. mpReturnPicThread->SendCommand_ReturnAllFrames(); mDevState = EIS_STATE_PREPARED; return NO_ERROR; } status_t EISDevice::stop() { AutoMutex lock(mLock); return stop_l(); } status_t EISDevice::reset() { status_t ret; AutoMutex lock(mLock); alogd("reset"); if(EIS_STATE_CONSTRUCTED == mDevState) { return NO_ERROR; } if(EIS_STATE_STARTED == mDevState) { ret = stop_l(); } if(EIS_STATE_PREPARED == mDevState) { ret = release_l(); } return NO_ERROR; } EIS_CHN EISDevice::openChannel(EIS_ATTR_S *pChnAttr) { AutoMutex lock(mLock); ERRORTYPE ret; EISChannelInfo eisChn; MPPCallbackInfo cbInfo; // need to move to the position after channel opening if(mDevState != EIS_STATE_PREPARED) { aloge("open channel in error state %d", mDevState); return INVALID_OPERATION; } EISChannel *pChannel = new EISChannel(mGroupId, pChnAttr); if(NULL != pChannel) { eisChn.mChnId = pChannel->getChannelId(); eisChn.mpChannel = pChannel; AutoMutex lock(mEISChannelVectorLock); mEISChannelVector.push_back(eisChn); return eisChn.mChnId; } else { return MM_INVALID_CHN; } } status_t EISDevice::closeChannel(EIS_CHN chnId) { AutoMutex lock(mLock); if(mDevState != EIS_STATE_PREPARED) { aloge("close channel in error state %d", mDevState); return INVALID_OPERATION; } bool found = false; vector::iterator it; AutoMutex lock2(mEISChannelVectorLock); for (it = mEISChannelVector.begin(); it != mEISChannelVector.end(); ++it) { if (it->mChnId == chnId) { found = true; break; } } if (!found) { aloge("EIS scaler channel %d is not exist!", chnId); return INVALID_OPERATION; } delete it->mpChannel; mEISChannelVector.erase(it); return NO_ERROR; } status_t EISDevice::startChannel(EIS_CHN chnId) { AutoMutex lock(mLock); if(mDevState != EIS_STATE_PREPARED) { aloge("close channel in error state %d", mDevState); return INVALID_OPERATION; } bool found = false; vector::iterator it; AutoMutex lock2(mEISChannelVectorLock); for (it = mEISChannelVector.begin(); it != mEISChannelVector.end(); ++it) { if (it->mChnId == chnId) { found = true; break; } } if (!found) { aloge("EIS scaler channel %d is not exist!", chnId); return INVALID_OPERATION; } return it->mpChannel->startChannel(); } status_t EISDevice::setParameters(int chnId, CameraParameters ¶m) { EISChannel *pEisChn = searchEISChannel(chnId); if (pEisChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pEisChn->setParameters(param); } status_t EISDevice::getParameters(int chnId, CameraParameters ¶m) { EISChannel *pEisChn = searchEISChannel(chnId); if (pEisChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pEisChn->getParameters(param); } status_t EISDevice::setChannelDisplay(int chnId, int hlay) { EISChannel *pEisChn = searchEISChannel(chnId); if (pEisChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pEisChn->setChannelDisplay(hlay); } bool EISDevice::previewEnabled(int chnId) { EISChannel *pChannel = searchEISChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return false; } return pChannel->isPreviewEnabled(); } status_t EISDevice::startRender(int chnId) { EISChannel *pChannel = searchEISChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->startRender(); } status_t EISDevice::stopRender(int chnId) { EISChannel *pChannel = searchEISChannel(chnId); if (pChannel == NULL) { aloge("channel %d is not exist!", chnId); return NO_INIT; } return pChannel->stopRender(); } status_t EISDevice::setEISChnAttr(EIS_ATTR_S *pAttr) { bool found = false; vector::iterator it; EIS_CHN chnId = 0; AutoMutex lock2(mEISChannelVectorLock); for (it = mEISChannelVector.begin(); it != mEISChannelVector.end(); ++it) { if (it->mChnId == chnId) { found = true; break; } } if (true == found) { //only can update main_chn(portId=0) attr, do not update scale_chn! return AW_MPI_EIS_SetChnAttr(chnId, pAttr); } else { aloge("set EIS_SetChnAttr fail!"); return UNKNOWN_ERROR; } } void EISDevice::releaseRecordingFrame(int chnId, uint32_t index) // index: frm id samuel.zhou { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("EIS channel %d is not exist!", chnId); return; } pChn->releaseRecordingFrame(index); } status_t EISDevice::startRecording(int chnId, CameraRecordingProxyListener *pCb, int recorderId) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("EIS channel %d is not exist!", chnId); return NO_INIT; } return pChn->startRecording(pCb, recorderId); } status_t EISDevice::stopRecording(int chnId, int recorderId) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("EIS channel %d is not exist!", chnId); return NO_INIT; } return pChn->stopRecording(recorderId); } void EISDevice::setDataListener(int chnId, DataListener *pCb) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("EIS channel %d is not exist!", chnId); return; } pChn->setDataListener(pCb); } void EISDevice::setNotifyListener(int chnId, NotifyListener *pCb) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("EIS channel %d is not exist!", chnId); return; } pChn->setNotifyListener(pCb); } status_t EISDevice::takePicture(int chnId, unsigned int msgType, PictureRegionCallback *pPicReg) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pChn->takePicture(msgType, pPicReg); } status_t EISDevice::notifyPictureRelease(int chnId) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pChn->notifyPictureRelease(); } status_t EISDevice::cancelContinuousPicture(int chnId) { EISChannel *pChn = searchEISChannel(chnId); if (pChn == NULL) { aloge("channel %d is not exit!", chnId); return INVALID_OPERATION; } return pChn->cancelContinuousPicture(); } status_t EISDevice::setCamera(std::vector& cameraChannels) { if(cameraChannels.size() <= 0) { aloge("fatal error! none camera is set!"); return BAD_VALUE; } if (mDevState != EIS_STATE_PREPARED) { aloge("setCamera in error state %d", mDevState); return INVALID_OPERATION; } mCameraProxies.clear(); mCameraProxies.resize(cameraChannels.size()); int i = 0; for(std::vector::iterator it = mCameraProxies.begin(); it!=mCameraProxies.end(); ++it) { it->SetCameraChannelInfo(&cameraChannels[i++]); } return NO_ERROR; } // will be called by fram sender such as camara samuel.zhou void EISDevice::dataCallbackTimestamp(int nCameraIndex, const VIDEO_FRAME_BUFFER_S *pCameraFrameInfo) { //AutoMutex lock(mLock); if(NULL == pCameraFrameInfo) { aloge("fatal error! camera frame is NULL?"); return; } if (mDevState != EIS_STATE_STARTED) { alogd("Be careful! camera[%d] call dataCallbackTimestamp when eis device state is [0x%x]", nCameraIndex, mDevState); //mCameraProxies[nCameraIndex].mpCameraProxy->releaseRecordingFrame(mCameraProxies[nCameraIndex].mnCameraChannel, pCameraFrameInfo->mFrameBuf.mId); //return; } CameraProxyInfo& CameraProxy = mCameraProxies[nCameraIndex]; { AutoMutex lock(CameraProxy.mFrameBufListLock); if(CameraProxy.mIdleFrameBufList.empty()) { alogd("Be careful! EIS input IdleFrameBuf list is empty, increase!"); VIDEO_FRAME_BUFFER_S elem; memset(&elem, 0, sizeof(VIDEO_FRAME_BUFFER_S)); CameraProxy.mIdleFrameBufList.insert(CameraProxy.mIdleFrameBufList.end(), 12, elem); } memcpy(&CameraProxy.mIdleFrameBufList.front(), pCameraFrameInfo, sizeof(VIDEO_FRAME_BUFFER_S)); CameraProxy.mReadyFrameBufList.splice(CameraProxy.mReadyFrameBufList.end(), CameraProxy.mIdleFrameBufList, CameraProxy.mIdleFrameBufList.begin()); if(false == mpSendPicThread->mbWaitInputFrameBuf) { return; } } for (std::vector::iterator it = mCameraProxies.begin(); it!=mCameraProxies.end(); ++it) { it->mFrameBufListLock.lock(); } bool bFrameReady = true; for (std::vector::iterator it = mCameraProxies.begin(); it!=mCameraProxies.end(); ++it) { if(it->mReadyFrameBufList.empty()) { bFrameReady = false; break; } } if(bFrameReady) { mpSendPicThread->SendMessage_InputFrameReady(); } for (std::vector::iterator it = mCameraProxies.begin(); it!=mCameraProxies.end(); ++it) { it->mFrameBufListLock.unlock(); } } // will be called by mpi_eis void EISDevice::notify(MPP_CHN_S *pChn, MPP_EVENT_TYPE event, void *pEventData) { if(MOD_ID_EIS == pChn->mModId) { switch(event) { case MPP_EVENT_RELEASE_VIDEO_BUFFER: { //ise callback to notify return frame to camera VIDEO_FRAME_INFO_S *pbuf = (VIDEO_FRAME_INFO_S *)pEventData; if(pbuf != NULL) { mCameraProxies[0].addReleaseFrame(pbuf); } mpReturnPicThread->notifyReturnPictureCome(); break; } default: { //postEventFromNative(this, event, 0, 0, pEventData); aloge("fatal error! unknown event[0x%x] from EIS group[0x%x][0x%x][0x%x]!", event, pChn->mModId, pChn->mDevId, pChn->mChnId); break; } } } else { aloge("fatal error! another MPP MOD?"); } } ERRORTYPE EISDevice::MPPCallbackWrapper(void *cookie, MPP_CHN_S *pChn, MPP_EVENT_TYPE event, void *pEventData) { ((EISDevice*)cookie)->notify(pChn, event, pEventData); return SUCCESS; } };