



解码器模型用于验证比特流是否遵守了某个编码级别所定义的规则和限制,以确保比特流可以被正确解码。除此之外,解码器模型还用于评估和确认解码器实现是否满足了某个编码级别的标准,从而验证解码器实现的合规性。在连续帧解码过程中,解码器模型将考虑解码器等待空闲帧缓冲区所需的时间、解码帧所需的时间,以及确保在预期时间内缓冲区卡槽被正确占用的多项基本检查。
AV1定义了一个存放视频帧的缓冲区,用于存储解码后的视频帧。因此,这个缓冲区往往称为DPB。DPB最多允许存储8个视频帧。为此,AV1定义一个缓冲池(BufferPool)用于存储解码过程需要的视频帧。除了DPB,AV1解码器还需要存储显示视频帧以及正在解码的视频帧,所以AV1标准文档要求解码器支持存储10个帧的物理帧缓冲区(Physical Frame Buffer),因此缓冲池的大小是10。在缓冲池中,每个帧的存储区域BufferPool[i]又称为帧缓冲区插槽(Slot)。插槽应该能够以相应级别规定的最大分辨率来存储帧。在帧间预测过程中,AV1使用虚拟缓冲区索引(Virtual Buffer Index,VBI)来引用DPB中的不同解码帧。VBI可以存储缓冲池中8个帧的索引,VBI[i]表示第i个VBI条目,其中i大于或等于0,小于8。假设缓冲池中的插槽使用索引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个物理帧缓冲区,该物理帧缓冲区由f 0~f 9表示帧缓冲区插槽组成。
图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的定义如下:
除了缓冲池之外,AV1解码器还包含平滑缓冲区(Smoothing Buffer)。平滑缓冲区用于存储还未被解码的比特流。在解码过程中,平滑缓冲区要确保解码器具有足够的内部存储器来存储到达(或读取)的比特流数据,并且还要确保下一帧的压缩数据在解码器需要时已经在缓冲区中。
为了描述平滑缓冲区的状态变化,解码器模型对帧时序进行了定义。AV1解码器模型以DFG(Decodable Frame Group,可解码帧组)为单位来描述平滑缓冲区的状态。索引为 i 的DFG(DFG i )是指由所有位于帧 i -1的最后一个OBU与帧 i 的最后一个OBU之间的OBU。这里需要注意的是,DFG i 除了包含构成帧 i 的OBU之外,还可能包含位于帧 i -1和帧 i 之间的show_existing_frame等于1的帧头OBU。此外,DFG的索引 i 仅在show_existing_frame标志为0的帧中递增,这意味着只有在需要进行解码操作的帧中,DFG的索引才会更新。这是因为,当show_existing_frame标志为1时,表示输出已经解码完成的帧。在这种情况下,解码器并不会解码新的视频帧,而只是输出已经解码完成的帧,所以DFG的索引 i 不会被更新。
1.到达开始和结束时间
在AV1的解码器模型中,比特流到达平滑缓冲区的速率只有两种:以恒定速率BitRate到达缓冲区,或者以速率0到达缓冲区,其中BitRate是峰值比特率,BitRate=MaxBitrate * BitrateProfileFactor,其中MaxBitrate和BitrateProfileFactor由P r o f i l e来确定。参数BitRate的具体设置方式请参考AV1标准文档A.3节。AV1解码器模型使用变量FirstBitArrival[i]表示DFG i 的第一个比特到达平滑缓冲区的时间,使用变量LastBitArrival[i]表示DFG i 最后一个比特到平滑达缓冲区的时间,使用变量ScheduledRemoval[i]表示计划把DFG i 从平滑缓冲区删除的时间。
对于DFG i ,其第一个比特必须在最迟的截止时间之前到达平滑缓冲区,这样才能保证DFG i 中的所有比特能够在DFG i 所对应的帧预定解码时间之前被完整接收。因此,FirstBitArrival[i]的计算方式如下:
其中,LatestArrivalTime[i]是指DFG i 的第一个比特必须到达平滑缓冲区的最晚时间,以确保在预定的移除时间ScheduledRemoval[i]来到时,整个DFG处于完整可用状态。默认情况下,这个时间是以秒为单位的。当接收到一组新的解码模型参数时,这个时间是以解码模型参数定义的解码时钟周期DecCT为单位的。因此,LatestArrivalTime[i]的计算方式如下:
其中,语法元素decoder_buffer_delay指定了第一个比特到达平滑缓冲区时刻和第一个编码帧数据从平滑缓冲区被移除时刻之间的时间间隔;语法元素encoder_buffer_delay指定了解码帧的第一个比特到达平滑缓冲区的时间。
DFG i 最后一个比特到达缓冲区的时间LastBitArrival[i]的计算方式如下:
其中,CodedBits[i]表示编码DFG i 所花费的比特总数。
2.移除时间
每个DFG都会有一个从平滑缓冲区预计移除时间ScheduledRemoval[i]和从平滑缓冲区实际移除时间Removal[i]。解码器模型在DFG i 从平滑缓冲区移除的那一刻开始解码一个视频帧。所以,实际移除时间Removal[i]也可以视为一个视频帧的解码时刻。AV1有两种不同的模式来确定ScheduledRemoval[i],分别是解码调度模式(Decoding Schedule Mode)和资源可用性模式(Resource Availability Mode)。
( 1 )解码调度模式
在解码调度模式下,编码器使用语法元素buffer_removal_time[i]来编码传输DFG i 从平滑缓冲区预计移除时间。假设ScheduledRemovalTiming[i]是DFG i 从平滑缓冲区预计移除时间,buffer_removal_time[i]与ScheduledRemovalTiming[i]之间的关系如下:
其中,decoder_buffer_delay是第一个DFG从平滑缓冲区移除的时间,因此buffer_removal_time[i]可以视为DFG i 从平滑缓冲区预计移除时间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数据可能无法在预定的移除时间Scheduled RemovalTiming[i]之前完全到达平滑缓冲区,也就是说,最后一个比特的到达时间LastBitArrival[i]会晚于预计移除时间,即ScheduledRemoval Timing[i]小于LastBitArrival[i]。因此,DFG i 的移除操作将被延后。直到整个DFG数据完全加载到平滑缓冲区之后的下一个解码时钟周期,解码器才开始把DFG i 从平滑缓冲区移除。因此,实际移除时间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 )资源可用性模式
在资源可用性模式下,对于DFG i ,解码器不再根据语法元素buffer_removal_time[i]来确定DFG i 从平滑缓冲区预计移除时间ScheduledRemoval[i],而是根据缓存池的可用状态来确定ScheduledRemoval[i]。具体来讲,第一帧(索引为0的帧)的ScheduledRemoval[0]时间由decoder_buffer_delay确定。对于DFG i ,当具有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来计算DFG i 的Removal[i]和ScheduledRemovalResource[i]。ScheduledRemoval[i]=Scheduled RemovalResource[i]。
3.平滑缓冲区填充度
基于FirstBitArrival[i]、LastBitArrival[i]、ScheduledRemoval[i]以及Removal[i],解码器模型可以估计平滑缓冲区填充度(Smooth Buffer Fullness)。图2-5所示为平滑缓冲区填充度随时间的变化。当第0帧的第一个比特到达缓冲区时,时钟开始计时。斜线的斜率对应于比特到平滑达缓冲区的速率。Removal[i]表示DFG i 从平滑缓冲区的实际移除时间,它对应于从平滑缓冲区中删除第 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都已经到达平滑缓存区。
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描述了如何计算解码一帧图像所需要的时间。其定义如下:
每个显示帧 j 都有一个预定的显示时间点。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指定了在开始显示帧之前,解码器需要提前解码并存储在缓冲区中的帧的数量。
解码器模型参数大多在序列和帧级别进行传输。序列头可能包括一个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语法元素,该语法元素用于计算显示帧的显示时间。
根据上面描述的等待空闲帧缓冲区所需的时间、解码帧所需的时间和视频帧显示时间等信息,解码器模型将会对比特流进行一致性检查。如果比特流不符合规范要求,将通过调用bitstream_non_conformant函数来报告问题。AV1标准文档E.5.2节定义了函数decode_process以描述解码器模型。
在函数decode_process中,变量UsingResourceAvailabilityMode用于确定如何计算DFG i 的平滑缓冲区预计移除时间ScheduledRemoval[i]。当使用资源可用性模式时,UsingResourceAvailabilityMode设置为1;当使用解码调度模式时,该变量设置为0。
函数decode_process的不符合AV1规范的错误代码符号包括:
❍DECODE_BUFFER_AVAILABLE_LATE、DECODE_FRAME_BUF_UNAVAILABLE
❍DECODE_EXISTING_FRAME_BUF_EMPTY、DISPLAY_FRAME_LATE
表2-4所示为不符合规范的错误代码符号的类型及描述。
表2-4 不符合规范的错误代码的类型及描述
(续)
函数get_next_frame按照解码顺序解码操作点的一帧,其定义如下: