【HEVC学习与研究】29、解码第一个Coding Quadtree结构(1)

在开始研究这部分代码之前,重新回顾一下理论部分。

众所周知,H.264及其之前的编码标准中,VCL层的核心结构称作“宏块”(MacroBlock, MB),大小为16×16像素。一个宏块里面包含着一个16×16分辨率的亮度采样矩阵和两个8×8分辨率的色度采样矩阵。相应的,在HEVC中,编码所采用的块结构为树形编码单元(Coding Tree Unit, CTU),每个CTU的大小由编码器决定,并且通常要大于宏块的16×16大小。比CTU更小的单位称为树形编码块(Coding Tree Block, CTB),一个CTU由一个亮度信号CTB及其相应的色度CTB,以及其他一些语法元素构成。一个正方形的亮度CTB的边长(以像素为单位)可能取16、32或者64个像素,CTB越大则压缩效率越高。HEVC标准支持将一个CTB按照四叉树的方法分割为多个更小的块结构。


采用了四叉树分割的方法后,这个树结构保存了亮度和色度编码单元(Coding Unit, CU)的位置和大小。这个四叉树结构的根与当前的这个CTU对应,也就是说,一个亮度CU最大可能的大小就是亮度CTB的大小。通常,一个CU的组成包括一个亮度编码块(Coding Block, CB),一个色度CB以及其他相应的语法元素。一个CTB可能包含一个CU,也可能被分割成多个CU,每一个CU进一步分割成预测单元(Prediction Unit, PU)和树结构的变换单元(Transform Unit, TU)。


判断采用帧内预测还是帧间预测在CU层完成。PU的分割结构就以CU为根,根据基本的预测模式判定,亮度和色度CB被进一步分割,由亮度和色度预测块(Prediction Block, PB)中获取预测值。每一个PB的大小可能由64×64到4×4不等。预测的残差信号由TU进行编码。同PU类似,TU树形结构的根节点也是CU,一个亮度CB的残差信号可能由一个完整的变换块(Transform Block, TB)表示,也可能树形分割成多个子TB。对4×4、8×8、16×16和32×32的正方形TB块,HEVC依然采用整数变换;当TB大小为4×4,且采用帧内编码的残差信号则采用了一种类离散正弦变换的方法。


标准文档的7.3.8.4节给出了Coding quadtree的语法结构:


该结构中的第一个语法元素split_cu_flag[x0][y0]表明这个Coding quadtree是否继续四等分,下标x0和y0表示当前拟作为cu的像素块左上角像素相对于该帧左上角的坐标。从该结构的定义来看,Coding quadtree采用了递归的结构,只要split_cu_flag[x0][y0]为1,则这个Coding quadtree就会继续分割下去,直到split_cu_flag[x0][y0]为0时,这个Coding quadtree进一步处理为一个coding unit。

