HEVC-I帧中CU,TU,PU之间的关系

这里主要是结合HEVC的解码端I帧进行讲解的,其中P,B帧基本上没有太大的出入,主要是PU还存在不规则的情况,因为我现在刚做完I帧,对P帧还没有把握

之后清楚解析后,再进行补充

在之前的博文中提到了编码树结构的相关概念,这里主要结合代码进行进一步的讲解

帧内模式中:

35中预测模式是在PU的基础上进行定义的,但是在具体的帧内预测过程中是以TU为单位的,标准规定PU可以四叉树的形式划分为TU,并且同一个PU内的TU共享一种预测模式

在实际的预测中,每一个TU自己预测自己的,自己参考自己周围的像素点

所以说:PU只是定义预测的方式,而真正的和预测像素和重构的过程都是通过TU进行处理的

下面是熵解码读出一些数据的记录线索:

pCu 代表的是一个CTU对应的结构体

uiAbsPartIdx 表示当前CU在CTU中的位置(以配置文档中最小TU为单位)

最后一个参数表示当前CU或者PU中有多少个TU

//<从CTU中递归进入CU的过程中记录深度信息

memset( pCu->pPuhDepth + uiAbsPartIdx, uiDepth+splitFlag, uiCurNumParts );

//<记录当前CU预测部分PU是N*N,or2N*2N,同时记录当前CU的width,height

memset(pCu->pPePartSize+uiAbsPartIdx,partSize,uiCurNumParts);

memset(pCu->pPuhWidth+uiAbsPartIdx,pSps->uiMaxCUWidth>>uiDepth,uiCurNumParts);

memset(pCu->pPuhHeight+uiAbsPartIdx,pSps->uiMaxCUHeight>>uiDepth,uiCurNumParts);

//<写入预测模式,帧内or帧间

memset(pCu->pPePredMode+uiAbsPartIdx,MODE_INTRA,uiCurNumParts);(目前都是写入帧内)

//<针对PU的模式写入亮度,色度预测部分的方向

memset(pCu->pPuhIntraDir[CHANNEL_TYPE_LUMA]+uiAbsPartIdx+i*partOffset,intraPredMode,uiCurNumParts);

i表示的是如果进行劈分,分四次写入

memset(pCu->pPuhIntraDir[CHANNEL_TYPE_CHROMA]+uiAbsPartIdx,symbol,uiCurNumParts);

//<从CU为根节点进入TU,递归获得最后的最小TU进行解残差系数的解码.帧内部分和PU相关的是:如果为帧内模式,同时PU劈分,那么TU需要劈分

//<在每一次递归过程中,CBF的值

memset(pCu->pPuhCbf[compID]+uiAbsPartIdx,uiCbf,pImg->numPartitionsInCtu>>(uiDepthAdj<<1));

//<TU递归到最小的时候,写入当前TU相对于CU的深度

memset(pCu->pPuhTrIdx + uiAbsPartIdx,uiTrDepth,uiCurNumParts);

//<每一个TU中残差系数

存储在:

pCoeff = pCu->pTrCoeff[compID]+pTu->offsets[compID];

Offsets表示的是通过递归获取的当前TU在CTU中的偏移位置

注意:每一次劈分到最小解码TU,并不代表当前TU就一定是配置信息中的最小TU,这是在编码端决定的 

得到对应的信息之后,进行解码CTU操作

首先是进入

m_pcCuDecoder->decompressCtu ( pCtu );  函数

之后进入递归过程,和读数据时候的过程是相同的,得到最小的CU之后进行解码:

<span style="font-size:18px;"> case MODE_INTRA:
      xReconIntraQT( m_ppcCU[uiDepth], uiDepth ); //<开始解帧内预测</span>

之后根据partSize 将CU划分为对应的PU

TComTURecurse <span style="color:#ff0000;"><strong>tuRecurseCU</strong></span>(pcCU, 0);
    TComTURecurse tuRecurseWithPU(tuRecurseCU, false, (uiInitTrDepth==0)?TComTU::DONT_SPLIT : TComTU::QUAD_SPLIT);

    do
    {
      xIntraRecQT( m_ppcYuvReco[uiDepth], m_ppcYuvReco[uiDepth], m_ppcYuvResi[uiDepth], chanType, tuRecurseWithPU );
    } while (tuRecurseWithPU.nextSection(tuRecurseCU));

因为虽然现在是PU获得预测模式,但是最后还是通过TU进行解码,所以这里还是用了TU的存储结构

while循环内就进入了PU开始解TU的过程

Void
TDecCu::<strong><span style="color:#ff0000;">xIntraRecQT</span></strong>(TComYuv*    pcRecoYuv,
                    TComYuv*    pcPredYuv,
                    TComYuv*    pcResiYuv,
                    const ChannelType chType,
                    TComTU     &rTu)
{
  UInt uiTrDepth    = rTu.GetTransformDepthRel();
  TComDataCU *pcCU  = rTu.getCU();
  UInt uiAbsPartIdx = rTu.GetAbsPartIdxTU();
  UInt uiTrMode     = pcCU->getTransformIdx( uiAbsPartIdx );
  if( uiTrMode == uiTrDepth )
  {
    if (isLuma(chType))
      xIntraRecBlk( pcRecoYuv, pcPredYuv, pcResiYuv, COMPONENT_Y,  rTu );
    else
    {
      const UInt numValidComp=getNumberValidComponents(rTu.GetChromaFormat());
      for(UInt compID=COMPONENT_Cb; compID<numValidComp; compID++)
      {
        xIntraRecBlk( pcRecoYuv, pcPredYuv, pcResiYuv, ComponentID(compID), rTu );
      }
    }
  }
  else
  {
    TComTURecurse tuRecurseChild(rTu, false);
    do
    {
      xIntraRecQT( pcRecoYuv, pcPredYuv, pcResiYuv, chType, tuRecurseChild );
    } while (tuRecurseChild.nextSection(rTu));
  }
}

从这个函数可以看出来,从PU进入TU之后还是进行一个和读参数对应的递归操作

从读数据和解数据的过程基本可以看出来了

CU,TU,PU可以说是相互独立的,因为他们各自负责一部分的模块

但是又有一定的联系,就帧内预测而言:

根节点都是CU,编码过程中是CU->PU,CU->TU,在帧内模式的情况下如果PU是2N*2N,那么CU->TU是一定会劈分一次

解码过程,先判断出帧内情况,所以根据PU先判断CU是否劈分了一次,之后再根据深度信息得到TU

对于帧间情况下,之后进行补充

时间: 2024-11-09 08:30:01

HEVC-I帧中CU,TU,PU之间的关系的相关文章

面向对象中多个对象之间的关系

http://www.cnblogs.com/wing011203/archive/2012/06/23/2559223.html 当谈到面向对象的设计时,我们经常说面向对象是符合人们对现实世界的思维模式,即人们采用针对非程序设计领域存在的复杂问题的解决方式,来解决软件设计过程中各种错综复杂的关系.利用面向对象设计,特别是采用各种设计模式来解决问题时,会设计多个类,然后创建多个对象,这些对象,有些主要是数据模型,有些则是行为描述占主体.一个设计良好的类,应该是兼顾信息和行为,并且是高内聚.而不同

ASP.NET-MVC中Entity和Model之间的关系

Entity 与 Model之间的关系图 ViewModel类是MVC中与浏览器交互的,Entity是后台与数据库交互的,这两者可以在MVC中的model类中转换 MVC基础框架 来自为知笔记(Wiz) 附件列表 ASP.Net MVC基础框架.png viewmodel.JPG

java中paint repaint update 之间的关系

最近总结了一下java中的paint,repaint和updata三者之间的关系,首先咱们都知道用paint方法来绘图,用repaint重绘,用update来写双缓冲.但是他们之间是怎么来调用的呢,咱们来分析一下(想直接看结果,请跳过分析过程): -----------------------------------------------------------------------------------------------------------------------------

PHP中array_map与array_column之间的关系分析

array_map()与array_column()用法如下: array_map();将回调函数作用到给定数组的单元上array_column();快速实现:将二维数组转为一维数组 array_column()函数格式为: array array_column ( array $input , mixed $column_key [, mixed $index_key ] ); 返回input数组中值为column_key的列; 如果指定了可选参数index_key,返回的数组中 对应键 为i

javascript中Object与Function之间的关系

首先看几个例子: Function instanceof Object //true Object instanceof Function // true 说明Object 是被Function 构造出来的 Function instanceof Function //true 说明自己被自己构造 Object.getPrototypeOf(Function) === Function.prototype // true Object.getPrototypeOf(Object.prototyp

exce中42093和日期之间的关系

在EXECEL中数字0 代表日期 1900-1-0 ,即这个日期为起始日期,算是第0天数字1 代表日期 1900-1-1 ,即第一天数字2 代表日期 1900-1-2 ,即第二天......数字41513 代表 2013-8-27 ,即第41513天 在时间中的规则是把1分成24份 =1/24 ,每一份就是1个小时,分成1440份 =1/(24*60) ,每一份就是1分钟,分成86400份 =1/(24*60*60) ,每一份就是1秒

PHP中 array_map 与 array_column 之间的关系

(PHP 5 >= 5.5.0) array_map()与array_column()用法如下: array_map();将回调函数作用到给定数组的单元上array_column();快速实现:将二维数组转为一维数组 array_column()函数格式为: array array_column ( array $input , mixed $column_key [, mixed $index_key ] ); 返回input数组中值为column_key的列; 如果指定了可选参数index_

浅谈JS中的构造函数、原型对象(prototype)、实例中的属性/方法之间的关系

原文链接:https://segmentfault.com/a/1190000016951069 构造函数:函数中的一种,通过关键字new可以创建其实例.为了便于区分,通常首字母大写:原型对象:一种特殊的对象,构造函数创建时自动生成:与构造函数形成一一对应,如同人和影子般的关系:实例:通过构造函数实例出来的对象: 在定义构造函数时,在其内部(“{“和”}”)进行定义属性和方法.当我们通过关键字new,对构造函数进行实例化的时候.实例会对构造函数的这些属性进行拷贝出一份副本,然后将其归属为当前实例

android中activity,window,view之间的关系

activity:控制单元 window:承载模型 view:显示视图 几个小tip: 1.一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个 2.每个window有一个 ViewRoot(是一个View或ViewGroup) 3.通过window的addview方法把元素添加到window上. 4.可以通过 LayoutInflater 的 inflater 方法,可以把一个布局文件转换成view对象 5.界面上的点击等操作是由 Window