视频编码SVC --- JSVM代码阅读笔记(三)

    技术2022-05-20  27

    LayerEncoder::process( UInt             uiAUIndex,     //这是CodingIndex

                       AccessUnitData&  rcAccessUnitData,

                       PicBufferList&   rcPicBufferInputList,    // H264AVCEncoder::m_acOrgPicBufferList  [uiLayer],

                                            PicBufferList&   rcPicBufferOutputList,  // H264AVCEncoder::m_acRecPicBufferList  [uiLayer],

                       PicBufferList&   rcPicBufferUnusedList,  // H264AVCEncoder::apcPicBufferUnusedList[uiLayer],

                       ParameterSetMng* pcParameterSetMng )

    xInitBitCounts()           //统计lower layer编码的比特数

    xUpdateELPics()

       //GOP每一帧,如果m_papcELFrame[uiIndex]Unvalid

         m_pcH264AVCEncoder->getELRefPic( m_uiDependencyId, uiTemporalId, uiFIdInTId );

            m_apcLayerEncoder[uiELId]->getRefPic( uiTemporalId, uiFrameIdInTId );    //得到相同分辨率的最高EL层图像

     

         m_papcELFrame[uiIndex]->copy( const_cast<Frame*>( pcELPic ), FRAME )    //拷贝到m_papcELFrame

     

         xFillAndUpsampleFrame( m_papcELFrame[uiIndex], FRAME, m_bFrameMbsOnlyFlag )   //对最高层EL参考图像进行处理

           m_pcYuvFullPelBufferCtrl->initMb()    //初始化整像素的宏块大小

    m_pcYuvHalfPelBufferCtrl->initMb()   //初始化1/2像素的宏块大小

    pcFrame->initHalfPel( pHPData )        // Frame

               getHalfPelYuvBuffer()->init( rpucYuvBuffer )

                  m_rcYuvBufferCtrl.initMb();    //进行1/2像素的扩充

           pcFrame->extendFrame( m_pcQuarterPelFilter, ePicType, bFrameMbsOnlyFlag )

               getFullPelYuvBuffer()->fillMargin( )      //边缘填充

                  m_rcYuvBufferCtrl.initMb();

                  xFillPlaneMargin()

               pcQuarterPelFilter->filterFrame(getFullPelYuvBuffer(), getHalfPelYuvBuffer() )   //进行int->1/2像素的插值滤波

     

    xEncodePicture( bPicCoded, uiTemporalId, uiFrameIdInGOP, rcAccessUnitData, rcPicBufferInputList )   //后面分析

     

    //当一个GOP编码完成

    xStoreReconstruction( rcPicBufferOutputList )

       //GOP中每一帧,从输出队列H264AVCEncoder::m_acRecPicBufferList中取出一个PicBuffer

    m_papcFrame[uiIndex<<m_uiNotCodedStages]->store( pcPicBuffer )

          getFullPelYuvBuffer()->storeToPicBuffer     ( pcPicBuffer )

     

    xFinishGOP ( rcPicBufferInputList, rcPicBufferOutputList, rcPicBufferUnusedList) //output队列中过多的图像放到Unused队列

     

     

    ErrVal                   // ×××××对每一个Layer GOP中的每一个AU ×××××

    LayerEncoder::xEncodePicture( Bool&   rbPictureCoded,        //是否编码,输出用

                                   UInt            uiTemporalId,            //时间层ID

                                    UInt            uiFrameIdInGOP,       //GOP中播放顺序

                             AccessUnitData& rcAccessUnitData,       //该帧的AU

                                     PicBufferList&  rcPicBufferInputList )      // H264AVCEncoder::m_acOrgPicBufferList  [uiLayer],  

    //如果是IDR

    LayerEncoder的成员Bool  m_abCoded[(1<<MAX_DSTAGES)+1]全部置0 (用来指示GOP中对应帧是否编码)

     

    //如果是非第一个GOP的第一个帧

    当前帧m_papcFramem_pcAnchorFrameReconstructed拷贝而来

    m_apcBaseFrame[0]m_apcBaseFrame[1]拷贝而来        //RefBasePic

     

    重要参数

    rcControlData

    m_pacControlData[ uiFrameIdInGOP ]

    帧控制类

    pcMbDataCtrl

    rcControlData.getMbDataCtrl()

    宏块控制类

    pcFrame

    m_papcFrame [ uiFrameIdInGOP]

    当前帧

    pcResidualLF

    m_pcResidualLF

    xStoreEstimation 去块滤波计算CBP

    pcResidualILPred

    m_pcResidualILPred

    xStoreEstimation

    pcOrgFrame

    m_apcFrameTemp  [ 2 ]

    pcFrame的编码前内容,原始帧像素

    pcPredSignal

    m_apcFrameTemp  [ 3 ]

    xStoreEstimation,没任何作用

    rcOutputList

    rcAccessUnitData.getNalUnitList()

    AUNalUnit队列

     

    m_pcSubband

    一层编码完成后的重建帧(去块滤波之前)

     

    m_apcBaseFrame[ 0/1 ]

    GOP的两个RefBasePic

    pcTempBaseFrame

    m_apcFrameTemp[0]

    辅助INTRA上采样用 (在xInitControlData里)

    pcTempFrame

    m_apcFrameTemp[1]

    辅助INTRA上采样用 (在xInitControlData里)

     

    //RateControl相关,未关注

     

    xInitControlData( uiFrameIdInGOP, uiTemporalId, ePicType )

    xSetBaseLayerData( uiFrameIdInGOP, ePicType )       //设置BaseLayer信息

      m_pcH264AVCEncoder->getBaseLayerStatus( uiBaseLayerId, m_uiDependencyId, ePicType, uiTemporalId )

    m_apcLayerEncoder[ruiBaseLayerId]->getBaseLayerStatus( bExists, ePicType, uiTemporalId )  //检查BaseLayerId

      //BaseLayerSize信息更新本层的ESS信息

      m_pcResizeParameters->updatePicParameters( m_papcFrame[ uiFrameIdInGOP ]->getPicParameters( ePicType ) );

      设置Inter-layer 预测的参数 BaseModeMotionResidual

      检查Level的约束

      rcControlData.setBaseLayer( uiBaseLayerId );     //最后才确定BaseLayerId

     

    设置QP & lambda

    pcSliceHeader->setTCoeffLevelPredictionFlag( m_pcLayerParameters->getTCoeffLevelPredictionFlag() );

     

    xGetAndSetPredictionLists( rcControlData, uiFrameIdInGOP, ePicType, true )   //设置参考帧队列

      //设置rcRefListStruct = rcControlData.getRefListStruct(); 

      //当前为RC队列:rcRefListStruct.acRefFrameListRC[ X ]

      获得当前帧状态eRLU RLU_REF_BASE_PIC (KeyPicture)或者 RLU_RECONSTRUCTION

      xGetPredictionLists( rcRefList0, rcRefList1, uiFrameIdCol, uiFrameIdInGOP, ePicType, eRLU, bHalfPel )

         //LayerEncoderm_acRefPicListFrameId_LX[ uiFrameIdInGOP ]队列每一帧

           pcFrame = xGetRefFrame( uiFrmId, eRefListUsage );       //获得对应index的参考帧

              //如果是RefBasePicm_apcBaseFrame[ 0/1 ] ,否则m_papcELFrameMGS)或m_papcFrame

           //如果没有extend,还要xFillAndUpsampleFrame() / xFillAndExtendFrame()

           rcRefListX.add( pcFrame->getPic( FRAME )   //加入队列

           pcFrame->setLongTerm( m_bUseLongTermPics );

         // uiFrameIdCol是最后加入RCList1FrameId,即List1的第一帧(因为是栈)

     

    如果是KeyPicture或者使用Std(MGScontrol=0)MEMC队列都用RC队列------同层的参考帧

    MGScontrol=1MEEL的队列,MCRC(std)的队列

    MGScontrol=2MEMC都用EL的队列

     

      SliceHeader写的是StdRC队列

      //当是B片时pcMbDataCtrl0L1 = m_pacControlData[ rcRefListStruct.uiFrameIdCol ].getMbDataCtrl(),否则为空

      rcControlData.setMbDataCtrl0L1( pcMbDataCtrl0L1 );  //这个是co-located MB的控制类

     

    //更新ESS信息

    m_pcResizeParameters->updatePicParameters( m_papcFrame[ uiFrameIdInGOP ]->getPicParameters( ePicType ) );

     

    xInitBaseLayerData( rcControlData, ePicType )

      先将m_pcBaseLayerRec m_pcBaseLayerSbbm_pcBaseLayerCtrl m_pcBaseLayerCtrlField 设置成0

      //如果BaseLayer存在

        m_pcH264AVCEncoder->getBaseLayerDataAvlb(pcBaseFrame, pcBaseResidual, pcBaseDataCtrl,

     rcControlData.getBaseLayerId(),bBaseDataAvailable,

                                               ePicType, pcSliceHeader->getTemporalId() )

           àm_apcLayerEncoder[uiBaseLayerId]->getBaseLayerDataAvlb(pcFrame,  pcResidual,  pcMbDataCtrl,

                                                  ePicType, uiTemporalId ) //获得BaseLayer信息

    LayerEncoder::xInitBaseLayerData()参数

    BaseLayer  LayerEncoder

    pcBaseFrame

    m_pcSubband

    pcBaseResidual

    m_pcResidualILPred

    pcBaseDataCtrl

    m_pacControlData[m_uiLastCodedFrameIdInGOP].getMbDataCtrl()

    BaseLayer的信息pcBaseDataCtrl更新ESS内容m_pcResizeParameters

    //判断分辨率是否改变并设置

    rcControlData.setSpatialScalability( m_pcResizeParameters->getSpatialResolutionChangeFlag() );

     

    m_pcH264AVCEncoder->getBaseLayerData( *pcSliceHeader, pcBaseFrame, pcBaseResidual, pcBaseDataCtrl,

                                            m_pcResizeParameters->getSpatialResolutionChangeFlag(),

                                            rcControlData.getBaseLayerId(),ePicType, 

    pcSliceHeader->getTemporalId() )

           à m_apcLayerEncoder[uiBaseLayerId]->getBaseLayerData( rcELSH, pcFrame, pcResidual, pcMbDataCtrl,

                                                           bSpatialScalability, ePicType, uiTemporalId ) );

             //再设置一遍,觉得多余

    LayerEncoder::xInitBaseLayerData()参数

    BaseLayer  LayerEncoder里,先复制给左边

    pcBaseFrame

    最后èm_pcBaseLayerFrame

    m_pcSubband    去块滤波前的重建帧

    pcBaseResidual

    最后èm_pcBaseLayerResidual

    m_pcResidualILPred

    pcBaseDataCtrl

    m_pacControlData[m_uiLastCodedFrameIdInGOP].getMbDataCtrl()

              //如果分辨率改变bSpatialScalability

               pcFrame = m_pcSubband = LayerEncoder::Frame m_apcFrameTemp[0] (数据一样,同一地址)

               m_pcLoopFilter->process(*pcSliceHeader, pcFrame, pcResidual, m_pacControlData[uiPos].getMbDataCtrl(),

                                     &rcELSH.getInterLayerDeblockingFilterParameter(),

                                     m_pacControlData[uiPos].getSpatialScalability() )  //因为是去块滤波前的

      //如果BaseLayer的控制器pcBaseDataCtrl存在

    pcSliceHeader->setSCoeffResidualPredFlag( m_pcResizeParameters );  //同分辨率的ELTCoeff=FALSE则为真

    m_pcBaseLayerCtrl->initSlice( *pcSliceHeader, PRE_PROCESS, false, NULL )

      把当前SliceHeader给了m_pcBaseLayerCtrlm_pcSliceHeader

          m_pcBaseLayerCtrl->upsampleMotion(…)

             //BaseLayer每个宏块

               cMotionUpsampling.resample( iMbX, iMbY )    MotionUpsampling

    xInitMb ( iMbXCurr, iMbYCurr )  //设置宏块大小、块模式、每块ref_idx等信息

    xSetPartIdcArray()

      //164x4

    xGetRefLayerPartIdc( ( iX << 2 ) + 1, ( iY << 2 ) + 1, m_aaiPartIdc[iX][iY] ) //得到该块在参考层的4x4id

          xGetRefLayerMb(iXInsideCurrMb,iYInsideCurrMb,iBaseMbIdx,iXInsideBaseMb, iYInsideBaseMb )

            //标准G6.1过程  得到该4x4块在参考层的宏块id和在宏块内的坐标

     

    //如果是InCropWindow且不是INTRA_BL,对每个List

       xGetRefIdxAndInitialMvPred( ListIdx( iListIdx ) )

         //对每个4x4

           xGetInitialBaseRefIdxAndMv() //获得BaseLayerMotionDataMv,修正Mv

                  //ref_idxMv保存在m_aaaiRefIdx / m_aaacMv

      

       //对每个8x8

         xDeriveBlockModeAndUpdateMv( iB8x8Idx )   //根据宏块分区更新Mv

       

       xDeriveMbMode ()   //BaseMbMode检查ref_idxMv,并得到MbMode

       xDeriveFwdBwd ()

       xSetInterIntraIdc ()    //设置m_aabBaseIntra[][]

     

    //如果是InCropWindow,则检查分区方式、ref_idxMv是否正确,设置m_bResPredSafe

    xSetResPredSafeFlag ()

     

    //BaseLayer得到MbMode、分区方式、ref_idxMv

    xSetPredMbData()

      //如果是INTRA_BL或非InCropWindow,则不得到Motion信息

      //否则拷贝每个List的每个8x8块的ref_idx和每个4x4块的Mv

     

      InCropWindow的话,MbModeFwdBwd等等也拷贝

     

      //SNR伸缩------SCoeff/TCoeff 且是InCropWindow

    rcMbData.copyTCoeffs    ( rcMbDataBase );    //拷贝BL的变换系数、CBPQPTransformSize

    拷贝BLSkipFlag

    IntraBL

    TCoeffPred

    拷贝BLMbMode

    拷贝IntraPredMode

    CBPQPTransformSize

     

    //如果BL有加权预测,直接拷贝BL的权值和加权表

    pcSliceHeaderCurr->setLumaLog2WeightDenom( pcSliceHeaderBase->getLumaLog2WeightDenom() );

    pcSliceHeaderCurr->setChromaLog2WeightDenom( pcSliceHeaderBase->getChromaLog2WeightDenom() );

    pcSliceHeaderCurr->getPredWeightTable( LIST_0 ).copy( pcSliceHeaderBase->getPredWeightTable( LIST_0 ) )

    pcSliceHeaderCurr->getPredWeightTable( LIST_1 ).copy( pcSliceHeaderBase->getPredWeightTable( LIST_1 ) );

    //如果BaseLayer可用(bBaseDataAvailable)

        m_pcBaseLayerResidual->residualUpsampling( pcBaseResidual, m_cDownConvert, m_pcResizeParameters, pcBaseDataCtrl )

           rcDownConvert.residualUpsampling( this, pcBaseFrame, pcParameters, pcMbDataCtrlBase );  //像素帧Resize

         //BLLayerEncoderm_pcResidualILPred进过残差上采样赋值给了m_pcBaseLayerResidual

     

       rcControlData.setBaseLayerSbb( m_pcBaseLayerResidual );

    //如果BaseLayer可用(bBaseDataAvailable)

    m_pcBaseLayerFrame->intraUpsampling( pcBaseFrame, pcTempBaseFrame, pcTempFrame,m_cDownConvert,

     m_pcResizeParameters, pcBaseDataCtrl, m_pcBaseLayerCtrl,

    m_pcBaseLayerCtrlField, m_pcReconstructionBypass, m_bCIUFlag,

     m_apabBaseModeFlagAllowedArrays[0], m_apabBaseModeFlagAllowedArrays[1] )

         //进行Intra上采样,从pcBaseFrame采样到m_pcBaseLayerFrame   pcTempBaseFramepcTempFrame辅助采样

    rcControlData保存了m_pcBaseLayerResidualm_pcBaseLayerFrame

     

    //如果是EL,用BaseLayer的加权预测:

    pcSliceHeader->setBasePredWeightTableFlag( true );

    //否则,自己计算

    m_pcSliceEncoder->xSetPredWeights( *pcSliceHeader, m_papcFrame[uiFrameIdInGOP], rcControlData.getRefListStruct() );

    pcSliceHeader->setBasePredWeightTableFlag( false );

     

     

    //SEIHRDRedundantPictureLARDOSIP,未关注

     

    xEncodeLayerRepresentation( rcOutputList, rcControlData,  pcOrgFrame, pcFrame, pcResidualLF, pcResidualILPred, pcPredSignal, 

                             uiBits, cPicOutputDataList, uiFrameIdInGOP, ePicType )        //后面分析

     

    m_pcSubband->copy( pcFrame, ePicType ) )    //保存去块滤波之前的重建帧

     

    //SEIRateControlRedPic相关,未关注

     

    //如果是增强层

    m_pcSliceEncoder->updateBaseLayerResidual( rcControlData, m_uiFrameWidthInMb );

        pcMbDataCtrl->initSlice( rcSliceHeader, DECODE_PROCESS, false, NULL )     //初始化宏块控制器

    //对每个宏块

           pcMbDataCtrl ->initMb( pcMbDataAccess,     uiMbY, uiMbX )

           pcBaseLayerCtrl ->initMb ( pcMbDataAccessBase, uiMbY, uiMbX )

           //如果该宏块不用ResidualPred,清除该BL对应的Residual宏块 (rcControlm_pcBaseLayerSbb,即LayerEncoderm_pcBaseLayerResidual)

     

    //去块滤波

    m_pcLoopFilter->process( *pcSliceHeader, pcFrame, pcResidualLF, pcMbDataCtrl, 0, rcControlData.getSpatialScalability() )

    注意:滤波的仍然是pcFramepcResidualLF只是用来计算CBP!!!!

     

    输出PSNR等信息

    xClearBufferExtensions()  //清除m_papcFrame[]m_papcELFrame[]m_pcSubbandm_pcResidualLF

    //m_pcResidualILPredm_apcBaseFrame[X]1/2像素缓存 注意,是整个GOP

    更新m_uiLastCodedFrameIdInGOP = uiFrameIdInGOP  m_uiLastCodedTemporalId   = uiTemporalId;

     

    //如果是GOP最后一帧

    m_pcAnchorFrameReconstructed拷贝该帧内容èm_papcFrame[ m_uiGOPSize ]


    最新回复(0)