文章目录
TEncTop.cpp
引言
TEncTop类是第二层编码类,也是执行实际编码计算工作的最顶层编码类。
Void TEncTop::encode是执行编码的入口函数,它主要实现为GOP压缩之前做一些准备工作,包括创建当前图像缓冲区、设定QP是否自适应、根据码率控制模式来确定是否需要先初始化GOP,然后调用TEncGop::compressGOP来压缩GOP。
Void TEncTop::encode
参数列表:
- flush:使编码器部分编码;
- pcPicYuvOrg、pcPicYuvTrueOrg:原始YUV图片;
- ipCS、snrCSC:色彩空间转换格式;
- rcListPicYuvRecOut:重建YUV图片列表;
- accessUnitOut:输出访问单元
- iNumEncoded:已编码图片数量
if (pcPicYuvOrg != NULL)
{
//获取原始YUV图
TComPic* pcPicCurr = NULL;//存放获取的图片缓存,主要用于更新缓存列表m_cListPic
Int ppsID=-1; // 使用默认PPSid
if (getWCGChromaQPControl().isEnabled())//如果启动宽色域色度QP控制
{
ppsID=getdQPs()[ m_iPOCLast+1 ];//设置PPSID
}
xGetNewPicBuffer( pcPicCurr, ppsID );//根据PPS获取新缓存
pcPicYuvOrg->copyToPic( pcPicCurr->getPicYuvOrg() );//将原始未编码的YUV缓存赋值到pcPicCurr内部成员m_apcPicYuv[PIC_YUV_ORG]和m_apcPicYuv[PIC_YUV_TRUE_ORG]
pcPicYuvTrueOrg->copyToPic( pcPicCurr->getPicYuvTrueOrg() );
//是否自适应QP控制,默认不用,用时计算图像特征
if ( getUseAdaptiveQP() )
{
m_cPreanalyzer.xPreanalyze( dynamic_cast<TEncPic*>( pcPicCurr ) );
}
}
if ((m_iNumPicRcvd == 0) || (!flush && (m_iPOCLast != 0) && (m_iNumPicRcvd != m_iGOPSize) && (m_iGOPSize != 0)))//判断是否开始编码
{
iNumEncoded = 0;
return;
}
//是否速率控制,默认不
if ( m_RCEnableRateControl )
{
m_cRateCtrl.initRCGOP( m_iNumPicRcvd );
}
// 压缩GOP编码
m_cGOPEncoder.compressGOP(m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut, accessUnitsOut, false, false, ipCSC, snrCSC, getOutputLogControl());
if ( m_RCEnableRateControl )
{
m_cRateCtrl.destroyRCGOP();
}
iNumEncoded = m_iNumPicRcvd;
m_iNumPicRcvd = 0;//接收图片数量
m_uiNumAllPicCoded += iNumEncoded; //增加已编码数量
}
执行流程
实现细节
Class TEncTop
private:
// picture
Int m_iPOCLast; ///< time index (POC)
Int m_iNumPicRcvd; ///< number of received pictures
UInt m_uiNumAllPicCoded; ///< number of coded pictures
TComList<TComPic*> m_cListPic; ///< dynamic list of pictures
// encoder search
TEncSearch m_cSearch; ///< 编码搜索类
//TEncEntropy* m_pcEntropyCoder; ///< 熵编码
TEncCavlc* m_pcCavlcCoder; ///< 变长编码
// coding tool
TComTrQuant m_cTrQuant; ///< 转换和量化类
TComLoopFilter m_cLoopFilter; ///< 去方块滤波
TEncSampleAdaptiveOffset m_cEncSAO; ///< SAO
TEncEntropy m_cEntropyCoder; ///< 熵编码
TEncCavlc m_cCavlcCoder; ///< 变长编码
TEncSbac m_cSbacCoder; ///< 并行的CABAC编码
TEncBinCABAC m_cBinCoderCABAC; ///< CABAC
// processing unit
TEncGOP m_cGOPEncoder; ///< GOP encoder
TEncSlice m_cSliceEncoder; ///< slice encoder
TEncCu m_cCuEncoder; ///< CU encoder
// SPS、PPS
ParameterSetMap<TComSPS> m_spsMap; ///< SPS. This is the base value. This is copied to TComPicSym
ParameterSetMap<TComPPS> m_ppsMap; ///< PPS. This is the base value. This is copied to TComPicSym
// RD cost computation码率失真计算
TComRdCost m_cRdCost; ///< RD cost computation class
TEncSbac*** m_pppcRDSbacCoder; ///< temporal storage for RD computation
TEncSbac m_cRDGoOnSbacCoder; ///< going on SBAC model for RD stage
#if FAST_BIT_EST
TEncBinCABACCounter*** m_pppcBinCoderCABAC; ///< 用于RD计算的临时CABAC状态存储
TEncBinCABACCounter m_cRDGoOnBinCoderCABAC; ///< going on bin coder CABAC for RD stage
#else
TEncBinCABAC*** m_pppcBinCoderCABAC; ///< temporal CABAC state storage for RD computation
TEncBinCABAC m_cRDGoOnBinCoderCABAC; ///< going on bin coder CABAC for RD stage
#endif
// quality control
TEncPreanalyzer m_cPreanalyzer; ///< image characteristics analyzer for TM5-step3-like adaptive QP
TEncRateCtrl m_cRateCtrl; ///< Rate control class
protected:
Void xGetNewPicBuffer ( TComPic*& rpcPic, Int ppsId ); ///< get picture buffer which will be processed. If ppsId<0, then the ppsMap will be queried for the first match.
Void xInitVPS (TComVPS &vps, const TComSPS &sps); ///< initialize VPS from encoder options
Void xInitSPS (TComSPS &sps); ///< initialize SPS from encoder options
Void xInitPPS (TComPPS &pps, const TComSPS &sps); ///< initialize PPS from encoder options
Void xInitScalingLists (TComSPS &sps, TComPPS &pps); ///< initialize scaling lists
Void xInitHrdParameters(TComSPS &sps); ///< initialize HRD parameters
Void xInitPPSforTiles (TComPPS &pps);
Void xInitRPS (TComSPS &sps, Bool isFieldCoding); ///< initialize PPS from encoder options
public:
TEncTop();
virtual ~TEncTop();
Void create ();
Void destroy ();
Void init (Bool isFieldCoding);
Void deletePicBuffer ();
// 成员访问函数
TComList<TComPic*>* getListPic () { return &m_cListPic; }
TEncSearch* getPredSearch () { return &m_cSearch; }
TComTrQuant* getTrQuant () { return &m_cTrQuant; }
TComLoopFilter* getLoopFilter () { return &m_cLoopFilter; }
TEncSampleAdaptiveOffset* getSAO () { return &m_cEncSAO; }
TEncGOP* getGOPEncoder () { return &m_cGOPEncoder; }
TEncSlice* getSliceEncoder () { return &m_cSliceEncoder; }
TEncCu* getCuEncoder () { return &m_cCuEncoder; }
TEncEntropy* getEntropyCoder () { return &m_cEntropyCoder; }
TEncCavlc* getCavlcCoder () { return &m_cCavlcCoder; }
TEncSbac* getSbacCoder () { return &m_cSbacCoder; }
TEncBinCABAC* getBinCABAC () { return &m_cBinCoderCABAC; }
TComRdCost* getRdCost () { return &m_cRdCost; }
TEncSbac*** getRDSbacCoder () { return m_pppcRDSbacCoder; }
TEncSbac* getRDGoOnSbacCoder () { return &m_cRDGoOnSbacCoder; }
TEncRateCtrl* getRateCtrl () { return &m_cRateCtrl; }
Void selectReferencePictureSet(TComSlice* slice, Int POCCurr, Int GOPid );
Int getReferencePictureSetIdxForSOP(Int POCCurr, Int GOPid );
Void setParamSetChanged(Int spsId, Int ppsId);
Bool PPSNeedsWriting(Int ppsId);
Bool SPSNeedsWriting(Int spsId);
//编码函数
///编码几个图片直到序列结束
Void encode( Bool bEos,
TComPicYuv* pcPicYuvOrg,
TComPicYuv* pcPicYuvTrueOrg,
const InputColourSpaceConversion ipCSC, const InputColourSpaceConversion snrCSC, // used for SNR calculations. Picture in original colour space.
TComList<TComPicYuv*>& rcListPicYuvRecOut,
std::list<AccessUnit>& accessUnitsOut, Int& iNumEncoded );
/// encode several number of pictures until end-of-sequence场编码
Void encode( Bool bEos, TComPicYuv* pcPicYuvOrg,
TComPicYuv* pcPicYuvTrueOrg,
const InputColourSpaceConversion ipCSC, const InputColourSpaceConversion snrCSC, // used for SNR calculations. Picture in original colour space.
TComList<TComPicYuv*>& rcListPicYuvRecOut,
std::list<AccessUnit>& accessUnitsOut, Int& iNumEncoded, Bool isTff);
//输出日志
TEncAnalyze::OutputLogControl getOutputLogControl() const
{
TEncAnalyze::OutputLogControl outputLogCtrl;
outputLogCtrl.printFrameMSE=m_printFrameMSE;
outputLogCtrl.printMSEBasedSNR=m_printMSEBasedSequencePSNR;
outputLogCtrl.printMSSSIM=m_printMSSSIM;
outputLogCtrl.printSequenceMSE=m_printSequenceMSE;
outputLogCtrl.printXPSNR=m_bXPSNREnableFlag;
outputLogCtrl.printHexPerPOCPSNRs=m_printHexPsnr;
return outputLogCtrl;
}
Void printSummary(Bool isField)
{
m_cGOPEncoder.printOutSummary (m_uiNumAllPicCoded, isField, getOutputLogControl(), m_spsMap.getFirstPS()->getBitDepths());
}
Void TEncTop::xGetNewPicBuffer ( TComPic*& rpcPic, Int ppsId )
完成功能:根据ppsid获取缓冲图片;
rpcPic=0;
// 此时,可以认为SPS和PPS是激活的——它们被复制到新的TComPic中。
//1. 根据PSSID取PPS和SPS
const TComPPS *pPPS=(ppsId<0) ? m_ppsMap.getFirstPS() : m_ppsMap.getPS(ppsId);
assert (pPPS!=0);
const TComPPS &pps=*pPPS;
//根据获得的PSS取SPS参数集
const TComSPS *pSPS=m_spsMap.getPS(pps.getSPSId());
assert (pSPS!=0);
const TComSPS &sps=*pSPS;
//2. 根据POC重排TEncTop类的动态图像列表m_cListPic内部图片
TComSlice::sortPicList(m_cListPic);
//3. 如果缓冲列表的缓存数目已达到需要缓冲的最大数量要求,则使用一个其中缓存图片
if (m_cListPic.size() >= (UInt)(m_iGOPSize + getMaxDecPicBuffering(MAX_TLAYER-1) + 2) )
{
TComList<TComPic*>::iterator iterPic = m_cListPic.begin();
Int iSize = Int( m_cListPic.size() );
for ( Int i = 0; i < iSize; i++ )//寻找有参考Slice的图片复制到rpcPic
{
rpcPic = *iterPic;
if(rpcPic->getSlice(0)->isReferenced() == false)
{
break;
}
iterPic++;
}
// 如果该图片的PPSID和现有的是相同的,我们将假定它自上次使用以来没有改变并返回旧的
if (pps.getPPSId() == rpcPic->getPicSym()->getPPS().getPPSId())
{
#if REDUCED_ENCODER_MEMORY //在需要减少编码内存量时释放它自身的重构数据类成员m_apcPicYuvv[PIC_YUV_REC]
rpcPic->releaseAllReconstructionData();
rpcPic->prepareForEncoderSourcePicYuv();
#endif
}
// 若ppsid不同则删除列表m_cListPic中对应的条目,重置rpcPic并在后面新建
else
{
delete rpcPic;
m_cListPic.erase(iterPic);
rpcPic=0;
}
}
//4. 根据现有的sps和pps创建一个图片,放入缓存列表m_cListPic,就像还没有达到3的最大缓冲状态时一样。
if (rpcPic==0)
{
if ( getUseAdaptiveQP() )
{
TEncPic* pcEPic = new TEncPic;
#if REDUCED_ENCODER_MEMORY
pcEPic->create( sps, pps, pps.getMaxCuDQPDepth()+1);
#else
pcEPic->create( sps, pps, pps.getMaxCuDQPDepth()+1, false);
#endif
rpcPic = pcEPic;
}
else
{
rpcPic = new TComPic;
#if REDUCED_ENCODER_MEMORY
rpcPic->create( sps, pps, true, false );
#else
rpcPic->create( sps, pps, false );
#endif
}
m_cListPic.pushBack( rpcPic );
}
//标记它未重建
rpcPic->setReconMark (false);
m_iPOCLast++;
m_iNumPicRcvd++;
//设置该图片的POC索引
rpcPic->getSlice(0)->setPOC( m_iPOCLast );
#if !REDUCED_ENCODER_MEMORY//若要节省内存
// 设置该图片边界扩展标志为否
rpcPic->getPicYuvRec()->setBorderExtension(false);
#endif