decompressSlice函数是解码端解码ctu数据的统领函数。其中调用coding_tree_unit函数实现ctu数据的解码,调用decompressCtu函数实现ctu数据和像素信息的解析恢复。
大致流程可以总结为:
当前帧picture.cs的各种数据的初始化,方便ctu各种数据的解码和存储;
读取到每个ctu的编码信息数据流,每个sub数据流可以解码得到一个ctu的数据;
for循环逐个处理一帧中的所有ctu:确定ctu位置和区域,初始化cabac解码器,读取sub数据流并调用coding_tree_unit函数解码一个ctu,调用decompressCtu函数实现ctu数据和像素信息的解析恢复。直到一帧中的所有ctu解码完成,解码剩余bit。
由于宏HEVC_TILES_WPP等关闭,所以删掉了一些无用的代码。函数流程和VTM1中差别不大,只是在每一行Ctu解码开始时,重置HMVP列表。
void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream )
{
//-- For time output for each slice
slice->startProcessingTimer(); //开启计时
const SPS* sps = slice->getSPS();
Picture* pic = slice->getPic(); //当前需要解码的一帧picture
#if HEVC_TILES_WPP
const TileMap& tileMap = *pic->tileMap;
#endif
CABACReader& cabacReader = *m_CABACDecoder->getCABACReader( 0 ); //新建一个CABAC解码器
// setup coding structure
CodingStructure& cs = *pic->cs; //当前解码picture的cs,进行各种数据的初始化,以便接下里ctu的解码
cs.slice = slice;
cs.sps = sps;
cs.pps = slice->getPPS();
#if HEVC_VPS
cs.vps = slice->getVPS();
#endif
cs.pcv = slice->getPPS()->pcv;
cs.chromaQpAdj = 0;
cs.picture->resizeSAO(cs.pcv->sizeInCtus, 0);
cs.picture->resizeAlfCtuEnableFlag( cs.pcv->sizeInCtus );
const unsigned numSubstreams = slice->getNumberOfSubstreamSizes() + 1; //sub数据流的个数
// init each couple {EntropyDecoder, Substream}
// Table of extracted substreams.
std::vector<InputBitstream*> ppcSubstreams( numSubstreams );
for( unsigned idx = 0; idx < numSubstreams; idx++ ) //将每个sub数据流存储到ppcSubstreams,用于接下来每个ctu的解码
{
ppcSubstreams[idx] = bitstream->extractSubstream( idx+1 < numSubstreams ? ( slice->getSubstreamSize(idx) << 3 ) : bitstream->getNumBitsLeft() );
}
#if HEVC_DEPENDENT_SLICES
const int startCtuTsAddr = slice->getSliceSegmentCurStartCtuTsAddr();
#else
const int startCtuTsAddr = slice->getSliceCurStartCtuTsAddr(); //CTU的起始ts扫描地址,即0
#endif
const unsigned numCtusInFrame = cs.pcv->sizeInCtus; //当前帧的ctu个数
const unsigned widthInCtus = cs.pcv->widthInCtus; //当前帧一行有多少个ctu
cabacReader.initBitstream( ppcSubstreams[0] ); //初始化cabac解码器
cabacReader.initCtxModels( *slice );
// Quantization parameter
#if HEVC_DEPENDENT_SLICES
if(!slice->getDependentSliceSegmentFlag())
{
#endif
pic->m_prevQP[0] = pic->m_prevQP[1] = slice->getSliceQp(); //量化系数qp
#if HEVC_DEPENDENT_SLICES
}
#endif
CHECK( pic->m_prevQP[0] == std::numeric_limits<int>::max(), "Invalid previous QP" );
DTRACE( g_trace_ctx, D_HEADER, "=========== POC: %d ===========\n", slice->getPOC() );
// The first CTU of the slice is the first coded substream, but the global substream number, as calculated by getSubstreamForCtuAddr may be higher.
// This calculates the common offset for all substreams in this slice.
// for every CTU in the slice segment...
bool isLastCtuOfSliceSegment = false; //当前解码的ctu是否为当前帧的最后一个ctu
for( unsigned ctuTsAddr = startCtuTsAddr; !isLastCtuOfSliceSegment && ctuTsAddr < numCtusInFrame; ctuTsAddr++ )
{ //ctu loop,对一帧中的所有ctu进行解码
const unsigned ctuRsAddr = ctuTsAddr;
const unsigned ctuXPosInCtus = ctuRsAddr % widthInCtus; //计算当前解码ctu的pos,area等信息
const unsigned ctuYPosInCtus = ctuRsAddr / widthInCtus;
#if HEVC_TILES_WPP
const unsigned subStrmId = tileMap.getSubstreamForCtuAddr( ctuRsAddr, true, slice ) - subStreamOffset;
#else
const unsigned subStrmId = 0;
#endif
const unsigned maxCUSize = sps->getMaxCUWidth();
Position pos( ctuXPosInCtus*maxCUSize, ctuYPosInCtus*maxCUSize) ; //解码ctu的pos
UnitArea ctuArea(cs.area.chromaFormat, Area( pos.x, pos.y, maxCUSize, maxCUSize ) ); //解码ctu的area
DTRACE_UPDATE( g_trace_ctx, std::make_pair( "ctu", ctuRsAddr ) );
cabacReader.initBitstream( ppcSubstreams[subStrmId] ); //CABAC解码器读取当前ctu的sub数据流,开始解码
#if JVET_L0646_GBI //广义Bi
bool updateGbiCodingOrder = cs.slice->getSliceType() == B_SLICE && ctuTsAddr == startCtuTsAddr;
if(updateGbiCodingOrder)
{
resetGbiCodingOrder(true, cs);
}
#endif
#if JVET_L0158_L0106_RESET_BUFFER //HMVP
if (cs.slice->getSliceType() != I_SLICE && ctuXPosInCtus == 0)
{
cs.slice->resetMotionLUTs(); //每一行CTU开始时重置HMVP列表
}
#endif
//coding_tree_unit 解码ctu数据
isLastCtuOfSliceSegment = cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr );
m_pcCuDecoder->decompressCtu( cs, ctuArea ); //decompressCtu 解析恢复ctu数据和像素信息
if( isLastCtuOfSliceSegment ) //当前ctu为一帧的最后一个ctu
{
#if DECODER_CHECK_SUBSTREAM_AND_SLICE_TRAILING_BYTES
cabacReader.remaining_bytes( false ); //读取完剩余bit
#endif
slice->setSliceCurEndCtuTsAddr( ctuTsAddr+1 );
}
}///ctu loop结束,一帧解码完成
CHECK( !isLastCtuOfSliceSegment, "Last CTU of slice segment not signalled as such" );
#if HEVC_DEPENDENT_SLICES
if( depSliceSegmentsEnabled )
{
m_lastSliceSegmentEndContextState = cabacReader.getCtx(); //ctx end of dep.slice
}
#endif
// deallocate all created substreams, including internal buffers.
for( auto substr: ppcSubstreams ) //一帧解码完成,存储的编码信息数据流delete
{
delete substr;
}
slice->stopProcessingTimer(); //停止计时
}