叠加模块示例源码解析
该实例程序会演示region模块如何叠加至VI/VE,以及如果在叠加后改变叠加的色块等。示例效果如下所示:
1.VI/VENC的初始化和绑定
1.1 初始化MPP平台
memset(&pContext->mSysConf, 0, sizeof(MPP_SYS_CONF_S));
pContext->mSysConf.nAlignWidth = 32;
AW_MPI_SYS_SetConf(&pContext->mSysConf);
AW_MPI_SYS_Init();
1.2 创建VIPP设备
if (pContext->mConfigPara.mOnlineEnable)
pContext->mVIDev = 0; // only vipp0 support online.
else
pContext->mVIDev = HVIDEO(pContext->mConfigPara.mVippDevID, 0);
pContext->mVIChn = 0;
eRet = AW_MPI_VI_CreateVipp(pContext->mVIDev);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VI_CreateVipp failed");
}
1.3 设置VIPP设备属性
VI_ATTR_S attr;
eRet = AW_MPI_VI_GetVippAttr(pContext->mVIDev, &attr);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VI_GetVippAttr failed");
}
memset(&attr, 0, sizeof(VI_ATTR_S));
if (pContext->mConfigPara.mOnlineEnable)
{
attr.mOnlineEnable = 1;
attr.mOnlineShareBufNum = pContext->mConfigPara.mOnlineShareBufNum;
}
attr.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
attr.memtype = V4L2_MEMORY_MMAP;
attr.format.pixelformat = map_PIXEL_FORMAT_E_to_V4L2_PIX_FMT(pContext->mConfigPara.mPicFormat);
attr.format.field = V4L2_FIELD_NONE;
attr.format.colorspace = V4L2_COLORSPACE_JPEG;
attr.format.width = pContext->mConfigPara.mCaptureWidth;
attr.format.height = pContext->mConfigPara.mCaptureHeight;
attr.nbufs = 5;//10;
attr.nplanes = 2;
attr.fps = pContext->mConfigPara.mFrameRate;
attr.mbEncppEnable = TRUE;
eRet = AW_MPI_VI_SetVippAttr(pContext->mVIDev, &attr);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_SetVippAttr failed");
}
1.4 运行ISP
AW_MPI_ISP_Run(0);
1.5 开启VIPP
eRet = AW_MPI_VI_EnableVipp(pContext->mVIDev);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VI_EnableVipp failed");
}
1.6 创建VI虚通道
eRet = AW_MPI_VI_CreateVirChn(pContext->mVIDev, pContext->mVIChn, NULL);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VI_CreateVirChn failed ");
}
1.7 设置编码属性
pContext->mVEChn = pContext->mConfigPara.mVeChnID;
memset(&pContext->mVEncChnAttr, 0, sizeof(VENC_CHN_ATTR_S));
if (pContext->mConfigPara.mOnlineEnable)
{
pContext->mVEncChnAttr.VeAttr.mOnlineEnable = 1;
pContext->mVEncChnAttr.VeAttr.mOnlineShareBufNum = pContext->mConfigPara.mOnlineShareBufNum;
}
SIZE_S wantedVideoSize = {pContext->mConfigPara.mCaptureWidth, pContext->mConfigPara.mCaptureHeight};
SIZE_S videosize = {pContext->mConfigPara.mCaptureWidth, pContext->mConfigPara.mCaptureHeight};
PAYLOAD_TYPE_E videoCodec = pContext->mConfigPara.EncoderType;
pContext->mVEncChnAttr.VeAttr.Type = videoCodec;
pContext->mVEncChnAttr.VeAttr.MaxKeyInterval = pContext->mConfigPara.mFrameRate;
pContext->mVEncChnAttr.VeAttr.SrcPicWidth = videosize.Width;
pContext->mVEncChnAttr.VeAttr.SrcPicHeight = videosize.Height;
pContext->mVEncChnAttr.VeAttr.Field = VIDEO_FIELD_FRAME;
pContext->mVEncChnAttr.VeAttr.PixelFormat = pContext->mConfigPara.mPicFormat;
pContext->mVEncChnAttr.VeAttr.mColorSpace = attr.format.colorspace;
pContext->mVEncChnAttr.EncppAttr.mbEncppEnable = TRUE;
pContext->mVencRcParam.product_mode = VENC_PRODUCT_IPC_MODE;
pContext->mVencRcParam.sensor_type = VENC_ST_EN_WDR;
int wantedVideoBitRate = pContext->mConfigPara.bit_rate;
1.8 根据编码类型设置属性
if(PT_H264 == pContext->mVEncChnAttr.VeAttr.Type)
{
pContext->mVEncChnAttr.VeAttr.AttrH264e.bByFrame = TRUE;
pContext->mVEncChnAttr.VeAttr.AttrH264e.Profile = 2;
pContext->mVEncChnAttr.VeAttr.AttrH264e.mLevel = VENC_H264Level51;
pContext->mVEncChnAttr.VeAttr.AttrH264e.PicWidth = wantedVideoSize.Width;
pContext->mVEncChnAttr.VeAttr.AttrH264e.PicHeight = wantedVideoSize.Height;
pContext->mVEncChnAttr.VeAttr.AttrH264e.mbPIntraEnable = TRUE;
pContext->mVEncChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H264CBR;
pContext->mVEncChnAttr.RcAttr.mAttrH264Cbr.mBitRate = wantedVideoBitRate;
pContext->mVencRcParam.ParamH264Cbr.mMaxQp = 51;
pContext->mVencRcParam.ParamH264Cbr.mMinQp = 1;
pContext->mVencRcParam.ParamH264Cbr.mMaxPqp = 50;
pContext->mVencRcParam.ParamH264Cbr.mMinPqp = 10;
pContext->mVencRcParam.ParamH264Cbr.mQpInit = 35;
pContext->mVencRcParam.ParamH264Cbr.mbEnMbQpLimit = 0;
}
else if(PT_H265 == pContext->mVEncChnAttr.VeAttr.Type)
{
pContext->mVEncChnAttr.VeAttr.AttrH265e.mbByFrame = TRUE;
pContext->mVEncChnAttr.VeAttr.AttrH265e.mProfile = 0;
pContext->mVEncChnAttr.VeAttr.AttrH265e.mLevel = VENC_H265Level62;
pContext->mVEncChnAttr.VeAttr.AttrH265e.mPicWidth = wantedVideoSize.Width;
pContext->mVEncChnAttr.VeAttr.AttrH265e.mPicHeight = wantedVideoSize.Height;
pContext->mVEncChnAttr.VeAttr.AttrH265e.mbPIntraEnable = TRUE;
pContext->mVEncChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H265CBR;
pContext->mVEncChnAttr.RcAttr.mAttrH265Cbr.mBitRate = wantedVideoBitRate;
pContext->mVencRcParam.ParamH265Cbr.mMaxQp = 51;
pContext->mVencRcParam.ParamH265Cbr.mMinQp = 1;
pContext->mVencRcParam.ParamH265Cbr.mMaxPqp = 50;
pContext->mVencRcParam.ParamH265Cbr.mMinPqp = 10;
pContext->mVencRcParam.ParamH265Cbr.mQpInit = 35;
pContext->mVencRcParam.ParamH265Cbr.mbEnMbQpLimit = 0;
}
else if(PT_MJPEG== pContext->mVEncChnAttr.VeAttr.Type)
{
pContext->mVEncChnAttr.VeAttr.AttrMjpeg.mbByFrame = TRUE;
pContext->mVEncChnAttr.VeAttr.AttrMjpeg.mPicWidth = wantedVideoSize.Width;
pContext->mVEncChnAttr.VeAttr.AttrMjpeg.mPicHeight = wantedVideoSize.Height;
pContext->mVEncChnAttr.RcAttr.mRcMode = VENC_RC_MODE_MJPEGCBR;
pContext->mVEncChnAttr.RcAttr.mAttrMjpegeCbr.mBitRate = wantedVideoBitRate;
}
1.9 开启VO设备
pContext->mVoDev = 0;
AW_MPI_VO_Enable(pContext->mVoDev);
1.10 设置VO设备属性
VO_PUB_ATTR_S spPubAttr;
memset(&spPubAttr, 0, sizeof(VO_PUB_ATTR_S));
AW_MPI_VO_GetPubAttr(pContext->mVoDev, &spPubAttr);
spPubAttr.enIntfType = VO_INTF_LCD;
spPubAttr.enIntfSync = VO_OUTPUT_NTSC;
AW_MPI_VO_SetPubAttr(pContext->mVoDev, &spPubAttr);
1.11 注册VO设备图层
int hlay0 = 0;
while(hlay0 < VO_MAX_LAYER_NUM)
{
if(SUCCESS == AW_MPI_VO_EnableVideoLayer(hlay0))
{
break;
}
++hlay0;
}
if(hlay0 == VO_MAX_LAYER_NUM)
{
aloge("error: enable video layer failed");
}
1.12 设置图层属性
pContext->mVoLayer = hlay0;
AW_MPI_VO_GetVideoLayerAttr(pContext->mVoLayer, &pContext->mLayerAttr);
pContext->mLayerAttr.stDispRect.X = 0;
pContext->mLayerAttr.stDispRect.Y = 0;
pContext->mLayerAttr.stDispRect.Width = pContext->mConfigPara.mDispWidth;
pContext->mLayerAttr.stDispRect.Height = pContext->mConfigPara.mDispHeight;
AW_MPI_VO_SetVideoLayerAttr(pContext->mVoLayer, &pContext->mLayerAttr);
1.13 创建VO通道
BOOL bSuccessFlag = FALSE;
pContext->mVOChn = 0;
while(pContext->mVOChn < VO_MAX_CHN_NUM)
{
eRet = AW_MPI_VO_CreateChn(pContext->mVoLayer, pContext->mVOChn);
if(eRet == SUCCESS)
{
bSuccessFlag = TRUE;
break;
}
else if(eRet == ERR_VO_CHN_NOT_DISABLE)
{
alogd("vo channel[%d] is exist, find next", pContext->mVOChn);
pContext->mVOChn++;
}
else
{
aloge("error:create vo channel[%d] ret[0x%x]", pContext->mVOChn, eRet);
}
}
1.14 设置VO通道回调函数
MPPCallbackInfo cbInfo;
cbInfo.cookie = (void *)pContext;
cbInfo.callback = (MPPCallbackFuncType)&SampleRegion_VOCallbackWrapper;
AW_MPI_VO_RegisterCallback(pContext->mVoLayer, pContext->mVOChn, &cbInfo);
AW_MPI_VO_SetChnDispBufNum(pContext->mVoLayer, pContext->mVOChn, 0);
1.15 创建VENC通道
eRet = AW_MPI_VENC_CreateChn(pContext->mVEChn, &pContext->mVEncChnAttr);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VENC_CreateChn failed");
goto _exit;
}
1.16 设置编码通道属性至对应通道
AW_MPI_VENC_SetRcParam(pContext->mVEChn, &pContext->mVencRcParam);
1.17 设置输入输出的帧率
VENC_FRAME_RATE_S stFrameRate;
stFrameRate.SrcFrmRate = pContext->mConfigPara.mFrameRate;
stFrameRate.DstFrmRate = pContext->mConfigPara.mFrameRate;
AW_MPI_VENC_SetFrameRate(pContext->mVEChn, &stFrameRate);
1.18 设置编码回调函数
MPPCallbackInfo cbInfo;
cbInfo.cookie = (void*)pContext;
cbInfo.callback = (MPPCallbackFuncType)&MPPCallbackWrapper;
AW_MPI_VENC_RegisterCallback(pContext->mVEChn, &cbInfo);
1.19 打开输出文件
VencHeaderData vencheader;
pContext->mOutputFileFp = fopen(pContext->mConfigPara.OutputFilePath,"wb+");
if(!pContext->mOutputFileFp)
{
aloge("error:can not open the file[%s]", pContext->mConfigPara.OutputFilePath);
goto _exit;
}
1.20 根据不同的编码类型写入不同的头部
if(PT_H264 == pContext->mVEncChnAttr.VeAttr.Type)
{
result = AW_MPI_VENC_GetH264SpsPpsInfo(pContext->mVEChn, &vencheader);
if (SUCCESS == result)
{
if(vencheader.nLength)
{
fwrite(vencheader.pBuffer, vencheader.nLength, 1, pContext->mOutputFileFp);
}
}
else
{
alogd("AW_MPI_VENC_GetH264SpsPpsInfo failed!\n");
result = -1;
}
}
else if(PT_H265 == pContext->mVEncChnAttr.VeAttr.Type)
{
result = AW_MPI_VENC_GetH265SpsPpsInfo(pContext->mVEChn, &vencheader);
if (SUCCESS == result)
{
if(vencheader.nLength)
{
fwrite(vencheader.pBuffer, vencheader.nLength, 1, pContext->mOutputFileFp);
}
}
else
{
alogd("AW_MPI_VENC_GetH265SpsPpsInfo failed!\n");
result = -1;
}
}
1.21 创建VI/VO/VENC的绑定变量
MPP_CHN_S VOChn = {MOD_ID_VOU, pContext->mVoLayer, pContext->mVOChn};
MPP_CHN_S VIChn = {MOD_ID_VIU, pContext->mVIDev, pContext->mVIChn};
MPP_CHN_S VeChn = {MOD_ID_VENC, 0, pContext->mVEChn};
1.22 绑定VI和VO通道并启动VO通道
if(bDisplayFlag)
{
AW_MPI_SYS_Bind(&VIChn, &VOChn);
//start vo, clock, vi_channel andvvenc
eRet = AW_MPI_VI_EnableVirChn(pContext->mVIDev, pContext->mVIChn);
if(eRet != SUCCESS)
{
aloge("error:enablecirchn failed");
}
AW_MPI_VO_StartChn(pContext->mVoLayer, pContext->mVOChn);
}
1.23 编码保存码流线程
if(bAddVencChannel)
{
if(pthread_create(&pContext->mEncThreadId, NULL, GetEncoderFrameThread, pContext) < 0)
{
aloge("error: the pthread can not be created");
}
alogw("the pthread[0x%x] of venc had created", pContext->mEncThreadId);
}
在该线程函数中,将VI和VENC通道进行绑定,即从摄像头输入获取图像帧,直接送到编码器进行编码。
1.23.1 创建VI虚通道
int eRet = AW_MPI_VI_CreateVirChn(pContext->mVIDev, pContext->mVI2VEncChn, NULL);
if(eRet != SUCCESS)
{
aloge("error:AW_MPI_VI_CreateVirChn failed");
}
1.23.2 绑定VI和VE通道
MPP_CHN_S ViChn = {MOD_ID_VIU, pContext->mVIDev, pContext->mVI2VEncChn};
MPP_CHN_S VeChn = {MOD_ID_VENC, 0, pContext->mVEChn};
AW_MPI_SYS_Bind(&ViChn,&VeChn);
1.23.3 开启VI虚通道
eRet = AW_MPI_VI_EnableVirChn(pContext->mVIDev, pContext->mVI2VEncChn);
if(eRet != SUCCESS)
{
aloge("error:enablecirchn failed");
}
1.23.4 开启VE编码通道
AW_MPI_VENC_StartRecvPic(pContext->mVEChn);
1.2.4 获取并保存码流
接下来会进入循环,不断的从编码器获取编码后的视频帧,并且将码流保存至文件中。
if(AW_MPI_VENC_GetStream(pContext->mVEChn, &VencFrame, 4000) < 0)
{
aloge("get first frame failed!\n");
continue;
}
将文件写入输出文件中
if(VencFrame.mpPack != NULL && VencFrame.mpPack->mLen0)
{
fwrite(VencFrame.mpPack->mpAddr0, 1, VencFrame.mpPack->mLen0, pContext->mOutputFileFp);
}
if(VencFrame.mpPack != NULL && VencFrame.mpPack->mLen1)
{
fwrite(VencFrame.mpPack->mpAddr1, 1, VencFrame.mpPack->mLen1, pContext->mOutputFileFp);
}
释放编码视频帧
AW_MPI_VENC_ReleaseStream(pContext->mVEChn, &VencFrame);
1.2.5 停止编码
AW_MPI_VENC_StopRecvPic(pContext->mVEChn);
1.2.6 关闭VI虚通道
AW_MPI_VI_DisableVirChn(pContext->mVIDev, pContext->mVI2VEncChn);
1.2.7 重置并销毁VENC通道
AW_MPI_VENC_ResetChn(pContext->mVEChn);
AW_MPI_VENC_DestroyChn(pContext->mVEChn);
1.2.8 销毁VI通道
AW_MPI_VI_DestroyVirChn(pContext->mVIDev, pContext->mVI2VEncChn);
2.叠加模块的使用
2.1 叠加至VI通道(OVERLAY_RGN)
2.1.1 配置区域属性
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = OVERLAY_RGN;
stRegion.unAttr.stOverlay.mPixelFmt = pContext->mConfigPara.mBitmapFormat; //MM_PIXEL_FORMAT_RGB_8888;
//stRegion.unAttr.stOverlay.mSize = {(unsigned int)pContext->mConfigPara.overlay_w, (unsigned int)pContext->mConfigPara.overlay_h};
stRegion.unAttr.stOverlay.mSize.Width = (unsigned int)pContext->mConfigPara.overlay_w;
stRegion.unAttr.stOverlay.mSize.Height = (unsigned int)pContext->mConfigPara.overlay_h;
2.1.2 创建区域
AW_MPI_RGN_Create(pContext->mOverlayHandle, &stRegion);
2.1.3 配置位图属性
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;
nSize = BITMAP_S_GetdataSize(&stBmp);
stBmp.mpData = malloc(nSize);
if(NULL == stBmp.mpData)
{
aloge("fatal error! malloc fail!");
}
memset(stBmp.mpData, 0xCC, nSize);
2.1.4 设置区域位图
AW_MPI_RGN_SetBitMap(pContext->mOverlayHandle, &stBmp);
free(stBmp.mpData);
2.1.5 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
//stRgnChnAttr.unChnAttr.stOverlayChn.stPoint = {pContext->mConfigPara.overlay_x, pContext->mConfigPara.overlay_y};
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.X = pContext->mConfigPara.overlay_x;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.Y = pContext->mConfigPara.overlay_y;
stRgnChnAttr.unChnAttr.stOverlayChn.mLayer = 0;
stRgnChnAttr.unChnAttr.stOverlayChn.mFgAlpha = 0x5C; // global alpha mode value for ARGB1555
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;
2.1.6 将区域叠加到通道上
AW_MPI_RGN_AttachToChn(pContext->mOverlayHandle, &VIChn, &stRgnChnAttr);
2.2 叠加至VE通道(OVERLAY_RGN)
2.2.1 配置区域属性
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = OVERLAY_RGN;
stRegion.unAttr.stOverlay.mPixelFmt = pContext->mConfigPara.mBitmapFormat; //MM_PIXEL_FORMAT_RGB_8888;
//stRegion.unAttr.stOverlay.mSize = {(unsigned int)pContext->mConfigPara.overlay_w, (unsigned int)pContext->mConfigPara.overlay_h};
stRegion.unAttr.stOverlay.mSize.Width = pContext->mConfigPara.overlay_w;
stRegion.unAttr.stOverlay.mSize.Height = pContext->mConfigPara.overlay_h;
2.2.2 创建区域
AW_MPI_RGN_Create(pContext->mOverlayHandle + 1, &stRegion);
2.2.3 配置位图属性
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;
nSize = BITMAP_S_GetdataSize(&stBmp);
stBmp.mpData = malloc(nSize);
if(NULL == stBmp.mpData)
{
aloge("fatal error! malloc fail!");
}
if(MM_PIXEL_FORMAT_RGB_1555 == pContext->mConfigPara.mBitmapFormat)
{
GenerateARGB1555(stBmp.mpData, nSize);
}
else if(MM_PIXEL_FORMAT_RGB_8888 == pContext->mConfigPara.mBitmapFormat)
{
GenerateARGB8888(stBmp.mpData, nSize);
}
else
{
aloge("fatal error! unsupport bitmap format:%d", pContext->mConfigPara.mBitmapFormat);
}
2.2.4 设置区域位图
AW_MPI_RGN_SetBitMap(pContext->mOverlayHandle + 1, &stBmp);
free(stBmp.mpData);
2.2.5 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
//stRgnChnAttr.unChnAttr.stOverlayChn.stPoint = {pContext->mConfigPara.overlay_x, pContext->mConfigPara.overlay_y};
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.X = pContext->mConfigPara.overlay_x+160;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.Y = pContext->mConfigPara.overlay_y+160;
stRgnChnAttr.unChnAttr.stOverlayChn.mLayer = 0;
stRgnChnAttr.unChnAttr.stOverlayChn.mFgAlpha = 0x40; // global alpha mode value for ARGB1555
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 = FALSE;
2.2.6 将区域叠加到通道上
AW_MPI_RGN_AttachToChn(pContext->mOverlayHandle + 1, &VeChn, &stRgnChnAttr);
2.3 叠加至VI通道(COVER_RGN)
2.3.1 创建区域
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = COVER_RGN;
AW_MPI_RGN_Create(pContext->mCoverHandle, &stRegion);
2.3.2 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stCoverChn.enCoverType = AREA_RECT;
//stRgnChnAttr.unChnAttr.stCoverChn.stRect = {pContext->mConfigPara.cover_x, pContext->mConfigPara.cover_y, (unsigned int)pContext->mConfigPara.cover_w, (unsigned int)pContext->mConfigPara.cover_h};
stRgnChnAttr.unChnAttr.stCoverChn.stRect.X = pContext->mConfigPara.cover_x;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Y = pContext->mConfigPara.cover_y;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Width = pContext->mConfigPara.cover_w;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Height= pContext->mConfigPara.cover_h;
stRgnChnAttr.unChnAttr.stCoverChn.mColor = 0;
stRgnChnAttr.unChnAttr.stCoverChn.mLayer = 0;
2.3.3 将区域叠加至通道上
AW_MPI_RGN_AttachToChn(pContext->mCoverHandle, &VIChn, &stRgnChnAttr);
2.4 叠加至VE通道(COVER_RGN)
2.4.1 创建区域
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = COVER_RGN;
// pContext->mCoverHandle += 1;
AW_MPI_RGN_Create(pContext->mCoverHandle + 1, &stRegion);
2.4.2 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stCoverChn.enCoverType = AREA_RECT;
//stRgnChnAttr.unChnAttr.stCoverChn.stRect = {pContext->mConfigPara.cover_x, pContext->mConfigPara.cover_y, (unsigned int)pContext->mConfigPara.cover_w, (unsigned int)pContext->mConfigPara.cover_h};
stRgnChnAttr.unChnAttr.stCoverChn.stRect.X = pContext->mConfigPara.cover_x + 96;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Y = pContext->mConfigPara.cover_y + 96;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Width = pContext->mConfigPara.cover_w;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Height= pContext->mConfigPara.cover_h;
stRgnChnAttr.unChnAttr.stCoverChn.mColor = 255;
stRgnChnAttr.unChnAttr.stCoverChn.mLayer = 0;
2.4.3 将区域叠加至通道上
AW_MPI_RGN_AttachToChn(pContext->mCoverHandle + 1, &VeChn, &stRgnChnAttr);
2.5 叠加至VI通道中(ORL_RGN)
2.5.1 创建区域
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = ORL_RGN;
AW_MPI_RGN_Create(pContext->mOrlHandle, &stRegion);
2.5.2 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stOrlChn.enAreaType = AREA_RECT;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.X = pContext->mConfigPara.orl_x;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Y = pContext->mConfigPara.orl_y;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Width = (unsigned int)pContext->mConfigPara.orl_w;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Height = (unsigned int)pContext->mConfigPara.orl_h;
stRgnChnAttr.unChnAttr.stOrlChn.mColor = 0x0000FF00;
stRgnChnAttr.unChnAttr.stOrlChn.mThick = (unsigned int)pContext->mConfigPara.orl_thick;
stRgnChnAttr.unChnAttr.stOrlChn.mLayer = 0;
2.5.3 将区域叠加至通道上
AW_MPI_RGN_AttachToChn(pContext->mOrlHandle, &VIChn, &stRgnChnAttr);
2.6 叠加至VE通道中(ORL_RGN)
2.6.1 创建区域
memset(&stRegion, 0, sizeof(RGN_ATTR_S));
stRegion.enType = ORL_RGN;
AW_MPI_RGN_Create(pContext->mOrlHandle + 1, &stRegion);
2.6.2 配置区域通道显示属性
stRgnChnAttr.bShow = TRUE;
stRgnChnAttr.enType = stRegion.enType;
stRgnChnAttr.unChnAttr.stOrlChn.enAreaType = AREA_RECT;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.X = pContext->mConfigPara.orl_x + 96;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Y = pContext->mConfigPara.orl_y + 96;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Width = (unsigned int)pContext->mConfigPara.orl_w;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Height = (unsigned int)pContext->mConfigPara.orl_h;
stRgnChnAttr.unChnAttr.stOrlChn.mColor = 0x0000FFFF;
stRgnChnAttr.unChnAttr.stOrlChn.mThick = 6;
stRgnChnAttr.unChnAttr.stOrlChn.mLayer = 0;
2.6.3 将区域叠加至通道上
AW_MPI_RGN_AttachToChn(pContext->mOrlHandle + 1, &VeChn, &stRgnChnAttr);
3.使用中改变叠加属性
3.1 改变VI通道(overlay)
3.1.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mOverlayHandle, &VIChn, &stRgnChnAttr);
3.1.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.X += 96;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.Y = 0;
AW_MPI_RGN_SetDisplayAttr(pContext->mOverlayHandle, &VIChn, &stRgnChnAttr);
3.2 改变VE通道(overlay)
3.2.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mOverlayHandle + 1, &VeChn, &stRgnChnAttr);
3.2.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.X += 96;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.Y += 96;
alogd("overlay attach to ve again");
AW_MPI_RGN_SetDisplayAttr(pContext->mOverlayHandle + 1, &VeChn, &stRgnChnAttr);
3.3 改变VI通道(cover)
3.3.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mCoverHandle, &VIChn, &stRgnChnAttr);
3.3.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stCoverChn.stRect.X = 0;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Y = 0;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Width += 48;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Height += 48;
AW_MPI_RGN_SetDisplayAttr(pContext->mCoverHandle, &VIChn, &stRgnChnAttr);
3.4 改变VE通道(cover)
3.4.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mCoverHandle + 1, &VeChn, &stRgnChnAttr);
3.4.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stCoverChn.stRect.X += 208;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Y += 208;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Width += 16;
stRgnChnAttr.unChnAttr.stCoverChn.stRect.Height += 16;
alogd("cover attach to ve again");
AW_MPI_RGN_SetDisplayAttr(pContext->mCoverHandle + 1, &VeChn, &stRgnChnAttr);
3.5 改变VI通道(orl)
3.5.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mOrlHandle, &VIChn, &stRgnChnAttr);
3.5.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stOrlChn.stRect.X += 60;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Y += 60;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Width += 60;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Height += 20;
alogd("orl attach to vipp again");
AW_MPI_RGN_SetDisplayAttr(pContext->mOrlHandle, &VIChn, &stRgnChnAttr);
3.6 改变VE通道(orl)
3.6.1 获取区域的通道显示属性
eRet = AW_MPI_RGN_GetDisplayAttr(pContext->mOrlHandle + 1, &VeChn, &stRgnChnAttr);
3.6.2 更新叠加属性属性
stRgnChnAttr.unChnAttr.stOrlChn.stRect.X += 30;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Y += 30;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Width += 60;
stRgnChnAttr.unChnAttr.stOrlChn.stRect.Height += 20;
AW_MPI_RGN_SetDisplayAttr(pContext->mOrlHandle + 1, &VeChn, &stRgnChnAttr);
4.退出与清理操作
4.1 叠加至VI通道的清理
AW_MPI_RGN_DetachFromChn(pContext->mOverlayHandle, &VIChn);
AW_MPI_RGN_Destroy(pContext->mOverlayHandle);
AW_MPI_RGN_DetachFromChn(pContext->mCoverHandle, &VIChn);
AW_MPI_RGN_Destroy(pContext->mCoverHandle);
AW_MPI_RGN_DetachFromChn(pContext->mOrlHandle, &VIChn);
AW_MPI_RGN_Destroy(pContext->mOrlHandle);
4.2叠加至VE通道的清理
AW_MPI_RGN_DetachFromChn(pContext->mOverlayHandle + 1, &VeChn);
AW_MPI_RGN_Destroy(pContext->mOverlayHandle + 1);
AW_MPI_RGN_DetachFromChn(pContext->mCoverHandle + 1, &VeChn);
AW_MPI_RGN_Destroy(pContext->mCoverHandle + 1);
AW_MPI_RGN_DetachFromChn(pContext->mOrlHandle + 1, &VeChn);
AW_MPI_RGN_Destroy(pContext->mOrlHandle + 1);
4.3 停止编码通道
AW_MPI_VENC_StopRecvPic(pContext->mVEChn);
4.4 停止VO通道
AW_MPI_VO_StopChn(pContext->mVoLayer, pContext->mVOChn);
4.5 关闭VI通道
AW_MPI_VI_DisableVirChn(pContext->mVIDev, pContext->mVIChn);
AW_MPI_VI_DisableVirChn(pContext->mVIDev, pContext->mVIChn + 1);
4.6 重置编码通道
AW_MPI_VENC_ResetChn(pContext->mVEChn);
4.7 销毁VO通道
AW_MPI_VO_DestroyChn(pContext->mVoLayer, pContext->mVOChn);
4.8 销毁VE和VI通道
pContext->mVOChn = MM_INVALID_CHN;
pContext->mClockChn = MM_INVALID_CHN;
AW_MPI_VENC_DestroyChn(pContext->mVEChn);
AW_MPI_VI_DestroyVirChn(pContext->mVIDev, pContext->mVIChn);
AW_MPI_VI_DestroyVirChn(pContext->mVIDev, pContext->mVIChn + 1);
4.9 关闭VIPP设备
AW_MPI_VI_DisableVipp(pContext->mVIDev);
4.10 停止ISP
AW_MPI_ISP_Stop(0);
4.11 销毁VIPP设备
AW_MPI_VI_DestroyVipp(pContext->mVIDev);
4.12 关闭图层并关闭VO设备
AW_MPI_VO_DisableVideoLayer(pContext->mVoLayer);
pContext->mVoLayer = -1;
AW_MPI_VO_RemoveOutsideVideoLayer(pContext->mUILayer);
//disalbe vo dev
AW_MPI_VO_Disable(pContext->mVoDev);
pContext->mVoDev = -1;
4.13 退出MPP平台
AW_MPI_SYS_Exit();
4.14 清理变量结构体
if(pContext->mOutputFileFp)
{
fclose(pContext->mOutputFileFp);
pContext->mOutputFileFp = NULL;
}
destroySampleRegionContext(pContext);
free(pContext);