王小根,赵海武,李国平,滕国伟,王国中
(上海大学通信与信息工程学院,上海 200072)
视频编码中每一帧的编码数据通常是不一样的,特别是在利用视频序列的时域相关性进行压缩编码时,采用帧内模式编码的帧和采用帧间模式编码的帧的编码数据量会差别很大。而信道的数据传输率经常是稳定而有限的,或者说从传输的角度,希望视频编码数据的速率越稳定越好,最好是恒定码率。因此,利用缓冲区对视频编码数据的速率进行平滑是必须的。在 MPEG-2[1]和 AVS[2]等标准中,都规定了码流缓冲区校验模型,来规范码流的缓冲。
缓冲区的本质是用延迟来换取码率的稳定,因为缓冲必然会带来延迟。缓冲的数据越多,码率越稳定,延迟也越大。然而,在电视广播等应用中延迟是不能太大的,当然,在其他应用中延迟可以很大,但也是有限制的。在延迟有限,也即缓冲区有限的情况下,就需要对每一帧的编码数据量进行控制,以达到码率稳定的目的。因此,缓冲和延迟最终需要用码率控制来实现[3]。
本文对MPEG-2和AVS的码流缓冲模型进行了比较详细的分析。
首先,讨论解码器何时开始解码的问题。解码器开始解码的时刻和码流中的bbv_delay,bbv_buffer_size以及low_delay等3个信息相关。
当bbv_delay!=0xFFFF时,某一帧(包括开始解码的第一帧)的解码时刻等于该帧的编码数据进入缓冲区的时刻加上该帧的bbv_delay(bbv_delay出现在每一帧的头部),这是最常见的情况。
当bbv_delay==0xFFFF时,第一帧的解码时刻是缓冲区被充满的时刻。缓冲区被充满的时间由bbv_buffer_size和bit_rate共同确定。事实上,缓冲区被充满的时间等于二者的商。显然,这种情况下,从第一帧的编码数据开始进入缓冲区到第一帧被解码的延迟是不确定的,它和第一帧以及后续若干帧的编码数据量有关。编码器要控制每一帧的编码数据量,以保证开始解码后缓冲区不会发生上溢或下溢。
当low_delay==1时(此时bbv_delay不应等于0xFFFF),在每一帧的头部会包含缓冲区检测次数信息bbv_check_times。解码器会按照规定的时间间隔检测缓冲区,检测bbv_check_times+1次后解码器开始解码。通常bbv_check_times的值是0,即解码器只检查缓冲区1次,这和low_delay==0时是一样的。
其次,讨论开始解码后每一帧的解码时刻,也就是解码时间间隔。
解码时间间隔和解码器的输出是密切相关的。解码器一旦开始输出解码图像,就必须连续输出解码图像,直到解码过程结束。要想做到连续不间断地输出解码图像,就必须在输出一个解码图像的同时解码下一个图像。因此,解码器输出图像的时间间隔就是解码图像的时间间隔。假设第n帧图像的解码时刻是tn,输出(或者说回放)第n帧图像的时间是in,那么第n+1帧图像的解码时刻
通常情况下,输出一帧的时间就是帧速率的倒数,也称帧时间间隔。输出一场的时间就是场速率的倒数,也称场时间间隔。但是,由于存在3∶2下拉等帧速率的转换,使得输出一帧图像(这里指的是码流中的一帧,以帧头开始,到下一帧的帧头结束)的时间显得有些复杂。
在AVS标准和MPEG-2标准中,图像输出显示的时间和序列头中的progressive_sequence(PSeq),progressive_frame(PF)以及帧头中的 picture_structure(PStr),top_field_first(TFF),repeat_first_field(RFF)等几个参数有关。为了读者参考方便,本文将它们之间的关系整理如表1所示。其中NA表示不起作用,第一列是progressive_sequence和progressive_frame两个参数的所有可能组合,最后一列是图像的输出情况。输出一帧所需的时间是帧时间间隔,在数值上等于帧速率的倒数,输出一场所需的时间是场时间间隔,在数值上等于场速率倒数。
表1 图像输出显示的时间和序列头中参数关系
当low_delay==1时,解码时间间隔更加复杂一些,因为码流中可能存在大图像。所谓大图像,就是图像头中的bbv_check_times不是0的图像。大图像的检测缓冲区时间间隔是帧速率的倒数,其他图像的解码时间间隔和low_delay==0时一样。所谓的“检测缓冲区”,实际上就是“尝试解码”。
当解码时刻到来时,被解码图像的所有编码数据是瞬时移出码流缓冲区的。一帧图像的编码数据包含的内容,在AVS和MPEG-2标准中有明确的定义,这里不再赘述。第n帧图像的编码数据量用fn来表示。
显然,对于一个视频序列,每一帧的编码数据是按照编码顺序进入缓冲区的。第n帧的编码数据进入缓冲区的时间记为en。解码器把收到第n帧开始码后第一个比特的时刻记录为en,它和编码器把第n帧开始码后第一个比特写入码流的时刻间隔一个固定的时间,这个时间是码流通过信道产生的延迟。假设码流通过信道产生的延迟是固定的,以此实现编码器和解码器的同步。
为方便起见,把第n帧头部的bbv_delay所表示的时间记为dn。解码器根据en和dn确定第一帧的解码时刻,即
因为解码器可能从码流的中间某些位置开始解码,所以上式中的序号仍然用n,而不是1。当bbv_delay==0xFFFF时,第一帧的解码时刻是码流缓冲区充满的时刻,这时(2)可以表示为
式中:S是码流缓冲区的容量,R是码率,这两个参数都是编码器在序列头中设定的。
第一帧的解码时刻确定以后,根据式(1)确定后续各帧的解码时刻,再根据各帧的解码时刻,和各帧的延迟dn,倒推出各帧数据进入缓冲区的时刻,即
这是确定编码数据进入缓冲区的时刻的过程。之所以这么复杂,是因为编码数据进入缓冲区的速率是可变的。即不总是以序列头中设置的速率R进入缓冲区。所以,无法根据fn和R来递推每一帧的编码数据进入缓冲区的时刻。
式(3)适用于解码器。对于编码器,具有一定的灵活性,即编码器可以在满足式(3)的前提下,调整dn和en。编码器调整dn和en,是通过调整第n-1帧的编码数据进入缓冲区的速率来实现的。第n-1帧的编码数据进入缓冲区的速率高,就会早一些结束,从而第n帧的编码数据就可以早一些开始,反之亦然。所以,这里有一个假设,即第n-1帧数据结束进入缓冲区的时刻就是第n帧数据开始进入缓冲区的时刻。即
式中:τn-1是第 n-1 帧进入缓冲区所需的时间。
当某一帧的解码时刻到来时,如果该帧的编码数据没有完全进入缓冲区,则缓冲区发生下溢;如果在某个时刻,缓冲区没有足够的空间存放需要进入缓冲区的编码数据,则缓冲区发生上溢。
通常情况下,编码器必须保证缓冲区不发生下溢和上溢。当bbv_delay==0xFFFF时,缓冲区不存在上溢,因为缓冲区被充满以后,编码数据可以等待,暂时不进入缓冲区。当low_delay==1时,如果某一帧的编码数据量太大,造成该帧的编码数据无法在按照式(1)递推的解码时刻完全进入缓冲区,则编码器可以将其设置成大图像,其实就是让解码器进行额外的等待,以保证缓冲区不发生下溢。即使如此,缓冲区还是可能发生下溢,例如当某一帧的编码数据量超过缓冲区的容量时,无论等待多少时间,缓冲区都会发生下溢。虽然当low_delay==1时,缓冲区下溢是允许的,但是会给解码带来很大的麻烦,而且标准中没有规定缓冲区发生下溢时解码器的处理方法,编码器也就不知道解码器会如何处理。因此,本文建议编码器还是要避免缓冲区发生下溢。
编码器可以通过控制每一帧的编码数据量、控制每一帧的编码数据进入缓冲区的时刻和设置合适的延迟来保证缓冲区不发生溢出。
首先考虑最常见的情况,即bbv_delay的值不是0xFFFF且low_delay的值不是1。如图1所示(此时可能存在帧率转换,可能是CBR,也可能是VBR)。
图1 缓冲区模型示意图
本节的目的是导出保证缓冲区不发生溢出的条件。
当第n-1帧编码结束时,根据解码时刻的递推关系,可以确定第n帧的解码时刻tn,即tn是已知的。根据编码数据进入缓冲区的假设式(4),第n帧编码数据开始进入缓冲区的时刻en也是已知的。根据(2)和(3),第n帧的延迟dn也是已知的。
由图1可知,第n帧编码数据在其解码时刻到来之前全部进入缓冲区(即缓冲区不下溢)的充分必要条件是
对于解码器,式(5)中的所有量都是已知的,可以通过上式检验缓冲区是否发生下溢。
缓冲区不上溢的条件是,在第n帧(n为任意值)的编码数据被移出缓冲区之前,进入缓冲区的数据总量不超过缓冲区的容量S。从第n帧数据进入缓冲区到移出缓冲区的时间是dn,在这段时间之内,可能有若干帧数据进入缓冲区。然而,在编码第n帧的时候,编码器无法知道后续尚未编码的帧的数据量。但是,编码器知道后续各帧数据进入缓冲区的速率都小于等于R。所以,编码器只需保证以下条件即可
但是,如前所述,当第n-1帧编码结束时,dn已经确定了,假设编码器在编码第n-1帧时已经保证了dn<D,编码第n帧需要做的,是保证dn+1<D。
当dn和D比较接近时,式(8)的右边是一个正值,这就要求传送第n帧数据的时间不能太短。
在CBR时,编码器必须保证第n帧的数据量
在VBR时,编码器可以通过降低第n帧数据进入缓冲区的速率来使式(8)成立,也可以像CBR时那样通过控制fn来使式(8)成立。如图2所示。其中rn表示第n帧数据进入缓冲区的速率。
图2 VBR时为防止缓冲区上溢所做的处理
需要注意的是,在CBR时,式(8)或(9)是缓冲区不上溢的充分必要条件,在VBR时,式(8)是充分但非必要条件。如果式(8)不成立,编码器可以通过降低后续各帧编码数据进入缓冲区的速率使缓冲区不上溢。但是,既然总数据量不大于S,编码器总是可以将这些数据放在长度不超过D的时间区间上传送(即强制第n帧数据延后至tn-D时再进入缓冲区),以保证式(8)成立。
当bbv_delay==0xFFFF时,AVS标准规定:如果BBV缓冲区没有充满,数据以速率R输入缓冲区;如果BBV缓冲区充满,则数据不能进入该缓冲区直到缓冲区中的部分数据被移出。因此,当bbv_delay==0xFFFF时,缓冲区不存在上溢的问题。
当bbv_delay==0xFFFF时,视频序列的第1帧图像的起始码前的所有数据和这个起始码输入BBV缓冲区后,数据继续输入BBV缓冲区直到缓冲区充满,并在这个时间开始解码处理。此时,第1帧的延迟可以看成是D=S/R,这是延迟的最大值,不妨把这种缓冲模型称为“高延迟模型”。后续各帧的解码时间依然按照式(1)来确定。
在高延迟模型中,只需保证缓冲区不发生下溢。缓冲区下溢是有可能发生的,比如某一帧的编码数据量大于缓冲区的容量,当该帧的解码时刻到来时,其数据不可能完全进入缓冲区,就会发生下溢。即使每一帧的编码数据量都小于缓冲区的容量,也可能发生缓冲区下溢,比如出现连续两帧的编码数据量都很大(大到接近缓冲区的容量)的时候。当前一帧的数据被移出缓冲区时,后一帧的数据只有一小部分进入了缓冲区,其余部分在两帧的解码时间间隔内无法全部进入缓冲区。
准确的说,保证第n帧编码数据能够及时全部进入缓冲区的充分必要条件是
当low_delay=1时,是低延迟模式。此时每一帧的编码数据头部存在BbvCheckTimes,在从缓冲区移出该帧数据解码之前,解码器要检查缓冲区BbvCheckTimes+1次。通常BbvCheckTimes=0,即解码器只需检查缓冲区1次,这和low_delay==0时是一样的,如果所有帧都是只需检查缓冲区1次,那整个码流就和low_delay==0时是一样的。这里所说的“检查缓冲区”的意思是“尝试解码”,检查缓冲区的时刻就是解码时刻,检查缓冲区的时间间隔就是解码时间间隔。
缓冲区下溢通常是由于大图像的编码数据量太大造成的。然而,并非某一帧的编码数据量大了就一定会发生下溢,根据fn<R×dn,可知是否下溢和该帧的延迟有关。而延迟又是由该帧的解码时刻和该帧数据进入缓冲区的时刻共同确定的,该帧编码数据进入缓冲区的时刻无法提前,因为在保证缓冲区不上溢的前提下,已经是尽量早的进入缓冲区了。所以,发生缓冲区下溢的原因是该帧的解码时刻过早,而该帧的解码时刻是按照tn+1=tn+in递推出来的,各帧的显示时间是确定的,最终决定该帧的解码时刻的是第1帧的解码时刻。
实际上,解码的第一帧在码流中是随机的。在低延迟模式下,编码器会将每一帧的延迟时间尽量设得短,以达到让解码器尽早解码,降低延迟的目的。这正是低延迟模式的含义。
当按照通常的设置(BbvCheckTimes=0)缓冲区发生下溢时,编码器通过将发生下溢的帧设置成大图像,告知解码器等待一段时间再解码。但是,额外的等待时间不一定能够保证不发生下溢,如果大图像的数据量太大,超过缓冲区的容量,或者需等待的时间超过某种上限,则只能放弃大图像。这时,编码器设置的等待时间不足以让大图像的全部数据到达。解码器在检测缓冲区指定的次数之后强行移出大图像。AVS标准没有详细规定在缓冲区发生下溢时的处理方法。编码器可以将大图像数据全部写入码流,也可以只写入一部分。解码器可以不解码大图像,也可以强行解码并输出不完整的解码图像。建议编码器避免缓冲区发生下溢,以避免解码器出现不可控的输出。
这里有两个问题需要解决:1)等待大图像解码的这段时间解码器如何输出?2)大图像解码后解码器如何输出?AVS标准并未明确回答这两个问题。但是,有一点是肯定的,即解码器必须按照指定的速率持续输出解码图像。根据这个原则,等待大图像解码的时候解码器应当有输出,大图像解码后,输出的速率不能提高。为了保持同步,编码器应当丢弃若干帧,否则会造成不同步。
上述3种缓冲模型对应着不同的应用。bbv_delay值不是0xFFFF且low_delay值不是1的模型是最常见的,主要应用于数字电视广播等。这种应用的特点是各方面的要求比较均衡。需要注意的是,这种应用可以用CBR编码,也可以用VBR编码。
bbv_delay==0xFFFF时是高延迟模型,主要应用于存储媒体。这种应用的特点是对延迟不敏感,信道可靠性好,能提供的数据传输率很高,但是存储容量有限,因此通常采用VBR编码。
低延迟模式通常用于可视电话、视频会议等对延迟要求很高的应用。同时,信道能够提供的数据传输率也是有限的。这就给码率控制带来了很大的难度,可能会出现某些帧数据量太大的情况。
前文列举的基本概念对理解码流缓冲模型是非常重要的,特别是解码时刻的确定方式。
另外,就是关于CBR和VBR。根据前文的叙述,可知CBR,VBR和bbv_delay,low_delay的值没有必然的联系。
编码器和解码器使用同样的码流缓冲区模型,但是任务是不同的。解码器是被动的,它首先要判断自己是否有足够的资源完成解码,然后按照码流中的设置实现对缓冲区的操作。解码器还必须处理意外情况和标准中没有明确规定的部分。
编码器首先要把用户的设置翻译成合适的缓冲区参数,然后采取合适的方法控制编码过程,使缓冲区不发生溢出。编码器通过控制缓冲区来控制解码器的行为。
本文从编码器的角度,针对3种不同的缓冲模式,给出了保证缓冲区不溢出的可操作的条件。其中,低延迟模式保证缓冲区不上溢的条件和常用的缓冲模式是一样的。
[1] ISO/EC 13818-2,Generic coding of moving pictures and associated audio:Video[S].1996.
[2]GB/T 20090.2—2006,信息技术 先进音视频编码 第2部分:视频[S].2006.
[3]杨其彤,诸巍杰,张兆扬,等.基于运动复杂度的AVS帧级码率控制算法[J]. 电视技术,2009,33(1):21-23.