av1编码--解码器模型
目录
2.5 解码器模型
解码器模型用于验证比特流是否遵守了某个编码级别所定义的规则和限制,以确保比特流可以被正确解码。除此之外,解码器模型还用于评估和确认解码器实现是否满足了某个编码级别的标准,从而验证解码器实现的合规性。在连续帧解码过程中,解码器模型将考虑解码器等待空闲帧缓冲区所需的时间、解码帧所需的时间,以及确保在预期时间内缓冲区卡槽被正确占用的多项基本检查。
2.5.1 图像缓冲区管理
缓冲池中的插槽使用索引idx来表示,那么,VBI[i]=idx表示第i个 VBI 条目指向了索引为idx的插槽。AV1 允许不同的 VBI 条目指向同一个帧缓冲区插槽,即VBI[i]=VBI[j]=idx,其中i≠j。当某个 VBI 条目为 - 1 时,表示这个 VBI 条目为空,即不指向任何帧缓冲区插槽。当前帧缓冲区索引(Current Frame Buffer Index,CFBI)表示正在解码的当前帧的插槽索引。VBI 和 CFBI 一共可以覆盖 9 个缓冲池插槽,剩余的一个插槽可以保存用于显示视频帧。
AV1 标准文档定义了函数initialize_buffer_pool初始化缓冲池和 VBI 数组,该过程描述如下:


随着解码过程的进行,解码器需要对缓冲池进行管理。为此,AV1 标准文档定义了两个数组变量DecoderRefCount[10]和PlayerRefCount[10],分别用于跟踪解码过程和显示过程中每个帧缓冲区插槽的使用状态。图 2-4 为 AV1 中 DPB 的管理示意图,其中FrameBuffers[10]表示 10 个物理帧缓冲区,该物理帧缓冲区由f0~f9表示帧缓冲区插槽组成。

图 2-4 AV1 中 DPB 管理示意图
变量DecoderRefCount[idx]表示在解码过程中位于缓冲池中索引为idx的槽位被引用的次数。它初始化为 0,并且每次解码器将缓冲池的卡槽idx添加到 VBI 索引槽时,该变量的值会增加 1。相应地,每次解码器从 VBI 索引槽中移除卡槽idx时,该变量的值会减少 1。这个参数由语法元素refresh_frame_flags更新。根据refresh_frame_flags的取值,解码器可能会使用缓冲池中的同一个卡槽idx更新多个 VBI 索引槽,如VBI[i]=VBI[j]=idx, i≠j,因此计数器DecoderRefCount[idx]可能会多次增加。
只有在当前视频帧完全解码后,解码器使用refresh_frame_flags来更新 VBI 索引时,计数器DecoderRefCount[idx]才会按照上述方式修改。当计数器DecoderRefCount[idx]=0时,表示缓冲池索引为idx的卡槽所存储的像素数据将永久失效,并且解码过程不应再使用这些数据。
在 AV1 标准文档中,函数update_ref_buffers用于在更新 DPB 时,更新数组 VBI 和DecoderRefCount。该函数定义的更新过程如下:

变量PlayerRefCount[idx]是一个计数器,用于指示解码过程中缓冲池中索引为idx的插槽所存储的解码帧是否仍然需要用于显示过程。它在初始化时被设置为 0,并且每当解码器确定某个帧是一个展示帧(即需要被显示的帧)时,这个计数器的值就会增加 1。当帧最后一次被展示后,PlayerRefCount[idx]会被重置为 0。因此,当show_frame等于 1 或者show_existing_frame等于 1 时,解码器需要设置对应的PlayerRefCount[idx]。该过程位于解码器模型函数decode_process之中,其描述如下:

当解码帧在其最后呈现时间已经显示了,则将PlayerRefCount[idx]设置为 0。在 AV1 标准文档中,函数start_decode_at_removal_time描述了PlayerRefCount[idx]设置为 0 的过程:

对于解码的每一帧视频数据,解码器都必须从缓冲池中找到一个尚未被使用的帧缓冲区插槽来存储解码后的数据。分配的帧缓冲区插槽用于临时保存解码过程中生成的帧数据,直到它们被用于显示或进一步的处理。函数get_free_buffer的作用是在缓冲池中搜索尚未被分配使用的帧缓冲区。在解码过程中,解码器需要统计存储在缓冲池中的解码帧数量,来计算显示帧的显示时间。函数frames_in_buffer_pool的作用是统计并返回缓冲池中已经被使用的帧缓冲区插槽总数。函数get_free_buffer和frames_in_buffer_pool的定义如下:

2.5.2平滑缓冲区
除了缓冲池之外,AV1 解码器还包含平滑缓冲区(Smoothing Buffer)。平滑缓冲区用于存储还未被解码的比特流。在解码过程中,平滑缓冲区要确保解码器具有足够的内部存储器来存储到达(或读取)的比特流数据,并且还要确保下一帧的压缩数据在解码器需要时已经在缓冲区中。
2.5.3 帧时序定义
为了描述平滑缓冲区的状态变化,解码器模型对帧时序进行了定义。AV1 解码器模型以 DFG(Decodable Frame Group,可解码帧组)为单位来描述平滑缓冲区的状态。索引为i的 DFG(DFGi)是指由所有位于帧i-1的最后一个 OBU 与帧i的最后一个 OBU 之间的 OBU。这里需要注意的是,DFG 除了包含构成帧的 OBU 之外,还可能包含位于帧i-1和帧i之间的show_existing_frame等于 1 的帧头 OBU。此外,DFG 的索引i仅在show_existing_frame标志为 0 的帧中递增,这意味着只有在需要进行解码操作的帧中,DFG 的索引才会更新。这是因为,当show_existing_frame标志为 1 时,表示输出已经解码完成的帧。在这种情况下,解码器并不会解码新的视频帧,而只是输出已经解码完成的帧,所以 DFG 的索引不会被更新。
1. 到达开始和结束时间
在 AV1 的解码器模型中,比特流到达平滑缓冲区的速率只有两种:以恒定速率BitRate到达缓冲区,或者以速率 0 到达缓冲区,其中BitRate是峰值比特率,BitRate = MaxBitrate * BitrateProfileFactor,其中MaxBitrate和BitrateProfileFactor由 Profile 来确定。参数BitRate的具体设置方式请参考 AV1 标准文档 A.3 节。AV1 解码器模型使用变量FirstBitArrival[i]表示 DFG 的第一个比特到达平滑缓冲区的时间,使用变量LastBitArrival[i]表示 DFG 最后一个比特到平滑缓冲区的时间,使用变量ScheduledRemoval[i]表示计划把 DFGi从平滑缓冲区删除的时间。
对于 DFGi,其第一个比特必须在最迟的截止时间之前到达平滑缓冲区,这样才能保证 DFGi中的所有比特能够在 DFGi所对应的帧预定解码时间之前被完整接收。因此,FirstBitArrival[i]的计算方式如下:
![]()
其中,LatestArrivalTime[i]是指 DFG 的第一个比特必须到达平滑缓冲区的最晚时间,以确保在预定的移除时间ScheduledRemoval[i]来到时,整个 DFG 处于完整可用状态。默认情况下,这个时间是以秒为单位的。当接收到一组新的解码模型参数时,这个时间是以解码模型参数定义的解码时钟周期DecCT为单位的。因此,LatestArrivalTime[i]的计算方式如下:
![]()
其中,语法元素decoder_buffer_delay指定了第一个比特到达平滑缓冲区时刻和第一个编码帧数据从平滑缓冲区被移除时刻之间的时间间隔;语法元素encoder_buffer_delay指定了解码帧的第一个比特到达平滑缓冲区的时间。
DFG 最后一个比特到达缓冲区的时间LastBitArrival[i]的计算方式如下:
![]()
其中,CodedBits[i]表示编码 DFGi所花费的比特总数。
2. 移除时间
每个 DFG 都会有一个从平滑缓冲区预计移除时间ScheduledRemoval[i]和从平滑缓冲区实际移除时间Removal[i]。解码器模型在 DFGi从平滑缓冲区移除的那一刻开始解码一个视频帧。所以,实际移除时间Removal[i]也可以视为一个视频帧的解码时刻。AV1 有两种不同的模式来确定ScheduledRemoval[i],分别是解码调度模式(Decoding Schedule Mode)和资源可用性模式(Resource Availability Mode)。
(1)解码调度模式
在解码调度模式下,编码器使用语法元素buffer_removal_time[i]来编码传输 DFGi从平滑缓冲区预计移除时间。假设ScheduledRemovalTiming[i]是 DFGi从平滑缓冲区预计移除时间,buffer_removal_time[i]与ScheduledRemovalTiming[i]之间的关系如下:

其中,decoder_buffer_delay是第一个 DFG 从平滑缓冲区移除的时间,因此buffer_removal_time[i]可以视为 DFGi从平滑缓冲区预计移除时间ScheduledRemovalTiming[i]相对于ScheduledRemovalTiming[0]的时间偏移量,即:
![]()
在解码调度模式下,实际移除时间Removal[i]和预计移除时间ScheduledRemoval[i]可能是不同的。解码调度模式有两种模式来确定实际移除时间Removal[i]。具体来讲:
- 当操作点的
low_delay_mode_flag设置为 0 时,解码器将按照严格到达模式(Strict Arrival Mode)进行操作。在这种模式下,DFG 会在预计移除时间ScheduledRemoval[i]准时从平滑缓冲区中移除,即:
![]()
- 当操作点的
low_delay_mode_flag设置为 1 时,解码器将进入低延迟模式(Low-Delay Mode)。在此模式下,DFG 数据可能无法在预定的移除时间ScheduledRemovalTiming[i]之前完全到达平滑缓冲区,也就是说,最后一个比特的到达时间LastBitArrival[i]会晚于预计移除时间,即ScheduledRemovalTiming[i] < LastBitArrival[i]。因此,DFG 的移除操作将被延后。直到整个 DFG 数据完全加载到平滑缓冲区之后的下一个解码时钟周期,解码器才开始把 DFGi从平滑缓冲区移除。因此,实际移除时间Removal[i]计算如下:
![]()
如果整个 DFG 在预定移除时间ScheduledRemovalTiming[i]之前已经在平滑缓冲区中可用,即ScheduledRemovalTiming[i] > LastBitArrival[i],那么 DFG 将在预定移除时间ScheduledRemovalTiming[i]从平滑缓冲区移除。即:
![]()
从中可见,解码调度模式灵活地定义了何时从平滑缓冲区中移除 DFG,何时开始解码帧以及何时显示帧。除了使用恒定的帧率外,解码调度模式还可以通过显式编码传输解码帧的呈现时间来支持变化的帧率。AV1 标准文档 E.3.2 节描述了解码调度模式的参数设置方法。为了使用解码调度模式,编码器需要在比特流中传输以下参数:
![]()
除了上述参数之外,编码器还需要传输decoder_buffer_delay、encoder_buffer_delay,以及解码器时钟周期相关语法元素num_units_in_decoding_tick。另外,编码器还需要为每帧传输ScheduledRemoval、和呈现时间相关的语法元素buffer_removal_time和frame_presentation_time。
(2)资源可用性模式
在资源可用性模式下,对于 DFGi,解码器不再根据语法元素buffer_removal_time[i]来确定 DFGi从平滑缓冲区预计移除时间ScheduledRemoval[i],而是根据缓冲池的可用状态来确定ScheduledRemoval[i]。具体来讲,第一帧(索引为 0 的帧)的ScheduledRemoval[0]时间由decoder_buffer_delay确定。对于 DFGi,当具有show_existing_frame标志等于 0 的前一帧解码完成并且缓冲池有空闲帧缓冲区时,解码器把这个时间设置为ScheduledRemoval[i]。
换句话说,在资源可用性模式下,如果缓冲池有可用的空闲插槽,则在前一帧解码完成后立即解码下一帧;否则,这个帧将在缓冲池有空闲插槽时才进行解码。如果比特流低于解码器的最大级别限制,则帧将一个接一个地进行解码,直到它们填满所有可用的帧缓冲区,之后解码速度会放缓。下一帧的解码仅在已解码帧缓冲区插槽空闲时才会发生。AV1 标准文档 E.3.1 节描述了资源可用性模式的参数设置方式。为了使用资源可用性模式,编码器需要在比特流中设置以下参数:
![]()
其中,equal_picture_interval=1表示使用恒定帧率,所以不需要在比特流中编码传输呈现时间(Presentation Time)。在这种情况下,呈现时间是从帧率和initial_display_delay_minus_1推导出来的。由于解码时刻Removal[i]由已解码帧缓冲区可用时刻确定,因此也不需要在比特流中对其进行传输。
在资源可用性模式下,某些解码器模型参数采用默认值,例如encoder_buffer_delay=20000、decoder_buffer_delay=70000和low_delay_mode_flag=0。解码过程调用函数time_next_buffer_is_free来计算 DFGi的Removal[i]和ScheduledRemovalResource[i]。ScheduledRemoval[i] = ScheduledRemovalResource[i]。

3. 平滑缓冲区填充度
基于FirstBitArrival[i]、LastBitArrival[i]、ScheduledRemoval[i]以及Removal[i],解码器模型可以估计平滑缓冲区填充度(Smooth Buffer Fullness)。图 2-5 所示为平滑缓冲区填充度随时间的变化。当第 0 帧的第一个比特到达缓冲区时,时钟开始计时。斜线的斜率对应于比特到平滑缓冲区的速率。Removal[i]表示 DFGi从平滑缓冲区的实际移除时间,它对应于从平滑缓冲区中删除第i帧的数据并且开始解码第i帧的时刻。这里需要注意,并不是所有时刻都会有新比特到达缓冲区。可能会存在一个时间段,在这段时间内,没有新的比特进入缓冲区。在图 2-5 中Removal[1]之后的一段时间内,就没有新比特进入缓冲区。这段时间对应着编码器没有比特发送的时间段,即编码器缓冲区为空的时间段。

图 2-5 平滑缓冲区填充度随时间的变化
在图 2-5 中,语法元素decoder_buffer_delay指定了平滑缓冲区中第一个比特到达缓冲区的时刻和第一个编码帧数据从缓冲区被移除的时刻之间的时间间隔。所以,解码开始时间,即Removal[0]由decoder_buffer_delay来决定。这里需要注意的是,在decoder_buffer_delay所指定的时间段内,平滑缓冲区可能已经缓存了不止 1 个编码帧。在图 2-5 中decoder_buffer_delay所指定的时间段内,DFG 0 和 DFG 1 都已经到达平滑缓存区。
2.5.4 视频帧解码时间
AV1 解码过程把平滑缓冲区与解码器帧缓冲区之间的操作相互关联。具体来说,解码器模型将控制帧解码的开始时刻以及比特流从平滑缓冲区中移除的时刻,这一过程会迅速降低平滑缓冲区填充度。此外,解码器模型还负责计算解码过程的完成时间,并将解码后的帧及时存入解码器帧缓冲区中。同时,它还决定何时将帧输出至显示器,并将该帧从解码器帧缓冲区中移除。
AV1 的一个特点是广泛使用 ARF,ARF 只用作帧间预测的参考帧,而不是用于显示的帧(关于 ARF 的详细描述,请参考第 4 章)。此外,AV1 在主要档次中支持参考帧的缩放(参考帧与编码帧的分辨率不同,参考第 9 章)和可扩展编码。所以,AV1 解码模型要适应不同类型帧的解码过程所需要的时间,并支持不同分辨率的帧解码和显示速率。为了支持 ARF 和不同分辨率的帧,AV1 解码器模型引入了以下功能:
- 解码时钟周期
DecCT和显示时钟周期DispCT是不同的,但是它们使用相同的时间尺度,并且这些时钟是同步的。这意味着解码过程和显示过程在处理视频帧时的时间基准是一致的。 - 解码一帧图像并非瞬间完成,其所需时间会根据图像的分辨率以及其他因素而有所差异。这也意味着解码过程的持续时间可能会因帧的复杂度、编码参数、硬件性能等因素而变化。
图 2-6 所示为 AV1 中的解码过程和显示过程。该图展示了 GOP 长度为 4 帧的金字塔预测编码结构,其中矩形框表示视频帧,上面的数字表示该视频帧的显示顺序。带有箭头的曲线和直线表示参考关系,比如,帧 2 的参考帧是帧 0 和 ARF,帧 1 的参考帧是帧 0 和帧 2。白色矩形表示 ARF,ARF 不会显示。通常,ARF 是同一时间位置上帧的滤波版本,可以提高帧间预测的准确性。为了在 ARF 的时间位置显示一帧,编码器可以重新编码一个重叠帧(图 2-6 中的 OL)。相比于 ARF,重叠帧添加了高频和纹理信息。在编码过程中,重叠帧可以使用 ARF 作为参考帧。

图 2-6 AV1 中的解码过程和显示过程
可以看出,图 2-6 中的解码时间线和显示时间线使用了不同的时钟周期。因为视频帧在显示之前必须完成解码,所以 AV1 标准引入了语法元素initial_display_delay_minus_1,用于明确缓冲池在首次帧显示前应缓存多少个已经解码完成的帧。这个设置确保了在首次帧展示之前,有足够的解码帧可供即时播放,从而保障视频播放的流畅性。
通过语法元素initial_display_delay_minus_1可调整显示过程相对于解码过程的时间偏差。如果不在比特流中指定initial_display_delay_minus_1,那么initial_display_delay_minus_1被设置为BUFFER_POOL_MAX_SIZE-1,其中BUFFER_POOL_MAX_SIZE=10,即缓冲区所能存储的最大帧数。
从图 2-6 可见,显示过程的整体显示延迟initial_presentation_delay(即第一个比特到达平滑缓冲区时刻与帧 0 的显示时刻之间的时间间隔)包含了decoder_buffer_delay(即第一个比特到达平滑缓冲区时刻与帧 0 开始解码时刻之间的时间间隔)。
AV1 标准文档 E.4.6 描述了如何计算解码一帧图像所需要的时间。其定义如下:

