



在实际的视频编码过程中,图像的宽度和高度可能不是128或64的整数倍,这会导致图像的右侧和底部的超级块可能会超出图像的实际边界。为了解决这个问题,当超级块的任何部分超出图像的底部或右侧边界时,这些超级块被强制进行划分,直到所有的编码像素块完全包含在图像的边界之内。在图3-2的示例中,由于该图片的分辨率是832×480,因此,当超级块大小是128×128时,右侧和底部的超级块都超出了图像边界;而当超级块大小是64×64时,仅底部超级块超出了图像边界。
对于这些超出图像边界的超级块,AV1标准会使用四叉树划分模式PARTITION_SPLIT,或者长宽比为1:2的水平划分模式PARTITION_HORZ,或者长宽比是2:1的垂直划分模式PARTITION_VERT,强制对这些超级块进行划分。在超级块强制划分过程中,如果生成的四叉树节点仍存在一部分区域位于图像边界之外,那么该四叉树节点将继续被强制划分,直到每个编码块的所有像素都位于图像边界内部。AV1使用语法元素split_or_horz和split_or_vert表示每个四叉树节点的划分模式。具体来讲:
❍如果当前四叉树节点的左上角四叉树子节点超出了图像的底部边界,那么AV1使用语法元素split_or_horz表示其划分模式。此时,split_or_horz等于0表示使用划分模式PARTITION_HORZ划分当前节点;否则,表示使用划分模式PARTITION_SPLIT划分当前节点。
❍如果当前四叉树节点的左上角四叉树子节点超出了图像的右侧边界,那么AV1使用语法元素split_or_vert表示其划分模式。split_or_vert等于0表示使用PARTITION_VERT划分当前节点;否则,使用PARTITION_SPLIT划分当前节点。
❍如果当前四叉树节点的左上角四叉树子节点既超出了图像的右侧边界,又超出了图像的底部边界,那么AV1使用划分模式PARTITION_SPLIT对该四叉树节点进行划分。此时,不需要编码任何语法元素。
假设变量r和c分别表示当前四叉树节点的行坐标和列坐标,r和c均以4亮度像素为基本单位;变量bSize表示四叉树节点的大小;函数parse(symbol)是解析语法元素symbol的函数。那么AV1标准文档定义的编码块划分流程decode_partition如下所示:
根据AV1标准文档定义的编码块划分流程decode_partition,如果当前四叉树节点仅仅超出了图像的底部边界但是没有超出图像的右侧边界,那么当前节点的split_or_vert似乎在任何条件下都能被赋值为PARTITION_VERT,而与当前节点所在图像内部区域的大小无关。但是,根据笔者观察,只有当四叉树节点所在图片内部区域正好可以通过划分模式PARTITION_VERT产生时,该节点的split_or_vert才能被赋值为PARTITION_VERT;否则,该节点不能被正确解码。同理,对于超出图像的右侧边界但是没有超出图像底部边界的超级块,只有当四叉树节点所在图片内部区域正好可以通过划分模式PARTITION_HORZ产生时,其split_or_horz才能被赋值为PARTITION_HORZ。图3-7为图像边界处的超级块划分示意图。
在图3-7中,图片分辨率是832×480,超级块的尺寸是128×128。对于图3-7中的超级块A/B/C/D中的节点1/2/3/4,按照编码块划分函数decode_partition()的执行流程,对应的语法元素取值可描述如下:
图3-7 图像边界处的超级块划分示意图
❍对于图像底部边界处的超级块A,其所在图片内部区域的大小是128×96。此时,变量hasRows和hasCols均为true,所以,编码器将使用语法元素partition来表示超级块A的划分状态。在这种情况下,超级块A的语法元素partition只能等于PARTITION_SPLIT。这是因为,如果语法元素partition等于其他值,如PARTITION_HORZ,超级块A的下方编码块所在图片内部区域的大小是128×32,而AV1解码器无法编码这种尺寸的编码块。当使用partition=PARTITION_SPLIT方式分割超级块A之后,对于新生成的左下角四叉树节点N,变量hasCols均为true,而变量hasRows为false,所以,编码器使用语法元素split_or_horz表示它的划分状态。由于其所在图片内部区域的大小是64×32,该区域可以通过PARTITION_HORZ来生成。因此,节点N的split_or_horz可以被设置为PARTITION_HORZ,也可以被设置为PARTITION_SPLIT。在这个示例中,编码器把节点N的split_or_horz设置为PARTITION_HORZ,生成了编码块1。编码块1完全包含在图片内部并且不再进行划分。
❍对于既超出图像底部边界又超出右侧边界的超级块B,其所在图片内部区域的大小是64×96。此时,变量hasCols均为false,而变量hasRows为true。所以,编码器使用语法元素split_or_vert表示超级块B的划分状态。由于B所在图片内部区域的大小是64×96,这个尺寸的区域无法通过划分模式PARTITION_VERT得到,所以,超级块B的语法元素split_or_vert只能等于PARTITION_SPLIT。对于新生成的左下角四叉树节点M,变量hasCols均为true,而变量hasRows为false,所以,编码器使用语法元素split_or_horz表示它的划分状态。在这个示例中,节点M的split_or_horz被设置为PARTITION_SPLIT,进而得到节点2。由于节点2完全包含在图片内部,所以节点2将按照正常节点继续编码,即使用语法元素partition来表示其划分模式。
❍对于图像右侧边界处的超级块C,其所在图片内部区域的大小是64×128。此时,变量hasCols均为false,而变量hasRows为true。所以,编码器使用语法元素split_or_vert表示超级块C的划分状态。由于超级块C所在图片内部区域正好可以通过划分模式PARTITION_VERT得到,所以,超级块C的split_or_vert可以被设置为PARTITION_VERT,也可以被设置为PARTITION_SPLIT。在这个示例中,超级块C的split_or_vert被设置为PARTITION_VERT,得到了编码块3。编码块3完全包含在图片内部,并且不再进行划分。
❍对于图像右侧边界处的超级块D,其所在图片内部区域的大小也是64×128。与超级块C类似,变量hasCols均为false,而变量hasRows为true。所以,编码器使用语法元素split_or_vert表示超级块D的划分状态。在这个示例中,超级块D的split_or_vert被设置为PARTITION_SPLIT,从而得到节点4。由于节点4完全包含在图片内部,所以节点4将按照正常节点继续编码,即使用语法元素partition来表示其划分模式。