您的位置:首页 > 其它

【HEVC学习与研究】28、第一帧第一个宏块的SAO部分完整解析结果

2014-12-16 22:29 435 查看
经过了前面一段时间的研究,现在大致将这第一个宏块SAO由码流到语法元素值的解析过程完整整理一下。这里没有太多原理部分,更多的像是一篇流水账一样,聊作记录。

在代码中,我们首先查看一下解析完条带头数据后,当前NAL中带解析的码流。还是看我们一直使用的这个demo序列的编码结果,码流中正式用语解析条带数据的值如:

(后面是第一个CTU的SAO参数部分二进制流中的数据)CE 67 A2 6B A7 57 (后面是CTU部分) F3 70 1D 23 2C 03 F5 45 C5 C7...
以上是当前NAL中带解析的数据,包含了slice中每一个CTU的SAO信息和Coding Quardtree信息。具体实现步骤如:

1、slice数据的解析由TDecTop::xDecodeSlice()执行,该函数调用TDecGop::decompressSlice()实现具体的工作。在该函数中调用TDecSbac::resetEntropy()函数,在末尾的TDecBinCABAC::start()函数中,码流中的前两个字符206和103赋予m_uiValue作为一个UInt值的低两位,m_uiValue的值为52839作为初值;

2、TDecGop::decompressSlice()调用TDecSlice::decompressSlice(),解析SAO的部分在TDecSbac::parseSaoOneLcuInterleaving()中实现。该函数中的一个参数为SAOParam结构体指针pSaoParam,该结构体的定义为:

[cpp] view
plaincopy





struct SAOParam

{

Bool bSaoFlag[2];

SAOQTPart* psSaoPart[3];

Int iMaxSplitLevel;

Bool oneUnitFlag[3];

SaoLcuParam* saoLcuParam[3];

Int numCuInHeight;

Int numCuInWidth;

~SAOParam();

};

在该结构中,TDecSbac::parseSaoOneLcuInterleaving()解析的内容赋予SAOParam类型saoLcuParam[3]数组,定义如下:

[cpp] view
plaincopy





typedef struct _SaoLcuParam

{

Bool mergeUpFlag;

Bool mergeLeftFlag;

Int typeIdx;

Int subTypeIdx; ///< indicates EO class or BO band position

Int offset[4];

Int partIdx;

Int partIdxTmp;

Int length;

} SaoLcuParam;

TDecSbac::parseSaoOneLcuInterleaving()函数首先对pSaoParam参数进行初始化:

[cpp] view
plaincopy





for (Int iCompIdx=0; iCompIdx<3; iCompIdx++)

{

pSaoParam->saoLcuParam[iCompIdx][iAddr].mergeUpFlag = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].mergeLeftFlag = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].subTypeIdx = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].typeIdx = -1;

pSaoParam->saoLcuParam[iCompIdx][iAddr].offset[0] = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].offset[1] = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].offset[2] = 0;

pSaoParam->saoLcuParam[iCompIdx][iAddr].offset[3] = 0;

}

由于当前CTU是slice中的第一个CTU,不存在左侧和上方的元素,因此parseSaoMerge()函数将不被执行。随后在3次for循环中,调用方法为parseSaoOffset(&(pSaoParam->saoLcuParam[iCompIdx][iAddr]), iCompIdx)。

第一次循环:

调用parseSaoType(),解析结果pSaoParam->saoLcuParam[0][0].typeIdx = -1;pSaoParam->saoLcuParam[0][0].length = 0。

第二次循环:

调用parseSaoType(),解析结果pSaoParam->saoLcuParam[1][0].typeIdx = 4;pSaoParam->saoLcuParam[0][0].length = 4;

循环调用4次parseSaoMaxUvlc(),解析结果为:pSaoParam->saoLcuParam[1][0].offset[0] = 0; pSaoParam->saoLcuParam[1][0].offset[1] = 3,解析过程中读取该段码流中第三个字符‘A2’; pSaoParam->saoLcuParam[1][0].offset[2] = 1; pSaoParam->saoLcuParam[1][0].offset[3]
= 1;

针对四个offset值中的非零者,解码下一个bit,若为非0值,则该offset取反。修正后, pSaoParam->saoLcuParam[1][0].offset[3] = -1;

调用parseSaoUflc(5, uiSymbol )函数,该函数读取码流中第四个字符‘6B’,解析结果pSaoParam->saoLcuParam[1][0].subTypeIdx = 13;

第三次循环:

由于compIdx为2,因此不再调用parseSaoType(),pSaoParam->saoLcuParam[2][0].typeIdx = pSaoParam->saoLcuParam[1][0].typeIdx = 4;

循环调用4次parseSaoMaxUvlc(),解析结果为:pSaoParam->saoLcuParam[2][0].offset[0] = 0; pSaoParam->saoLcuParam[2][0].offset[1] = 1;

pSaoParam->saoLcuParam[2][0].offset[2] = 3,解析过程中读取码流中下一个字符‘A7’; pSaoParam->saoLcuParam[2][0].offset[3] = 2;

针对四个offset值中的非零者,解码下一个bit,若为非0值,则该offset取反。修正后, pSaoParam->saoLcuParam[1][0].offset[1] = -1; pSaoParam->saoLcuParam[2][0].offset[2] = 3,解析该bit时读取下一个字符‘57’;pSaoParam->saoLcuParam[2][0].offset[3] = -2;

调用parseSaoUflc(5, uiSymbol )函数,解析结果pSaoParam->saoLcuParam[2][0].subTypeIdx = 10;

至此,TDecSbac::parseSaoOneLcuInterleaving()对第一个CTU的SAO部分解析完成。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: