具体实施方式
图2示出了根据本发明一方面的基于CUDA的视频解码器中的基本模块分配。可变长度解码101和逆扫描102在CPU上执行。逆量化103可以在CPU或者GPU上执行。离散余弦逆变换(iDCT)104a和运动补偿(MC)105a分配给GPU,这是特别有利的,因为它们是计算密集型任务。在GPU内的帧存储器106a中存储运动补偿所需的在前解码的参考图像。最后,将图像的解码采样d[y][x]输出至显示器。注意,本文中“帧”代表可以在特定时刻隔行扫描(interlaced)或逐行扫描(progressive)的图像。
通过根据本发明的解码器框架来解决下列问题:
1、将图1所示的解码过程中的不同处理步骤(即,模块)分配给CPU或者GPU。该分配最小化CPU和GPU之间的数据通信,平衡了CPU和GPU之间的工作负载以最大化CPU-GPU流水线效果,并且确保分配的模块适合高效的CUDA实现。
2、确定在哪里存储图像数据、以及在哪里存储残差图像(即,波形变换结果)。本发明最小化访问工作量并且达到精确的采样。
下面将描述系统流程图,并且还将解释几个关键方面。
系统流程图
图3示出了基于CUDA的加速的视频解码系统202的示例架构,其接收编码视频比特流,对接收的数据进行解码,并且将解码的数据传送至显示设备204(TV、计算机监视器、或者其它类似显示设备)。注意,视频解码系统202还可以实现为显示设备204的集成组件,或者反之亦然,显示设备204可以是视频解码系统202的集成组件。
可以在个人计算机、视频游戏控制台、或者配置为接收、解码以及呈现视频数据的其它类似设备中实现视频解码系统202。视频解码系统202包括中央处理单元CPU 206、具有CUDA功能的图形处理单元GPU 208、用于存储针对CPU的程序和数据的主机存储器210、以及用于存储针对GPU的程序和数据的设备存储器212。可以在一个器件(例如,芯片、板、等等)中将主机存储器210和CPU 206集成在一起,并且在通常情况下还可以将设备存储器212和GPU 208集成在一起。
主机存储器210具有:CPU缓冲器214,针对CPU程序所需的数据,并且可由CPU访问;主机上内核输入数据缓冲器216,其存储由CPU程序收集的并且GPU上的CUDA内核执行所需的数据;视频解码应用218,其为运行在CPU上的解码程序;可以驻留在主机存储器中的一个或者更多应用220。注意,主机上图像缓冲器234是主机存储器中的可选块,包含设备图像缓冲器226的副本。
设备存储器212具有:内核程序222,其为运行在GPU上的解码程序;设备上内核输入数据缓冲器224(设备缓冲器),其为主机上内核输入数据缓冲器216的GPU副本203;图像缓冲器226,其存储包括参考图像在内的解码的图像;残差图像缓冲器228,其存储解码的残差图像数据(即,波形变换结果)。用于其它应用230的程序和数据也可以驻留在设备存储器中。注意,用于存储用于显示目的的图像的显示缓冲器232是可选模块。备选地,图像缓冲器226可以用作显示缓冲器。
图4示出了在基于CUDA的加速的视频解码过程系统202上进行解码的整体过程。块302-310代表由CPU 206执行的处理,而块312-326代表由GPU 208执行的处理。
在块302,视频解码系统202接收编码视频比特流。所描述的实施方式示例地应用于根据MPEG-2逐行扫描视频格式编码的视频比特流。可以配置备选实施方式,对根据其它格式编码(比如MPEG-2隔行扫描、MPEG-4和H.26x)的视频比特流进行解码。在块304,处理公共的解码步骤,比如针对图像的所有MB解码多种报头、执行可变长度解码等等。在块306,对从MB的可变长度解码中获得的波形变换系数执行逆量化。在块308,对解码的图像数据进行缓冲,这些数据是GPU上的内核执行所需的,它们驻留在(与CPU相关的)主机缓冲器216中,然后被复制203到(与GPU相关的)设备缓冲器224中。针对每一个图像单元(通常是MB或者块)的此类数据可以包括位置数据或者坐标、逆量化的波形变换系数、运动向量以及一些影响GPU上的程序执行的标志。块310从主机缓冲器216中将缓冲的数据复制到设备缓冲器224中。
在块312,以一些重建的图像为基础形成参考图像。在一个优选实施方式中,在CUDA的全局存储器中存储重建的图像,并且直接使用重建的图像作为参考图像。在另一个优选实施方式中,重建的图像在全局存储器中,而参考图像在纹理存储器中,并且在块312中将来自全局存储器中的数据复制到纹理存储器中。下面给出关于确定在哪里存储图像的进一步细节。
在块314,在GPU上作为CUDA内核来执行波形变换(例如,逆DCT),以从CPU解码过程期间所收集的一些数据中获得残差图像数据。下面描述该块的更多细节。
在块316,在GPU上作为一个或者多个CUDA内核来执行运动补偿(MC),以通过将残差图像数据与参考图像数据相加来重建图像。下面描述该块的更多细节。
在块318,可以对重建的图像进行缓冲,以用于可选的其它处理,比如可选地传送回主机存储器320、可选地传送至显示缓冲器322、以及可选的面向显示的处理324(比如颜色空间转换、特殊效果创建等等)。最终,在块326将图像发送至显示设备。
图5示出了用于在基于CUDA的GPU加速的视频解码系统202上进行解码的整体过程的另一变体。在该实施例中,逆量化也被卸载至GPU,这样可以在块315中将逆量化与波形变换一起执行。因此,在图5中跳过了图4中的逆量化块306。
下面,进一步解释本发明的几个关键构思。
对CPU/GPU的模块分配
从编程的角度来说,具有CUDA功能的GPU(本文中称为设备)是能够并行执行数量非常大的线程的计算设备。GPU作为主CPU(称为主机)的协处理器来操作,运行应用的数据并行的、计算密集的部分。将该部分(称为内核)下载至该设备,并且在GPU上作为很多不同的线程来执行。将来自一个内核的一批线程组织为线程块网格(grid)。首先,由能够一起协作的多个线程来形成线程块,其中这些线程通过一些共享存储器来高效共享数据,并且将它们的执行同步以协调存储器访问,从而能够一起协作。线程块内的每一个线程由该线程的线程ID来标识,该线程ID可以是2或者3个分量的数组索引。其次,可以将多个线程块分批地一起成为块网格,在该网格中由2个分量的数组索引(块ID)来标识每一个块。在图7中示出了该线程分批(batching)组织。如果输入和输出数据组织良好,则线程可以基于块ID和线程ID,单独地访问不同的数据部分,从而可以实现对不同数据的并行执行。
波形变换(比如DCT、逆DCT等等)是数据并行的计算密集型模块,从而适合CUDA实现。为了最小化CPU-GPU数据通信,还将运动补偿分配给GPU。因此,在GPU上分配针对所有图像的帧存储存储器并维护该帧存储存储器。最终,图2示出了基本的模块分配结果。该分配达到了CPU-GPU工作负载的良好平衡(几乎相等的时间成本)。数据通信非常低。在一个实施例中,仅从CPU向GPU传送非零波形系数(例如,DCT系数)、运动向量以及块地址。
该基本分配的变体是可能的。在一个实施例中,可以将逆量化改变为在GPU上运行,从而对CPU-GPU工作负载进行轻微调整。在一个实施例中,可以从GPU向CPU传送解码的采样或者图像,例如用于CPU上的后处理等应用。
这里提出的不同模块向不同硬件平台(CPU或者GPU)的分配至少具有下列优点:
1、最小化CPU和GPU之间的数据通信;
2、平衡了CPU和GPU的工作负载;
3、可以用CUDA高效地实现卸载至GPU的模块,即,它们是数据并行的、计算密集型模块。
确定针对图像的存储
针对GPU上的图像存储,必须决定至少两个问题:如何确定用于存储的存储器空间、以及如何确定用于Y、U、V分量的数据封装(packing)格式。
对于第一个问题,可以在比如寄存器、局部存储器、共享存储器、全局存储器、常数存储器以及纹理存储器等不同空间处分配由CUDA访问的GPU存储器。它们在总的可用大小、访问许可(只读/读写)、等待时间(latency)、访问限制(例如从CPU或GPU可访问)、同步支持等等方面相当不同。优选解决方案是使用全局存储器,而不是使用纹理存储器,全局存储器支持线程中的读写操作并且可以处理大量的图像数据,而纹理存储器对于线程来说是只读的。因此,这使得线程可以既执行读操作又执行写操作。然而,使用全局存储器具有两个缺点:第一,全局存储器数据的读操作比纹理数据的读操作要慢很多,第二,必须在用于对参考图像进行采样的线程中显式地管理插值计算。这是复杂并且低效率的,而如果使用纹理存储器,这是可以自动地处理的。
本发明该方面是基于认识到下述事实:当使用图像作为对新图像进行解码的参考时,运动补偿模块仅执行读操作,而仅当对图像进行解码时才需要写操作。即,当对图像进行解码时,仅由一个操作来访问具体图像的数据,即要么是读操作(当作为参考图像使用时),要么是写操作(当作为正被解码的结果图像时)。从而,本发明的一个方面是使用全局存储器来存储解码的图像,在对新图像(如果将使用它作为参考图像的话)进行解码之前将解码的数据复制到纹理存储器中,并且从纹理存储器访问参考图像。
在一个实施例中,可以将所有图像复制到纹理存储器中,而另一个实施例包括下述步骤:确定解码的图像是否将作为参考图像使用,仅当将使用它作为参考时才将它复制到纹理存储器中。根据视频编码,可以对作为解码用的参考图像的图像进行标记,例如通过标志进行标记,或者可以接收参考图像的列表。注意,在主机功能中允许对纹理存储器的写操作。“主机功能”是由CPU发起的功能,但是效果可以是在GPU上,例如从全局存储器向纹理存储器复制数据,或者从纹理存储器向全局存储器复制数据。在本文使用的CUDA术语中,“主机”意味着CPU,并且“设备”意味着GPU。与GPU相关的其它主机功能是例如CPU-GPU数据通信、GPU-GPU数据通信、内核发起或者GPU能力查询。“内核”是在GPU上执行的功能。然而,CPU执行“内核发起”,其中将代码复制到GPU上,并且为内核执行准备GPU资源。
该方案解决了全局存储器访问的上述两个缺点(读操作较慢,如果在用于对参考图像进行采样的线程中管理插值计算,则效率很低)。从全局存储器向纹理存储器复制数据的附加成本是可忽略的。
对于第二个问题,即如何确定针对MB的Y、U、V分量的数据封装格式,提议的解决方案是适应性的,取决于所使用的色度格式。GPU通常对顶点进行操作;顶点是多边形的边缘。每一个顶点不仅具有x、y、z坐标系形式的位置,还具有用于将纹理映射至顶点的三个纹理坐标u、v、w。因此,GPU架构提供了针对u、v以及w纹理坐标的、分离的所谓通道或者平面。注意,必须将顶点的纹理坐标u、v、w与图像的亮度/色度分量YUV区分开来。
根据本发明一个方面,如图8所示,根据使用的色度格式,在不同的架构平面801、802中存储并且处理MB的YUV分量,或者将MB的YUV分量成组为单个3分量的平面803。该单个平面方案让实施清晰简单,而3平面方案更有效率,这是由于可以通过单个存储器访问来获取三个分量。然而,对于通常使用的色度格式(4:2:0以及4:2:2)来说,需要对U、V数据进行上采样以达到与Y数据相同的分辨率,这是附加的处理步骤。这导致纹理获取(采样)操作中的精确度的牺牲。
如图8a)所示,为了对效率和精确两者进行优化,针对4:2:0和4:2:2颜色空间格式420、422,使用2平面数据封装格式801、802。更具体地,将Y数据组织为1分量平面801,并将U和V数据封装进2分量平面802。对于4:4:4色度格式444,采用3分量方案803,如图8b)所示。
确定针对残差图像的存储
类似于上面描述的图像存储,对于如何确定残差图像(即,相应的波形变换结果)的存储,出现两个相似的问题。残差图像是以至少一个参考图像为基础的预测的剩余部分,即,其原理上为预测误差。在接收端,必须将参考图像与残差相加,以获得重建的图像。
对于第一个问题,即如何确定使用哪个存储器空间来存储残差图像,情况和分析类似于非残差图像的情况。有两个选择:要么仅在全局存储器中存储波形变换结果(WTR)并且从该全局存储器中读取该结果,要么首先在波形变换模块内部的全局存储器中存储WTR,然后将WTR复制到纹理存储器,然后从纹理存储器中将WTR读取至运动补偿模块(运动补偿执行参考图像数据和WTR的相加)。根据本发明的一个方面,选择第一方案。其具有可以节约从全局存储器向纹理存储器复制数据的附加成本(尽管该成本较低)这一优点。与上述非残差图像的情况的不同之处在于:第一,当对WTR进行采样时不需要插值操作;第二,已经发现,运动补偿模块的瓶颈是图像数据写操作,而不是WTR的读取。因此,在全局存储器中存储WTR而不将它们复制到纹理存储器是有好处的。
对于确定针对残差的Y、U、V分量的数据封装格式的问题,对于这些分量,波形变换的输入数据是独立的。参见图8c),在一个实施例中,选择三个1分量平面作为针对残差图像的封装格式。
本发明的一个具体优点是其非常高效,同时提供高精确度级别。
波形变换(WT)
下面,描述与波形变换块相关的更多细节。波形变换是重要的并且是在数字视频处理中广泛应用的变换。它们是不同图像和视频编码标准(比如JPEG、JPEG2000、MPEG-1、-2、-4、H.261、H.263、4等等)的关键组成部分。尽管存在大量的波形变换,波形变换使用非常相似的计算公式。尽管在本公开内容中仅示例地描述DCT(离散余弦变换,也称作“正向DCT”)和逆DCT(iDCT),但是原理上可以将相同的讨论应用于其它的波形变换。
在编码器中使用DCT,其将一组图像像素变换为系数;系数的数目与输入数据的数目相同。然后在解码器中使用逆DCT,用于将系数变换回像素值。最普通的情况是应用DCT/iDCT,以变换/重建8*8像素的2D图像数据,其中DCT公式为:
其中
8*8图像数据是f(x,y):x=0,...,7和y=0,...,7
8*8DCT系数是F(u,v):u=0,...,7和v=0,...,7
是常数。
逆DCT公式为:
可以用具有相同形式的矩阵乘法来表示两种变换(DCT和iDCT)。我们使用iDCT作为例子:
Pict=B*Coeff*BT (3)
所有矩阵是8*8维的,并且它们的元素为:
其中
令B=[b0 b1 ... b7],得到等价的矩阵表示:
或者令Mi,j=bjbi T,得到
由于DCT和iDCT如此重要,因此存在在不同的平台上的不同的软件/硬件实现。现有的基于GPU的实现1是基于等式3或者JPEG ANN快速算法的。这两种类型都可以达到与优化的CPU实施可比的性能,并且由于规则的存储器访问,第一种1具有比第二种高的性能。另一种提议2是基于等式5的GPU实现,获得了高效的GPU解决方案。然而,依然具有一些缺点:存储了用于计算的所有Mi,j矩阵,总共64*64个浮点值。这是对存储器空间的浪费,并且因此该方法效率不高。
1Fang B.,Shen G.,Li S.,Chen H.:Techniques for efficient DCT/iDCT implementation on generic GPU.In:Proceedings of IEEE International Symposium on Circuit and Systems(2005),pp.1126-1129
2Bo Han,Bingfeng Zhou,Efficient Video Decoding on GPUs by Point Based Rendering,In HWWS’06,Proceedings of the ACM SIGGRAPH/Euro-graphics conference on Graphics Hardware(Vienna,2006)
根据本发明的一个方面,波形变换(使用iDCT作为下面描述的例子)在GPU上作为CUDA内核进行运行。在上面描述了一些CUDA概念,比如内核、线程、线程块、以及网格。
在图3的系统202中,下列块与iDCT任务相关:主机上内核输入数据缓冲器216、视频解码应用218、内核程序222、设备上内核输入数据缓冲器224以及残差图像缓冲器228。
内核程序222包括所有内核。多个波形变换内核可以用于不同的数据块分辨率以及不同的常数矩阵(即,等式3中的矩阵B)。例如对于8x8 iDCT来说,使用一个内核kernel_iDCT_8x8就足够了。将基于CUDA的iDCT内核作为多个线程来执行。线程分批如下:一个线程处理一行上的所有数据元素,一个线程块处理固定数目(典型的,16或者8,记录为RESIDUAL_BLOCK_BASE_NUM)的8x8数据块。线程ID是2维索引,一个值代表在数据块内部的垂直位置,并且另一个值代表不同的数据块。块ID是1维的,并且对于每RESIDUAL_BLOCK_BASE_NUM个数据块,该块ID增加1。注意,该方案要求数据块的总数为RESIDUAL_BLOCK_BASE_NUM的整数倍。为了解决该问题,插入“伪”数据块(例如空数据块),如下所解释的。
GPU上的iDCT执行需要一些输入数据,这些输入数据存储在图3的内核输入数据缓冲器216和224中。尽管可以存储所有系数(即,等式3的矩阵Coeff中的所有数据),但是当大多数系数为零时,这种方案浪费太多存储器和CPU/GPU通信带宽。根据本发明一方面,更好的方案是仅存储非零系数。在一个实施例中,存储非零系数值和它们的坐标(即,该系数在等式3的矩阵Coeff中的位置)。该方案在存储器使用和带宽上更有效率。
当仅存储非零数据时,由于非零系数的数目对于不同数据块来说是不同的,因此每一个数据块需要的存储器大小是可变的。在图9所示的实施例中,为了让存储器大小统一,将系数数据存储进两个数据结构(例如存储区)中:第一公共数据结构904、904a是针对图像中所有非零系数的大型的1维(1D)纹理,包括值和坐标;第二数据结构902、902a是针对每一个数据块的统一大小的数据集合,包括1D纹理中的起始地址和非零系数的总数目。
第一线程901获得具有恒定的预定义大小和特定结构的输入数据902。输入数据902至少包括对1D纹理存储器903中的特定数据范围904进行标识的地址和长度值。第二线程901a获得具有相同大小和结构的不同输入数据902a,但是地址和长度值标识纹理存储器903中不同的范围904a。可以从纹理存储器903中获取用于处理的实际非零系数以及它们的矩阵坐标。图9b)示例地示出了系数和它们的坐标可以如何在1D数据结构904、904a中可进行格式化。可以看到,例如系数i,j+1和i,j+2是零,因此不存储它们。用于坐标的比特的数目(例如,每个是3比特)从矩阵大小得到。本发明的该方面具有下述优点:所有残差图像块的线程输入数据具有统一的存储空间,从而可以在内核中容易地访问它们。
在一个实施例中,iDCT输入数据包括图10所示的数据元素。这些是:大小独立的第一块1802,其存储图像的所有非零系数(包括值和坐标);以及大小统一的第二块1804,其存储针对每一个线程的输入数据,并与图9的块902、902a相对应。在块1802中,与图9的数据结构904、904a相对应,将来自一个数据块的系数和它们的坐标以连续地址存储。大小独立的数据块1802是针对完整图像的一个数据列表,而块1804具有分别针对每一个数据块的独立的数据。注意,将块1802分配为GPU上的CUDA纹理。
在一个实施例中,块1804至少包括下列数据元素:一个数据块中非零系数的总数1806、完整列表中非零系数的起始地址1808、残差图像中数据块的目标位置1810(即,在哪里写入iDCT结果)、以及指示DCT类型的一比特标志1812(即,帧DCT或者域DCT)。标志1812影响残差图像中的间隔值,即,在残差图像中具有相同水平坐标的相邻行上的两个像素之间的位置差异。
当在GPU上执行逆量化(IQ)时,存在如图10中的块1814所示的附加输入数据。块1814可以具有针对来自不同视频标准的不同IQ操作的不同数据元素。例如,针对MPEG-2,块1814可以具有下列元素:
-量化器矩阵索引,指示哪个量化器矩阵将用于IQ。所有量化器矩阵是IQ过程中使用的常量值;
-量化器缩放因子,用于对除了帧内DC(intra DC)值之外的所有系数执行逆量化算术;以及
-乘法因子,用于帧内DC IQ。如果在CPU上执行帧内DC IQ,则可以省略该值。
为了节约存储器,可以将多个值封装进一个数据元素中。可以在CPU上的解码步骤304期间,至少将要作为波形变换线程的线程输入数据而使用的那些数据收集到内核数据输入缓冲器块216中。然后通过图4或者图5的块310中的特定CUDA API调用,将所有数据复制203到GPU上的块224中。在一个实施例中,可以创建一个或者更多“伪”数据块,以让数据的总量为RESIDUAL_BLOCK_BASE_NUM的倍数。这些伪块中的数据应当使得相应线程进行无害的操作。例如,可以将目的地址设置在残差图像范围之外,并且将非零系数的数目设置为零。
对每一个图像执行iDCT。iDCT需要全局初始化操作,对于整个序列来说,全局初始化操作仅执行一次。初始化包括下列步骤:分配残差图像缓冲器,其中在全局存储器中分配残差图像数据(即,iDCT结果),并且可以分配附加存储器以处理上述“伪”数据块;以及准备常数矩阵,其中,准备等式3中的常数矩阵B用于iDCT计算。可以切换至针对任意其它波形变换的另一常数矩阵,而可以直接应用相同的处理步骤。准备的步骤包括选择恰当的常数矩阵。
由于在MC和iDCT中都使用残差图像,因此还可以在下述运动补偿中执行分配残差图像缓冲器的步骤。针对每一个图像的iDCT是图4中的块314,当还执行IQ时针对每一个图像的iDCT还可以是图5中的块315。可以如图11所示的下列步骤进一步将其内核分为:
在块1002中,读取统一大小的数据;
在块1004中,执行用于iDCT计算的初始化步骤。由于等式4用于计算,因此将求和结果初始化为零;
在块1006、1008、1010以及1012中,执行iDCT计算,其中顺序地处理所有非零系数。在读取每一个系数之后1008,可以可选地执行IQ1010。然后用等式3中的矩阵B的合适的常数系数乘以系数值,并且与求和结果相加1012。最后,在处理了所有非零系数之后,将结果修剪(clip)至给定范围1014,并且将结果输出至残差图像存储器1016。在块1016,如在下面“WT内核设计”节所解释的,在写入之前封装经修剪的值。
WT内核任务规范
如等式2所示,对于iDCT来说,内核任务主要是从系数计算图像数据。然而,对算法的选择不是小事。在一个实施例中,使用等式4,带来了比如US 2006/0056513或者EP1641278A2中披露的已知方法更快和更有效率的实现。时间成本减少大约50%。还极大的减少了对常数存储器的需求,从64*64个浮点值减少至仅仅64个浮点值。
WT数据组织
上面已经描述并且在图10中详细示出了用于在数据块上执行iDCT所需的数据。一个实施例中的数据组织的特征在于,针对非零系数使用两个数据结构(块802和804),并且在CUDA纹理缓冲器中组织所有系数。然而,在一些情况下,例如对于具有极高比特率的视频序列来说,直接存储所有系数(零和非零)是有利的。根据是在CPU还是GPU上执行逆量化(IQ),存在两个版本的所需的输入数据。可以将多个值封装进一个数据元素,以节约存储器。
WT内核设计
如上所述,在一个实施例中,内核设计的一些关键点是:使用一个线程来处理一个数据块中一行上的所有数据,使用“伪”数据块,以及使用封装的数据来用于写入。将来自一个线程的所有重建的残差图像数据封装进一个结构中,并且通过一次值分配操作写入存储器中。这些构思是彼此独立的(即,这些构思中的各个可以使用或者不使用)。第一个构思,即,使用一个线程来处理一个数据块中一行上的所有数据,是对于效率来说最关键的因素。
在示例的内核实现中,RESIDUAL_BLOCK_BASE_NUM是8。还可以将该方案应用于执行针对以例如MPEG-1、MPEG-4、H.264等其它标准编码的视频序列的iDCT。本发明原理上还可以用于在编码器中使用的DCT操作,例如具有与等式3相似的公式的其它波形变换可以使用本算法。等式3中的矩阵维度可以是除了8以外的其他整数。
运动补偿(MC)
下面,描述与运动补偿块相关的更多细节。
运动补偿(MC)是视频解码器中的基础模块。编码视频数据(通常被组织为方块(square block))包含:运动向量,运动向量指示了相似块在参考图像中的位置;以及残差图像数据,残差图像数据对编码块和参考块(或者一个或者更多参考块的插值结果)的差进行编码。MC可以找到参考块,执行恰当的采样和平均,并且加上残差图像数据,以重建图像。当数据是帧内编码并且不存在参考时,MC可以使用残差数据来用于图像重建。在MPEG-2中,针对逐行扫描序列的MC模块是非常简单的:预测模式(即,使用参考图像的模式)始终是帧预测,即,将运动向量分配给针对Y分量(亮度)数据的完整16*16宏块。
然而,由于逐行扫描序列在实际应用中非常普遍,因此该简单的MC已经具有非常大的实际价值。此外,由于MC的所有基本操作对于逐行扫描和隔行扫描视频是共享的,比如半像素采样、加上波形变换结果(即,残差图像数据)、以及写入解码的图像等,因此至隔行扫描序列的扩展是非常容易的。此外,逐行扫描视频已经包括了MPEG-2中所有的图像编码类型(帧内编码、预测编码以及双向预测编码)。
在执行运动补偿时,分析和解决下列问题:
-指定运动补偿的具体子任务,作为内核。为了最优化效率,内核执行高效构建的、数据并行的计算密集型任务。
-组织用于内核执行的输入和输出数据。可以在CPU和GPU功能中容易地访问数据,同时最小化CPU和GPU之间的数据通信。
-通过纹理获取来对参考图像进行采样。
根据本发明一个方面,MC作为GPU上的一个或者更多CUDA内核而运行。在图3中,下列块与MC相关:主机上内核输入数据缓冲器216、视频解码应用218、内核程序222、设备上内核输入数据缓冲器224、图像缓冲器226以及残差图像缓冲器228。
内核程序222包括所有内核。图12示出了针对CUDA执行的所有MC内核的可能的实现。下面给出对MC内核定义的更多解释。
在图12a)中,16x16、8x16以及8x8是不同的图像块分辨率;参考的不同情况是帧内、前向、后向以及双向。在分离的内核中分别处理块分辨率和参考的每一种组合。图12b)示出了另一种MC内核选择:在“xxxx_inter”内核426、428、430以及“xxxx_intra”内核402、410、418中,将针对帧间和帧内预测的三种参考情况,即前向、后向、双向,合并并一起进行处理。图12c)示出了MC内核的第三种选择,其中在一个内核432、434、436中将针对帧间和帧预测的所有参考情况进行合并并且处理。具体地,对于第二和第三种情况来说,可以将较大的块分为较小的块并作为较小的块进行处理。
在CUDA中,将MC内核作为多个线程加以执行。内核设计依赖于所使用的线程分批。在一个实施例中,使用一个线程处理一个图像块中一行上的所有像素,并且使用一个线程块处理固定数目的图像块(典型地是16或者8,记录为PICT_BLOCK_BASE_NUM)。
GPU上的MC执行需要一些输入数据,这些输入数据包括在图3的内核输入数据缓冲器块216和224中。在“MC数据组织”节中进一步解释了与MC相关的数据元素。与上面对于波形变换所描述的类似,可以创建一个或者更多“伪”数据块,以让数据块的总数为PICT_BLOCK_BASE_NUM的倍数。
对于每一个图像执行MC,MC需要全局初始化操作,对于整个序列,全局初始化操作仅执行一次。如图13所示,初始化包括下列步骤:分配残差图像缓冲器502、分配用于写入的图像缓冲器504、以及分配用于读取的图像缓冲器506。
在分配残差图像缓冲器的块502中,在全局存储器中分配残差图像数据(即,波形变换结果)。
在块“分配用于写入的图像缓冲器”504中,在全局存储器中分配用于写入的图像数据(即重建的图像)。分配附加存储器,以用于处理“伪”图像块。
在“分配用于读取的图像缓冲器”的块506中,将用于读取的图像数据(即,参考图像)分配作为纹理。启用针对线性过滤和数据归一化的标志。在下面的“通过纹理获取的图像采样”节中给出更多的解释。
在图4的MC模块316中进行针对每一个图像的MC。还可以根据图14中所示的下列步骤进一步划分其内核。这些步骤对于上述所有MC内核都是可应用的。
在读取残差像素数据的块602中,如下面“内核设计”节中所进一步解释的,使用封装的数据来用于读取,以减少存储器访问的次数。
在读取参考像素数据的块604中,如在“通过纹理获取的图像采样”节中所解释的,纹理获取用于对参考图像的访问以及采样。如果将多个参考类型合并到一个内核中,使用条件性检查来执行针对不同参考类型的不同操作。在将参考数据与残差数据相加的块606中,将参考数据与残差数据相加。如果参考类型是零参考图像(即,帧内MB),则残差数据直接给出结果。在修剪块608中,将来自块606的相加结果修剪至适当范围,通常该范围是[0,255]。更具体地,如果值小于0,则将该值设置为0;如果值大于255,则将该值设置为255;否则不进行改变。在将修剪的数据写入图像缓冲器的块610中,如下面“MC内核设计”节中所解释的,将修剪的值封装并且写入用于写入的图像缓冲器中。
MC内核任务规范
如图13所示,每一个MC内核的基本操作是:找到参考块,进行数据采样,读取残差图像数据,以及执行加法。几个因素让该过程灵活。对于MPEG-2逐行扫描序列来说,这些因素是:
-图像块的分辨率:对于Y分量,始终为16x16,对于U和V分量,取决于序列的色度格式,可以为16x16、8x16、或者8x8。
-参考块:存在四种情况,比如零参考块、一个前向参考块、一个后向参考块、以及两个参考块(双向)。
-参考上的采样位置:也有四种情况。水平和垂直坐标都可以位于整数或者半值(两个相邻整数位置的中间)位置。
在一个实施例中,如果在一个内核中处理不同情况,则针对每一个线程执行条件性检查。由于维护了并行性,所以这比不同的线程进入不同的分支而言好得多。
在一个实施例中,将较大块分为几个较小块,使得它们的大小统一,并且对于不同的分辨率使用不同数目的内核。例如,可以将16x16块划分为四个8x8块并进行处理,8x16块可以分为两个8x8块并进行处理。
取决于不同的情形,可以在一个内核中处理或者不在一个内核中处理参考的变化:
如果图像分辨率高以及/或者比特率高,则对于不同的参考情况使用不同的内核是有利的。在一个实施例中,对于4:4:4色度格式来说,总共存在4个内核,分别与零、一个前向、一个后向以及两个参考相对应。对于4:2:0和4:2:2格式来说,存在8个内核,4个用于Y分量数据,4个用于UV分量数据。在一些图像中,使用的参考类型少于四个(例如,在帧内编码图像中所有图像块都是零参考类型)。因此,执行的内核少于理论值。
如果不满足上述条件,则将一些参考类型合并进一个内核并且使用针对不同类型的分支的条件性检查是有利的。对于参考类型来说,可以存在不同的组合风格。
MC数据组织
运动补偿所需的数据包括:
-待运动补偿的块的位置(如左上像素坐标,或者到该点的常数偏移量)
-参考类型,其为指示零、一个前向、一个后向、两个参考的标志。
-前向参考块的位置(可以由运动向量或者绝对坐标等来代表)。
-后向参考块的位置(可以由运动向量或者绝对坐标等来代表)。
如果对于不同的参考类型定义了不同的内核,则一些数据不是必需的。例如,如果由专用内核来处理每一个参考类型,则不需要参考类型和未使用参考块位置。
当在一个内核中处理不同参考时,将具有相同参考类型的块的数据封装在一起,这最小化了进入不同分支的线程的出现次数。
在运行在CPU上的可变长度解码过程期间收集这些数据。然后通过特定CUDA API调用,将所有数据复制到GPU上。最后,内核在GPU上以多线程方式运行:读取这些数据,执行MC操作,并且将补偿值写入到重建的图像。
MC内核设计
对于算法效率来说,内核设计是关键的。由于对每一个像素执行相同的计算,所以简单的实现会是在分离的线程中分别处理单个像素。然而,该解决方案在性能上非常糟糕。主要问题在于MC是存储器密集型的,而不是计算密集型的,因此不是正好适合CUDA实施。下面的措施提高了效率:
-使用一个线程来处理一个图像块中一行上的所有像素。在一个实施例中,使用一个线程块来处理固定数目(典型地是16或8,记录为PICT_BLOCK_BASE_NUM)的图像块。以及针对线程ID使用2D索引,一个值用于垂直位置,另一个值用于不同的图像块。
-使用封装的数据来用于读取。在一个实施例中,将线程中所需的所有残差图像数据封装进一个结构,并且通过一次值分配操作来读取这些数据。
-使用封装的数据来用于写入。在一个实施例中,将来自一个线程的所有经运动补偿的像素封装进一个结构,并且通过一次值分配操作写入存储器中。
-使用附加存储器来处理“伪”图像块。
如前所述,在一个线程块中处理PICT_BLOCK_BASE_NUM个图像块。如果图像块的总数不是PICT_BLOCK_BASE_NUM的倍数,则与伪图像块相对应的一些线程将进行非法操作。简单的解决方案是引入对块ID和线程ID的条件性检查。然而,这是低效率的。根据本发明的一个方面,更好的解决方案是创建一些“伪”图像块,以让总数成为PICT_BLOCK_BASE_NUM的倍数。在这些伪块中,相应线程执行无害的操作。例如,将目的地址设置在原始图像范围外部,使得不干扰相关数据,并且参考位置与块位置相同。在该例子中,可以在图像数据分配阶段分配很少的附加存储器,以包含这些外部像素。
注意,上述措施是彼此独立的,即它们中的各个是可以使用或者不使用的。对于效率而言,第一个因素(使用一个线程来处理一个图像块中一行上的所有像素)是最关键的因素。由此极大地增强了性能。
通过纹理获取的MC图像采样
在运动补偿期间,将参考像素值加到残差图像数据上。通过纹理获取来实现该任务。将目标位置(整像素或者半像素)设置为纹理坐标,并且可以使用texfetch(CUDA API调用)来获得像素值。如果纹理坐标指示半像素位置,则自动执行采样(插值)。代码类似于下述:
INT_TYPE pixel_val= (6)
texfetch(tex_ref_picture,x_coord,y_coord)*RANGE+ROUND
图15示出了与图3类似的使用基于CUDA的视频解码系统的改进的示例视频解码过程。但是,来自多个内核的任务被封装进一个内核。具体地,图15所示的实施例不具有残差图像缓冲器。取而代之地,所有GPU任务(IQ、波形变换、以及MC)是一起执行的,从而有利地,中间存储不是必要的,并且不需要残差图像缓冲器的全局存储空间。
图16示出了与图4类似的使用基于CUDA的视频解码系统的相应的改进的示例视频解码过程。根据图15所示的实施例,在单个内核314a中执行GPU任务(逆量化IQ、波形变换、以及MC)。从而可以节约用于残差图像缓冲器的全局存储空间。
可以使用一个或者更多CPU以及一个或者更多基于CUDA的GPU来实施本发明。但是,还可以基于GPU本地指令和编程语言之间的应用程序接口(API)来操作一个或者更多、甚至所有的图形处理单元(GPU)。还可以在将任务分配给一个或者更多GPU和CPU的软件中实施本发明。通常,这种软件是在数据载体(比如光盘)上存储并且分发的。根据本发明的一个方面,一种计算机可读介质存储了用于引起计算机执行如方法权利要求之一所披露的方法的指令。根据本发明的另一个方面,制造产品包括提供指令的机器可读介质,当机器执行该指令时,该指令引起机器执行包括如方法权利要求之一披露的方法在内的操作。
此外,还可以将本发明应用于对其它视频标准的视频序列的解码上,其它视频标准是比如MPEG-1、MPEG-4、H.264等等。
可以在视频编解码器中使用解码器,该视频编解码器在TV质量的数字视频/音频应用(比如数字电视(有线、卫星以及地面广播)、视频点播、数字通用碟(DVD)、个人计算、卡付费、测试和测量、等等)中广泛使用。
将理解,这里仅通过示例描述了本发明,可以在不背离本发明范围的情况下进行细节上的修改。
可以独立地或者以任意恰当组合的形式来提供说明书和(如果适合)权利要求以及附图中披露的每一个特征。如果恰当,可以将特征实现为硬件、软件、或者二者的组合。如果恰当,可以将连接实施为无线连接或者有线(但不一定是直接的或者专用的)连接。权利要求中出现的附图标记仅作为说明之用,而不应当对权利要求的范围具有限制影响。