3.2 Superblock解码
作者:chai51
出处:https://www.cnblogs.com/chai51
版权:本文版权归作者和博客园共有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
引言
Superblock(超级块)是AV1解码的基本处理单元,每个Superblock可以独立解码,是Tile解码的核心。Superblock解码包括上下文初始化、参数读取和块划分解码等步骤,为后续的块级解码奠定基础。
源码说明: 本文档基于作者自己编写的AV1解码器Python实现,所有代码示例和实现细节均来自实际可运行的源码。源码仓库:GitHub - av1_learning
Superblock概述
Superblock的基本概念
Superblock是AV1的基本编码单元,具有以下特点:
- 尺寸:可以是64x64或128x128像素(由序列头中的
use_128x128_superblock决定) - 独立性:每个Superblock可以独立解码
- 边界对齐:Superblock边界必须对齐到4x4块边界
- 递归划分:Superblock可以递归划分为更小的块
Superblock与Tile的关系
- Tile:由多个Superblock组成的矩形区域
- Superblock:Tile内的基本处理单元
- Tile边界必须对齐到Superblock边界,确保解码的独立性
Superblock尺寸计算
Superblock的尺寸由序列头中的use_128x128_superblock标志决定:
use_128x128_superblock = seq_header.use_128x128_superblock
sbSize = SUB_SIZE.BLOCK_128X128 if use_128x128_superblock else SUB_SIZE.BLOCK_64X64
sbSize4 = Num_4x4_Blocks_Wide[sbSize] # 转换为4x4块单位
- 如果
use_128x128_superblock == 1:Superblock为128x128像素(32x32个4x4块) - 如果
use_128x128_superblock == 0:Superblock为64x64像素(16x16个4x4块)
Superblock解码流程
位置: src/tile/tile_group.py - __decode_tile()
规范文档: 5.11.2 Decode tile syntax
主要步骤
Superblock解码在Tile解码过程中进行,主要流程如下:
def __decode_tile(self, av1: AV1Decoder):
"""
规范文档 5.11.2 Decode tile syntax
"""
seq_header = av1.seq_header
frame_header = av1.frame_header
tile_group = self.tile_group
MiRows = frame_header.MiRows
MiCols = frame_header.MiCols
use_128x128_superblock = seq_header.use_128x128_superblock
NumPlanes = seq_header.color_config.NumPlanes
# 1. 初始化上下文和参数
clear_above_context(av1)
tile_group.DeltaLF = [0] * FRAME_LF_COUNT
for plane in range(NumPlanes):
for pass_val in range(2):
tile_group.RefSgrXqd[plane][pass_val] = Sgrproj_Xqd_Mid[pass_val]
for i in range(WIENER_COEFFS):
tile_group.RefLrWiener[plane][pass_val][i] = Wiener_Taps_Mid[i]
# 2. 计算Superblock尺寸
sbSize = SUB_SIZE.BLOCK_128X128 if use_128x128_superblock else SUB_SIZE.BLOCK_64X64
sbSize4 = Num_4x4_Blocks_Wide[sbSize]
# 3. 初始化CDEF索引数组
tile_group.cdef_idx = Array(
tile_group.cdef_idx, (MiRows + 32, MiCols + 32))
# 4. 遍历每个Superblock
for r in range(tile_group.MiRowStart, tile_group.MiRowEnd, sbSize4):
clear_left_context(av1) # 清除左侧上下文
for c in range(tile_group.MiColStart, tile_group.MiColEnd, sbSize4):
tile_group.ReadDeltas = frame_header.delta_q_present
# 5. Superblock级别的处理
self.__clear_cdef(av1, r, c) # 清除CDEF上下文
self.__clear_block_decoded_flags(av1, r, c, sbSize4) # 清除块解码标志
self.__read_lr(av1, r, c, sbSize) # 读取Loop Restoration参数
self.__decode_partition(av1, r, c, sbSize) # 解码块划分
Superblock解码流程图
详细技术文档参考
说明: 以下内容来自详细技术文档,包含完整的实现细节和代码说明。这些内容主要用于技术参考。
点击展开查看详细技术文档
1. 上下文初始化
在开始解码Superblock之前,需要初始化各种上下文和参数:
清除上方上下文
位置: src/tile/tile_group.py - clear_above_context()
规范文档: 6.10.2 clear_above_context()
clear_above_context(av1)
清除上方块的上下文信息,为新的Tile行做准备。
初始化Loop Restoration参数
tile_group.DeltaLF = [0] * FRAME_LF_COUNT
for plane in range(NumPlanes):
for pass_val in range(2):
tile_group.RefSgrXqd[plane][pass_val] = Sgrproj_Xqd_Mid[pass_val]
for i in range(WIENER_COEFFS):
tile_group.RefLrWiener[plane][pass_val][i] = Wiener_Taps_Mid[i]
初始化Loop Restoration的参考参数,包括SGR投影参数和Wiener滤波参数。
2. 清除CDEF上下文
位置: src/tile/tile_group.py - __clear_cdef()
规范文档: 5.11.55 Clear CDEF function
def __clear_cdef(self, av1: AV1Decoder, r: int, c: int):
"""
清除CDEF上下文
规范文档 5.11.55 Clear CDEF function
"""
seq_header = av1.seq_header
frame_header = av1.frame_header
tile_group = self.tile_group
use_128x128_superblock = seq_header.use_128x128_superblock
tile_group.cdef_idx[r][c] = -1
if use_128x128_superblock:
cdefSize4 = Num_4x4_Blocks_Wide[SUB_SIZE.BLOCK_64X64]
tile_group.cdef_idx[r][c + cdefSize4] = -1
tile_group.cdef_idx[r + cdefSize4][c] = -1
tile_group.cdef_idx[r + cdefSize4][c + cdefSize4] = -1
清除CDEF(Constrained Directional Enhancement Filter)索引,为后续的CDEF参数解码做准备。
- 对于64x64 Superblock:清除1个CDEF索引
- 对于128x128 Superblock:清除4个CDEF索引(每个64x64块一个)
3. 清除块解码标志
位置: src/tile/tile_group.py - __clear_block_decoded_flags()
规范文档: 5.11.3 Clear block decoded flags function
def __clear_block_decoded_flags(self, av1: AV1Decoder, r: int, c: int, sbSize4: int):
"""
清除块解码标志
规范文档 5.11.3 Clear block decoded flags function
"""
seq_header = av1.seq_header
tile_group = self.tile_group
subsampling_x = seq_header.color_config.subsampling_x
subsampling_y = seq_header.color_config.subsampling_y
NumPlanes = seq_header.color_config.NumPlanes
for plane in range(NumPlanes):
subX = subsampling_x if plane > 0 else 0
subY = subsampling_y if plane > 0 else 0
sbWidth4 = (tile_group.MiColEnd - c) >> subX
sbHeight4 = (tile_group.MiRowEnd - r) >> subY
for y in range(-1, (sbSize4 >> subY) + 1):
for x in range(-1, (sbSize4 >> subX) + 1):
if y < 0 and x < sbWidth4:
tile_group.BlockDecoded[plane][y][x] = 1 # 上方参考像素已解码
elif x < 0 and y < sbHeight4:
tile_group.BlockDecoded[plane][y][x] = 1 # 左侧参考像素已解码
else:
tile_group.BlockDecoded[plane][y][x] = 0 # 当前块未解码
tile_group.BlockDecoded[plane][sbSize4 >> subY][-1] = 0
清除块解码标志,标记哪些块已经解码(用于参考),哪些块尚未解码。
- 上方参考像素:标记为已解码(
BlockDecoded = 1) - 左侧参考像素:标记为已解码(
BlockDecoded = 1) - 当前Superblock内的块:标记为未解码(
BlockDecoded = 0)
4. 读取Loop Restoration参数
位置: src/tile/tile_group.py - __read_lr()
规范文档: 5.11.57 Read loop restoration syntax
def __read_lr(self, av1: AV1Decoder, r: int, c: int, sbSize: int):
"""
读取Loop Restoration参数
规范文档 5.11.57 Read loop restoration syntax
"""
seq_header = av1.seq_header
frame_header = av1.frame_header
subsampling_x = seq_header.color_config.subsampling_x
subsampling_y = seq_header.color_config.subsampling_y
NumPlanes = seq_header.color_config.NumPlanes
if frame_header.allow_intrabc:
return
w = Num_4x4_Blocks_Wide[sbSize]
h = Num_4x4_Blocks_High[sbSize]
for plane in range(NumPlanes):
if frame_header.FrameRestorationType[plane] != FRAME_RESTORATION_TYPE.RESTORE_NONE:
# 计算Loop Restoration单元的范围
# ... 计算unitRowStart, unitRowEnd, unitColStart, unitColEnd ...
for unitRow in range(unitRowStart, unitRowEnd):
for unitCol in range(unitColStart, unitColEnd):
self.__read_lr_unit(av1, plane, unitRow, unitCol)
读取Loop Restoration(环路恢复)参数,用于后续的后处理阶段。
- 如果启用了Loop Restoration,需要读取每个恢复单元的参数
- 参数包括Wiener滤波系数或SGR投影参数
5. 解码块划分
位置: src/tile/tile_group.py - __decode_partition()
规范文档: 5.11.4 Decode partition syntax
这是Superblock解码的核心步骤,递归解码块的划分方式。
def __decode_partition(self, av1: AV1Decoder, r: int, c: int, bSize: SUB_SIZE):
"""
解码划分
规范文档 5.11.4 Decode partition syntax
"""
frame_header = av1.frame_header
tile_group = self.tile_group
MiRows = frame_header.MiRows
MiCols = frame_header.MiCols
if r >= MiRows or c >= MiCols:
return 0
# 检查上方和左侧块是否可用
tile_group.AvailU = is_inside(av1, r - 1, c)
tile_group.AvailL = is_inside(av1, r, c - 1)
# 计算块尺寸和边界检查
num4x4 = Num_4x4_Blocks_Wide[bSize]
halfBlock4x4 = num4x4 >> 1
quarterBlock4x4 = halfBlock4x4 >> 1
hasRows = (r + halfBlock4x4) < MiRows
hasCols = (c + halfBlock4x4) < MiCols
# 解码划分模式
if bSize < SUB_SIZE.BLOCK_8X8:
tile_group.partition = PARTITION.PARTITION_NONE
elif hasRows and hasCols:
tile_group.partition = read_S(av1, "partition", r=r, c=c, bSize=bSize)
elif hasCols:
split_or_horz = read_S(av1, "split_or_horz", r=r, c=c, bSize=bSize)
tile_group.partition = PARTITION.PARTITION_SPLIT if split_or_horz else PARTITION.PARTITION_HORZ
elif hasRows:
split_or_vert = read_S(av1, "split_or_vert", r=r, c=c, bSize=bSize)
tile_group.partition = PARTITION.PARTITION_SPLIT if split_or_vert else PARTITION.PARTITION_VERT
else:
tile_group.partition = PARTITION.PARTITION_SPLIT
# 根据划分模式递归解码子块
subSize: SUB_SIZE = Partition_Subsize[tile_group.partition][bSize]
if tile_group.partition == PARTITION.PARTITION_NONE:
self.__decode_block(av1, r, c, subSize)
elif tile_group.partition == PARTITION.PARTITION_SPLIT:
# 递归解码4个子块
self.__decode_partition(av1, r, c, subSize)
self.__decode_partition(av1, r, c + halfBlock4x4, subSize)
self.__decode_partition(av1, r + halfBlock4x4, c, subSize)
self.__decode_partition(av1, r + halfBlock4x4, c + halfBlock4x4, subSize)
# ... 其他划分模式 ...
块划分解码是递归过程,根据划分模式将Superblock划分为更小的块,直到达到最小块尺寸或PARTITION_NONE。
Superblock遍历顺序
Superblock按照光栅扫描顺序遍历:
for r in range(tile_group.MiRowStart, tile_group.MiRowEnd, sbSize4):
clear_left_context(av1) # 每行开始时清除左侧上下文
for c in range(tile_group.MiColStart, tile_group.MiColEnd, sbSize4):
# 处理Superblock (r, c)
- 行优先:从上到下逐行处理
- 列优先:每行内从左到右处理
- 上下文管理:每行开始时清除左侧上下文,确保行间独立性
关键数据结构
Superblock相关参数
# Superblock尺寸
sbSize: SUB_SIZE # Superblock尺寸(BLOCK_64X64或BLOCK_128X128)
sbSize4: int # Superblock尺寸(4x4块单位)
# Superblock位置
r: int # Superblock行位置(MI单位)
c: int # Superblock列位置(MI单位)
# CDEF索引
cdef_idx: List[List[int]] # CDEF索引数组,用于存储CDEF参数索引
块解码标志
BlockDecoded: List[List[List[int]]] # BlockDecoded[plane][row][col]
# -1 <= row <= 32, -1 <= col <= 32
# 0: 未解码
# 1: 已解码(可用作参考)
与Tile解码的集成
Superblock解码是Tile解码的核心部分:
Tile解码(__decode_tile)
→ 初始化上下文和参数
→ 遍历Superblock
→ 清除左侧上下文(每行)
→ 对每个Superblock:
→ 清除CDEF上下文
→ 清除块解码标志
→ 读取Loop Restoration参数
→ 解码块划分(递归)
→ 解码块模式信息
→ 解码预测
→ 解码残差
→ 重建块
总结
Superblock解码是AV1解码的基础,主要工作包括:
- 上下文管理:清除和初始化各种上下文信息
- 参数读取:读取CDEF和Loop Restoration参数
- 块划分:递归解码块的划分方式
- 独立性保证:确保每个Superblock可以独立解码
Superblock解码为后续的块级解码(模式信息、预测、残差)奠定了基础,是AV1高效解码的关键环节。
参考资源:
- AV1规范文档
- 源码实现: GitHub - av1_learning
- Tile解码:
src/tile/tile_group.py - 上下文管理:
src/tile/tile_group.py-clear_above_context(),clear_left_context()
- Tile解码:
上一篇: Tile划分和并行处理
下一篇: 块划分(Block Partitioning)

浙公网安备 33010602011771号