注意:本次代码运用的是encoder_intra_vtm的设置,所以GOP_size 只有一帧,都是I帧
EncApp::encode()
const InputColourSpaceConversion snrCSC = ( !m_snrInternalColourSpace ) ? m_inputColourSpaceConvert : IPCOLOURSPACE_UNCHANGED;
bool keepDoing = false;// call encoding function for one frame
if( m_isField )
{
keepDoing = m_cEncLib.encode( snrCSC, m_recBufList, m_numEncoded, m_isTopFieldFirst );
}
else
{
keepDoing = m_cEncLib.encode( snrCSC, m_recBufList, m_numEncoded );//调用编码函数
}
从EncLib::encode进入compressgop()函数
bool EncLib::encode( const InputColourSpaceConversion snrCSC, std::list<PelUnitBuf*>& rcListPicYuvRecOut, int& iNumEncoded )
{
// compress GOP
m_cGOPEncoder.compressGOP( m_iPOCLast, m_iNumPicRcvd, m_cListPic, rcListPicYuvRecOut,
false, false, snrCSC, m_printFrameMSE, m_printMSSSIM, false, m_picIdInGOP );
snrCSC:色彩空间转换形式 m_iPOCLast:图像序列号(POC)的最后一位
m_iNumPicRcvd:当前GOP已接收到几帧数据
iNumEncoded:已编码数量
rcListPicYuvRecOut的意思在EncLib::encode上面的绿色注释中:
\retval rcListPicYuvRecOut list of reconstruction YUV pictures 重建YUV图片列表
compressGOP()函数
1.初始设置
// TODO: Split this function up.
Picture* pcPic = NULL;
PicHeader* picHeader = NULL;
Slice* pcSlice;
OutputBitstream *pcBitstreamRedirect; //将码流装入VCL-NALU之前暂存的地方
pcBitstreamRedirect = new OutputBitstream;
AccessUnit::iterator itLocationToPushSliceHeaderNALU; // used to store location where NALU containing slice header is to be inserted
Picture* scaledRefPic[MAX_NUM_REF] = {};
xInitGOP( iPOCLast, iNumPicRcvd, isField, isEncodeLtRef );
isEncodeLtRef:猜测是已编码左侧参考像素的意思
【H.264/AVC视频编解码技术详解】 九、序列参数集Sequence Paramater Set(SPS)解析_取次花丛懒回顾的博客-CSDN博客
【H.264/AVC视频编解码技术详解】十一、H.264的Slice Header解析_取次花丛懒回顾的博客-CSDN博客_avc slice
pcBitstreamRedirect:将码流装入VCL-NALU之前暂存的地方
scaledRefPic:存储着缩放后的参考帧
xInitGOP:设置m_iGopSize,表示当前GOP的大小,除了第一帧是1的情况外是恒定的,即使当前GOP没有读取到足够的帧数
MAX_NUM_REF:图片参考队列可能达到的最大长度,最大为16。(存疑)
m_iNumPicCoded = 0; //已编码图片数
SEIMessages leadingSeiMessages;
SEIMessages nestedSeiMessages;
SEIMessages duInfoSeiMessages;
SEIMessages trailingSeiMessages;
std::deque<DUData> duData;
EfficientFieldIRAPMapping effFieldIRAPMap; //随机接入点
if (m_pcCfg->getEfficientFieldIRAPEnabled()) //与场编码有关,跳过
{
effFieldIRAPMap.initialize(isField, m_iGopSize, iPOCLast, iNumPicRcvd, m_iLastIDR, this, m_pcCfg);
}
if( isField && picIdInGOP == 0 )
{
for( int iGOPid = 0; iGOPid < max(2, m_iGopSize); iGOPid++ )
{
m_pcCfg->setEncodedFlag( iGOPid, false );
}
}
//重设flag指明图片是否已被编码 reset flag indicating whether pictures have been encoded
for( int iGOPid = picIdInGOP; iGOPid <= picIdInGOP; iGOPid++ )
{
m_pcCfg->setEncodedFlag( iGOPid, false ); //表示当前帧还未编码
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
iGOPid=effFieldIRAPMap.adjustGOPid(iGOPid);
}
//-- For time output for each slice
auto beforeTime = std::chrono::steady_clock::now();
读H.265/HEVC编码笔记(一)_qq_27901569的博客-CSDN博客
IRAP(Intra Random Access Point)——随机接入点:
为了满足压缩视频流的随机介入需求,如电视频道的切换、视频播放中的快进、拖曳等,一段视频流中通常会间隔地存在一些随机介入点。从IRAP开始,后续视频流(播放顺序在IRAP后的图像)可以独立正确解码,无需参考IRAP前面的视频信息。IRAP后的第一幅解码图像被称为IRAP图像。IRAP图像只包含帧内编码片,不采用帧间预测技术,可以独立解码。
setEncodedFlag():将m_RPLList0、m_RPLList1、m_GOPList中的m_isEncoded设置为false,表示当前帧还未编码。m_GOPList里面存着一个GOP内每个帧的一些信息(例如POC、I/B/P帧等等),这些都是直接从cfg文件中得到的。m_RPLList0和m_RPLList1相对侧重于存储每个帧有关参考帧列表1和0的信息。
now():记录一下起始时间
iGOPid:猜测为 GOP id,这幅图片的序列号
picIdInGOP:猜测为 这幅图片在GOP中的序列号
初始化以便开始编码
int iTimeOffset;
int pocCurr;
int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1; //倍乘因子
if(iPOCLast == 0) //帧编码或顶场编码case first frame or first top field
{
pocCurr=0;
iTimeOffset = isField ? (1 - multipleFactor) : multipleFactor;
}
else if(iPOCLast == 1 && isField) //底场编码case first bottom field, just like the first frame, the poc computation is not right anymore, we set the right value
{
pocCurr = 1;
iTimeOffset = multipleFactor + 1;
}
else //帧编码的POC
{
pocCurr = iPOCLast - iNumPicRcvd * multipleFactor + m_pcCfg->getGOPEntry(iGOPid).m_POC - ((isField && m_iGopSize>1) ? 1 : 0);
iTimeOffset = m_pcCfg->getGOPEntry(iGOPid).m_POC;
}
pocCurr:表示当前编码帧的POC
iTimeOffset:表示当前编码帧是当前GOP播放顺序的第几帧
int multipleFactor = m_pcCfg->getUseCompositeRef() ? 2 : 1; //Composite Reference综合参考。应该是从配置里看是否运用这种技术.默认为0
编码顺序、frame_num和POC_chinabinlang的博客-CSDN博客
因为此时我设置的只编码一帧,所以iPOCLast = 0.之后可以试试改为编码多帧时的运行结果
if (m_pcCfg->getUseCompositeRef() && isEncodeLtRef)
{
pocCurr++;
iTimeOffset--;
}
if (pocCurr / multipleFactor >= 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;
}
I 帧和 IDR 帧的区别_chenchong_219的博客-CSDN博客_idr帧
前两个if:跳过。之后再看
m_iLastIDR(getNalUnitType()中有注释):最后一个IDR帧的POC序号
getNalUnitType():检查配置并为图片返回适当的NAL单元类型
第三个if:如果当前帧的NAL单元类型为IDR,则更新m_iLastIDR为最近一个IDR帧的POC编码顺序
RADL:注意看万帅书P274。朱秀昌书P236
// start a new access unit: create an entry in the list of output access units
AccessUnit accessUnit;
accessUnit.temporalId = m_pcCfg->getGOPEntry( iGOPid ).m_temporalId;
xGetBuffer( rcListPic, rcListPicYuvRecOut,
iNumPicRcvd, iTimeOffset, pcPic, pocCurr, isField );
picHeader = pcPic->cs->picHeader;
picHeader->setSPSId( pcPic->cs->pps->getSPSId() );
picHeader->setPPSId( pcPic->cs->pps->getPPSId() );
picHeader->setSplitConsOverrideFlag(false);
// initial two flags to be false
picHeader->setPicInterSliceAllowedFlag(false);
picHeader->setPicIntraSliceAllowedFlag(false);
#if ER_CHROMA_QP_WCG_PPS
// th this is a hot fix for the choma qp control
if( m_pcEncLib->getWCGChromaQPControl().isEnabled() && m_pcEncLib->getSwitchPOC() != -1 )
{
static int usePPS = 0; /* TODO: MT */
if( pocCurr == m_pcEncLib->getSwitchPOC() )
{
usePPS = 1;
}
const PPS *pPPS = m_pcEncLib->getPPS(usePPS);
// replace the pps with a more appropriated one
pcPic->cs->pps = pPPS;
}
#endif
// create objects based on the picture size
const int picWidth = pcPic->cs->pps->getPicWidthInLumaSamples();//帧的宽度
const int picHeight = pcPic->cs->pps->getPicHeightInLumaSamples();//帧的高度
const int maxCUWidth = pcPic->cs->sps->getMaxCUWidth();//最大CU允许宽度
const int maxCUHeight = pcPic->cs->sps->getMaxCUHeight();//最大CU允许高度
const ChromaFormat chromaFormatIDC = pcPic->cs->sps->getChromaFormatIdc(); //色度采样格式
const int maxTotalCUDepth = floorLog2(maxCUWidth) - pcPic->cs->sps->getLog2MinCodingBlockSize();//最大CU深度
m_pcSliceEncoder->create( picWidth, picHeight, chromaFormatIDC, maxCUWidth, maxCUHeight, maxTotalCUDepth );
pcPic->createTempBuffers( pcPic->cs->pps->pcv->maxCUWidth );
pcPic->cs->createCoeffs((bool)pcPic->cs->sps->getPLTMode());
// Slice data initialization
pcPic->clearSliceBuffer();
pcPic->allocateNewSlice();
m_pcSliceEncoder->setSliceSegmentIdx(0);
m_pcSliceEncoder->initEncSlice(pcPic, iPOCLast, pocCurr, iGOPid, pcSlice, isField, isEncodeLtRef, m_pcEncLib->getLayerId(), getNalUnitType(pocCurr, m_iLastIDR, isField) );
DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 0 ) ) );
m_pcSliceEncoder->create():通过片编码器类建立一个片的编码器,分配内存,输入参数
compressGOP中的一些函数解释_青椒鸡汤的博客-CSDN博客
createTempBuffers():创建预测值和残差值的buffer
createCoeffs():创建和TU有关的buffer
clearSliceBuffer():清空slices的buffer
allocateNewSlice():分配一个新的slice
setSliceSegmentIdx():设置m_uiSliceSegmentIdx,表示当前编码slice的Index
initEncSlice():初始化slice.这个函数之后看,可参考HM编码器代码阅读(9)——片编码器的初始化_NB_vol_1的博客-CSDN博客
2.slice的设置
pcSlice->setLastIDR(m_iLastIDR);
pcSlice->setIndependentSliceIdx(0);
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);
}
pcSlice->setTLayer(m_pcCfg->getGOPEntry(iGOPid).m_temporalId);
#if GDR_ENABLED
if (m_pcCfg->getGdrEnabled() && pocCurr >= m_pcCfg->getGdrPocStart() && ((pocCurr - m_pcCfg->getGdrPocStart()) % m_pcCfg->getGdrPeriod() == 0))
{
pcSlice->setSliceType(B_SLICE);
}
// note : first picture is GDR(I_SLICE)
if (m_pcCfg->getGdrEnabled() && pocCurr == 0)
{
pcSlice->setSliceType(I_SLICE);
}
#endif
// Set the nal unit type
pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
// set two flags according to slice type presented in the picture
if (pcSlice->getSliceType() != I_SLICE)
{
picHeader->setPicInterSliceAllowedFlag(true);
}
if (pcSlice->getSliceType() == I_SLICE)
{
picHeader->setPicIntraSliceAllowedFlag(true);
}
picHeader->setGdrOrIrapPicFlag(picHeader->getGdrPicFlag() || pcSlice->isIRAP());
setLastIDR():设置m_iLastIDR,表示这个slice所在帧之前最近的一个IDR帧的POC序号
setIndependentSliceIdx():设置m_independentSliceIdx,表示独立slice的index。万帅书68页
iGOPid(POC offset for hierarchical structure)代表一个GOP中的第几帧图。
查看SliceType 枚举函数可知
enum SliceType
{
B_SLICE = 0,
P_SLICE = 1,
I_SLICE = 2,
NUMBER_OF_SLICE_TYPES = 3
};
这里可以用cout << pcSlice->getSliceType() << endl;直接验证得出这个片的IPB类型
两个if语句:应该是当前片的类型为B_slice但 从cfg配置中根据当前帧的序号读取到当前slice的类型为I或P时,对slice类型的设置方法。以配置为准
setTLayer():设置所在的时域层,不清楚的可以看万老师书P275
// Set the nal unit type
pcSlice->setNalUnitType(getNalUnitType(pocCurr, m_iLastIDR, isField));
// set two flags according to slice type presented in the picture
if (pcSlice->getSliceType() != I_SLICE)
{
picHeader->setPicInterSliceAllowedFlag(true);
}
if (pcSlice->getSliceType() == I_SLICE)
{
picHeader->setPicIntraSliceAllowedFlag(true);
}
picHeader->setGdrOrIrapPicFlag(picHeader->getGdrPicFlag() || pcSlice->isIRAP());
if (m_pcCfg->getEfficientFieldIRAPEnabled())
{
if ( 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) // IRAP picture
{
m_associatedIRAPType[pcPic->layerId] = pcSlice->getNalUnitType();//IRAP帧所在时域层标记NAL单元类型
m_associatedIRAPPOC[pcPic->layerId] = pocCurr;//IRAP帧所在时域层标记当前帧的POC序号
if (m_pcEncLib->getEdrapIndicationSEIEnabled())
{
m_latestEDRAPPOC = MAX_INT;
pcPic->setEdrapRapId(0);
}
}
pcSlice->setAssociatedIRAPType(m_associatedIRAPType[pcPic->layerId]);//设置IRAP帧对应时域层的NALU类型
pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC[pcPic->layerId]);//设置IRAP帧对应时域层的POC序号
}
setNalUnitType():设置NALU的类型
前两个if:判断是否是I_SLICE,然后设置pictureheader的m_picIntraSliceAllowedFlag标志位,设为true
Gdr(gradual decoding refresh picture ):逐步解码刷新帧。GDR(Gradual Decoder Refresh)帧_KeepSimpleKeepHungry的博客-CSDN博客_gdr编码
isIRAP():return一个getNalUnitType()的值,限定在7~9,即IDR_W_RADL,IDR_N_LP,CRA这三个模式。RADL帧的解释在万帅书p273和p280,还有VVC正式标准的87页
setGdrOrIrapPicFlag(): 判断并设置Gdr或Irap帧的标志位
getEfficientFieldIRAPEnabled():允许以特定的、可能更有效的顺序编码场。
时域层:根据万帅书p275页,每幅图像都有一个标识所属时域层的时域层标识号,低层图像(时域层标识号小)不适用比其时域层高的图像作参考。也就是说,低层图像解码不依赖比其时域层高的图像。IRAP图像的时域层标识号为0,既属于第0个时域层。
m_associatedIRAPType[pcPic->layerId]和_associatedIRAPPOC[pcPic->layerId]:为对应时域层的IRAP帧赋给相应的NALU类型,POC序号
getEdrapIndicationSEIEnabled():这个函数暂时不知道
pcSlice->decodingRefreshMarking(m_pocCRA, m_bRefreshPending, rcListPic, m_pcCfg->getEfficientFieldIRAPEnabled());//重置某些帧的referenced和m_hashMap,更新m_pocCRA。m_pocCRA表示编码顺序之前最近CRA帧的POC
if (m_pcCfg->getUseCompositeRef() && isEncodeLtRef)
{
setUseLTRef(true);
setPrepareLTRef(false);
setNewestBgPOC(pocCurr);
setLastLTRefPoc(pocCurr);
}
else if (m_pcCfg->getUseCompositeRef() && getLastLTRefPoc() >= 0 && getEncodedLTRef()==false && !getPicBg()->getSpliceFull() && (pocCurr - getLastLTRefPoc()) > (m_pcCfg->getFrameRate() * 2))
{
setUseLTRef(false);
setPrepareLTRef(false);
setEncodedLTRef(true);
setNewestBgPOC(-1);
setLastLTRefPoc(-1);
}
if (m_pcCfg->getUseCompositeRef() && m_picBg->getSpliceFull() && getUseLTRef())
{
m_pcEncLib->selectReferencePictureList(pcSlice, pocCurr, iGOPid, m_bgPOC);
}
else
{
m_pcEncLib->selectReferencePictureList(pcSlice, pocCurr, iGOPid, -1);
}
if (!m_pcCfg->getEfficientFieldIRAPEnabled())
{
if ( 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) // IRAP picture
{
m_associatedIRAPType[pcPic->layerId] = pcSlice->getNalUnitType();
m_associatedIRAPPOC[pcPic->layerId] = pocCurr;
if (m_pcEncLib->getEdrapIndicationSEIEnabled())
{
m_latestEDRAPPOC = MAX_INT;
pcPic->setEdrapRapId(0);
}
}
pcSlice->setAssociatedIRAPType(m_associatedIRAPType[pcPic->layerId]);
pcSlice->setAssociatedIRAPPOC(m_associatedIRAPPOC[pcPic->layerId]);
}
pcSlice->setEnableDRAPSEI(m_pcEncLib->getDependentRAPIndicationSEIEnabled());
if (m_pcEncLib->getDependentRAPIndicationSEIEnabled())
{
// Only mark the picture as DRAP if all of the following applies:
// 1) DRAP indication SEI messages are enabled
// 2) The current picture is not an intra picture
// 3) The current picture is in the DRAP period
// 4) The current picture is a trailing picture
pcSlice->setDRAP(m_pcEncLib->getDependentRAPIndicationSEIEnabled() && m_pcEncLib->getDrapPeriod() > 0 && !pcSlice->isIntra() &&
pocCurr % m_pcEncLib->getDrapPeriod() == 0 && pocCurr > pcSlice->getAssociatedIRAPPOC());
if (pcSlice->isDRAP())
{
int pocCycle = 1 << (pcSlice->getSPS()->getBitsForPOC());
int deltaPOC = pocCurr > pcSlice->getAssociatedIRAPPOC() ? pocCurr - pcSlice->getAssociatedIRAPPOC() : pocCurr - ( pcSlice->getAssociatedIRAPPOC() & (pocCycle -1) );
CHECK(deltaPOC > (pocCycle >> 1), "Use a greater value for POC wraparound to enable a POC distance between IRAP and DRAP of " << deltaPOC << ".");
m_latestDRAPPOC = pocCurr;
pcSlice->setTLayer(0); // Force DRAP picture to have temporal layer 0
}
pcSlice->setLatestDRAPPOC(m_latestDRAPPOC);
pcSlice->setUseLTforDRAP(false); // When set, sets the associated IRAP as long-term in RPL0 at slice level, unless the associated IRAP is already included in RPL0 or RPL1 defined in SPS
PicList::iterator iterPic = rcListPic.begin();
Picture *rpcPic;
while (iterPic != rcListPic.end())
{
rpcPic = *(iterPic++);
if ( pcSlice->isDRAP() && rpcPic->getPOC() != pocCurr )
{
rpcPic->precedingDRAP = true;
}
else if ( !pcSlice->isDRAP() && rpcPic->getPOC() == pocCurr )
{
rpcPic->precedingDRAP = false;
}
}
}
pcSlice->setEnableEdrapSEI(m_pcEncLib->getEdrapIndicationSEIEnabled());
if (m_pcEncLib->getEdrapIndicationSEIEnabled())
{
// Only mark the picture as Extended DRAP if all of the following applies:
// 1) Extended DRAP indication SEI messages are enabled
// 2) The current picture is not an intra picture
// 3) The current picture is in the EDRAP period
// 4) The current picture is a trailing picture
if (m_pcEncLib->getEdrapIndicationSEIEnabled() && m_pcEncLib->getEdrapPeriod() > 0 && !pcSlice->isIntra() &&
pocCurr % m_pcEncLib->getEdrapPeriod() == 0 && pocCurr > pcSlice->getAssociatedIRAPPOC())
{
pcSlice->setEdrapRapId(pocCurr / m_pcEncLib->getEdrapPeriod());
pcSlice->getPic()->setEdrapRapId(pocCurr / m_pcEncLib->getEdrapPeriod());
}
if (pcSlice->getEdrapRapId() > 0)
{
m_latestEDRAPPOC = pocCurr;
m_latestEdrapLeadingPicDecodableFlag = false;
pcSlice->setTLayer(0); // Force Extended DRAP picture to have temporal layer 0
msg( NOTICE, "Force the temporal sublayer identifier of the EDRAP picture equal to 0.\n");
}
pcSlice->setLatestEDRAPPOC(m_latestEDRAPPOC);
pcSlice->setLatestEdrapLeadingPicDecodableFlag(m_latestEdrapLeadingPicDecodableFlag);
pcSlice->setUseLTforEdrap(false); // When set, sets the associated IRAP/EDRAP as long-term in RPL0 at slice level, unless the associated IRAP/EDRAP is already included in RPL0 or RPL1 defined in SPS
PicList::iterator iterPic = rcListPic.begin();
Picture *rpcPic;
while (iterPic != rcListPic.end())
{
rpcPic = *(iterPic++);
if ( pcSlice->getEdrapRapId() > 0 && rpcPic->getPOC() != pocCurr && rpcPic->getPOC() >= pcSlice->getAssociatedIRAPPOC() )
{
if (rpcPic->getEdrapRapId() >= 0 && rpcPic->getPOC() % m_pcEncLib->getEdrapPeriod() == 0)
{
bool bRefExist = false;
for (int i = 0; i < pcSlice->getEdrapNumRefRapPics(); i++)
{
if (pcSlice->getEdrapRefRapId(i) == rpcPic->getEdrapRapId())
bRefExist = true;
}
if (!bRefExist)
{
pcSlice->addEdrapRefRapIds(rpcPic->getPOC() / m_pcEncLib->getEdrapPeriod());
pcSlice->setEdrapNumRefRapPics(pcSlice->getEdrapNumRefRapPics() + 1);
}
}
}
}
}
if (pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL0(), 0, false) != 0 || pcSlice->checkThatAllRefPicsAreAvailable(rcListPic, pcSlice->getRPL1(), 1, false) != 0 ||
(m_pcEncLib->getDependentRAPIndicationSEIEnabled() && !pcSlice->isIRAP() && ( pcSlice->isDRAP() || !pcSlice->isPOCInRefPicList(pcSlice->getRPL0(), pcSlice->getAssociatedIRAPPOC())) ) ||
(m_pcEncLib->getEdrapIndicationSEIEnabled() && !pcSlice->isIRAP() && ( pcSlice->getEdrapRapId() > 0 || !pcSlice->isPOCInRefPicList(pcSlice->getRPL0(), pcSlice->getAssociatedIRAPPOC()) ) )
|| ((m_pcEncLib->getAvoidIntraInDepLayer() || !pcSlice->isIRAP()) && pcSlice->getPic()->cs->vps && m_pcEncLib->getNumRefLayers(pcSlice->getPic()->cs->vps->getGeneralLayerIdx(m_pcEncLib->getLayerId())))
)
{
xCreateExplicitReferencePictureSetFromReference( pcSlice, rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1() );
}
pcSlice->applyReferencePictureListBasedMarking( rcListPic, pcSlice->getRPL0(), pcSlice->getRPL1(), pcSlice->getPic()->layerId, *(pcSlice->getPPS()));
if(pcSlice->getTLayer() > 0
&& !(pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RADL // Check if not a leading picture
|| pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL)
)
{
if (pcSlice->isStepwiseTemporalLayerSwitchingPointCandidate(rcListPic))
{
bool isSTSA=true;
for(int ii=0;(ii<m_pcCfg->getGOPSize() && isSTSA==true);ii++)
{
int lTid = m_pcCfg->getRPLEntry(0, ii).m_temporalId;
if (lTid == pcSlice->getTLayer())
{
const ReferencePictureList* rpl0 = pcSlice->getSPS()->getRPLList0()->getReferencePictureList(ii);
for (int jj = 0; jj < pcSlice->getRPL0()->getNumberOfActivePictures(); jj++)
{
int tPoc = pcSlice->getPOC() + rpl0->getRefPicIdentifier(jj);
int kk = 0;
for (kk = 0; kk<m_pcCfg->getGOPSize(); kk++)
{
if (m_pcCfg->getRPLEntry(0, kk).m_POC == tPoc)
{
break;
}
}
int tTid = m_pcCfg->getRPLEntry(0, kk).m_temporalId;
if (tTid >= pcSlice->getTLayer())
{
isSTSA = false;
break;
}
}
const ReferencePictureList* rpl1 = pcSlice->getSPS()->getRPLList1()->getReferencePictureList(ii);
for (int jj = 0; jj < pcSlice->getRPL1()->getNumberOfActivePictures(); jj++)
{
int tPoc = pcSlice->getPOC() + rpl1->getRefPicIdentifier(jj);
int kk = 0;
for (kk = 0; kk<m_pcCfg->getGOPSize(); kk++)
{
if (m_pcCfg->getRPLEntry(1, kk).m_POC == tPoc)
{
break;
}
}
int tTid = m_pcCfg->getRPLEntry(1, kk).m_temporalId;
if (tTid >= pcSlice->getTLayer())
{
isSTSA = false;
break;
}
}
}
}
if(isSTSA==true)
{
pcSlice->setNalUnitType(NAL_UNIT_CODED_SLICE_STSA);
}
}
}
if (m_pcCfg->getUseCompositeRef() && getUseLTRef() && (pocCurr > getLastLTRefPoc()))
{
pcSlice->setNumRefIdx(REF_PIC_LIST_0, (pcSlice->isIntra()) ? 0 : min(m_pcCfg->getRPLEntry(0, iGOPid).m_numRefPicsActive + 1, pcSlice->getRPL0()->getNumberOfActivePictures()));
pcSlice->setNumRefIdx(REF_PIC_LIST_1, (!pcSlice->isInterB()) ? 0 : min(m_pcCfg->getRPLEntry(1, iGOPid).m_numRefPicsActive + 1, pcSlice->getRPL1()->getNumberOfActivePictures()));
}
else
{
pcSlice->setNumRefIdx(REF_PIC_LIST_0, (pcSlice->isIntra()) ? 0 : pcSlice->getRPL0()->getNumberOfActivePictures());
pcSlice->setNumRefIdx(REF_PIC_LIST_1, (!pcSlice->isInterB()) ? 0 : pcSlice->getRPL1()->getNumberOfActivePictures());
}
if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
{
arrangeCompositeReference(pcSlice, rcListPic, pocCurr);
}
// Set reference list
pcSlice->constructRefPicList(rcListPic);
decodingRefreshMarking():重置某些帧的referenced和m_hashMap,更新m_pocCRA。m_pocCRA表示编码顺序之前最近CRA帧的POC.当遇到IDR/CRA/CRANT/BLA/BLANT时,标记参考图片.具体函数之后再看
第一个if语句:getUseCompositeRef():复合参考列表?PicBg:不知道什么意思。跳过
第二个if语句:selectReferencePictureList():设置slice的RPL0和RPL1.
第三个if语句getEfficientFieldIRAPEnabled()在前面已经设置过了,所以跳过。
2349行~~2437行与图片标记为DRAP和EDRAP有关,暂时不考虑
setEnableDRAPSEI():DRAP(Dependent Random Access Point),设置m_enableDRAPSEI
checkThatAllRefPicsAreAvailable():检查图像参考列表是否存在。4个参数:rcListPic( m_cListPic):动态图片列表。pRPL:参考图像列表。rplIdx:参考图像列表序号。printErrors:错误输出
if语句中还有几个判断函数和DARP,EDRAP,layer有关,暂时不看,以后再说
xCreateExplicitReferencePictureSetFromReference():用来解决参考帧无效的情况。没仔细看
applyReferencePictureListBasedMarking():根据图像参考列表来申请图像标记 。(1)检查是否应该保留为参考图片(2)如果图片未在参考图像列表中,标记为unused picture(3)标记long~term 图片
接下来的if语句(if(pcSlice->getTLayer() > 0......):检查当前编码帧是不是STSA
if (m_pcCfg->getUseCompositeRef() && getUseLTRef() && (pocCurr > getLastLTRefPoc())):
推测因为我使用的是encoder_intra_vtm的设置,都是I帧,所以不需要参考帧。所以getUseLTRef() ,推测意思是左边的参考帧都为0.这一段在改变设置后可重新验证一次
setNumRefIdx():设置m_aiNumRefIdx,表示参考帧的数量。I帧都是0,P帧RPL1的参考帧数量为0。
constructRefPicList():构建参考帧列表