VTM3.0代码阅读:decompressSlice函数

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();		//停止计时
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值