sdk-hwV1.3/external/eyesee-mpp/framework/sun8iw21/media/motion/EyeseeMotion.cpp

700 lines
19 KiB
C++
Raw Normal View History

2024-05-07 10:09:20 +00:00
/*
********************************************************************************
* eyesee framework module
*
* (c) Copyright 2010-2018, Allwinner Microelectronic Co., Ltd.
* All Rights Reserved
*
* File : EyeseeMotion.cpp
* Version: V1.0
* By : zing huang
* Date : 2018-06-28
* Description:
********************************************************************************
*/
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <plat_log.h>
#include <mpi_sys.h>
#include <mpi_demux.h>
#include <mpi_venc.h>
#include <mpi_vdec.h>
#include <mpi_clock.h>
#include <ion_memmanager.h>
#include <cvt_color.h>
#include <aw_ai_mt.h>
#include <Clock_Component.h>
#include <EyeseeMotion.h>
namespace EyeseeLinux {
EyeseeMotion::EyeseeMotion():
mMotionTrailRet(-1)
{
mMotionHandle = NULL;
memset(&mImageYUV, 0, sizeof mImageYUV);
memset(&mImageBGR, 0, sizeof mImageBGR);
ClearConfig();
}
EyeseeMotion::~EyeseeMotion()
{
reset();
}
status_t EyeseeMotion::setVideoFileSource(const char * url)
{
status_t opStatus;
if(0 == access(url, F_OK))
{
int fd = open(url, O_RDONLY);
if(fd < 0)
{
aloge("Failed to open file %s(%s)", url, strerror(errno));
return UNKNOWN_ERROR;
}
opStatus = setVideoFileSource(fd, 0, 0x7ffffffffffffffL);
close(fd);
}
else
{
aloge("fatal error! open file path[%s] fail!", url);
opStatus = INVALID_OPERATION;
}
return opStatus;
}
status_t EyeseeMotion::setVideoFileSource(int fd, int64_t offset, int64_t length)
{
Mutex::Autolock _l(mLock);
if(!(mCurrentState & MEDIA_MOTION_IDLE || mCurrentState == MEDIA_MOTION_STATE_ERROR))
{
aloge("called in wrong state %d", mCurrentState);
return INVALID_OPERATION;
}
ERRORTYPE ret;
bool nSuccessFlag = false;
//mDmxChnAttr.mStreamType = STREAMTYPE_LOCALFILE;
mDmxChnAttr.mSourceType = SOURCETYPE_FD;
mDmxChnAttr.mSourceUrl = NULL;
mDmxChnAttr.mFd = dup(fd);
mDmxChnAttr.mDemuxDisableTrack |= DEMUX_DISABLE_AUDIO_TRACK;
mDmxChnAttr.mDemuxDisableTrack |= DEMUX_DISABLE_SUBTITLE_TRACK;
mDmxChn = 0;
while(mDmxChn < DEMUX_MAX_CHN_NUM)
{
ret = AW_MPI_DEMUX_CreateChn(mDmxChn, &mDmxChnAttr);
if(SUCCESS == ret)
{
nSuccessFlag = TRUE;
alogd("create demux channel[%d] success!", mDmxChn);
break;
}
else if(ERR_DEMUX_EXIST == ret)
{
alogd("demux channel[%d] is exist, find next!", mDmxChn);
mDmxChn++;
}
else if(ERR_DEMUX_FILE_EXCEPTION == ret)
{
aloge("demux detect media file exception!");
return BAD_FILE;
}
else
{
alogd("create demux channel[%d] ret[0x%x]!", mDmxChn, ret);
break;
}
}
if(false == nSuccessFlag)
{
mDmxChn = MM_INVALID_CHN;
aloge("fatal error! create demux channel fail!");
return UNKNOWN_ERROR;
}
ret = AW_MPI_DEMUX_GetMediaInfo(mDmxChn, &mMediaInfo);
if(SUCCESS == ret)
{
if( (mMediaInfo.mVideoNum > 0 && mMediaInfo.mVideoIndex >= mMediaInfo.mVideoNum)
|| (mMediaInfo.mAudioNum > 0 && mMediaInfo.mAudioIndex >= mMediaInfo.mAudioNum)
|| (mMediaInfo.mSubtitleNum > 0 && mMediaInfo.mSubtitleIndex >= mMediaInfo.mSubtitleNum)
)
{
alogd("fatal error, trackIndex wrong! [%d][%d],[%d][%d],[%d][%d]",
mMediaInfo.mVideoNum, mMediaInfo.mVideoIndex, mMediaInfo.mAudioNum, mMediaInfo.mAudioIndex, mMediaInfo.mSubtitleNum, mMediaInfo.mSubtitleIndex);
return UNKNOWN_ERROR;
}
}
else
{
return UNKNOWN_ERROR;
}
mCurrentState = MEDIA_MOTION_INITIALIZED;
return NO_ERROR;
}
std::shared_ptr<CMediaMemory> EyeseeMotion::getMotionJpeg(const MotionPictureParam &jpegParam)
{
Mutex::Autolock _l(mLock);
if(mCurrentState != MEDIA_MOTION_INITIALIZED)
{
aloge("called in error state 0x%x", mCurrentState);
return NULL;
}
mPictureWidth = jpegParam.mPicWidth;
mPictureHeight = jpegParam.mPicHeight;
mStartTimeMs = jpegParam.mStartTimeUs / 1000;
mSourceFrameNums = jpegParam.mSourceFrameNums;
mSourceFrameStep = jpegParam.mSourceFrameStep;
mObjectNums = jpegParam.mObjectNums;
if(!(mPictureWidth > 0 && mPictureHeight > 0))
{
aloge("fatal error! picturesize[%d, %d]", mPictureWidth, mPictureHeight);
return NULL;
}
if(mStartTimeMs > static_cast<int>(mMediaInfo.mDuration) || mStartTimeMs < 0)
{
aloge("fatal error, starttime[%d] ms!", mStartTimeMs);
return NULL;
}
if(mSourceFrameNums < 1 || mSourceFrameStep < 0)
{
aloge("fatal error, SourceFrameNums[%d], SourceFrameStep[%d]", mSourceFrameNums, mSourceFrameStep);
return NULL;
}
if(jpegParam.mTempBMPFileBasePath.empty())
{
mTempBMPFileBasePath = "./tmp_picture/";
}
else
{
mTempBMPFileBasePath = jpegParam.mTempBMPFileBasePath;
if(jpegParam.mTempBMPFileBasePath[jpegParam.mTempBMPFileBasePath.size() - 1] != '/')
{
mTempBMPFileBasePath += "/";
}
}
prepare();
seekTo();
start();
getMotionTrail();
stop();
cvtBGR2YUV(&mImageBGR, &mImageYUV, PIXEL_FORMAT_YUV_PLANAR_420);
return PictureAsJpeg(mImageYUV);
}
std::shared_ptr<CMediaMemory> EyeseeMotion::getMotionBMP(const MotionPictureParam &jpegParam)
{
#if 0
Mutex::Autolock _l(mLock);
if(mCurrentState != MEDIA_MOTION_INITIALIZED)
{
aloge("called in error state 0x%x", mCurrentState);
return INVALID_OPERATION;
}
mPictureWidth = picWidth;
mPictureHeight = picHeight;
mStartTimeMs = startTimeUs / 1000;
mSourceFrameNums = sourceFrameNums;
mSourceFrameStep = sourceFrameStep;
if(!(mPictureWidth > 0 && mPictureHeight > 0))
{
aloge("fatal error! picturesize[%d, %d]", mPictureWidth, mPictureHeight);
return NULL;
}
if(mStartTimeMs > mMediaInfo.mDuration || mStartTimeMs < 0)
{
aloge("fatal error, starttime[%d] ms!", mStartTimeMs);
return NULL;
}
if(mSourceFrameNums < 1 || mSourceFrameStep < 0)
{
aloge("fatal error, SourceFrameNums[%d], SourceFrameStep[%d]", mSourceFrameNums, mSourceFrameStep);
return NULL;
}
prepare();
seekTo();
start();
getMotionTrail();
stop();
return PictureAsBMP(mImageBGR);
#else
aloge("sorry, this version no realize func!");
return NULL;
#endif
}
status_t EyeseeMotion::reset()
{
Mutex::Autolock _l(mLock);
status_t result = NO_ERROR;
if(mCurrentState == MEDIA_MOTION_INITIALIZED)
{
if(mDmxChn >= 0)
{
AW_MPI_DEMUX_DestroyChn(mDmxChn);
mDmxChn = MM_INVALID_CHN;
}
}
ClearConfig();
//mCurrentState = MEDIA_MOTION_IDLE;
return result;
}
void EyeseeMotion::ClearConfig()
{
memset(&mDmxChnAttr, 0, sizeof mDmxChnAttr);
memset(&mMediaInfo, 0, sizeof mMediaInfo);
memset(&mVdecChnAttr, 0, sizeof mVdecChnAttr);
memset(&mClockChnAttr, 0, sizeof mClockChnAttr);
mDmxChn = MM_INVALID_CHN;
mVdecChn = MM_INVALID_CHN;
mClockChn = MM_INVALID_CHN;
if(mMotionHandle)
{
AW_AI_MT_Reset(mMotionHandle);
AW_AI_MT_UnInit(mMotionHandle);
mMotionHandle = NULL;
}
DestroyImage(&mImageYUV);
DestroyImage(&mImageBGR);
mPictureWidth = 0;
mPictureHeight = 0;
mStartTimeMs = 0;
mSourceFrameNums = 0;
mSourceFrameStep = 0;
mObjectNums = 0;
mCurrentState = MEDIA_MOTION_IDLE;
}
status_t EyeseeMotion::prepare()
{
status_t result = NO_ERROR;
ERRORTYPE ret;
//basepath
if(access(mTempBMPFileBasePath.c_str(), 0) != 0)
{
if(mkdir(mTempBMPFileBasePath.c_str(), 0) != 0)
{
aloge("fatal error, can not creat directory[%s], %s", mTempBMPFileBasePath.c_str(), strerror(errno));
return UNKNOWN_ERROR;
}
}
if(mMediaInfo.mVideoNum > 0 && !(mDmxChnAttr.mDemuxDisableTrack & DEMUX_DISABLE_VIDEO_TRACK))
{
DEMUX_VIDEO_STREAM_INFO_S *pStreamInfo = &mMediaInfo.mVideoStreamInfo[mMediaInfo.mVideoIndex];
mVdecChnAttr.mType = pStreamInfo->mCodecType;
mVdecChnAttr.mPicWidth = mPictureWidth;
mVdecChnAttr.mPicHeight = mPictureHeight;
mVdecChnAttr.mInitRotation = (ROTATE_E)0;
mVdecChnAttr.mOutputPixelFormat = MM_PIXEL_FORMAT_YVU_PLANAR_420;
mVdecChnAttr.mVdecVideoAttr.mMode = VIDEO_MODE_FRAME;
mVdecChnAttr.mVdecVideoAttr.mSupportBFrame = 1;
bool bSuccessFlag = false;
mVdecChn = 0;
while(mVdecChn < VDEC_MAX_CHN_NUM)
{
ret = AW_MPI_VDEC_CreateChn(mVdecChn, &mVdecChnAttr);
if(SUCCESS == ret)
{
bSuccessFlag = true;
alogd("create vdec channel[%d] success!", mVdecChn);
break;
}
else if(ERR_VDEC_EXIST == ret)
{
alogd("vdec channel[%d] is exist, find next!", mVdecChn);
mVdecChn++;
}
else
{
alogd("error, create vdec channel[%d] ret[0x%x]!", mVdecChn, ret);
break;
}
}
if(!bSuccessFlag)
{
mVdecChn = MM_INVALID_CHN;
aloge("fatal error! create vdec channel failed");
result = UNKNOWN_ERROR;
goto _err0;
}
MPP_CHN_S DmxChn{MOD_ID_DEMUX, 0, mDmxChn};
MPP_CHN_S VdecChn{MOD_ID_VDEC, 0, mVdecChn};
AW_MPI_SYS_Bind(&DmxChn, &VdecChn);
mClockChnAttr.nWaitMask |= 1<<CLOCK_PORT_INDEX_VIDEO;
}
if(mDmxChn >= 0)
{
bool bSuccessFlag = false;
mClockChn = 0;
while(mClockChn < CLOCK_MAX_CHN_NUM)
{
ret = AW_MPI_CLOCK_CreateChn(mClockChn, &mClockChnAttr);
if(SUCCESS == ret)
{
bSuccessFlag = true;
alogd("creat clock channel[%d] success!", mClockChn);
break;
}
else if(ERR_CLOCK_EXIST == ret)
{
alogd("clock channel[%d] is exist, find next!", mClockChn);
++mClockChn;
}
else
{
alogd("creat clock channel[%d] ret[0x%x]", mClockChn, ret);
break;
}
}
if(!bSuccessFlag)
{
mClockChn = MM_INVALID_CHN;
aloge("fatal error! create clock channel fail!");
result = UNKNOWN_ERROR;
goto _err0;
}
MPP_CHN_S ClockChn{MOD_ID_CLOCK, 0, mClockChn};
MPP_CHN_S DmxChn{MOD_ID_DEMUX, 0, mDmxChn};
AW_MPI_SYS_Bind(&ClockChn, &DmxChn);
}
mLpMtParam.Width = mPictureWidth;
mLpMtParam.Height = mPictureHeight;
mLpMtParam.bAntishakeEnable = true;
mMotionHandle = AW_AI_MT_Init(&mLpMtParam);
if(!mMotionHandle)
{
aloge("init mt lib fail");
result = UNKNOWN_ERROR;
goto _err0;
}
CreateImage(&mImageYUV, mLpMtParam.Width, mLpMtParam.Height, 3, PIXEL_FORMAT_YVU_PLANAR_420);
CreateImage(&mImageBGR, mLpMtParam.Width, mLpMtParam.Height, 3, PIXEL_FORMAT_BGR_888);
mCurrentState = MEDIA_MOTION_PREPARED;
_err0:
return result;
}
status_t EyeseeMotion::start()
{
status_t opStatus = NO_ERROR;
if(mVdecChn >= 0)
{
//VDEC_DECODE_FRAME_PARAM_S DecodeParam;
//DecodeParam.mDecodeFrameNum = (mSourceFrameNums -1) * mSourceFrameStep + mSourceFrameNums;
//AW_MPI_VDEC_StartRecvStreamEx(mVdecChn, &DecodeParam);
AW_MPI_VDEC_StartRecvStream(mVdecChn);
}
if(mDmxChn >= 0)
{
AW_MPI_DEMUX_Start(mDmxChn);
}
if(mClockChn >= 0)
{
AW_MPI_CLOCK_Start(mClockChn);
}
mCurrentState = MEDIA_MOTION_STARTED;
return opStatus;
}
status_t EyeseeMotion::stop()
{
status_t opStatus = NO_ERROR;
if(mClockChn >= 0)
{
AW_MPI_CLOCK_Stop(mClockChn);
}
if(mDmxChn >= 0)
{
AW_MPI_DEMUX_Stop(mDmxChn);
}
if(mVdecChn >= 0)
{
AW_MPI_VDEC_StopRecvStream(mVdecChn);
}
if(mVdecChn >= 0)
{
AW_MPI_VDEC_DestroyChn(mVdecChn);
mVdecChn = MM_INVALID_CHN;
}
if(mDmxChn >= 0)
{
AW_MPI_DEMUX_DestroyChn(mDmxChn);
mDmxChn = MM_INVALID_CHN;
}
if(mClockChn >= 0)
{
AW_MPI_CLOCK_DestroyChn(mClockChn);
mClockChn = MM_INVALID_CHN;
}
mCurrentState = MEDIA_MOTION_STOPPED;
return opStatus;
}
status_t EyeseeMotion::seekTo()
{
status_t opStatus = NO_ERROR;
if(mDmxChn >= 0 && mStartTimeMs > 0)
{
AW_MPI_DEMUX_Seek(mDmxChn, mStartTimeMs);
alogd("the demux had set %d ms!", mStartTimeMs);
}
return opStatus;
}
status_t EyeseeMotion::getMotionTrail()
{
mMotionTrailRet = -1;
VIDEO_FRAME_INFO_S tVideoFrameInfo;
const int nFramSum = (mSourceFrameNums -1) * mSourceFrameStep + mSourceFrameNums;
int nSendFrameCounts = 0;
if(nFramSum <= 20){
aloge("The voide is too short,video frame number nFramSum %d <= 20,",nFramSum);
mMotionTrailRet = -1;
return NO_ERROR;
}
for(int i = 0; i < nFramSum; i++)
{
ERRORTYPE ret = AW_MPI_VDEC_GetImage(mVdecChn, &tVideoFrameInfo, 500);
if(SUCCESS == ret)
{
if(i > nFramSum / 10 && i < (nFramSum - nFramSum / 10) )
{
if(0 == mSourceFrameStep || 0 == i % mSourceFrameStep)
{
assert(MM_PIXEL_FORMAT_YVU_PLANAR_420 == tVideoFrameInfo.VFrame.mPixelFormat);
const int size = mLpMtParam.Width * mLpMtParam.Height;
memcpy(mImageYUV.mpData, tVideoFrameInfo.VFrame.mpVirAddr[0], size);
memcpy(mImageYUV.mpData + size, tVideoFrameInfo.VFrame.mpVirAddr[1], size / 4);
memcpy(mImageYUV.mpData + size + size / 4, tVideoFrameInfo.VFrame.mpVirAddr[2], size / 4);
cvtYUV2BGR(&mImageYUV, &mImageBGR);
//AW_AI_MT_SendFrame(mMotionHandle, &mImageBGR);
char tmpFileName[32] = {0};
sprintf(tmpFileName, "%d.bmp", nSendFrameCounts++);
std::string TempFilePathName = mTempBMPFileBasePath + tmpFileName;
SaveBMP(&mImageBGR, const_cast<char*>(TempFilePathName.c_str()));
AW_AI_MT_SetFrame(mMotionHandle, TempFilePathName.c_str());
}
}
AW_MPI_VDEC_ReleaseImage(mVdecChn, &tVideoFrameInfo);
}
else
{
aloge("why not get frame from vdec, maybe EOF [0x%x]", ret);
}
}
alogd("__send frame to MT, count[%d]", nSendFrameCounts);
mMotionTrailRet = AW_AI_MT_GenMotionTrail(mMotionHandle, &mImageBGR);
return NO_ERROR;
}
int EyeseeMotion::GetmMotionTrailRet()
{
return mMotionTrailRet;
}
std::shared_ptr<CMediaMemory> EyeseeMotion::PictureAsJpeg(IMAGE_DATA_I &ImageYUV)
{
VENC_CHN VecChn = 0;
VENC_CHN_ATTR_S VecChnAttr;
memset(&VecChnAttr, 0, sizeof VecChnAttr);
VecChnAttr.VeAttr.Type = PT_JPEG;
VecChnAttr.VeAttr.AttrJpeg.MaxPicWidth = 0;
VecChnAttr.VeAttr.AttrJpeg.MaxPicHeight = 0;
VecChnAttr.VeAttr.AttrJpeg.BufSize = ((((ImageYUV.mWidth * ImageYUV.mHeight * 3) >> 2) + 1023) >> 10) << 10;
VecChnAttr.VeAttr.AttrJpeg.bByFrame = TRUE;
VecChnAttr.VeAttr.AttrJpeg.PicWidth = ImageYUV.mWidth;
VecChnAttr.VeAttr.AttrJpeg.PicHeight = ImageYUV.mHeight;
VecChnAttr.VeAttr.AttrJpeg.bSupportDCF = FALSE;
VecChnAttr.VeAttr.MaxKeyInterval = 1;
VecChnAttr.VeAttr.SrcPicWidth = ImageYUV.mWidth;
VecChnAttr.VeAttr.SrcPicHeight = ImageYUV.mHeight;
VecChnAttr.VeAttr.Field = VIDEO_FIELD_FRAME;
VecChnAttr.VeAttr.PixelFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
ERRORTYPE ret;
bool bSuccessFlag = false;
while(VecChn < VENC_MAX_CHN_NUM)
{
ret = AW_MPI_VENC_CreateChn(VecChn, &VecChnAttr);
if(SUCCESS == ret)
{
bSuccessFlag = true;
alogd("create venc channel[%d] success!", VecChn);
break;
}
else if(ERR_VENC_EXIST == ret)
{
alogd("venc channel[%d] is exist, find next!", VecChn);
VecChn++;
}
else
{
alogd("create venc channel[%d] ret[0x%x], find next!", VecChn, ret);
break;
}
}
if(!bSuccessFlag)
{
aloge("fatal error! create venc channel fail!");
return NULL;
}
VIDEO_FRAME_INFO_S tVideoFrameInfo;
memset(&tVideoFrameInfo, 0, sizeof tVideoFrameInfo);
tVideoFrameInfo.mId = 0;
tVideoFrameInfo.VFrame.mWidth = ImageYUV.mWidth;
tVideoFrameInfo.VFrame.mHeight = ImageYUV.mHeight;
tVideoFrameInfo.VFrame.mPixelFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
tVideoFrameInfo.VFrame.mOffsetLeft = 0;
tVideoFrameInfo.VFrame.mOffsetRight = ImageYUV.mWidth;
tVideoFrameInfo.VFrame.mOffsetTop = 0;
tVideoFrameInfo.VFrame.mOffsetBottom = ImageYUV.mHeight;
const int size = ImageYUV.mWidth * ImageYUV.mHeight;
for(int i =0 ; i < 2; i++)
{
tVideoFrameInfo.VFrame.mpVirAddr[i] = ion_allocMem(size);
tVideoFrameInfo.VFrame.mPhyAddr[i] = ion_getMemPhyAddr(tVideoFrameInfo.VFrame.mpVirAddr[i]);
}
memcpy(tVideoFrameInfo.VFrame.mpVirAddr[0], ImageYUV.mpData, size);
ion_flushCache(tVideoFrameInfo.VFrame.mpVirAddr[0], size);
unsigned char *ptr_uv = static_cast<unsigned char *>(tVideoFrameInfo.VFrame.mpVirAddr[1]);
unsigned char *ptr_u = ImageYUV.mpData + size;
unsigned char *ptr_v = ImageYUV.mpData + size + size / 4;
for(int i = 0; i < size / 4; i++)
{
*ptr_uv++ = *ptr_v++;
*ptr_uv++ = *ptr_u++;
}
ion_flushCache(tVideoFrameInfo.VFrame.mpVirAddr[1], size);
VENC_RECV_PIC_PARAM_S RecvParam;
RecvParam.mRecvPicNum = 1;
AW_MPI_VENC_StartRecvPicEx(VecChn, &RecvParam);
AW_MPI_VENC_SendFrame(VecChn, &tVideoFrameInfo, 500);
std::shared_ptr<CMediaMemory> spJpegBuf;
VENC_STREAM_S JpegStream;
VENC_PACK_S Jpeg_pack;
JpegStream.mPackCount = 1;
JpegStream.mpPack = &Jpeg_pack;
if(SUCCESS == AW_MPI_VENC_GetStream(VecChn, &JpegStream, 500))
{
const int JpegSize = JpegStream.mpPack[0].mLen0 + JpegStream.mpPack[0].mLen1;
spJpegBuf = std::make_shared<CMediaMemory>(JpegSize);
char *ptr = (char *)spJpegBuf->getPointer();
memcpy(ptr, JpegStream.mpPack[0].mpAddr0, JpegStream.mpPack[0].mLen0);
ptr += JpegStream.mpPack[0].mLen0;
memcpy(ptr, JpegStream.mpPack[0].mpAddr1, JpegStream.mpPack[0].mLen1);
if(AW_MPI_VENC_ReleaseStream(VecChn, &JpegStream) != SUCCESS)
{
aloge("jpeg stream data return fail!");
}
}
else
{
aloge("get jpeg stream data fail!");
}
AW_MPI_VENC_StopRecvPic(VecChn);
for(int i = 0; i < 2; i++)
{
ion_freeMem(tVideoFrameInfo.VFrame.mpVirAddr[i]);
}
AW_MPI_VENC_DestroyChn(VecChn);
return spJpegBuf;
}
std::shared_ptr<CMediaMemory> EyeseeMotion::PictureAsBMP(IMAGE_DATA_I &ImageBGR)
{
aloge("sorry, this version no realize func!");
return NULL;
}
};