



AV1比特流是由一系列名为开放比特流单元(OBU)的数据单元组成。每个OBU由一个可变长度的字节串(Byte String)组成。具体来讲,OBU包含一个头部信息(Header)和一个有效载荷(Payload)。头部信息用于识别OBU类型并指定有效载荷的大小。OBU头部信息包含obu_forbidden_bit、obu_type、obu_extension_flag、obu_has_size_field和obu_reserved_1bit。其中obu_forbidden_bit占用1比特,其值必须设置为0;obu_type占用4比特,所以obu_type共有16种取值;obu_extension_flag、obu_has_size_field和obu_reserved_1bit各占用1比特。图2-2所示为AV1中OBU的组成结构。
图2-2 AV1中OBU的组成结构
在图2-2中,0表示obu_forbidden_bit;e、s和r分别表示obu_extension_flag、obu_has_size_field和obu_reserved_1bit;temp_id表示语法元素temporal_id,占用3比特;s_id表示语法元素spatial_id,占用2比特;reserved表示语法元素extension_header_reserved_3bits,占用3比特;obu_size表示以字节为单位指定OBU的大小,但是不包括obu_header中的字节或obu_size语法元素中的字节,它是可选的,即OBU不需要必须包含obu_size;trail、bits包括语法元素trailing_one_bit和trailing_zero_bit。
OBU头部信息中的obu_type指定OBU有效载荷中包含的数据结构类型。表2-1所示为obu_type的取值以及其代表的含义。其中,“保留值”是为将来使用而保留的,AV1解码器应该忽略它们。
表2-1 obu_type的取值以及其代表的含义
根据obu_type的取值,OBU可以分为序列头部OBU(OBU_SEQUENCE_HEADER)、帧头部OBU(OBU_FRAME_HEADER)、元数据信息OBU(OBU_METADATA)、时间分隔符OBU(OBU_TEMPORAL_DELIMITER)和切片组OBU(OBU_TILE_GROUP)。
OBU头部信息中的obu_extension_flag用于指明可选的OBU扩展头信息(OBU Extension Header)是否存在。当obu_extension_flag等于1时,表示存在OBU扩展头信息。此时,解码器将从OBU扩展头信息读取当前OBU的时域索引temporal_id和空域索引spatial_id。OBU的temporal_id指定了OBU所包含数据的时域层(Temporal Level)。OBU的spatial_id则指定了OBU所包含数据的空域层(Spatial Level)。如果当前OBU的temporal_id或spatial_id不存在,那么解码器将把其temporal_id或spatial_id设置为0。如果使用了扩展性编码(Scalable Coding),则temporal_id和spatial_id都等于0的切片组OBU称为基础层(Base Layer),而spatial_id大于0或者temporal_id大于0的切片组OBU称为增强层(Enhancement Layer)。如果一个编码视频序列包含至少一个增强层,那么所有与基础层和增强层数据相关的帧头OBU和切片组OBU都必须包括OBU扩展头信息。也就是说,当编码视频序列包含增强层时,需要用OBU扩展头信息来指明OBU的spatial_id和temporal_id。这是因为AV1利用压缩视频数据的spatial_id和temporal_id来决定它们之间的参考关系。假设有2个压缩视频数据A和B,其中A的temporal_id和spatial_id分别是 T 和 S ,B的temporal_id和spatial_id分别是 T′ 和 S′ ,那么,只有当 T ≥ T′ 并且 S ≥ S′ 时,A才能够参考B。
在AV1中,要解码的空域层或时域层称为操作点(Operating Point,OP)。所有的操作点组成了编码视频序列(Coded Video Sequence)。如果没有使用扩展性编码,则可以视为整个编码视频序列只包含一个操作点。
序列头部OBU的内容是序列头信息(Sequence Header)。类似于HEVC中的序列级参数集(Sequence Parameter Set,SPS),序列头信息包含适用于整个编码序列的参数信息。这些参数在编码视频序列中的每个图像之间不会发生改变。序列头信息中的一些参数提供了编码序列的关键描述,这对于系统接口非常有用,其他参数则描述了编码工具的使用状态,或者提供了编码工具参数,这可以提高编码效率。除此之外,序列头信息还可以选择性地包含视频可用性信息数据。这些信息虽然不会直接影响解码过程,但提供了两类有价值的数据。第一类与解码图片的显示有关,比如色度配置(Color Config Syntax)等信息。第二类包括假设参考解码器(Hypothetical Reference Decoder,HRD)使用的时间信息(Timing Info Syntax)、解码模型信息(Decoder Model Info Syntax)以及解码操作参数信息(Operating Parameters Info Syntax)。比如:
❍语法元素still_picture用于指示编码视频序列是否仅由单一编码帧组成。
●当still_picture设置为1时,意味着整个编码视频序列仅由单一的编码帧组成,这通常用于静态图像或类似于图片的场景。
●当still_picture设置为0时,表示编码视频序列由一系列视频帧组成。
❍语法元素operating_points_cnt_minus_1用于指示编码视频序列包含多少个操作点,它的数值等于操作点的总数减去1。所以,实际的操作点数量需要在该值的基础上加1来得到。例如,如果operating_points_cnt_minus_1的值为3,那么视频序列中就有4个操作点。
❍语法元素operating_point_idc[i]包含一个位掩码(Bit Mask),用于指示操作点i应该解码哪些空域层和时域层。在这个位掩码中,低8位(索引为0~7)表示时域层,高4位(索引为8~11)表示空域层。每一位的值(0或1)决定了对应的层是否应该被解码器处理。具体来讲,如果要解码时域层 k ,则把第 k 位设置为1,其中 k 的范围是0~7。如果要解码空域层 j ,则把第 j +8位设置为1,其中 j 的范围是0~3。
描述编码序列特性的关键参数也包含在序列头信息中。语法元素seq_profile和seq_level_idx指明编码视频所使用的档次和级别。档次和级别指定了解码比特流所需的能力限制。档次指定了支持的视频位宽和色度下采样格式,而级别定义了分辨率和性能特征,比如对最大采样率、图片大小和解码图片缓冲区等能力施加限制。
在序列头信息中,可以设置各种编码工具的启用或禁用选项,以及对这些工具的限制。例如,如果将序列头中的use_128x128_superblock参数设置为0,那么编码器就不会使用128×128像素的超级块进行编码。同样,如果将enable_warped_motion参数设置为0,那么在帧间预测时就不会使用畸变运动补偿技术。这样做的结果是,编码器无须传输与畸变运动补偿相关的语法元素,从而简化了编码过程。
帧头OBU的内容是帧头(Frame Header)信息。类似于HEVC中的帧级参数集(Picture Parameter Set,PPS),帧头信息包含的参数可能在同一编码视频序列中的不同图片之间发生变化。下面介绍几个常用的帧头信息的语法元素。
帧头信息中的语法元素show_frame在AV1中用于控制解码后的视频帧是否立即显示。当show_frame的值设置为1时,表示一旦该视频帧完成解码,它就应该立即显示;相反,如果show_frame的值设置为0,则意味着该帧在解码后不会立即显示。此外,如果后续接收到的帧头信息中包含语法元素show_existing_frame,并且其值被设置为1,那么之前那些解码完成但show_frame为0的帧就可能被展示。在视频编码的特定应用场景中,这些语法元素用于控制解码视频帧的输出顺序。比如,在带有B帧(双向预测帧)的编码配置(图2-1所示编码结构)下,编码顺序等于1的视频帧在解码后不会立即展示,而是通过后续的指令才会被展示。所以,正如Andrey Norkin在其技术博客中所描述的,根据帧头信息中的语法元素show_existing_frame的取值,AV1的帧头信息可以分为两种类型:show_existing_frame等于0的帧头表示当前帧是需要正常解码的常规帧;show_existing_frame等于1的帧头指定了一个操作命令,该操作命令用于在该帧头指定的显示时间显示一个之前已经解码过的帧,这个待显示的帧由语法元素frame_to_show_map_idx指明。图2-3所示为显示帧与语法元素frame_to_show_map_idx之间的关系,其中FrameHdr2是一个帧头信息,该帧头信息中的语法元素show_existing_frame等于1,并且语法元素frame_to_show_map_idx指向之前已经解码过的显示顺序为2的帧。因此,一个显示帧(Shown Frame)可以是show_frame等于1的帧,也可以是show_existing_frame等于1的帧。基于show_frame和show_existing_frame的视频帧显示机制,AV1解码器在解码顺序与输出顺序不同时,可以进行帧重排序,以使解码视频帧按照输出顺序显示。
帧头信息中的语法元素frame_type用于指明视频图片的帧类型。AV1定义了4种帧类型:KEY_FRAME、INTER_FRAME、INTRA_ONLY_FRAME和SWITCH_FRAME。表2-2所示为frame_type的取值及帧类型。
表2-2 frame_type的取值及帧类型
语法元素refresh_frame_flags用于指明DPB的更新机制。具体来讲,当一个视频帧编码结束后,编码器根据该帧头信息中refresh_frame_flags的取值来决定把当前视频帧放入DPB中的哪个位置。当帧头信息中的frame_type=KEY_FRAME并且show_frame=1时,refresh_frame_flags被设置为0xFF,这个关键帧将占据DPB中的所有位置。从这个角度来看,AV1中的KEY_FRAME类似于HEVC中的IDR帧,因为它们都会重新设置DPB状态。
下面再总结一下不同帧类型之间的区别。如果当前帧的语法元素frame_type=KEY_FRAME,则当前帧通常被称为关键帧。关键帧中的所有编码块只能使用帧内预测模式,并且当关键帧的语法元素show_frame=1时,关键帧将会重新设置DPB状态。所以,当关键帧的语法元素show_frame=1时,任何编码顺序位于此关键帧之后的视频帧都不能把编码顺序位于它之前的视频帧作为参考帧。这样的规则确保了在关键帧之后编码的视频帧仅依赖于关键帧本身,而不依赖于在关键帧之前编码的任何视频帧,从而保持了关键帧的随机访问特性。
如果当前帧的frame_type=INTRA_ONLY_FRAME,则当前帧通常又称为普通帧内预测帧。与关键帧类似,普通帧内预测帧中的所有编码块也只能使用帧内预测模式。然而,与关键帧不同的是,普通帧内预测帧不会重新设置DPB状态。因此,在普通帧内预测帧之后编码的视频帧均可以把在该普通帧内预测帧之前编码的视频帧作为参考帧。这样的设计允许视频编码过程中的后续帧利用先前帧的信息,以优化预测效果并提高编码效率。
如果当前帧的语法元素frame_type=INTER_FRAME,则当前帧的编码块不但可以使用帧内预测模式,还可以使用帧间预测模式。如果当前帧的语法元素frame_type=SWITCH_FRAME,则表示当前帧的分辨率将发生变换,即当前帧的分辨率不再等于序列头传输的视频帧分辨率。对于语法元素frame_type=SWITCH_FRAME的视频帧,其编码块可以使用帧内预测模式,也可以帧间预测模式。当编码块使用帧间预测时,由于当前帧与参考帧之间的分辨率可能不同,因此要使用缩放帧间预测(关于缩放帧间预测,请参考第9章)。另外需要注意的是,语法元素frame_type=SWITCH_FRAME的视频帧也能够重新设置DPB状态。所以,frame_type=SWITCH_FRAME的帧具备重新设置DPB状态的能力,而无须强制进行帧内预测,从而使视频编码更加灵活。
元数据信息OBU的作用是传输视频编码过程中的元数据信息。元数据包括色彩空间信息、高动态范围(High Dynamic Range,HDR)信息、可扩展性编码信息以及时间信息。为了区分元数据中的信息,AV1定义了语法元素metadata_type,以指明元数据存储的数据类型。表2-3所示为metadata_type的取值及元数据类型。
这里需要注意的是,当metadata_type等于3时,即元数据类型是METADATA_TYPE_SCALABILITY,此时元数据OBU是可扩展性编码信息。可扩展性编码信息旨在让中间处理模块不需要解码单独帧,就能了解视频比特流的结构。为了使这些中间处理模块能够尽早了解视频序列的可扩展性结构,可扩展性编码信息应紧跟在序列头之后放置。
表2-3 metadata_type的取值及元数据类型
时间分隔符OBU用于传输时间分隔符信息。时间分隔符用于指明帧在显示过程中的时间戳。所有在时间分隔符OBU之后显示的帧都将使用这个时间戳,直到下一个时间分隔符OBU到达。这意味着从时间分隔符OBU开始,所有后续的帧都会根据这个时间戳来同步播放,直到遇到下一个时间分隔符OBU,这时可能会开始一个新的时间戳序列。
在AV1编码中,一个视频帧可以被分割成多个尺寸更小、更易于处理的切片(Tile)。每个切片包含视频帧的一部分数据,并且可以单独解码。所有切片都完成解码并且经过环路滤波器处理之后会被组合起来,形成完整的重构图像。切片组包含了一帧图像中所有切片的数据,用于解码和呈现整个帧。比如,编码块的帧内预测模式、运动向量和残差数据等信息都属于切片组信息。为了提高效率,帧头OBU和切片组OBU会打包成一个OBU,在这种情况下,帧头信息后面紧跟着的是切片组信息。包含帧头信息和切片组信息的OBU又称为帧OBU(Frame OBU)。