一、基本结构
VTM的数据模型图如下所示:
数据结构分三种类型:
1. 导航信息
- Size、Position、Area(Position+Size):基本二维信息(位置、尺寸)
- CompArea:继承自Area,表示特定分量的二维信息
- UnitArea:包含了多个分量的Area,表示多个分量的二维信息,描述同一位置处的一组块
参考:
- Size
- width,height:UInt-描述了一个矩形的大小
- Position
- x,y:Int-描述了一个点的二维位置信息
- Area:Size,Position
- 继承自Size和Position,一个位于特定位置的特定大小的矩形
- CompArea:Area
- 一个多分量信号中的特定分量的(compID)Area
- UnitArea
- blocks[0…N-1]:CompArea
- N个多分量信号blocks的融合
2. 存储区域
- AreaBuf:包含了一个二维信号在内存中的存储(buf 和 Stride),可以根据位置访问到相应的信号值,包含内存的操作方法(fill、copy等)
- UnitBuf:包含了多个分量的二维信号在内存中到的存储,包含内存的操作方法(fill、copy等)
- PelStorage:一个UnitBuf(Pel类型),需要分配自己的内存空间
参考:
- AreaBuf< T >(为Pel和TCoeff定义为PelAreaBuf和CoeffAreaBuf)
- at(x, y):返回信号在(x, y)处的值
- bufAt(x, y):返回一个指向(x, y)位置的缓冲区的未加工(raw)的指针
- subBuf(x, y, w, h):返回一个AreaBuf,描述距离(x, y)的偏移量为(w, h)的位置的缓冲区
- fill(val):使用特定的值填充特定的区域
- copyFrom(other):从别的区域将内容复制过来
- substract,addVag, reconstruct,removeHighFreq:取代TComYuv功能的方法
- UnitBuf< T >,与AreaBuf有相似的接口
- bufs[0…N-1]:AreaBuf:包含了信号不同分量的描述信息
3. 编码信息
- Picture:包含了输入输出信号作为元数据(slice info等等),还包括了许多帧级信息(poc、temporalId等)
- CodingUnit, PredictionUnit, TransformUnit:包含相应的信息(模式信息、位置信息(继承自UnitArea))
- CodingStructure:管理CU、PU和TU等,通过Picture链接他们;包含自上向下进行RD搜索的方法
参考;
- CoingUnit:UnitArea
- 描述如何编码被UnitArea所描述的这个区域
- PredictionUnit:UnitArea
- 描述此UnitArea的预测信号是怎样生成的
- TransformUnit:UnitArea
- 描述此UnitArea的变换编码是如何应用的
coding structure basics:
- area:UnitArea类型,描述了CodingStructure包括了图像的哪些区域
- addCU(UnitArea):创建并定位跨越了UnitArea的CodingUnit
- getCU(position):返回位于指定位置的CodingUnit(TransformUnit和PredictionUnit存在模拟接口)
- setDecomp(CompArea):将指定的CompArea设置为已重建
- setDecomp(UnitArea):模拟多通道的操作
- isDecomp(Position):返回这个位置的重建信号是否已被生成
RD-Search with CodingStructure
- initStructData(…):清除当前包含的所有数据(信号和编码信息)
- initSubStructure(…):在层次结构的底部链接一个新的编码结构
- useSubStructure(…):从子结构中复制编码数据
- copyStructure(…):从其他结构中复制编码信息,并不受到父子之间的约束关系
二、具体细节
1. Coding Structure
CondingStrcture包含了CodingUnit等等一系列的对象, 并可以将他们映射到Picture上面。
CondingStrcture并不局限于CTU,全局动态分配。CS区域大到可以覆盖整个帧,小到一个CU
- 上层的的CoddingStructure包括了在当前帧的所有CU、PU、TU
- 下层的CodingStructure则是包含了一个特定的UnitArea表示。
CondingStrcture在创建之后内容为空,需要被填满。
- 使用addCU/PU/TU方法创建映射到特定的对象
- getCU/PU/TU方法可以获取到使用全局位置寻址的特定对象
使用dynamic_cache动态地分配需要的资源以提高性能。
使用CodingStructure进行RD-Search
- 允许使用全局上下文transparent的局部编码
- 遵循经典的best-temp向上传播方案
- CodingStructure以表示一个局部UnitArea而建立,访问UnitArea之外的信息需要返回上层CodingStructure
- 父节点不知道子节点,但是最好的子节点将传递给父节点
实例:
如下图所示,cs1是位于上层的coding structure,cs2是下层的coding structure
通过cs2访问位于(32,32)的CU,直接返回cu2
通过cs2访问位于(16,32)位置的CU,通过其父节点cs1,访问返回cu1;
通过cs1访问位于(32,32)位置的CU,cu2属于cs1的子cs,父节点不能知道子节点,返回null。
2. Partitioner
- Partitioner是一个管理划分的类(CU、TU,QT和所有可能的划分)。
- VTM将区域划分模型建模为栈,即新的划分将在当前已处理区域上创建下一级别的划分。
- 包含对当前划分信息的访问方法,划分信息包括实际划分区域的UnitArea和CU/TU深度信息。
- 包含设置划分限制的方法,即在特定CU深度级(区域尺寸)上的划分限制。
- 包含对划分的合理性检查(cansplit)
3. Data Ownership
每一个数据都属于某一个对象,并需要分配内存以及释放
- Picture
- 归属于EncLib或DecLib
- 拥有信号的缓冲区,Slice对象,SEI消息和TileMap
- AreaBuf, UnitBuf
- 不保存任何数据
- PelStorage
- 可能拥有某些缓冲区,取决于创建时调用的是create还是createFromBuf
- 数据保存在m_origin成员中
- CodingStructure
- Top-Layer:属于Picture
- 链接至图像的信号缓冲区,但是并不拥有这些缓冲区
- Other(暂时存在于RD-Search):属于EncCu或IntraSearch
- 包含一些信号的缓冲区,并拥有他们
- 总是拥有描述结构和布局的缓冲区(非信号)
- 拥有变换系数缓冲区
- 不拥有CodingUnit,仅仅是通过dynamic_cache链接到他们
- Top-Layer:属于Picture
- CodingUnit,PredictionUnit,TransformUnit
- 属于dynamic_cache,其中对象是通过get获取,通过cache来释放
- TransformUnit
- 不拥有变换系数缓冲区
- 从CodingStructure链接到缓冲区
- dynamic_cache
- Top-Level的缓冲区是全局的(在运行时动态分配。并在退出的时候释放)
- RD-Search的缓冲区是属于EncCu和IntraSearch
4. 代码片段
迭代CU中的所有TU(traverseTUs),所有PU(traversePUs)
// call xDecodeInterTU for all TUs in the CU described by cu
for( auto& currTU : CU::traverseTUs( cu ) )
{
xDecodeInterTU( currTU, compID );
}
迭代特定区域中的所有CUs
// iterate over all CUs which are contained in the area described by ctuArea
for( auto &currCU : cs.traverseCUs( ctuArea ) )
{
// decompress CU
xDecompress( currCU );
}
5. 常见问题
- 最初使用HEVC,运动矢量存储的最小分辨率是PU
- 针对h.266标准最新提出的工具打破了这一常规(VCEG-AZ10)
- 对于运动矢量信息来说Sub-Pu的分辨率将被需要
- 将sub-PUs存储为PUs将会破坏提出PU的逻辑
- 解决方案:用于子PU解析的运动信息的附加缓冲器
例子:
Mv mvL0 = cs.getPU( pos )->mv[0]; // obsolete low-res call
Mv mvL0 = cs.getMotionInfo( pos ).mv[0]; // new next-style high-res call
- 旧的调用还在允许,可能会提供子分辨的结果
- PU::spanMotionInfo方法用于设置这个缓冲区