回到代码中。实现解析Coding quadtree的函数由Void TDecCu::xDecodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt& ruiIsLast)实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Void TDecCu::xDecodeCU( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth, UInt& ruiIsLast)  
  2. {  
  3.     TComPic* pcPic = pcCU->getPic();  
  4.     UInt uiCurNumParts    = pcPic->getNumPartInCU() >> (uiDepth<<1);  
  5.     UInt uiQNumParts      = uiCurNumParts>>2;  
  6.   
  7.     Bool bBoundary = false;  
  8.     UInt uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiAbsPartIdx] ];  
  9.     UInt uiRPelX   = uiLPelX + (g_uiMaxCUWidth>>uiDepth)  - 1;  
  10.     UInt uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiAbsPartIdx] ];  
  11.     UInt uiBPelY   = uiTPelY + (g_uiMaxCUHeight>>uiDepth) - 1;  
  12.   
  13.     TComSlice * pcSlice = pcCU->getPic()->getSlice(pcCU->getPic()->getCurrSliceIdx());  
  14.     Bool bStartInCU = pcCU->getSCUAddr()+uiAbsPartIdx+uiCurNumParts>pcSlice->getSliceSegmentCurStartCUAddr()&&pcCU->getSCUAddr()+uiAbsPartIdx<pcSlice->getSliceSegmentCurStartCUAddr();  
  15.     if((!bStartInCU) && ( uiRPelX < pcSlice->getSPS()->getPicWidthInLumaSamples() ) && ( uiBPelY < pcSlice->getSPS()->getPicHeightInLumaSamples() ) )  
  16.     {  
  17.         m_pcEntropyDecoder->decodeSplitFlag( pcCU, uiAbsPartIdx, uiDepth );  
  18.     }  
  19.     else  
  20.     {  
  21.         bBoundary = true;  
  22.     }  
  23.   
  24.     if( ( ( uiDepth < pcCU->getDepth( uiAbsPartIdx ) ) && ( uiDepth < g_uiMaxCUDepth - g_uiAddCUDepth ) ) || bBoundary )  
  25.     {  
  26.         UInt uiIdx = uiAbsPartIdx;  
  27.         if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP())  
  28.         {  
  29.             setdQPFlag(true);  
  30.             pcCU->setQPSubParts( pcCU->getRefQP(uiAbsPartIdx), uiAbsPartIdx, uiDepth ); // set QP to default QP  
  31.         }  
  32.   
  33.         for ( UInt uiPartUnitIdx = 0; uiPartUnitIdx < 4; uiPartUnitIdx++ )  
  34.         {  
  35.             uiLPelX   = pcCU->getCUPelX() + g_auiRasterToPelX[ g_auiZscanToRaster[uiIdx] ];  
  36.             uiTPelY   = pcCU->getCUPelY() + g_auiRasterToPelY[ g_auiZscanToRaster[uiIdx] ];  
  37.   
  38.             Bool bSubInSlice = pcCU->getSCUAddr()+uiIdx+uiQNumParts>pcSlice->getSliceSegmentCurStartCUAddr();  
  39.             if ( bSubInSlice )  
  40.             {  
  41.                 if ( !ruiIsLast && ( uiLPelX < pcCU->getSlice()->getSPS()->getPicWidthInLumaSamples() ) && ( uiTPelY < pcCU->getSlice()->getSPS()->getPicHeightInLumaSamples() ) )  
  42.                 {  
  43.                     xDecodeCU( pcCU, uiIdx, uiDepth+1, ruiIsLast );  
  44.                 }  
  45.                 else  
  46.                 {  
  47.                     pcCU->setOutsideCUPart( uiIdx, uiDepth+1 );  
  48.                 }  
  49.             }  
  50.   
  51.             uiIdx += uiQNumParts;  
  52.         }  
  53.         if( (g_uiMaxCUWidth>>uiDepth) == pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP())  
  54.         {  
  55.             if ( getdQPFlag() )  
  56.             {  
  57.                 UInt uiQPSrcPartIdx;  
  58.                 if ( pcPic->getCU( pcCU->getAddr() )->getSliceSegmentStartCU(uiAbsPartIdx) != pcSlice->getSliceSegmentCurStartCUAddr() )  
  59.                 {  
  60.                     uiQPSrcPartIdx = pcSlice->getSliceSegmentCurStartCUAddr() % pcPic->getNumPartInCU();  
  61.                 }  
  62.                 else  
  63.                 {  
  64.                     uiQPSrcPartIdx = uiAbsPartIdx;  
  65.                 }  
  66.                 pcCU->setQPSubParts( pcCU->getRefQP( uiQPSrcPartIdx ), uiAbsPartIdx, uiDepth ); // set QP to default QP  
  67.             }  
  68.         }  
  69.         return;  
  70.     }  
  71.   
  72.     if( (g_uiMaxCUWidth>>uiDepth) >= pcCU->getSlice()->getPPS()->getMinCuDQPSize() && pcCU->getSlice()->getPPS()->getUseDQP())  
  73.     {  
  74.         setdQPFlag(true);  
  75.         pcCU->setQPSubParts( pcCU->getRefQP(uiAbsPartIdx), uiAbsPartIdx, uiDepth ); // set QP to default QP  
  76.     }  
  77.   
  78.     if (pcCU->getSlice()->getPPS()->getTransquantBypassEnableFlag())  
  79.     {  
  80.         m_pcEntropyDecoder->decodeCUTransquantBypassFlag( pcCU, uiAbsPartIdx, uiDepth );  
  81.     }  
  82.   
  83.     // decode CU mode and the partition size  
  84.     if( !pcCU->getSlice()->isIntra())  
  85.     {  
  86.         m_pcEntropyDecoder->decodeSkipFlag( pcCU, uiAbsPartIdx, uiDepth );  
  87.     }  
  88.   
  89.     if( pcCU->isSkipped(uiAbsPartIdx) )  
  90.     {  
  91.         m_ppcCU[uiDepth]->copyInterPredInfoFrom( pcCU, uiAbsPartIdx, REF_PIC_LIST_0 );  
  92.         m_ppcCU[uiDepth]->copyInterPredInfoFrom( pcCU, uiAbsPartIdx, REF_PIC_LIST_1 );  
  93.         TComMvField cMvFieldNeighbours[MRG_MAX_NUM_CANDS << 1]; // double length for mv of both lists  
  94.         UChar uhInterDirNeighbours[MRG_MAX_NUM_CANDS];  
  95.         Int numValidMergeCand = 0;  
  96.         for( UInt ui = 0; ui < m_ppcCU[uiDepth]->getSlice()->getMaxNumMergeCand(); ++ui )  
  97.         {  
  98.             uhInterDirNeighbours[ui] = 0;  
  99.         }  
  100.         m_pcEntropyDecoder->decodeMergeIndex( pcCU, 0, uiAbsPartIdx, uiDepth );  
  101.         UInt uiMergeIndex = pcCU->getMergeIndex(uiAbsPartIdx);  
  102.         m_ppcCU[uiDepth]->getInterMergeCandidates( 0, 0, cMvFieldNeighbours, uhInterDirNeighbours, numValidMergeCand, uiMergeIndex );  
  103.         pcCU->setInterDirSubParts( uhInterDirNeighbours[uiMergeIndex], uiAbsPartIdx, 0, uiDepth );  
  104.   
  105.         TComMv cTmpMv( 0, 0 );  
  106.         for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )  
  107.         {          
  108.             if ( pcCU->getSlice()->getNumRefIdx( RefPicList( uiRefListIdx ) ) > 0 )  
  109.             {  
  110.                 pcCU->setMVPIdxSubParts( 0, RefPicList( uiRefListIdx ), uiAbsPartIdx, 0, uiDepth);  
  111.                 pcCU->setMVPNumSubParts( 0, RefPicList( uiRefListIdx ), uiAbsPartIdx, 0, uiDepth);  
  112.                 pcCU->getCUMvField( RefPicList( uiRefListIdx ) )->setAllMvd( cTmpMv, SIZE_2Nx2N, uiAbsPartIdx, uiDepth );  
  113.                 pcCU->getCUMvField( RefPicList( uiRefListIdx ) )->setAllMvField( cMvFieldNeighbours[ 2*uiMergeIndex + uiRefListIdx ], SIZE_2Nx2N, uiAbsPartIdx, uiDepth );  
  114.             }  
  115.         }  
  116.         xFinishDecodeCU( pcCU, uiAbsPartIdx, uiDepth, ruiIsLast );  
  117.         return;  
  118.     }  
  119.   
  120.     m_pcEntropyDecoder->decodePredMode( pcCU, uiAbsPartIdx, uiDepth );  
  121.     m_pcEntropyDecoder->decodePartSize( pcCU, uiAbsPartIdx, uiDepth );  
  122.   
  123.     if (pcCU->isIntra( uiAbsPartIdx ) && pcCU->getPartitionSize( uiAbsPartIdx ) == SIZE_2Nx2N )  
  124.     {  
  125.         m_pcEntropyDecoder->decodeIPCMInfo( pcCU, uiAbsPartIdx, uiDepth );  
  126.   
  127.         if(pcCU->getIPCMFlag(uiAbsPartIdx))  
  128.         {  
  129.             xFinishDecodeCU( pcCU, uiAbsPartIdx, uiDepth, ruiIsLast );  
  130.             return;  
  131.         }  
  132.     }  
  133.   
  134.     UInt uiCurrWidth      = pcCU->getWidth ( uiAbsPartIdx );  
  135.     UInt uiCurrHeight     = pcCU->getHeight( uiAbsPartIdx );  
  136.   
  137.     // prediction mode ( Intra : direction mode, Inter : Mv, reference idx )  
  138.     m_pcEntropyDecoder->decodePredInfo( pcCU, uiAbsPartIdx, uiDepth, m_ppcCU[uiDepth]);  
  139.   
  140.     // Coefficient decoding  
  141.     Bool bCodeDQP = getdQPFlag();  
  142.     m_pcEntropyDecoder->decodeCoeff( pcCU, uiAbsPartIdx, uiDepth, uiCurrWidth, uiCurrHeight, bCodeDQP );  
  143.     setdQPFlag( bCodeDQP );  
  144.     xFinishDecodeCU( pcCU, uiAbsPartIdx, uiDepth, ruiIsLast );  
  145. }  

TDecEntropy::decodeSplitFlag   ( TComDataCU* pcCU, UInt uiAbsPartIdx, UInt uiDepth )函数调用m_pcEntropyDecoderIf->parseSplitFlag( pcCU, uiAbsPartIdx, uiDepth )来解析 split_cu_flag[x0][y0]的值。在这个过程中,由于规定了最大的CUDepth为4,所以只进行了4次分割便返回。其后,将处理coding block数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值