10-3_叠加模块示例源码解析

叠加模块示例源码解析

该实例程序会演示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);