sdk-hwV1.3/external/eyesee-mpp/framework/sun8iw21/media/camera/CallbackNotifier.cpp

1147 lines
38 KiB
C++
Executable File

/******************************************************************************
Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd.
******************************************************************************
File Name : CallbackNotifier.cpp
Version : Initial Draft
Author : Allwinner BU3-PD2 Team
Created : 2016/06/03
Last Modified :
Description : camera wrap MPP components.
Function List :
History :
******************************************************************************/
//#define LOG_NDEBUG 0
#define LOG_TAG "CallbackNotifier"
#include <utils/plat_log.h>
#include <stdlib.h>
#include <memory.h>
#include <type_camera.h>
#include <mpi_region.h>
#include <memoryAdapter.h>
#include "CallbackNotifier.h"
#include "CameraJpegEncoder.h"
#include <ModData.h>
#include <AdasData.h>
#include "VIDEO_FRAME_INFO_S.h"
//#include <ion_memmanager.h>
#define PictureThumbQuality_DEFAULT 60
using namespace std;
namespace EyeseeLinux {
static int getMeminfo(const char* pattern)
{
FILE* fp = fopen("/proc/meminfo", "r");
if (fp == NULL) {
return -1;
}
int result = -1;
char buf[256];
while (fgets(buf, sizeof(buf), fp) != NULL) {
if (sscanf(buf, pattern, &result) == 1) {
break;
}
}
fclose(fp);
return result;
}
static int getTotalMemory(void)
{
return getMeminfo("MemTotal: %d kB");
}
static int getFreeMemory(void)
{
return getMeminfo("MemFree: %d kB");
}
static int getCachedMemory(void)
{
return getMeminfo("Cached: %d kB");
}
static int getBuffersMemory(void)
{
return getMeminfo("Buffers: %d kB");
}
CallbackNotifier::DoSavePictureThread::DoSavePictureThread(CallbackNotifier *pCallbackNotifier)
: mpCallbackNotifier(pCallbackNotifier)
{
mbWaitPicture = false;
mbWaitReleasePicture = false;
}
status_t CallbackNotifier::DoSavePictureThread::startThread()
{
status_t ret = run("SavePictureTh");
if(ret != NO_ERROR)
{
aloge("fatal error! run thread fail!");
}
return ret;
}
void CallbackNotifier::DoSavePictureThread::stopThread()
{
EyeseeMessage msg;
msg.mMsgType = MsgTypeSavePic_Exit;
mMsgQueue.queueMessage(&msg);
join();
mMsgQueue.flushMessage();
}
status_t CallbackNotifier::DoSavePictureThread::notifyNewPictureCome()
{
AutoMutex lock(mWaitLock);
if(mbWaitPicture)
{
mbWaitPicture = false;
EyeseeMessage msg;
msg.mMsgType = MsgTypeSavePic_InputPictureAvailable;
mMsgQueue.queueMessage(&msg);
}
return NO_ERROR;
}
status_t CallbackNotifier::DoSavePictureThread::notifyPictureRelease()
{
AutoMutex lock(mWaitLock);
if(mbWaitReleasePicture)
{
mbWaitReleasePicture = false;
EyeseeMessage msg;
msg.mMsgType = MsgTypeSavePic_ReleasePicture;
mMsgQueue.queueMessage(&msg);
}
return NO_ERROR;
}
bool CallbackNotifier::DoSavePictureThread::threadLoop()
{
if(!exitPending())
{
return mpCallbackNotifier->savePictureThread();
}
else
{
return false;
}
}
CallbackNotifier::CallbackNotifier(int chnId, CameraBufferReference *pCbr)
: mChnId(chnId)
, mpCamBufRef(pCbr)
, mpDataCallback(NULL)
, mpNotifyCallback(NULL)
, mPictureWidth(640)
, mPictureHeight(480)
, mPictureThumbWidth(320)
, mPictureThumbHeight(240)
, mPictureThumbQuality(PictureThumbQuality_DEFAULT)
, mJpegQuality(90)
, mJpegRotate(0)
, mGpsLatitude(0.0)
, mGpsLongitude(0.0)
, mGpsAltitude(0.0)
, mGpsTimestamp(0)
, mpGpsProcessingMethod(NULL)
, mMessageEnabler(0)
, mpFolderPath(NULL)
, mpSnapPath(NULL)
, mSavePictureCnt(0)
, mpPictureRegionCallback(NULL)
{
alogv("CallbackNotifier construct");
mPictureNum = 1;
mpJpegenc = NULL;
mbWaitPicBufListEmpty = false;
memset(&mJpegEncConfig, 0, sizeof(CameraJpegEncConfig));
mpSavePicThread = new DoSavePictureThread(this);
mpSavePicThread->startThread();
}
CallbackNotifier::~CallbackNotifier()
{
alogv("CallbackNotifier destruct");
if (mpSavePicThread != NULL)
{
mpSavePicThread->stopThread();
delete mpSavePicThread;
}
if (mpGpsProcessingMethod != NULL) {
free(mpGpsProcessingMethod);
mpGpsProcessingMethod = NULL;
}
if (mpFolderPath != NULL) {
free(mpFolderPath);
mpFolderPath = NULL;
}
if (mpSnapPath != NULL) {
free(mpSnapPath);
mpSnapPath = NULL;
}
mPicBufLock.lock();
if(!mPicBufList.empty())
{
alogw("impossible! some pictureBuf not send, release them!");
// for (std::list<PictureBuffer>::iterator it = mPicBufList.begin(); it != mPicBufList.end(); ++it)
// {
// delete[] it->mpData;
// }
}
if(!mWaitReleasePicBufList.empty())
{
alogw("impossible! some pictureBuf not return, release them!");
// for (std::list<PictureBuffer>::iterator it = mWaitReleasePicBufList.begin(); it != mWaitReleasePicBufList.end(); ++it)
// {
// delete[] it->mpData;
// }
}
mPicBufLock.unlock();
if(mpJpegenc)
{
alogw("jpeg encoder is exist, maybe user sets keeping picture encoder? destroy now!");
destoryPictureRegion();
mpJpegenc->destroy();
delete mpJpegenc;
mpJpegenc = NULL;
}
}
status_t CallbackNotifier::NotifyRenderStart()
{
unsigned int nCameraMsgType = CAMERA_MSG_INFO; //CAMERA_MSG_COMPRESSED_IMAGE;
CameraMsgInfoType eMsgInfoType = CAMERA_INFO_RENDERING_START;
mpNotifyCallback->notify(nCameraMsgType, mChnId, eMsgInfoType, 0);
return NO_ERROR;
}
status_t CallbackNotifier::NotifyCameraDeviceTimeout()
{
unsigned int nCameraMsgType = CAMERA_MSG_ERROR;
CameraMsgErrorType eMsgInfoType = CAMERA_ERROR_SELECT_TIMEOUT;
mpNotifyCallback->notify(nCameraMsgType, mChnId, eMsgInfoType, 0);
return NO_ERROR;
}
status_t CallbackNotifier::NotifyG2DTimeout()
{
unsigned int nCameraMsgType = CAMERA_MSG_ERROR;
CameraMsgErrorType eMsgInfoType = CAMERA_ERROR_G2D_TIMEOUT;
mpNotifyCallback->notify(nCameraMsgType, mChnId, eMsgInfoType, 0);
return NO_ERROR;
}
status_t CallbackNotifier::NotifyCameraTakePicFail()
{
unsigned int nCameraMsgType = CAMERA_MSG_ERROR;
CameraMsgErrorType eMsgInfoType = CAMERA_ERROR_TAKE_PIC_FAIL;
mpNotifyCallback->notify(nCameraMsgType, mChnId, eMsgInfoType, 0);
return NO_ERROR;
}
int CallbackNotifier::onNextFrameAvailable(void* frame, int chnId)
{
int ret = 0;
AutoMutex lock(mRecListenerLock);
for (vector<RecordingProxyListener>::iterator it = mRecListener.begin(); it != mRecListener.end(); ++it)
{
if(it->mInputChnId == chnId)
{
mpCamBufRef->increaseBufRef((VIDEO_FRAME_BUFFER_S*)frame);
it->mpListener->dataCallbackTimestamp(frame);
}
else
{
alogw("Be careful! impossible chnId[%d]!=[%d]", it->mInputChnId, chnId);
}
}
return ret;
}
status_t CallbackNotifier::postMODData(std::shared_ptr<CMediaMemory>& spData)
{
unsigned int nCameraMsgType = 0; //CAMERA_MSG_COMPRESSED_IMAGE
nCameraMsgType |= CAMERA_MSG_MOD_DATA;
mpDataCallback->postData(nCameraMsgType, mChnId, spData, sizeof(MotionDetectResult));
return NO_ERROR;
}
status_t CallbackNotifier::postAdasData(std::shared_ptr<CMediaMemory>& spData)
{
unsigned int nCameraMsgType = 0; //CAMERA_MSG_COMPRESSED_IMAGE
nCameraMsgType |= CAMERA_MSG_ADAS_DATA;
mpDataCallback->postData(nCameraMsgType, mChnId, spData, sizeof(AW_AI_ADAS_DETECT_R_));
return NO_ERROR;
}
status_t CallbackNotifier::postFaceDetectData(std::shared_ptr<CMediaMemory>& spData)
{
unsigned int nCameraMsgType = 0; //CAMERA_MSG_COMPRESSED_IMAGE
nCameraMsgType |= CAMERA_MSG_FACEDETECT_DATA;
//mpDataCallback->postData(nCameraMsgType, mChnId, spData, sizeof(AW_AI_EVE_EVENT_RESULT_S));
return NO_ERROR;
}
status_t CallbackNotifier::postVLPRData(std::shared_ptr<CMediaMemory>& spData)
{
unsigned int nCameraMsgType = 0; //CAMERA_MSG_COMPRESSED_IMAGE
nCameraMsgType |= CAMERA_MSG_VLPR_DATA;
//mpDataCallback->postData(nCameraMsgType, mChnId, spData, sizeof(AW_AI_CVE_VLPR_RULT_S));
return NO_ERROR;
}
void CallbackNotifier::setPictureNum(int num)
{
mPictureNum = num;
}
status_t CallbackNotifier::startRecording(CameraRecordingProxyListener *pCb, int recorderId, int chnId)
{
RecordingProxyListener listener;
listener.mRecorderId = recorderId;
listener.mInputChnId = chnId;
listener.mpListener = pCb;
AutoMutex lock(mRecListenerLock);
mRecListener.push_back(listener);
return NO_ERROR;
}
status_t CallbackNotifier::stopRecording(int recorderId)
{
AutoMutex lock(mRecListenerLock);
for (vector<RecordingProxyListener>::iterator it = mRecListener.begin(); it != mRecListener.end(); ++it)
{
if (it->mRecorderId == recorderId)
{
delete it->mpListener;
mRecListener.erase(it);
break;
}
}
return NO_ERROR;
}
void CallbackNotifier::setDataListener(DataListener *pCb)
{
AutoMutex lock(mLock);
mpDataCallback = pCb;
}
void CallbackNotifier::setNotifyListener(NotifyListener *pCb)
{
AutoMutex lock(mLock);
mpNotifyCallback = pCb;
}
void CallbackNotifier::enableMessage(unsigned int msg_type)
{
alogv("msg_type = 0x%x", msg_type);
AutoMutex lock(&mLock);
mMessageEnabler |= msg_type;
alogv("**** Currently enabled messages:");
}
void CallbackNotifier::disableMessage(unsigned int msg_type)
{
alogv("msg_type = 0x%x", msg_type);
AutoMutex lock(&mLock);
mMessageEnabler &= ~msg_type;
alogv("**** Currently enabled messages:");
}
void CallbackNotifier::getCurrentDateTime(char *buf, int bufsize)
{
time_t t;
struct tm *tm_t;
time(&t);
tm_t = localtime(&t);
snprintf(buf, bufsize, "%4d:%02d:%02d %02d:%02d:%02d",
tm_t->tm_year+1900, tm_t->tm_mon+1, tm_t->tm_mday,
tm_t->tm_hour, tm_t->tm_min, tm_t->tm_sec);
}
void CallbackNotifier::setGPSMethod(const char *gpsMethod)
{
if (mpGpsProcessingMethod != NULL) {
free(mpGpsProcessingMethod);
}
if (gpsMethod == NULL) {
mpGpsProcessingMethod = NULL;
} else {
mpGpsProcessingMethod = strdup(gpsMethod);
}
}
/*
void CallbackNotifier::setSaveFolderPath(const char *str)
{
if (mpFolderPath != NULL) {
free(mpFolderPath);
}
if (str == NULL) {
mpFolderPath = NULL;
} else {
mpFolderPath = strdup(str);
}
}
void CallbackNotifier::setSnapPath(const char *str)
{
if (mpSnapPath != NULL) {
free(mpSnapPath);
}
if (str == NULL) {
mpSnapPath = NULL;
} else {
mpSnapPath = strdup(str);
}
}
*/
/*
void CallbackNotifier::postDataCompleted(const void *pData, int size)
{
AutoMutex lock(mPicBufLock);
int bFind = 0;
std::list<PictureBuffer>::iterator DstIt;
for(std::list<PictureBuffer>::iterator it=mWaitReleasePicBufList.begin(); it!=mWaitReleasePicBufList.end(); ++it)
{
if(it->mpData == pData)
{
if(it->mDataSize != (size_t)size)
{
aloge("fatal error! release PictureBuffer's dataSize is not match[%d]!=[%d]", it->mDataSize, size);
}
if(0 == bFind)
{
DstIt = it;
delete[] (const char*)pData;
}
else
{
aloge("fatal error! repeat PictureBuffer in list! check code!");
}
bFind++;
}
}
if(bFind > 0)
{
mWaitReleasePicBufList.erase(DstIt);
}
}
*/
void CallbackNotifier::setExifMake(char *make, int size)
{
}
void CallbackNotifier::setExifModel(char *model, int size)
{
}
void CallbackNotifier::setExifCameraSerialNum(char *model, int size)
{
}
bool CallbackNotifier::takePicture(const void *frame,
bool isContinuous,
bool isThumbnailPic,
const struct isp_exif_attribute* pIspExif)
{
bool bRet = true;
VIDEO_FRAME_BUFFER_S *pbuf = (VIDEO_FRAME_BUFFER_S*)frame;
PIXEL_FORMAT_E src_format = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
unsigned char *src_addr_phyY = NULL;
unsigned char *src_addr_phyC = NULL;
unsigned int src_width = 0;
unsigned int src_height = 0;
unsigned int picWidth = 0, picHeight = 0;
int thumbnailWidth, thumbnailHeight;
int jpegQuality, thumbnailQuality;
int msgType = CAMERA_MSG_COMPRESSED_IMAGE;
size_t jpegsize = 0, bufsize = 0;
off_t thumboffset = 0;
size_t thumblen = 0;
status_t ret;
PictureBuffer buf;
if (isMessageEnabled(CAMERA_MSG_RAW_IMAGE) && (!isThumbnailPic))
{
msgType = CAMERA_MSG_RAW_IMAGE;
VideoFrameBufferSizeInfo FrameSizeInfo;
getVideoFrameBufferSizeInfo(&pbuf->mFrameBuf, &FrameSizeInfo);
int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize};
bufsize = FrameSizeInfo.mYSize + FrameSizeInfo.mUSize + FrameSizeInfo.mVSize;
alogd("takePicture: Raw size %dx%d", bufsize);
buf.mbSharedMemPrepared = true;
buf.mMsgType = msgType;
buf.mIsContinuous = true;
buf.mPicBuf = std::make_shared<CMediaMemory>(bufsize);
buf.mDataSize = bufsize;
char *p = (char*)buf.mPicBuf->getPointer();
for (int i=0; i<3; i++)
{
if(pbuf->mFrameBuf.VFrame.mpVirAddr[i] != NULL)
{
memcpy(p , pbuf->mFrameBuf.VFrame.mpVirAddr[i], yuvSize[i]);
p += yuvSize[i];
alogv("virAddr[%d]=[%p], length=[%d]", i, pbuf->mFrameBuf.VFrame.mpVirAddr[i], yuvSize[i]);
}
}
mPicBufLock.lock();
mPicBufList.push_back(buf);
mpSavePicThread->notifyNewPictureCome();
mPicBufLock.unlock();
return true;
}
if (isThumbnailPic)
{
if (!isMessageEnabled(CAMERA_MSG_POSTVIEW_FRAME))
{
return false;
}
picWidth = mPictureThumbWidth;
picHeight = mPictureThumbHeight;
jpegQuality = mPictureThumbQuality;
thumbnailWidth = 0;
thumbnailHeight = 0;
thumbnailQuality = PictureThumbQuality_DEFAULT;
msgType = CAMERA_MSG_POSTVIEW_FRAME;
}
else
{
if (!isMessageEnabled(CAMERA_MSG_COMPRESSED_IMAGE))
{
return false;
}
picWidth = mPictureWidth;
picHeight = mPictureHeight;
jpegQuality = mJpegQuality;
thumbnailWidth = mPictureThumbWidth;
thumbnailHeight = mPictureThumbHeight;
if(mPictureThumbQuality < 20 || mPictureThumbQuality > 100)
{
aloge("the picture thumbnailQuality must be in [20, 100],and it will be set as default");
mPictureThumbQuality = PictureThumbQuality_DEFAULT;
}
thumbnailQuality = mPictureThumbQuality;
msgType = CAMERA_MSG_COMPRESSED_IMAGE;
}
// if ((pbuf->mIsThumbAvailable == 1) && (pbuf->mThumbUsedForPhoto == 1 || isThumbnailPic))
// {
// aloge("can't take thumb nail picture!");
// return false;
// }
// else
{
src_format = pbuf->mFrameBuf.VFrame.mPixelFormat;
src_addr_phyY = (unsigned char*)pbuf->mFrameBuf.VFrame.mPhyAddr[0];
src_addr_phyC = (unsigned char*)pbuf->mFrameBuf.VFrame.mPhyAddr[1];
src_width = pbuf->mFrameBuf.VFrame.mWidth;
src_height = pbuf->mFrameBuf.VFrame.mHeight;
}
if(MM_PIXEL_FORMAT_BUTT == src_format)
{
alogd("frame buf may contain compressed frame, need not encode.");
jpegsize = pbuf->mFrameBuf.VFrame.mStride[0];
bufsize = jpegsize + sizeof(off_t) + sizeof(size_t) + sizeof(size_t);
thumboffset = 0;
thumblen = 0;
buf.mbSharedMemPrepared = true;
buf.mMsgType = msgType;
buf.mIsContinuous = isContinuous;
buf.mPicBuf = std::make_shared<CMediaMemory>(bufsize);
buf.mDataSize = bufsize;
memcpy(buf.mPicBuf->getPointer(), pbuf->mFrameBuf.VFrame.mpVirAddr[0], jpegsize);
char *p = (char*)buf.mPicBuf->getPointer() + jpegsize;
memcpy(p, &thumboffset, sizeof(off_t));
p += sizeof(off_t);
memcpy(p, &thumblen, sizeof(size_t));
p += sizeof(size_t);
memcpy(p, &jpegsize, sizeof(size_t));
mPicBufLock.lock();
mPicBufList.push_back(buf);
mpSavePicThread->notifyNewPictureCome();
mPicBufLock.unlock();
goto JPEG_INIT_ERR;
}
if(mpJpegenc)
{
if(mJpegEncConfig.mSourceWidth != src_width || mJpegEncConfig.mSourceHeight != src_height
|| mJpegEncConfig.mPicWidth != picWidth || mJpegEncConfig.mPicHeight != picHeight)
{
alogd("srcSize-dstSize change [%dx%d,%dx%d]->[%dx%d,%dx%d], need reset encoder",
mJpegEncConfig.mSourceWidth, mJpegEncConfig.mSourceHeight, mJpegEncConfig.mPicWidth, mJpegEncConfig.mPicHeight,
src_width, src_height, picWidth, picHeight);
mpJpegenc->destroy();
delete mpJpegenc;
mpJpegenc = NULL;
}
}
if(NULL == mpJpegenc)
{
memset(&mJpegEncConfig, 0, sizeof(CameraJpegEncConfig));
mJpegEncConfig.mPixelFormat = src_format;
mJpegEncConfig.mSourceWidth = src_width;
mJpegEncConfig.mSourceHeight = src_height;
mJpegEncConfig.mPicWidth = picWidth;
mJpegEncConfig.mPicHeight = picHeight;
mJpegEncConfig.mThumbnailWidth = thumbnailWidth;
mJpegEncConfig.mThumbnailHeight = thumbnailHeight;
mJpegEncConfig.mThunbnailQuality = thumbnailQuality;
mJpegEncConfig.mQuality = jpegQuality;
//ion_memGetTotalSize();
unsigned int minVbvBufSize = picWidth * picHeight * 3/2;
unsigned int vbvThreshSize = picWidth*picHeight;
unsigned int vbvBufSize = (picWidth * picHeight * 3/2 /10 * mPictureNum) + vbvThreshSize;
if(vbvBufSize < minVbvBufSize)
{
vbvBufSize = minVbvBufSize;
}
if(vbvBufSize > 16*1024*1024)
{
alogd("Be careful! vbvSize[%d]MB is too large, decrease to threshSize[%d]MB + 1MB", vbvBufSize/(1024*1024), vbvThreshSize/(1024*1024));
vbvBufSize = vbvThreshSize + 1*1024*1024;
}
mJpegEncConfig.nVbvBufferSize = AWALIGN(vbvBufSize, 1024);
mJpegEncConfig.nVbvThreshSize = vbvThreshSize;
mpJpegenc = new CameraJpegEncoder();
ret = mpJpegenc->initialize(&mJpegEncConfig);
if (ret != NO_ERROR)
{
aloge("CameraJpegEncoder initialize error!");
goto JPEG_INIT_ERR;
}
}
alogd("takePicture: Picture size %dx%d, Thumb size %dx%d, vbv buffer size %u", picWidth, picHeight, thumbnailWidth, thumbnailHeight, mJpegEncConfig.nVbvBufferSize);
//every picture need set exifInfo.
VENC_EXIFINFO_S stExifInfo;
memset(&stExifInfo, 0, sizeof(VENC_EXIFINFO_S));
setExifMake((char*)stExifInfo.CameraMake, MM_INFO_LENGTH);
setExifModel((char*)stExifInfo.CameraModel, MM_INFO_LENGTH);
getCurrentDateTime((char*)stExifInfo.DateTime, MM_DATA_TIME_LENGTH);
stExifInfo.ThumbWidth = thumbnailWidth;
stExifInfo.ThumbHeight = thumbnailHeight;
stExifInfo.thumb_quality = thumbnailQuality;
stExifInfo.Orientation = mJpegRotate;
if (pIspExif != NULL)
{
//stExifInfo.fr32ExposureTime = FRACTION32(pIspExif->exposure_time.denominator, pIspExif->exposure_time.numerator);
stExifInfo.ExposureTime.num = pIspExif->exposure_time.numerator;
stExifInfo.ExposureTime.den = pIspExif->exposure_time.denominator;
}
//stExifInfo.fr32FNumber = FRACTION32(10, 26);
stExifInfo.FNumber.num = 26;
stExifInfo.FNumber.den = 10;
if(pIspExif != NULL)
{
stExifInfo.ISOSpeed = (short)pIspExif->iso_speed;
stExifInfo.ExposureBiasValueNum.num = pIspExif->exposure_bias;
stExifInfo.ExposureBiasValueNum.den = 1;
}
stExifInfo.MeteringMode = METERING_MODE_AVERAGE;
//stExifInfo.fr32FocalLength = FRACTION32(100, 228);
stExifInfo.FocalLength.num = 228;
stExifInfo.FocalLength.den = 100;
stExifInfo.WhiteBalance = 0;
if (mpGpsProcessingMethod != NULL)
{
stExifInfo.enableGpsInfo = 1;
stExifInfo.gps_latitude = mGpsLatitude;
stExifInfo.gps_longitude = mGpsLongitude;
stExifInfo.gps_altitude = mGpsAltitude;
stExifInfo.gps_timestamp = mGpsTimestamp;
strcpy((char*)stExifInfo.gpsProcessingMethod, mpGpsProcessingMethod);
}
setExifCameraSerialNum((char*)stExifInfo.CameraSerialNum, MM_INFO_LENGTH);
stExifInfo.FocalLengthIn35mmFilm = 18;
strcpy((char*)stExifInfo.ImageName, "aw-photo");
// strcpy((char*)stExifInfo.ImageDescription, "This photo is taken by AllWinner"); // not need any more
if(!isThumbnailPic)
{
createPictureRegion();
}
ret = mpJpegenc->encode(&pbuf->mFrameBuf, &stExifInfo);
if(!isThumbnailPic)
{
destoryPictureRegion();
}
if (ret != NO_ERROR)
{
aloge("CameraJpegEncoder encode error!");
goto JPEG_ENCODE_ERR;
}
if (mpJpegenc->getFrame() != 0)
{
aloge("CameraJpegEncoder getFrame error!");
goto JPEG_GET_FRAME_ERR;
}
mpJpegenc->getThumbOffset(thumboffset, thumblen);
buf.mbSharedMemPrepared = false;
buf.mMsgType = msgType;
buf.mIsContinuous = isContinuous;
buf.mpData0 = mpJpegenc->mOutStream.mpPack[0].mpAddr0;
buf.mpData1 = mpJpegenc->mOutStream.mpPack[0].mpAddr1;
buf.mpData2 = mpJpegenc->mOutStream.mpPack[0].mpAddr2;
buf.mLen0 = mpJpegenc->mOutStream.mpPack[0].mLen0;
buf.mLen1 = mpJpegenc->mOutStream.mpPack[0].mLen1;
buf.mLen2 = mpJpegenc->mOutStream.mpPack[0].mLen2;
buf.mThumbOffset = thumboffset;
buf.mThumbLen = thumblen;
buf.mDataSize = buf.mLen0+buf.mLen1+buf.mLen2;
mPicBufLock.lock();
mPicBufList.push_back(buf);
mpSavePicThread->notifyNewPictureCome();
mPicBufLock.unlock();
//mpJpegenc->returnFrame();
//pJpegenc->destroy();
//delete pJpegenc;
alogv("take one photo end");
return bRet;
JPEG_GET_FRAME_ERR:
JPEG_ENCODE_ERR:
mpJpegenc->destroy();
JPEG_INIT_ERR:
if(mpJpegenc)
{
delete mpJpegenc;
mpJpegenc = NULL;
}
return bRet;
}
void CallbackNotifier::takePictureEnd()
{
int64_t nWaitInterval = 200; //unit:ms
status_t ret;
mPicBufLock.lock();
while(!mPicBufList.empty())
{
alogw("Be careful! Before destroy jpegEnc, PicBufList has [%d] pictures to send!", mPicBufList.size());
mbWaitPicBufListEmpty = true;
ret = mCondWaitPicBufListEmpty.waitRelative(mPicBufLock, nWaitInterval*1000*1000);
if(ret != NO_ERROR)
{
alogw("wait ret[0x%x], wait [%lld]ms, still has some pictures to send!", ret, nWaitInterval);
}
}
mPicBufLock.unlock();
if(mpJpegenc)
{
mpJpegenc->destroy();
delete mpJpegenc;
mpJpegenc = NULL;
}
alogv("take picture end.");
}
void CallbackNotifier::setPictureRegionCallback(PictureRegionCallback *pCb)
{
AutoMutex lock(mPictureRegionLock);
mpPictureRegionCallback = pCb;
}
void CallbackNotifier::createPictureRegion()
{
//status_t ret = NO_ERROR;
AutoMutex lock(mPictureRegionLock);
if(!mpPictureRegionCallback)
{
return ;
}
mpPictureRegionCallback->addPictureRegion(mPictureRegionList);
if(!mPictureRegionList.empty())
{
alogd("had %d picture regions input!" , mPictureRegionList.size());
mPictureRegionHandleList.clear();
int regionId = 0; //just for debug info
MPP_CHN_S PictureVeChn = {MOD_ID_VENC, 0, mpJpegenc->getJpegVenChn()};
for(std::list<PictureRegionType>::iterator it = mPictureRegionList.begin(); it != mPictureRegionList.end(); ++it, ++regionId )
{
RGN_ATTR_S stRegion;
RGN_CHN_ATTR_S stRgnChnAttr;
if(OVERLAY_RGN == it->mType)
{
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = OVERLAY_RGN;
if(MM_PIXEL_FORMAT_RGB_8888 == it->mInfo.mOverlay.mPixFmt || MM_PIXEL_FORMAT_RGB_1555 == it->mInfo.mOverlay.mPixFmt)
{
stRegion.unAttr.stOverlay.mPixelFmt = it->mInfo.mOverlay.mPixFmt;//??
}
else
{
aloge("fatal error! [ %d ] PictureRegion had error PixFmt ,and it will be ignored!", regionId);
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX); // invaild handle.
continue;
}
stRegion.unAttr.stOverlay.mSize.Width = it->mRect.Width;
stRegion.unAttr.stOverlay.mSize.Height = it->mRect.Height;
}
else if(COVER_RGN == it->mType )
{
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = COVER_RGN;
}
else
{
aloge("fatal error! [ %d ] PictureRegion had error Type , and it will be ignored!", regionId);
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX); // invaild handle.
continue;
}
bool bSuccess = false;
int handle = 0;
while(handle < RGN_HANDLE_MAX)
{
ERRORTYPE Ret = AW_MPI_RGN_Create(handle, &stRegion);
if(SUCCESS == Ret)
{
alogd("[ %d ] PictureRegion had create, the region handle is %d", regionId, handle);
bSuccess = true;
mPictureRegionHandleList.push_back(handle);
break;
}
else if(ERR_RGN_EXIST == Ret)
{
//alogv("region[%d] is exist, find next!", handle);
handle++;
}
else
{
aloge("fatal error! create [ %d ] PictureRegion, ret[0x%x]!", regionId, Ret);
bSuccess = false;
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX); // invaild handle.
break;
}
}
if(bSuccess)
{
memset(&stRgnChnAttr, 0, sizeof(RGN_CHN_ATTR_S));
if(OVERLAY_RGN == stRegion.enType)
{
BITMAP_S stBmp;
memset(&stBmp, 0, sizeof(BITMAP_S));
stBmp.mPixelFormat = stRegion.unAttr.stOverlay.mPixelFmt;
stBmp.mWidth = stRegion.unAttr.stOverlay.mSize.Width;
stBmp.mHeight = stRegion.unAttr.stOverlay.mSize.Height;
stBmp.mpData = it->mInfo.mOverlay.mBitmap;
if(AW_MPI_RGN_SetBitMap(handle, &stBmp) != SUCCESS)
{
aloge("fatal error! create [ %d ] PictureRegion will be ignored!", regionId);
AW_MPI_RGN_Destroy(handle);
mPictureRegionHandleList.pop_back();
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX);
continue;
}
free(stBmp.mpData);
it->mInfo.mOverlay.mBitmap = NULL;
stBmp.mpData = NULL;
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.X = it->mRect.X;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.Y = it->mRect.Y;
stRgnChnAttr.unChnAttr.stOverlayChn.mLayer = it->mInfo.mOverlay.mPriority;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.Width = 16;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.Height = 16;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.mLumThresh = 60;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.enChgMod = LESSTHAN_LUMDIFF_THRESH;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.bInvColEn = TRUE;
if(it->mInfo.mOverlay.mbInvColEn)
{
aloge("Sorry, This version not support color invert in [ %d ] PictureRegion ", regionId);
}
if(AW_MPI_RGN_AttachToChn(handle, &PictureVeChn, &stRgnChnAttr) != SUCCESS)
{
aloge("fatal error! create [ %d ] PictureRegion will be ignored!", regionId);
AW_MPI_RGN_Destroy(handle);
mPictureRegionHandleList.pop_back();
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX);
continue;
}
}
else if(COVER_RGN == stRegion.enType)
{
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stCoverChn.enCoverType = AREA_RECT;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.X = it->mRect.X;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Y = it->mRect.Y;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Width = it->mRect.Width;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Height = it->mRect.Height;
stRgnChnAttr.unChnAttr.stCoverChn.mColor = it->mInfo.mCover.mChromaKey;
stRgnChnAttr.unChnAttr.stCoverChn.mLayer = it->mInfo.mCover.mPriority;
if(AW_MPI_RGN_AttachToChn(handle, &PictureVeChn, &stRgnChnAttr) != SUCCESS)
{
aloge("fatal error! create [ %d ] PictureRegion will be ignored!", regionId);
AW_MPI_RGN_Destroy(handle);
mPictureRegionHandleList.pop_back();
mPictureRegionHandleList.push_back(RGN_HANDLE_MAX);
continue;
}
}
}
}
alogd("had %d picture region work!" , mPictureRegionHandleList.size());
}
}
void CallbackNotifier::destoryPictureRegion()
{
AutoMutex lock(mPictureRegionLock);
if(!mPictureRegionHandleList.empty())
{
MPP_CHN_S PictureVeChn = {MOD_ID_VENC, 0, mpJpegenc->getJpegVenChn()};
for(std::list<RGN_HANDLE>::iterator it = mPictureRegionHandleList.begin(); it != mPictureRegionHandleList.end(); ++it)
{
if(*it < RGN_HANDLE_MAX)
{
AW_MPI_RGN_DetachFromChn(*it, &PictureVeChn);
AW_MPI_RGN_Destroy(*it);
}
}
mPictureRegionHandleList.clear();
alogd("the pictureregionhandlelist had clear!");
}
if(!mPictureRegionList.empty())
{
for(std::list<PictureRegionType>::iterator it = mPictureRegionList.begin(); it != mPictureRegionList.end(); ++it)
{
if(OVERLAY_RGN == it->mType)
{
if(it->mInfo.mOverlay.mBitmap)
{
free(it->mInfo.mOverlay.mBitmap);
it->mInfo.mOverlay.mBitmap = NULL;
}
}
}
mPictureRegionList.clear();
alogd("the pictureregionlist had clear!");
}
//alogd("the pictureregionlist and pictureregionhandlelist had clear!!!");
}
status_t CallbackNotifier::notifyPictureRelease()
{
mPicBufLock.lock();
if(!mWaitReleasePicBufList.empty())
{
//alogd("notify waitReleasePicBufList to pop!");
mWaitReleasePicBufList.pop_front();
}
else
{
aloge("fatal error! why waitReleasePicBufList is empty?");
}
mpSavePicThread->notifyPictureRelease();
mPicBufLock.unlock();
return NO_ERROR;
}
bool CallbackNotifier::savePictureThread()
{
bool bRunningFlag = true;
EyeseeMessage msg;
status_t getMsgRet;
ERRORTYPE ret;
PROCESS_MESSAGE:
getMsgRet = mpSavePicThread->mMsgQueue.dequeueMessage(&msg);
if(getMsgRet == NO_ERROR)
{
if(DoSavePictureThread::MsgTypeSavePic_InputPictureAvailable == msg.mMsgType)
{
}
else if(DoSavePictureThread::MsgTypeSavePic_ReleasePicture == msg.mMsgType)
{
}
else if(DoSavePictureThread::MsgTypeSavePic_Exit == msg.mMsgType)
{
bRunningFlag = false;
alogw("save_pic_thrd_force_rls_when_exit:%d",mPicBufList.size());
mPicBufLock.lock();
while(!mPicBufList.empty())
{
VENC_STREAM_S tmpVencStream;
VENC_PACK_S tmpVencPack;
memset(&tmpVencStream, 0, sizeof(VENC_STREAM_S));
memset(&tmpVencPack, 0, sizeof(VENC_PACK_S));
PictureBuffer pbuf = mPicBufList.front();
mPicBufList.pop_front();
tmpVencStream.mpPack = &tmpVencPack;
tmpVencStream.mPackCount = 1;
tmpVencStream.mpPack[0].mpAddr0 = pbuf.mpData0;
tmpVencStream.mpPack[0].mpAddr1 = pbuf.mpData1;
tmpVencStream.mpPack[0].mpAddr2 = pbuf.mpData2;
tmpVencStream.mpPack[0].mLen0 = pbuf.mLen0;
tmpVencStream.mpPack[0].mLen1 = pbuf.mLen1;
tmpVencStream.mpPack[0].mLen2 = pbuf.mLen2;
mpJpegenc->returnFrame(&tmpVencStream);
}
mPicBufLock.unlock();
goto _exit0;
}
else
{
aloge("unknown msg[0x%x]!", msg.mMsgType);
}
goto PROCESS_MESSAGE;
}
while(1)
{
mPicBufLock.lock();
if (mPicBufList.empty())
{
alogv("wait for picture to save");
mpSavePicThread->mWaitLock.lock();
mpSavePicThread->mbWaitPicture = true;
mpSavePicThread->mWaitLock.unlock();
if(mbWaitPicBufListEmpty)
{
alogd("need notify picture thread that all pictures have been sent.");
mbWaitPicBufListEmpty = false;
mCondWaitPicBufListEmpty.signal();
}
mPicBufLock.unlock();
mpSavePicThread->mMsgQueue.waitMessage();
goto PROCESS_MESSAGE;
}
if(mWaitReleasePicBufList.size() > 0)
{
alogd("wait user to notify to release PicBuffer");
mpSavePicThread->mWaitLock.lock();
mpSavePicThread->mbWaitReleasePicture = true;
mpSavePicThread->mWaitLock.unlock();
mPicBufLock.unlock();
mpSavePicThread->mMsgQueue.waitMessage();
goto PROCESS_MESSAGE;
}
mWaitReleasePicBufList.splice(mWaitReleasePicBufList.end(), mPicBufList, mPicBufList.begin());
PictureBuffer *pbuf = &mWaitReleasePicBufList.back();
size_t bufsize = pbuf->mDataSize;
if(false == pbuf->mbSharedMemPrepared)
{
size_t jpegsize = pbuf->mDataSize;
bufsize = jpegsize + sizeof(off_t) + sizeof(size_t) + sizeof(size_t);
// int freeMemKb = getFreeMemory();
// int buffersMemKb = getBuffersMemory();
// int cachedMemKb = getCachedMemory();
// if ((unsigned int)(freeMemKb/*+buffersMemKb+cachedMemKb*/) < (bufsize+2*1024*1024)>>10)
// {
// alogw("Be careful! Free memory too small! bufsize=%dKB, MemTotal=%dKB, MemFree=%dKB, Buffers=%dKB, Cached=%dKB",
// bufsize/1024, getTotalMemory(), freeMemKb, buffersMemKb, cachedMemKb);
// //goto ALLOC_MEM_ERR;
// }
pbuf->mPicBuf = std::make_shared<CMediaMemory>(bufsize);
char *p = (char*)pbuf->mPicBuf->getPointer();
if(NULL == p)
{
aloge("fatal error! malloc fail!");
}
if(pbuf->mLen0 > 0)
{
memcpy(p, pbuf->mpData0, pbuf->mLen0);
p += pbuf->mLen0;
}
if(pbuf->mLen1 > 0)
{
memcpy(p, pbuf->mpData1, pbuf->mLen1);
p += pbuf->mLen1;
}
if(pbuf->mLen2 > 0)
{
memcpy(p, pbuf->mpData2, pbuf->mLen2);
p += pbuf->mLen2;
}
off_t thumboffset = pbuf->mThumbOffset;
size_t thumblen = pbuf->mThumbLen;
memcpy(p, &thumboffset, sizeof(off_t));
p += sizeof(off_t);
memcpy(p, &thumblen, sizeof(size_t));
p += sizeof(size_t);
memcpy(p, &jpegsize, sizeof(size_t));
//after finish sharedMem, return venc frame now.
VENC_STREAM_S tmpVencStream;
VENC_PACK_S tmpVencPack;
memset(&tmpVencStream, 0, sizeof(VENC_STREAM_S));
memset(&tmpVencPack, 0, sizeof(VENC_PACK_S));
tmpVencStream.mpPack = &tmpVencPack;
tmpVencStream.mPackCount = 1;
tmpVencStream.mpPack[0].mpAddr0 = pbuf->mpData0;
tmpVencStream.mpPack[0].mpAddr1 = pbuf->mpData1;
tmpVencStream.mpPack[0].mpAddr2 = pbuf->mpData2;
tmpVencStream.mpPack[0].mLen0 = pbuf->mLen0;
tmpVencStream.mpPack[0].mLen1 = pbuf->mLen1;
tmpVencStream.mpPack[0].mLen2 = pbuf->mLen2;
mpJpegenc->returnFrame(&tmpVencStream);
}
mPicBufLock.unlock();
//mpDataCallback->postData(pbuf->mMsgType, mMppChnInfo.mChnId, pbuf->mpData, pbuf->mDataSize);
mpDataCallback->postData(pbuf->mMsgType, mChnId, pbuf->mPicBuf, bufsize);
//mWaitReleasePicBufList.pop_front();
}
return true;
_exit0:
return bRunningFlag;
}
}; /* namespace EyeseeLinux */