注意:本次代码运用的是encoder_intra_vtm的设置,所以GOP_size 只有一帧
// store sub-picture numbers, sizes, and locations with a picture
pcSlice->getPic()->subPictures.clear();
for( int subPicIdx = 0; subPicIdx < pcPic->cs->pps->getNumSubPics(); subPicIdx++ )
{
pcSlice->getPic()->subPictures.push_back( pcPic->cs->pps->getSubPic( subPicIdx ) );//好像是根据序号,把子图片移动到队列末尾?
}
const VPS* vps = pcPic->cs->vps;//视频参数集
int layerIdx = vps == nullptr ? 0 : vps->getGeneralLayerIdx(pcPic->layerId);
if (vps && !vps->getIndependentLayerFlag(layerIdx) && pcPic->cs->pps->getNumSubPics() > 1)
{
CU::checkConformanceILRP(pcSlice);
}
xPicInitHashME( pcPic, pcSlice->getPPS(), rcListPic );
if( m_pcCfg->getUseAMaxBT() )
{
if (!pcSlice->isIRAP())
{
int refLayer = pcSlice->getDepth();
if (refLayer > 9)
{
refLayer = 9; // Max layer is 10
}
if( m_bInitAMaxBT && pcSlice->getPOC() > m_uiPrevISlicePOC )
{
::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
::memset( m_uiNumBlk, 0, sizeof( m_uiNumBlk ) );
m_bInitAMaxBT = false;
}
if( refLayer >= 0 && m_uiNumBlk[refLayer] != 0 )
{
picHeader->setSplitConsOverrideFlag(true);
double dBlkSize = sqrt( ( double ) m_uiBlkSize[refLayer] / m_uiNumBlk[refLayer] );
unsigned int newMaxBtSize = picHeader->getMaxBTSize(pcSlice->getSliceType(), CHANNEL_TYPE_LUMA);
if( dBlkSize < AMAXBT_TH32 )
{
newMaxBtSize = 32;
}
else if( dBlkSize < AMAXBT_TH64 )
{
newMaxBtSize = 64;
}
else
{
newMaxBtSize = 128;
}
newMaxBtSize = Clip3(picHeader->getMinQTSize(pcSlice->getSliceType()), pcPic->cs->sps->getCTUSize(), newMaxBtSize);
picHeader->setMaxBTSize(1, newMaxBtSize);
m_uiBlkSize[refLayer] = 0;
m_uiNumBlk [refLayer] = 0;
}
}
else
{
if( m_bInitAMaxBT )
{
::memset( m_uiBlkSize, 0, sizeof( m_uiBlkSize ) );
::memset( m_uiNumBlk, 0, sizeof( m_uiNumBlk ) );
}
m_uiPrevISlicePOC = pcSlice->getPOC();
m_bInitAMaxBT = true;
}
bool identicalToSPS=true;
const SPS* sps =pcSlice->getSPS();
if (picHeader->getPicInterSliceAllowedFlag())
{
if (picHeader->getMinQTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMinQTSize(pcSlice->getSliceType()) ||
picHeader->getMaxMTTHierarchyDepth(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxMTTHierarchyDepth() ||
picHeader->getMaxBTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxBTSize() ||
picHeader->getMaxTTSize(pcSlice->getSliceType()) != pcSlice->getSPS()->getMaxTTSize()
)
{
identicalToSPS=false;
}
}
if (identicalToSPS && picHeader->getPicIntraSliceAllowedFlag())
{
if (picHeader->getMinQTSize(I_SLICE) != sps->getMinQTSize(I_SLICE) ||
picHeader->getMaxMTTHierarchyDepth(I_SLICE) != sps->getMaxMTTHierarchyDepthI() ||
picHeader->getMaxBTSize(I_SLICE) != sps->getMaxBTSizeI() ||
picHeader->getMaxTTSize(I_SLICE) != sps->getMaxTTSizeI()
)
{
identicalToSPS=false;
}
if (identicalToSPS && sps->getUseDualITree())
{
if (picHeader->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMinQTSize(I_SLICE, CHANNEL_TYPE_CHROMA) ||
picHeader->getMaxMTTHierarchyDepth(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxMTTHierarchyDepthIChroma() ||
picHeader->getMaxBTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxBTSizeIChroma() ||
picHeader->getMaxTTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxTTSizeIChroma()
)
{
identicalToSPS=false;
}
}
}
if (identicalToSPS)
{
picHeader->setSplitConsOverrideFlag(false);
}
}
subPictures.clear():清空缓存并存放一个图片的子图片编号、大小和位置
getNumSubPics():设置m_numSubPics,已使用的子图片数量,必须与SPS相匹配。默认设置为0. software_manual里有相关名词解释。
第一个if语句:看vps参数,得到m_generalLayerIdx,代表设置的分层层数。由layerId的值决定,最大64.
xPicInitHashME():初始化m_uiBlkSize,m_uiNumBlk并设置为0.
第二个if语句(2545~2640):查看是否使用AMaxBT(Adaptive maximal BT-size)这个技术,默认都使用。再看是什么帧.B,P帧有一个if语句,i帧是另一个if语句
memset用法详解(转)_luxuejuncarl的博客-CSDN博客
两个memset:初始化m_uiBlkSize,m_uiNumBlk并设置为0.Blk(BLOCK),
identicalToSPS:因为此时设置的全为I帧,所以帧内预测。这个参数也设置为true。
getPicIntraSliceAllowedFlag():slice帧内的一个标志。
maxBTSize[3]:允许的二叉树根节点最大尺寸.// 0: I slice luma; 1: P/B slice; 2: I slice chroma
if语句(picHeader->getMaxBTSize(I_SLICE) != sps->getMaxBTSizeI()):如果从图片头信息中得到的maxBTSize和从sps中得到的maxBTSize不同,则将identicalToSPS设置为false。注意这里是getMaxBTSizeI(),得到的是I slice 的亮度分量的maxBTSize。
getUseDualITree():dualtree(Enables or disables the use of separate QTBT trees for intra slice luma and chroma channel types.),即亮色度具有不同的编码树结构
if语句(picHeader->getMaxBTSize(I_SLICE, CHANNEL_TYPE_CHROMA) != sps->getMaxBTSizeIChroma()):如果从图片头信息中得到的maxBTSize和从sps中得到的maxBTSize不同,则将identicalToSPS设置为false.这里得到的是I slice 的色度分量的maxBTSize。
setSplitConsOverrideFlag():设置m_splitConsOverrideFlag为false。划分受限操控标志,表示现在划分不受限
// Slice info. refinement
if ( (pcSlice->getSliceType() == B_SLICE) && (pcSlice->getNumRefIdx(REF_PIC_LIST_1) == 0) )
{
pcSlice->setSliceType ( P_SLICE );
}
xUpdateRasInit( pcSlice );
if (pcSlice->getPendingRasInit() || pcSlice->isIRAP())
{
// this ensures that independently encoded bitstream chunks can be combined to bit-equal
pcSlice->setEncCABACTableIdx( pcSlice->getSliceType() );
}
else
{
pcSlice->setEncCABACTableIdx( m_pcSliceEncoder->getEncCABACTableIdx() );
}
if (pcSlice->getSliceType() == B_SLICE)
{
bool bLowDelay = true;
int iCurrPOC = pcSlice->getPOC();
int iRefIdx = 0;
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_0) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_0, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
for (iRefIdx = 0; iRefIdx < pcSlice->getNumRefIdx(REF_PIC_LIST_1) && bLowDelay; iRefIdx++)
{
if ( pcSlice->getRefPic(REF_PIC_LIST_1, iRefIdx)->getPOC() > iCurrPOC )
{
bLowDelay = false;
}
}
pcSlice->setCheckLDC(bLowDelay);
}
else
{
pcSlice->setCheckLDC(true);
}
第一个if语句:修正slice的类型,如果检验为B slice且无参考帧列表1,则修正为P slice
xUpdateRasInit():设置m_lastRasPoc和slice的m_pendingRasInit。m_lastRasPoc表示按编码顺序之前最近的IRAP帧的POC,包括自身。m_pendingRasInit和下面的if分支有关。
如果当前slice的poc序号大于m_lastRasPoc,代表当前不是I帧,则把m_pendingRasInit设为true。否则m_lastRasPoc设为当前帧的poc序号。
第二个if语句:如果m_pendingRasInit为true或当前帧为i帧,则执行setEncCABACTableIdx()。
setEncCABACTableIdx():好像是关于自适应算术编码的一个确保机制,之后再修改
第三个if语句:与low _delay模式有关,之后再看
pcSlice->setRefPOCList();
pcSlice->setList1IdxToList0Idx();
if (m_pcEncLib->getTMVPModeId() == 2)
{
if (iGOPid == 0) // first picture in SOP (i.e. forward B)
{
picHeader->setEnableTMVPFlag(0);
}
else
{
// Note: pcSlice->getColFromL0Flag() is assumed to be always 0 and getcolRefIdx() is always 0.
picHeader->setEnableTMVPFlag(1);
}
}
else if (m_pcEncLib->getTMVPModeId() == 1)
{
picHeader->setEnableTMVPFlag(1);
}
else
{
picHeader->setEnableTMVPFlag(0);
}
// disable TMVP when current picture is the only ref picture
if (pcSlice->isIRAP() && pcSlice->getSPS()->getIBCFlag())
{
picHeader->setEnableTMVPFlag(0);//当前图片是唯一的参考图片时禁用TMVP
}
if( pcSlice->getSliceType() != I_SLICE && picHeader->getEnableTMVPFlag() )
{
int colRefIdxL0 = -1, colRefIdxL1 = -1;
for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); refIdx++ )
{
CHECK( pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L0 reference picture" );
if( pcSlice->getRefPic( REF_PIC_LIST_0, refIdx )->isRefScaled( pcSlice->getPPS() ) == false )
{
colRefIdxL0 = refIdx;
break;
}
}
if( pcSlice->getSliceType() == B_SLICE )
{
for( int refIdx = 0; refIdx < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); refIdx++ )
{
CHECK( pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->unscaledPic == nullptr, "unscaledPic is not set for L1 reference picture" );
if( pcSlice->getRefPic( REF_PIC_LIST_1, refIdx )->isRefScaled( pcSlice->getPPS() ) == false )
{
colRefIdxL1 = refIdx;
break;
}
}
}
if( colRefIdxL0 >= 0 && colRefIdxL1 >= 0 )
{
const Picture *refPicL0 = pcSlice->getRefPic( REF_PIC_LIST_0, colRefIdxL0 );
if( !refPicL0->slices.size() )
{
refPicL0 = refPicL0->unscaledPic;
}
const Picture *refPicL1 = pcSlice->getRefPic( REF_PIC_LIST_1, colRefIdxL1 );
if( !refPicL1->slices.size() )
{
refPicL1 = refPicL1->unscaledPic;
}
CHECK( !refPicL0->slices.size(), "Wrong L0 reference picture" );
CHECK( !refPicL1->slices.size(), "Wrong L1 reference picture" );
const uint32_t uiColFromL0 = refPicL0->slices[0]->getSliceQp() > refPicL1->slices[0]->getSliceQp();
picHeader->setPicColFromL0Flag( uiColFromL0 );
pcSlice->setColFromL0Flag( uiColFromL0 );
pcSlice->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
picHeader->setColRefIdx( uiColFromL0 ? colRefIdxL0 : colRefIdxL1 );
}
else if( colRefIdxL0 < 0 && colRefIdxL1 >= 0 )
{
picHeader->setPicColFromL0Flag( false );
pcSlice->setColFromL0Flag( false );
pcSlice->setColRefIdx( colRefIdxL1 );
picHeader->setColRefIdx( colRefIdxL1 );
}
else if( colRefIdxL0 >= 0 && colRefIdxL1 < 0 )
{
picHeader->setPicColFromL0Flag( true );
pcSlice->setColFromL0Flag( true );
pcSlice->setColRefIdx( colRefIdxL0 );
picHeader->setColRefIdx( colRefIdxL0 );
}
else
{
picHeader->setEnableTMVPFlag( 0 );
}
}
setRefPOCList():设置slice的m_aiRefPOCList,表示参考帧列表中对应帧的POC。
几个函数解释(在 B 帧时记得验证一下)_青椒鸡汤的博客-CSDN博客
setList1IdxToList0Idx():设置slice的m_list1IdxToList0Idx,含义是RPL1的帧如果同时存在RPL0中,则为帧在RPL0中的Index,否则为-1。等后面再验证
第一个和第二个if分支:设置PictureHeader的m_enableTMVPFlag,表示是否开启TMVP。默认设置sbTMVP = 1.
setEnableTMVPFlag():设置m_enableTMVPFlag,是否启用时间运动矢量预测
if( pcSlice->getSliceType() != I_SLICE:进行有关TMVP的非I帧的设置,没仔细看
#if GDR_ENABLED
PicHeader *picHeader = new PicHeader;
*picHeader = *pcPic->cs->picHeader;
pcSlice->scaleRefPicList(scaledRefPic, picHeader, m_pcEncLib->getApss(), picHeader->getLmcsAPS(), picHeader->getScalingListAPS(), false);
picHeader = pcPic->cs->picHeader;
#else
pcSlice->scaleRefPicList( scaledRefPic, pcPic->cs->picHeader, m_pcEncLib->getApss(), picHeader->getLmcsAPS(), picHeader->getScalingListAPS(), false );
#endif
// set adaptive search range for non-intra-slices
if (m_pcCfg->getUseASR() && !pcSlice->isIntra())
{
m_pcSliceEncoder->setSearchRange(pcSlice);//如果开启ASR,设置运动搜索范围
}
bool bGPBcheck=false;//为true表示RPL0和RPL1相同
if ( pcSlice->getSliceType() == B_SLICE)
{
if ( pcSlice->getNumRefIdx(RefPicList( 0 ) ) == pcSlice->getNumRefIdx(RefPicList( 1 ) ) )
{
bGPBcheck=true;
int i;
for ( i=0; i < pcSlice->getNumRefIdx(RefPicList( 1 ) ); i++ )
{
if ( pcSlice->getRefPOC(RefPicList(1), i) != pcSlice->getRefPOC(RefPicList(0), i) )
{
bGPBcheck=false;
break;
}
}
}
}
if(bGPBcheck)
{
picHeader->setMvdL1ZeroFlag(true);
}
else
{
picHeader->setMvdL1ZeroFlag(false);
}
if ( pcSlice->getSPS()->getUseSMVD() && pcSlice->getCheckLDC() == false
&& picHeader->getMvdL1ZeroFlag() == false
)
{
int currPOC = pcSlice->getPOC();
int forwardPOC = currPOC;
int backwardPOC = currPOC;
int ref = 0, refIdx0 = -1, refIdx1 = -1;
// search nearest forward POC in List 0
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
if ( poc < currPOC && (poc > forwardPOC || refIdx0 == -1) && !isRefLongTerm )
{
forwardPOC = poc;
refIdx0 = ref;
}
}
// search nearest backward POC in List 1
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
if ( poc > currPOC && (poc < backwardPOC || refIdx1 == -1) && !isRefLongTerm )
{
backwardPOC = poc;
refIdx1 = ref;
}
}
if ( !(forwardPOC < currPOC && backwardPOC > currPOC) )
{
forwardPOC = currPOC;
backwardPOC = currPOC;
refIdx0 = -1;
refIdx1 = -1;
// search nearest backward POC in List 0
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_0 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_0, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_0, ref)->longTerm;
if ( poc > currPOC && (poc < backwardPOC || refIdx0 == -1) && !isRefLongTerm )
{
backwardPOC = poc;
refIdx0 = ref;
}
}
// search nearest forward POC in List 1
for ( ref = 0; ref < pcSlice->getNumRefIdx( REF_PIC_LIST_1 ); ref++ )
{
int poc = pcSlice->getRefPic( REF_PIC_LIST_1, ref )->getPOC();
const bool isRefLongTerm = pcSlice->getRefPic(REF_PIC_LIST_1, ref)->longTerm;
if ( poc < currPOC && (poc > forwardPOC || refIdx1 == -1) && !isRefLongTerm )
{
forwardPOC = poc;
refIdx1 = ref;
}
}
}
if ( forwardPOC < currPOC && backwardPOC > currPOC )
{
pcSlice->setBiDirPred( true, refIdx0, refIdx1 );
}
else
{
pcSlice->setBiDirPred( false, -1, -1 );
}
}
else
{
pcSlice->setBiDirPred( false, -1, -1 );
}
if( pcSlice->getNalUnitType() == NAL_UNIT_CODED_SLICE_RASL && m_pcCfg->getRprRASLtoolSwitch() )
{
pcSlice->setDisableLmChromaCheck( true );
picHeader->setDmvrDisabledFlag( true );
xUpdateRPRtmvp( picHeader, pcSlice );
}
scaleRefPicList():如果参考帧的分辨率和编码帧的不一致,则要进行缩放
getUseASR():adaptive search range,自适应搜索范围,默认关闭
第一个if语句:当ASR开启且不是I帧时,设置运动搜索范围
第二个if语句:查验当为B 帧时,参考帧列表0和1是否相同,相同则bGPBcheck=true
if(bGPBcheck):如果参考帧列表0和1相同,设置PictureHeader的m_mvdL1ZeroFlag,为true表示不用传输RPL1的MVD
第三个if分支:设置是否开启SMVD,以及前后向参考帧在RPL中的Index。SMVD默认关闭
最后一个if语句:设置一些标志
【八】 H.266/vvc中对称MVD模式(SMVD)_Cohen_ina的博客-CSDN博客
H.266/VVC帧间预测总结_涵小呆的博客-CSDN博客_vvc帧间
double lambda = 0.0;//定义lambda,并且赋初值
int actualHeadBits = 0;//写入码流中的slice header的比特数(可能包括picture header)
int actualTotalBits = 0;//写入码流中的总比特数
int estimatedBits = 0;//预测比特数
int tmpBitsBeforeWriting = 0;
xPicInitRateControl(estimatedBits, iGOPid, lambda, pcPic, pcSlice);//初始化码率控制
uint32_t uiNumSliceSegments = 1;
pcSlice->setDefaultClpRng(*pcSlice->getSPS());//设置slice的m_clpRngs,有关于clip
// Allocate some coders, now the number of tiles are known.
const uint32_t numberOfCtusInFrame = pcPic->cs->pcv->sizeInCtus;//一帧内CTU的数量
const int numSubstreamsColumns = pcSlice->getPPS()->getNumTileColumns();//一般为1
const int numSubstreamRows = pcSlice->getSPS()->getEntropyCodingSyncEnabledFlag() ? pcPic->cs->pcv->heightInCtus : (pcSlice->getPPS()->getNumTileRows());//一般为1
const int numSubstreams = std::max<int> (numSubstreamRows * numSubstreamsColumns, (int) pcPic->cs->pps->getNumSlicesInPic());//一帧内substreams的数量,一般为1
std::vector<OutputBitstream> substreamsOut(numSubstreams);//substreams的输出buffer
可参考 HEVC码率控制代码追踪(一)(HEVC code tracing-Rate control)_yang-彧的博客-CSDN博客
actualTotalBits:写入码流中的总比特数
actualHeadBits:写入码流中的slice header的比特数(可能包括picture header)
xPicInitRateControl:初始化码率控制,虽然cfg中默认不开,但还是提一下方便以后找
uiNumSliceSegments:slices的数量
setDefaultClpRng:设置slice的m_clpRngs,有关于clip
一个slice会形成一个stream,然后封装在VCL-NALU中。在形成stream之前会先形成substreams然后再合成stream。如何划分substreams和slice划分、tile划分、是否开启WaveFrontSynchro都有关系
getNumTileColumns():得到tile单元的列数
getEntropyCodingSyncEnabledFlag():WPP的标志。默认关闭
#if ENABLE_QPA
pcPic->m_uEnerHpCtu.resize (numberOfCtusInFrame);
pcPic->m_iOffsetCtu.resize (numberOfCtusInFrame);
#if ENABLE_QPA_SUB_CTU
if (pcSlice->getPPS()->getUseDQP() && pcSlice->getCuQpDeltaSubdiv() > 0)
{
const PreCalcValues &pcv = *pcPic->cs->pcv;
const unsigned mtsLog2 = (unsigned)floorLog2(std::min (pcPic->cs->sps->getMaxTbSize(), pcv.maxCUWidth));
pcPic->m_subCtuQP.resize ((pcv.maxCUWidth >> mtsLog2) * (pcv.maxCUHeight >> mtsLog2));
}
#endif
#endif
if (pcSlice->getSPS()->getSAOEnabledFlag())
{
pcPic->resizeSAO( numberOfCtusInFrame, 0 );
pcPic->resizeSAO( numberOfCtusInFrame, 1 );
}
// it is used for signalling during CTU mode decision, i.e. before ALF processing
if( pcSlice->getSPS()->getALFEnabledFlag() )
{
pcPic->resizeAlfCtuEnableFlag( numberOfCtusInFrame );
pcPic->resizeAlfCtuAlternative( numberOfCtusInFrame );
pcPic->resizeAlfCtbFilterIndex(numberOfCtusInFrame);
}
bool decPic = false;
bool encPic = false;
// test if we can skip the picture entirely or decode instead of encoding
trySkipOrDecodePicture( decPic, encPic, *m_pcCfg, pcPic, m_pcEncLib->getApsMap() );
这几个函数是关于一些新技术还有SAO(采样点自适应偏移),ALF(环路滤波)的标志等设定
pcPic->cs->slice = pcSlice; // please keep this
#if ENABLE_QPA
if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs) && !m_pcCfg->getUsePerceptQPA() && (m_pcCfg->getSliceChromaOffsetQpPeriodicity() == 0))
#else
if (pcSlice->getPPS()->getSliceChromaQpFlag() && CS::isDualITree (*pcSlice->getPic()->cs))
#endif
{
// overwrite chroma qp offset for dual tree
pcSlice->setSliceChromaQpDelta(COMPONENT_Cb, m_pcCfg->getChromaCbQpOffsetDualTree());
pcSlice->setSliceChromaQpDelta(COMPONENT_Cr, m_pcCfg->getChromaCrQpOffsetDualTree());
if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
{
pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
}
m_pcSliceEncoder->setUpLambda(pcSlice, pcSlice->getLambdas()[0], pcSlice->getSliceQp());
}
xPicInitLMCS(pcPic, picHeader, pcSlice);//进行LMCS的初始化
if( pcSlice->getSPS()->getScalingListFlag() && m_pcCfg->getUseScalingListId() == SCALING_LIST_FILE_READ )
{
picHeader->setExplicitScalingListEnabledFlag( true );
pcSlice->setExplicitScalingListUsed( true );
int apsId = std::min<int>( 7, m_pcEncLib->getVPS() == nullptr ? 0 : m_pcEncLib->getVPS()->getGeneralLayerIdx( m_pcEncLib->getLayerId() ) );
picHeader->setScalingListAPSId( apsId );
ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
APS* scalingListAPS = apsMap->getPS( ( apsId << NUM_APS_TYPE_LEN ) + SCALING_LIST_APS );
assert( scalingListAPS != NULL );
picHeader->setScalingListAPS( scalingListAPS );
}
pcPic->cs->picHeader->setPic(pcPic);//设置变量m_valid,表明图片头信息是否正确
pcPic->cs->picHeader->setValid();//设置指针变量 m_pcPic,接收指向图片的指针变量pcPic
if(pcPic->cs->sps->getFpelMmvdEnabledFlag())
{
// cannot set ph_fpel_mmvd_enabled_flag at slice level - need new picture-level version of checkDisFracMmvd algorithm?
// m_pcSliceEncoder->checkDisFracMmvd( pcPic, 0, numberOfCtusInFrame );
bool useIntegerMVD = (pcPic->lwidth()*pcPic->lheight() > 1920 * 1080);
pcPic->cs->picHeader->setDisFracMMVD( useIntegerMVD );
}
if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
{
m_pcSliceEncoder->setJointCbCrModes(*pcPic->cs, Position(0, 0), pcPic->cs->area.lumaSize());
}
if (!pcSlice->getSPS()->getSpsRangeExtension().getReverseLastSigCoeffEnabledFlag() || pcSlice->getSliceQp() > 12)
{
pcSlice->setReverseLastSigCoeffFlag(false);
}
else
{
/*for RA serial and parallel alignment start*/
if (m_pcCfg->getIntraPeriod() > 1)
{
if (pcSlice->isIntra())
{
m_cnt_right_bottom = 0;
}
if ((pocCurr % m_pcCfg->getIntraPeriod()) <= m_pcCfg->getGOPSize() && iGOPid == 0 && !pcSlice->isIntra())
{
m_cnt_right_bottom = m_cnt_right_bottom_i;
}
}
/*for RA serial and parallel alignment end*/
pcSlice->setReverseLastSigCoeffFlag(m_cnt_right_bottom >= 0);
}
setReverseLastSigCoeffFlag():设置m_reverseLastSigCoeffFlag,默认为false。
if( encPic )
// now compress (trial encode) the various slice segments (slices, and dependent slices)
{
DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "poc", pocCurr ) ) );
const std::vector<uint16_t> sliceLosslessArray = *(m_pcCfg->getSliceLosslessArray());
bool mixedLossyLossless = m_pcCfg->getMixedLossyLossless();
if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
{
pcPic->fillSliceLossyLosslessArray(sliceLosslessArray, mixedLossyLossless);
}
for(uint32_t sliceIdx = 0; sliceIdx < pcPic->cs->pps->getNumSlicesInPic(); sliceIdx++ )
{
pcSlice->setSliceMap( pcPic->cs->pps->getSliceMap( sliceIdx ) );
if (pcSlice->getSPS()->getSpsRangeExtension().getTSRCRicePresentFlag() && (pcPic->cs->pps->getNumSlicesInPic() == 1))
{
if (!pcSlice->isIntra())
{
int nextRice = 1;
if (m_preIPOC < pocCurr)
{
for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
{
m_riceBit[idx][0] = m_riceBit[idx][1];
}
m_preQP[0] = m_preQP[1];
m_preIPOC = MAX_INT;
}
if (m_preQP[0] != pcSlice->getSliceQp())
{
m_riceBit[pcSlice->get_tsrc_index()][0] = (int) (m_riceBit[pcSlice->get_tsrc_index()][0] * 9 / 10);
}
for (int idx = 2; idx < 9; idx++)
{
if (m_riceBit[idx - 2][0] > m_riceBit[idx - 1][0])
{
nextRice = idx;
}
else
{
m_riceBit[idx - 1][0] = m_riceBit[idx - 2][0];
}
m_riceBit[idx - 2][0] = 0;
}
m_riceBit[7][0] = 0;
pcSlice->set_tsrc_index(nextRice - 1);
}
else
{
m_preIPOC = pocCurr;
m_preQP[0] = MAX_INT;
m_preQP[1] = pcSlice->getSliceQp();
for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
{
m_riceBit[idx][0] = 0;
}
}
for (int idx = 0; idx < MAX_TSRC_RICE; idx++)
{
pcSlice->setRiceBit(idx, m_riceBit[idx][0]);
}
}
if( pcPic->cs->pps->getRectSliceFlag() )
{
Position firstCtu;
firstCtu.x = pcSlice->getFirstCtuRsAddrInSlice() % pcPic->cs->pps->getPicWidthInCtu();//SLICE中第一个CTU的位置
firstCtu.y = pcSlice->getFirstCtuRsAddrInSlice() / pcPic->cs->pps->getPicWidthInCtu();
int subPicIdx = NOT_VALID;//为后面check函数初始化赋值
for( int sp = 0; sp < pcPic->cs->pps->getNumSubPics(); sp++ )
{
if( pcPic->cs->pps->getSubPic( sp ).containsCtu( firstCtu ) )
{
subPicIdx = sp;
break;
}
}
CHECK( subPicIdx == NOT_VALID, "Sub-picture was not found" );
pcSlice->setSliceSubPicId( pcPic->cs->pps->getSubPic( subPicIdx ).getSubPicID() );
}
encPic:encode picture ,在前面的trySkipOrDecodePicture()变成了true.
列表中包含矩形模式slice下左上角的CTU RS地址,右下角的CTU RS地址。RS代表Rectangular slice。
getPicWidthInCtu():得到m_picWidthInCtu,应该是一帧图像一行包含CTU个数。在encodectus()函数中可体现出
firstCtu.x:得到矩形模式SLICE中第一个CTU的X地址
if (pcPic->cs->sps->getUseLmcs())
{
pcSlice->setLmcsEnabledFlag(picHeader->getLmcsEnabledFlag());
if (pcSlice->getSliceType() == I_SLICE)
{
//reshape original signal
if(m_pcCfg->getGopBasedTemporalFilterEnabled())
{
pcPic->getOrigBuf().copyFrom(pcPic->getFilteredOrigBuf());
}
else
{
pcPic->getOrigBuf().copyFrom(pcPic->getTrueOrigBuf());
}
if (pcSlice->getLmcsEnabledFlag())
{
pcPic->getOrigBuf(COMPONENT_Y).rspSignal(m_pcReshaper->getFwdLUT());
m_pcReshaper->setSrcReshaped(true);
m_pcReshaper->setRecReshaped(true);
}
else
{
m_pcReshaper->setSrcReshaped(false);
m_pcReshaper->setRecReshaped(false);
}
}
}
getUseLmcs():使用LMCS
LMCS设置一些参数,先跳过
bool isLossless = false; //关闭无损编码
if (m_pcCfg->getCostMode() == COST_LOSSLESS_CODING)
{
isLossless = pcPic->losslessSlice(sliceIdx);
}
m_pcSliceEncoder->setLosslessSlice(pcPic, isLossless);
if( pcSlice->getSliceType() != I_SLICE && pcSlice->getRefPic( REF_PIC_LIST_0, 0 )->subPictures.size() > 1 )
{
clipMv = clipMvInSubpic;
m_pcEncLib->getInterSearch()->setClipMvInSubPic(true);
}
else
{
clipMv = clipMvInPic;
m_pcEncLib->getInterSearch()->setClipMvInSubPic(false);
}
m_pcSliceEncoder->precompressSlice( pcPic );
m_pcSliceEncoder->compressSlice ( pcPic, false, false );
前两个if语句:与无损编码设置有关,跳过
precompressSlice():检查deltaQP,如果还没使用,直接return
【笔记】HEVC 编码标准(六)——量化_lock。的博客-CSDN博客
compressSlice():进入compressSlice()