ErrVal
ControlData& rcControlData, // m_pacControlData[ uiFrameIdInGOP ];
Frame* pcOrgFrame, // m_apcFrameTemp[ 2 ]
Frame* pcFrame, // m_papcFrame[ uiFrameIdInGOP ]
Frame* pcResidualLF, // m_pcResidualLF
Frame* pcResidualILPred, // m_pcResidualILPred
Frame* pcPredSignal, // m_apcFrameTemp[ 3 ];
UInt& ruiBits, // 计算编码比特数
PicOutputDataList& rcPicOutputDataList, // 输出图像list ,仅仅输出屏幕用
UInt uiFrameIdInGOP, // GOP内第几帧
PicType ePicType ) // FRAME
参数:
ExtBinDataAccessorList cTmpExtBinDataAccessorList; // 给closeAndAppendNalUnits 函数用的临时NALUNIT list
ExtBinDataAccessorList acExtBinDataAccessorList[16]; // 每个MGSVector 的NalUnit的list
PicOutputDataList acPicOutputDataList [16];
//对每个SliceGroup
//对每个Slice
设置每个Slice的起止宏块
//当发nal_unit_type=1/5的NAL单元时,必然会先发一个nal_unit_type=14的prefix NAL unit
xWritePrefixUnit( acExtBinDataAccessorList[0], *pcSliceHeader, uiBits )
xInitExtBinDataAccessor (m_cExtBinDataAccessor ) //与LayerEncoder 中的BinData m_cBinData关联起来
m_pcNalUnitEncoder->initNalUnit( &m_cExtBinDataAccessor ) //m_cExtBinDataAccessor 是操纵LayerEncoder的比特流用的
现在与NalUnit关联了
m_pcBitWriteBuffer->initPacket( (UInt*)(m_pucTempBuffer), m_uiPacketLength-1 ) //初始化packet 对齐比特
//BitWriteBuffer 的m_pulStreamPacket 与NalUnitEncoder 的m_pucTempBuffer 联系起来了
m_pcNalUnitEncoder->writePrefix( rcSH )
rcSH.writePrefix( *m_pcHeaderSymbolWriteIf ) ); //写到了m_pcHeaderSymbolWriteIf变量中
m_pcNalUnitEncoder->closeNalUnit( uiBit ) ); //与NalUnitEncoder 脱离关系 数据仍在 m_cExtBinDataAccessor 中
xWriteTrailingBits() //写1000…补齐
m_pcBitWriteBuffer->flushBuffer() //把拖尾等最后的数据写入并计算bit
convertRBSPToPayload( uiBits, uiHeaderBytes, m_pucBuffer, m_pucTempBuffer, m_uiPacketLength ) ); //加上0x03
xAppendNewExtBinDataAccessor( rcOutExtBinDataAccessorList, &m_cExtBinDataAccessor ) ); //把NalUnit数据存入List中
//初始化Slice数据的NalUnit
xInitExtBinDataAccessor ( m_cExtBinDataAccessor ) //与LayerEncoder 中的BinData m_cBinData关联起来
m_pcNalUnitEncoder->initNalUnit( &m_cExtBinDataAccessor ) //同前面的PrefixNalUnit
m_pcNalUnitEncoder->write( *pcSliceHeader ) // 写SliceHeader
m_pcSliceEncoder->encodeSliceSVC( rcControlData, *pcOrgFrame, *pcFrame, pcResidualLF, pcResidualILPred, pcPredSignal,
ePicType,m_uiNumMaxIter, m_uiIterSearchRange, m_bBiPred8x8Disable,
m_bMCBlks8x8Disable,m_uiMaxDeltaQp, uiBits ) 后面分析
m_pcNalUnitEncoder->closeAndAppendNalUnits( auiBits, cTmpExtBinDataAccessorList, &m_cExtBinDataAccessor,
m_cBinData, m_pcH264AVCEncoder, m_uiQualityLevelCGSSNR,m_uiLayerCGSSNR )
xWriteTrailingBits() //拖尾0
m_pcBitWriteBuffer->flushBuffer() //刷新比特流
convertRBSPToPayload( uiBytes, uiHeaderBytes, pucPayload, pucRBSP, uiPayloadBufferSize )
//如果有MGSVector,需要递归调用pcCurrentWriteBuffer去写比特流
m_pcBitWriteBuffer->uninit()
把临时的NALUNIT的list cTmpExtBinDataAccessorList分别存入不同的MGSVector的NALUNIT list
acExtBinDataAccessorList[iMGSIdx]中
//所有SliceGroup编码完毕后
每个MGSVector的list连接起来到输出list =rcAccessUnitData.getNalUnitList() = 中
EL层 SCoeff
TCoeff
m_pcSliceEncoder->updatePictureResTransform( rcControlData, m_uiFrameWidthInMb )
根据当前宏块和BL宏块的关系(CBP、MbMode等)更新QP和TransformSize等
m_pcSliceEncoder->updatePictureAVCRewrite( rcControlData, m_uiFrameWidthInMb )
从BaseLayer继承MbMode/IntraPredMode,修改TransformSize和Qp等
ErrVal
Frame& rcOrgFrame, // original frame
Frame& rcFrame, // reconstructed frame
Frame* pcResidualFrameLF, // reconstructed residual for loop filter Frame* pcResidualFrameILPred,// reconstructed residual for inter-layer prediction
Frame* pcPredFrame, // prediction signal
PicType ePicType, // picture type
UInt uiNumMaxIter, // maximum number of iteration for bi-predictive search
UInt uiIterSearchRange, // search range for iterative search
Bool bBiPred8x8Disable, // if bi-prediction for blocks smaller than 8x8 is allowed
Bool bMCBlks8x8Disable, // if blocks smaller than 8x8 are disabled
UInt uiMaxDeltaQp, // maximum delta QP
UInt& ruiBits // size of coded data
)
参数
pcBaseIntraRecFrame
rcControlData.getBaseLayerRec()
LayerEncoder的
m_pcBaseLayerFrame
pcBaseResidualFrame
rcControlData.getBaseLayerSbb()
LayerEncoder的
m_pcBaseLayerResidual
rcOrgPic
rcOrgFrame.getPic( ePicType )
原始帧
rcPic
rcFrame.getPic( ePicType )
原始帧/编码帧/重建帧
pcResidualPicLF
pcResidualFrameLF ->getPic( ePicType )
xStoreEstimation
pcResidualPicILPred
pcResidualFrameILPred ->getPic( ePicType )
xStoreEstimation
pcPredPic
pcPredFrame->getPic( ePicType )
xStoreEstimation
pcBaseIntraRecPic
pcBaseIntraRecFrame ->getPic( ePicType )
pcBaseResidualPic
pcBaseResidualFrame ->getPic( ePicType )
pcMbDataCtrl->initSlice ( rcSliceHeader, ENCODE_PROCESS, false, pcMbDataCtrl0L1 )
//B-slice设置co-located宏块控制
//设置去块滤波器
在MbDataCtrl的DynBuf<DBFilterParameter*> m_cDBFPBuffer中加入该Slice的滤波参数
//设置高宽信息和QP
pcBaseMbDataCtrl->initSlice ( rcSliceHeader, PRE_PROCESS, false, NULL )
//相比上面的,没有去块滤波的设置
m_pcControlMng->initSliceForCoding( rcSliceHeader ) ControlMngH264AVCEncoder
//选择熵编码模式
ControlMngH264AVCEncoder的MbSymbolWriteIf* m_pcMbSymbolWriteIf指向m_pcCabacWriter/m_pcUvlcWriter;
m_pcMbSymbolWriteIf ->startSlice( rcSH ) //只关注CABAC
xInitContextModels( rcSliceHeader ) //调用每个模型的initBuffer()函数初始化上下文
CabaEncoder::start() //初始化cabac编码器参数
m_pcBitWriteBufferIf->writeAlignOne() //前面的0补齐
//每个MGSVector层都要嵌套调用pcCurrentWriter->startSlice( rcSH )初始化cabac上下文
m_pcMbEncoder ->initSlice ( rcSH ) //初始化成员MbEncoder* m_pcMbEncoder; 它只支持Uvlc!!
MbCoder::initSlice( rcSH, this, MbEncoder::m_pcRateDistortionIf ) //关联MbCoder和RD计算类的指针
UvlcWriter::init( m_BitCounter ) // 关联Uvlc编码器和比特计数成员
UvlcWriter::startSlice( rcSH ) // 嵌套初始化MGSVector的Uvlc编码器状态
m_pcIntMbBestData
m_acIntMbTempData[0]
m_pcIntMbTempData
m_acIntMbTempData[1]
m_pcIntMbBest8x8Data
m_acIntMbTempData[2]
m_pcIntMbTemp8x8Data
m_acIntMbTempData[3]
//初始化成员 MbCoder* m_pcMbCoder;
m_pcMbCoder ->initSlice ( rcSH, m_pcMbSymbolWriteIf, m_pcRateDistortion ) //关联实际熵编码器和RD计算类
m_pcMotionEstimation ->initSlice ( rcSH )
m_pcSampleWeighting->initSliceForWeighting(rcSH); //初始化加权预测参数
MotionVectorCalculation::initSlice( rcSH ) //初始化Mv计算 (MaxMv个数和SpatialDirect)
m_pcSampleWeighting ->initSlice ( rcSH ) //初始化加权预测参数,与前面有一些不同
//设置FMO
m_pcMbCoder->getBitCount() //得到已编码比特数
//对每个宏块
//RateControl部分,未看
pcMbDataCtrl ->initMb( pcMbDataAccess, uiMbY, uiMbX ) )
//宏块数据在MbDataCtrl的成员 MbData* m_pcMbData中
rcMbDataCurr = m_pcMbData[ uiCurrIdx ];
rcMbDataCurr.getMbTCoeffs().clear(); //清空变换系数
rcMbDataCurr.initMbData( … ); //设置上个Mb的Qp和这个Mb的id、地址等信息
rcMbDataCurr.clear(); //清空Mb数据信息
给MbDataCtrl成员MbDataAccess* m_pcMbDataAccess开辟空间并初始化
调用了:
xGetRefMbData() //获得宏块周围宏块 MbData
xGetOutMbData() //返回不可用的宏块m_pcMbData[m_uiSize]
xGetColMbData( uiIdxColTop ), //返回List1的第一帧的相同位置宏块
//设置宏块ForceQP
pcBaseMbDataCtrl->initMb ( pcMbDataAccessBase, uiMbY, uiMbX ) // 同上面的函数
m_pcControlMng ->initMbForCoding ( *pcMbDataAccess, uiMbY, uiMbX, false, false) ControlMngH264AVCEncoder
m_apcYuvFullPelBufferCtrl[m_uiCurrLayer]->initMb( uiMbY, uiMbX, bMbAff ) //设置该宏块的Y/U/V的offset
m_apcYuvHalfPelBufferCtrl[m_uiCurrLayer]->initMb( uiMbY, uiMbX, bMbAff )
//参数保存在YuvBufferCtrl的成员YuvBufferParameter m_acBufferParam[ MAX_FRAME_TYPE ]中
//每次都要重新计算,由传入的宏块x,y号转换成posX和posY再计算宏块的offset
// int-pel 和 1/2-pel都计算
m_pcMotionEstimation->initMb( uiMbY, uiMbX, rcMbDataAccess )
MotionCompensation::initMb( uiMbPosY, uiMbPosX, rcMbDataAccess) //设置Mv最大和最小范围
//真正设置宏块Qp,写入pcMbDataAccess->getMbData()
m_pcMbEncoder->encodeMacroblockSVC(*pcMbDataAccess, pcMbDataAccessBase, rcOrgPic, rcPic, pcResidualPicLF,
pcResidualPicILPred, pcPredPic, pcBaseIntraRecPic, pcBaseResidualPic, rcRefListStruct, uiMaxMvPerMb,
uiNumMaxIter, uiIterSearchRange, bBiPred8x8Disable, bMCBlks8x8Disable, true, uiDeltaQp, dLambda, dCost ) );
后面分析
//用Cabac/Cavlc进行熵编码,用m_pcMbSymbolWriteIf进行写码流
m_pcMbCoder->encode( *pcMbDataAccess, pcMbDataAccessBase, ( uiMbAddress == uiLastMbAddress ), true )
//计算slice data的编码数据
ErrVal
// current macroblock data
MbDataAccess* pcMbDataAccessBase, // inferred macroblock data (from base layer)
const Frame& rcOrgFrame, // original frame
Frame& rcFrame, // reconstructed frame
Frame* pcResidualLF, // reconstructed residual for loop filter
Frame* pcResidualILPred, // reconstructed residual for inter-layer prediction
Frame* pcPredSignal, // prediction signal
const Frame* pcBaseLayerIntraRec, // base layer intra reconstruction
const Frame* pcBaseLayerResidual, // base layer residual reconstruction
RefListStruct& rcRefListStruct, // reference picture lists
UInt uiMaxNumMv, // maximum number of MVs for current macroblock
UInt uiNumMaxIter, // number of iteration for bi-predictive search
UInt uiIterSearchRange, // search range for iterative search
Bool bBiPred8x8Disable, // if bi-prediction for blocks smaller than 8x8 is allowed
Bool bMCBlks8x8Disable, // if blocks smaller than 8x8 are disabled
Bool bSkipModeAllowed, // if skip mode is allowed
UInt uiMaxDeltaQp, // maximum delta QP
Double dLambda, // Langrangian multiplier
Double& rdCost // r-d cost for coded macroblock
)
m_pcRateDistortionIf->setMbQpLambda( rcMbDataAccess, uiCurrQP, dLambda ) //设置计算RD的qp和lambda
//宏块数据初始化并清空
m_pcIntMbBestData ->init( rcMbDataAccess );
m_pcIntMbTempData ->init( rcMbDataAccess );
m_pcIntMbBest8x8Data->init( rcMbDataAccess );
m_pcIntMbTemp8x8Data->init( rcMbDataAccess );
m_pcXDistortion->loadOrgMbPelData( rcOrgFrame.getFullPelYuvBuffer(), m_pcIntOrgMbPelData );
//把原始帧的该宏块内容复制到XDistortion的成员YuvMbBuffer m_cOrgData; 中,地址给m_pcIntOrgMbPelData
参数
IsEnhLayer
通过no_inter_layer_pred_flag判断是不是增强层
InCropWindow
参考层的InCropWindowFlag为true
pcMbDataAccessBase
只有InCropWindow为true, 该值才不为NULL
bSNRMode
InCropWindow为true,且TCoeff或者SCoeff的一种
bTCoeffPredFlag
Slice Header的TCoeffLevelPredFlag
bSCoeffPredFlag
Slice Header的SCoeffResidualPredFlag, BL是INTER或者INTRA_BL
bARP
Slice Header的AdaptiveResidualPredictionFlag
bDRP
Slice Header的DefaultResidualPredictionFlag
bELMbRefInter
InCropWindow为true,为P/B slice,且参考层不是INTRA预测
bCheckWithResPred
为P/B slice,InCropWindow为true,ARP(bELMbRefInter)或者DRP
bCheckWithoutResPred
为P/B slice,ARP或者DRP=false或者InCropWindow=false
bWithAndWithoutRP
P/B slice,InCropWindow为true,ARP
bPreferResPred
1是CABAC 0是CAVLC
bABM
Slice Header的AdaptiveBaseModeFlag
bDBM
Slice Header的DefaultBaseModeFlag
bCheckBaseMode
InCropWindow=true,ABM或者DBM
bNonBaseModeOk
DBM=false或者InCropWindow=false或者ABM=true
bCheckStdInter
不是InCropWindow,或者AdaptiveBaseMode,或者不是BaseMode
bCheckIntraBL
InCropWindow,允许INTRA,参考层是INTRA预测,ABM或DBM
bCheckSpatialIntra
允许INTRA,非InCropWindow或者ABM或者不是DBM
注:
SCoeff
TCoeff
no_inter_layer_pred_flag = 0
SpatialResolutionChangeFlag = 0
tcoeff_level_prediction_flag = 0
no_inter_layer_pred_flag = 0
SpatialResolutionChangeFlag = 0
tcoeff_level_prediction_flag = 1
1 m_rcSliceHeader.getSCoeffResidualPredFlag() = true
2 m_pcMbDataAccessBase != NULL
3 m_rcMbCurr.isIntra() = false
m_rcMbCurr.getResidualPredFlag() = true
m_pcMbDataAccessBase->getMbData().isIntra() = false
或者
m_rcMbCurr.isIntraBL () = true
m_pcMbDataAccessBase->getMbData().isIntraBL() = true
1 m_rcSliceHeader.getTCoeffLevelPredictionFlag() = true
2 m_pcMbDataAccessBase != NULL
3 m_rcMbCurr.isIntra() = false
m_rcMbCurr.getResidualPredFlag() = true
m_pcMbDataAccessBase->getMbData().isIntra() = false
或者
m_rcMbCurr.isIntra() = true
m_rcMbCurr.getBLSkipFlag() = true
// m_eMbMode >= INTRA_4X4 m_bBLSkipFlag
当前INTER预测
支持Residual预测
参考层不是INTRA预测
当前宏块和参考层宏块都是INTRA_BL
当前INTER预测
支持Residual预测
参考层不是INTRA预测
当前INTRA预测
当前宏块是base mode
如果bZeroBaseLayerResFlag = true,
bPreferResPred
1 cabac
0 cavlc
bCheckWithoutResPred
0
1
bCheckWithResPred
1
0
我的思考:如果BL的残差系数为0且两者都要计算,则用cabac时ResidualPred效率高些(EL很可能也全0,那么省比特,且省变换时的计算量)
bCheckWithResPred
bTCoeffPredFlag
bSCoeffPredFlag
其他
cBaseLayerBuffer
原始宏块减去它作为后面的原始参照,在过程中不改变!!
这是像素域的残差预测
全零
参考层的预测值
XPel m_sPred
(BL是INTER or INTRA_BL)
参考层的残差
m_ResidualILPred)
bZeroBaseLayerResFlag
参考层量化系数
参考层反量化系数和预测值
m_ResidualILPred
先看看xStoreEstimation函数
rcMbBestData.getMbTCoeffs()的m_sPred 拷入
INTRA_BL且非TCoeff
INTRA
Residual Pred
其他(TCoeff / INTER且非Residual Pred)
rcMbBestData.getTempYuvMbBuffer()
rcMbBestData
pcBaseLayerBuffer
0
INTRA预测值
但这里是INTRA_BL
应该是其BL的INTRA重建值(去块滤波之前)
INTRA预测重建的(去块滤波之前)
就是上面的表格中的cBaseLayerBuffer
预测的残差
全零
//流程
bCheckWithResPred
bCheckWithoutResPred
subtract( cBaseLayerBuffer )
bCheckBaseMode
参考层不是INTRA
xEstimateMbBLSkip TRUE
xEstimateMbBLSkip FALSE
bCheckStdInter
xEstimateMbDirect TRUE
xEstimateMb16x16 TRUE
xEstimateMb16x8 TRUE
xEstimateMb8x16 TRUE
xEstimateMb8x8 TRUE
xEstimateMb8x8Frext TRUE
xEstimateMbDirect FALSE
xEstimateMb16x16 FALSE
xEstimateMb16x8 FALSE
xEstimateMb8x16 FALSE
xEstimateMb8x8 FALSE
xEstimateMb8x8Frext FALSE
P Slice
DRP=true
xEstimateMbSkip TRUE
P Slice
xEstimateMbSkip FALSE
P Slice
DRP=false
bCheckWithoutResPred=false
xEstimateMbSkip FALSE
bWithAndWithoutRP=true
bCheckWithoutResPred = false
xEstimateMbDirect FALSE
参考层是INTER
未使用上面的所有
xEstimateMb16x16 TRUE
xEstimateMb16x16 FALSE
add( cBaseLayerBuffer )
下面是全新的开始
bCheckSpatialIntra
bCheckIntraBL
xEstimateMbIntra16
xEstimateMbIntra8
xEstimateMbIntra4
xEstimateMbPCM
xEstimateMbIntraBL
xStoreEstimation(rcMbDataAccess, *m_pcIntMbBestData, pcResidualLF, pcResidualILPred, pcPredSignal,
rcRefListStruct, &cBaseLayerBuffer )
//INTRA预测清除MotionData和Mvd,SKIP模式清除Mvd
//设置FwdBwd,可见是宏块编码完成后使用
【8x8块_3】【8x8块_2】【8x8块_1】【0 0 Use_List1 Use_List0】
rcMbBestData.getMbTCoeffs()的m_sPred 拷入下面的内容
INTRA_BL且非TCoeff
INTRA
Residual Pred
其他(TCoeff / INTER且非Residual Pred)
rcMbBestData.getTempYuvMbBuffer()
rcMbBestData
pcBaseLayerBuffer
0
INTRA预测值
但这里是INTRA_BL
应该是其BL的INTRA重建值(去块滤波之前)
INTRA预测重建的(去块滤波之前)
就是上面的表格中的cBaseLayerBuffer
全零啊
rcMbBestData.copyTo ( rcMbDataAccess ); // rcMbBestData 的一些信息(MbData/Coeff/Mv)存到 rcMbDataAccess
把RC参考队列中对于ref_idx的参考帧读出存入m_rcMbCurr.getMbMotionData ( eListIdx )的m_acRefPicIdc [4]中
INTRA
pcPredSignal = rcMbBestData.getTempYuvMbBuffer()
Intra预测样点
pcResidualLF = cResidual.setAllSamplesToZero();
全零
pcResidualILPred = cResidual.setAllSamplesToZero();
全零
Residual Pred
Base Mode
pcPredSignal = rcMbBestData.getTempYuvMbBuffer() - rcMbBestData.getTempBLSkipResBuffer () +*pcBaseLayerBuffer
RC预测 - BLSkip的BL的残差+ BaseLayerBuffer(全零) 赋值给 rcMbBestData
pcResidualLF = rcMbBestData - rcMbBestData.getTempYuvMbBuffer() + rcMbBestData.getTempBLSkipResBuffer ()
MC重建 - RC预测 + BLSkip的BL的残差(由cBaseLayerBuffer得来)
pcResidualILPred = rcMbBestData - rcMbBestData.getTempYuvMbBuffer() + pcBaseLayerBuffer
MC重建 - RC预测 + BaseLayerBuffer(全零)
Others
pcPredSignal = rcMbBestData.getTempYuvMbBuffer();
RC预测 赋值给rcMbBestData
pcResidualLF = rcMbBestData - rcMbBestData.getTempYuvMbBuffer() + pcBaseLayerBuffer
MC重建 - RC预测 + BaseLayerBuffer(全零)
pcResidualILPred = rcMbBestData - rcMbBestData.getTempYuvMbBuffer() + pcBaseLayerBuffer
MC重建 - RC预测 + BaseLayerBuffer(全零)
Others
pcPredSignal = rcMbBestData.getTempYuvMbBuffer()
RC预测(非ResidualPred的INTER) | BL的intra预测(INTRA_BL)
pcResidualLF = rcMbBestData - rcMbBestData.getTempYuvMbBuffer()
MC重建 -- RC预测(非ResidualPred的INTER) | BL的intra预测(INTRA_BL)
pcResidualILPred = rcMbBestData - rcMbBestData.getTempYuvMbBuffer()
MC重建 -- RC预测(非ResidualPred的INTER) | BL的intra预测(INTRA_BL)
//计算RD
rdCost = m_pcIntMbBestData->rdCost(); //最终的RD
//无函数体
m_pcIntMbBestData ->uninit();
m_pcIntMbTempData ->uninit();
m_pcIntMbBest8x8Data->uninit();
m_pcIntMbTemp8x8Data->uninit();