之前的学习中对encode函数进行了跟踪解读,在里面调用了compressGOP函数(代码太多了,看完得猴年马月,要人命,对付一下对付一下!),看到这个代码名字就联想到视频的编码过程了吧,视频先分成GOP(两种形式的GOP),然后GOP又可以分成Slice和Tile(片和块),再往下就是CTU了,而CTU是由CU构成的,是不是就可以立即推视频编码压缩等等操作主要就是再CU之间啦!
Void TEncGOP::compressGOP( Int iPOCLast, Int iNumPicRcvd, TComList<TComPic*>& rcListPic,
TComList<TComPicYuv*>& rcListPicYuvRecOut, std::list<AccessUnit>& accessUnitsInGOP,
Bool isField, Bool isTff, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE )
{
// TODO: Split this function up.
TComPic* pcPic = NULL;
TComPicYuv* pcPicYuvRecOut;
TComSlice* pcSlice;
TComOutputBitstream *pcBitstreamRedirect;
pcBitstreamRedirect = new TComOutputBitstream;
AccessUnit::iterator itLocationToPushSliceHeaderNALU; // used to store location where NALU containing slice header is to be inserted
xInitGOP( iPOCLast, iNumPicRcvd, isField );
m_iNumPicCoded = 0;
SEIMessages leadingSeiMessages;
SEIMessages nestedSeiMessages;
SEIMessages duInfoSeiMessages;
SEIMessages trailingSeiMessages;
std::deque<DUData> duData;
SEIDecodingUnitInfo decodingUnitInfoSEI;
EfficientFieldIRAPMapping effFieldIRAPMap;
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
effFieldIRAPMap.initialize(isField, m_iGopSize, iPOCLast, iNumPicRcvd, m_iLastIDR, this, m_pcCfg);
}
//重设flag指明图片是否已被编码 reset flag indicating whether pictures have been encoded
for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )
{
m_pcCfg->setEncodedFlag(iGOPid, false);
}
for ( Int iGOPid=0; iGOPid < m_iGopSize; iGOPid++ )
{
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
iGOPid=effFieldIRAPMap.adjustGOPid(iGOPid);
}
//每一个slice的用时-- For time output for each slice
clock_t iBeforeTime = clock();
UInt uiColDir = calculateCollocatedFromL1Flag(m_pcCfg, iGOPid, m_iGopSize);
/// 初始化开始编码Initial to start encoding
Int iTimeOffset;
Int pocCurr;
if(iPOCLast == 0) //第一帧或者顶场的情况case first frame or first top field
{
pocCurr=0;
iTimeOffset = 1;
}
else if(iPOCLast == 1 && isField) //底场的情况,和第一帧一样,poc计算不正确,我们自行设置正确的值case first bottom field, just like the first frame, the poc computation is not right anymore, we set the right value
{
pocCurr = 1;
iTimeOffset = 1;
}
else
{
pocCurr = iPOCLast - iNumPicRcvd + m_pcCfg->getGOPEntry(iGOPid).m_POC - ((isField && m_iGopSize>1) ? 1:0);
iTimeOffset = m_pcCfg->getGOPEntry(iGOPid).m_POC;
}
if(pocCurr>=m_pcCfg->getFramesToBeEncoded())//获取待编码帧
{
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
iGOPid=effFieldIRAPMap.restoreGOPid(iGOPid);
}
continue;
}
if( getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_W_RADL || getNalUnitType(pocCurr, m_iLastIDR, isField) == NAL_UNIT_CODED_SLICE_IDR_N_LP )
{
m_iLastIDR = pocCurr;
}
// start a new access unit: create an entry in the list of output access units
accessUnitsInGOP.push_back(AccessUnit());
AccessUnit& accessUnit = accessUnitsInGOP.back();
xGetBuffer( rcListPic, rcListPicYuvRecOut, iNumPicRcvd, iTimeOffset, pcPic, pcPicYuvRecOut, pocCurr, isField );
//片数据初始化 Slice data initialization
pcPic->clearSliceBuffer();
pcPic->allocateNewSlice();
m_pcSliceEncoder->setSliceIdx(0);
pcPic->setCurrSliceIdx(0);
m_pcSliceEncoder->initEncSlice ( pcPic, iPOCLast, pocCurr, iGOPid, pcSlice, isField );
//设置帧或场的编码Set Frame/Field coding
pcSlice->getPic()->setField(isField);
pcSlice->setLastIDR(m_iLastIDR);
pcSlice->setSliceIdx(0);
//设置默认的片层标志和序列参数集的层标志一样 set default slice level flag to the same as SPS level flag
pcSlice->setLFCrossSliceBoundaryFlag( pcSlice->getPPS()->getLoopFilterAcrossSlicesEnabledFlag() );
if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='P')
{
pcSlice->setSliceType(P_SLICE);
}
if(pcSlice->getSliceType()==B_SLICE&&m_pcCfg->getGOPEntry(iGOPid).m_sliceType=='I')
{
pcSlice->setSliceType(I_SLICE);
}
// 设置NAL单元的类型 Set the nal unit type
pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
if(pcSlice->getTemporalLayerNonReferenceFlag())
{
if (pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_TRAIL_R &&
!(m_iGopSize == 1 && pcSlice->getSliceType() == I_SLICE))
// Add this condition to avoid POC issues with encoder_intra_main.cfg configuration (see #1127 in bug tracker)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_TRAIL_N);
}
if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RADL_R)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RADL_N);
}
if(pcSlice->getNalUnitType()==NAL_UNIT_CODED_SLICE_RASL_R)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_RASL_N);
}
}
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_N_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_W_RADL
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_IDR_N_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_CRA ) /*(随机接入点Intra Random Access Point) IRAP picture,
一种IRAP(intra random access point)帧,称为BLA(broken link access picture)帧,
这种帧一般用做两段序列之间的连接。功能类似IDR帧,但可能之后会跟随RASL帧。*/
{
m_associatedIRAPType = pcSlice->getNalUnitType();
m_associatedIRAPPOC = pocCurr;
}
pcSlice->setAssociatedIRAPType(m_associatedIRAPType);
pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC);
}
// Do decoding refresh marking if any
pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic, m_pcCfg->getEfficientFieldIRAPEnabled());
m_pcEncTop->selectReferencePictureSet(pcSlice, pocCurr, iGOPid);
if (!m_pcCfg->getEfficientFieldIRAPEnabled())
{
if ( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_LP
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_BLA_W_RADL