2.5.5 视频帧显示时间
每个显示帧都有一个预定的显示时间点。AV1 使用变量PresentationTime[j]表示显示帧j的显示时间,并且PresentationTime[j]必须是显示时钟周期DispCT的整数倍。AV1 使用语法元素frame_presentation_time传输显示帧的显示时间。当equal_picture_interval等于 0 时,解码器以可变帧率模式运行。在这种模式下,对于显示帧j,其PresentationTime[j]计算如下:
![]()
当equal_picture_interval等于 1 时,解码器以恒定帧率模式运行。在这种模式下,对于显示帧j,其PresentationTime[j]计算如下:
![]()
无论equal_picture_interval等于 0 还是等于 1,PresentationTime[j]都依赖于初始显示时间延迟InitialPresentationDelay,其计算如下:
![]()
语法元素initial_display_delay_minus_1指定了在开始显示帧之前,解码器需要提前解码并存储在缓冲区中的帧的数量。
2.5.6 解码器模型参数的传输
解码器模型参数大多在序列和帧级别进行传输。序列头可能包括一个timing_info()结构(标准文档 5.5.3),包含显示时序信息。解码器模型的基本信息在decoder_model_info()结构(标准文档 5.5.4)中。timing_info()结构包含了时间单位time_scale和显示时钟周期中的时间单位数num_units_in_display_tick。而decoder_model_info()结构包含解码时钟周期的时间单位数num_units_in_decoding_tick以及其他解码器模型语法元素的长度。这两个语法元素定义了显示时钟周期DispCT和解码时钟周期DecCT的持续时间,如下所示:

operating_parameters_info()结构包含操作点的encoder_buffer_delay、decoder_buffer_delay以及低延迟模式标志low_delay_mode_flag。如果使用解码器模型,则可以在帧头信息中为选定的操作点传输以解码时钟周期为单位的buffer_removal_time,以计算ScheduledRemovalTiming[i]。
帧头中的temporal_point_info()结构包含frame_presentation_time语法元素,该语法元素用于计算显示帧的显示时间。
2.5.7 解码器模型描述
根据上面描述的等待空闲帧缓冲区所需的时间、解码帧所需的时间和视频帧显示时间等信息,解码器模型将会对比特流进行一致性检查。如果比特流不符合规范要求,将通过调用bitstream_non_conformant函数来报告问题。AV1 标准文档 E.5.2 节定义了函数decode_process以描述解码器模型。


// 使用缓冲池中索引为 displayIdx 的卡槽存储当前显示帧,并把当前显示帧的显示时间赋值给 PresentationTimes[displayIdx]。这是因为在资源可用模式下,一旦有空闲的参考缓冲区可用,解码器就可能开始解码下一帧。
// 如果没有空闲的帧缓冲区可用,就可能使用 PresentationTimes[i] 来计算何时会有一个空闲的缓冲区变得可用。
在函数decode_process中,变量UsingResourceAvailabilityMode用于确定如何计算 DFGi的平滑缓冲区预计移除时间ScheduledRemoval[i]。当使用资源可用性模式时,UsingResourceAvailabilityMode设置为 1;当使用解码调度模式时,该变量设置为 0。
函数decode_process的不符合 AV1 规范的错误代码符号包括:
DECODE_BUFFER_AVAILABLE_LATE、DECODE_FRAME_BUF_UNAVAILABLEDECODE_EXISTING_FRAME_BUF_EMPTY、DISPLAY_FRAME_LATE
表 2-4 不符合规范的错误代码的类型及描述
|
错误代码类型 |
描述 |
|
|
一个空闲的帧缓冲区仅在应该展示该帧的时间点之后才对解码器变得可用 |
|
|
所有的帧缓冲区都在使用中 |
|
|
由一个具有 的帧指定展示的帧缓冲区索引是空的 |
|
|
该帧被解码得太晚了,以至于无法在与帧相关联的显示时间 及时显示 |
函数get_next_frame按照解码顺序解码操作点的一帧,其定义如下:

参考资料:[1] https://norkin.org/research/av1_decoder_model/index.html.
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)