第一时间了解Real最新资讯
迎着新春的朝气是时候来一期荡气回肠的干货满血回归了。本期终于迎来我们的videocoding专家吴刚,为大家解读如何基于GPU加速实现高效高质的视频编码。
没错!瑞哥采访到了攻城狮吴刚大大!面对专家崇拜感油然而生,赶紧拿小本本记下来给大家分享。
01在您看来,GPU加速为何对视频编码来说至关重要呢?
近些年来,随着视频应用普及,网络带宽资源等的不断提升。高分辨率,高码率逐渐成为视频业务的主流,随之而来是的视频压缩算法的复杂度也日益增长。从H./AVC到H./HEVC,编解码复杂度成倍的增加,导致在现有的处理平台上已经很难满足高清/超高清视频图像的实时转码/编码,这极大的制约了高清视频业务的发展。另一方面,图形运算的特点是大量同类型数据的密集运算——如矩阵运算,GPU的微架构就是面向适合于矩阵类型的数值计算而设计的,大量重复设计的计算单元,而且数据之间没有较多逻辑关联性。所以随着GPU强大的并行通用计算(GPGPU)能力的发展,利用GPU对视频编解码进行加速很好的解决了上述的制约。
02RealMediaHD在GPU加速方面有怎样的优势?
迄今为止,已有许多关于使用GPU加速视频编解码以及图像处理的文章发表,如Table1所示。
可以看出目前GPU加速视频编码的主要集中在运动估计(ME,MotionEstimate),运动补偿(MC,MotionCompensation)和帧内预测(IntraPrediction)。
Real近些年来一直致力于研究和开发基于GPU版本加速的编码器,在提供高速转码的同时保障超清画质。目前,GPGPU的编程框架主要有两种,一种是Nvidia公司推出的CUDA(ComputeUnifiedDeviceArchitecture),目前只能在Nvidia公司的显卡中使用;另一种是由非盈利性技术组织KhronosGroup发起的OpenCL(OpenComputingLanguage),是业界的标准,通用性更广。所以Real选择了后者。
凭借着多年与Intel合作积累的经验,RealMediaHD是全球第一家基于IntelGPU使用QuickSyncVideo部分功能完成私有编码格式的4K超实时转码解决方案。无论从速度上还是画质上,IntelQuickSync都是不错的选择,Real的GPU加速正是基于此,现在市场上广泛的GPU加速策略,主要就是运动估计,运动补偿以及帧内预测,这些策略粒度较粗糙,而且考虑到并行度以及计算量,会有一些舍入,例如运动搜索范围,搜索点数,MV代价,所以一个较为直接的问题就是GPU加速导致画质下降。与竞争对手不同的是,RealMediaHD采用的是更为精细控制的devicesideVME(以下简称VME)来指导RV11的整个编码流程,VME提供更为精细化的IME(Integermotionestimation),REF(Motionestimationrefinement),SkipandIntracheck(SIC)等等,可以根据QP以及帧类型设置不同的Inter/Intracostfunction,可以多帧参考决定最佳的参考帧,可以根据帧结构进行双向加权预测等等。另外借助于Intel平台的通用性,RealMediaHD可以为广大用户提供高画质的GPU加速方案。
03这样的优势反映在实际应用过程中带来的好处是什么?
主要体现有3点。
1、RealMediaHD有了GPU的加速,可以让用户和合作伙伴更快的产生高清RMHD内容,这是很重要的一个特性,试想如果编码时间过长,那用户对于产品的感受是相当糟糕的。尤其是当前快节奏的社会,大家对时间要求很严格。图1展示了开启GPU加速和没有GPU加速的编码速度对比。可以看出在4K序列上,GPU加速可以在一般家用的IntelCorei7上,达到接近每秒50帧的超实时转码速度。
图1.有/无GPU加速之编码速度对比
2、IntelGPU使用较为广泛,目前基本上所有的IntelCPU都集成有核芯显卡,支撑性较好。
3、GPU加速,画质损失较少。图2和图3分别是没有GPU加速和开启GPU加速在图像细节上的表现。以pRaceHorse为例。
图2.DisabledGPUaccelerate
图3.EnabledGPUaccelerate
04在设计RealMediaHD时,Real工程师团队的设计思路是如何的呢?
首先我先简单介绍下devicesideVME。
准确的说是Intel开发的一款基于OpenCL1.2以及H./AVC的一个扩展。由于GPU倾向于大规模数据计算,所以VME是基于16x16块MB一整帧图像做ME。目前有三个版本,分别是VMEextension1.0、VMEextension2.0和DevicesideVMEextension(也叫VME++)。RealMediaHD用的是第三种。前面两个版本的VME较为粗略,只提供简单的ME,INTRAPREDICTION功能,用户不需要去单独写OpenCLkernel。而DevicesideVME提供了非常非常多的接口,需要用户根据自己的需求去写kernel,然后在GPU上执行,再将所需要的信息回传到CPU。这一点CPUGPU之间的数据传输是不可避免的,除非整个编码器都在GPU端,但是我们可以尽量减少I/O次数,用最优的方法优化数据传输。在后面我会分享一些GPU数据传输的经验。
DevicesideVME有三大部分,即IME,REF,SIC。RealMediaHD主要用的就是这三部分功能完成GPU加速。IME执行MB的整像素搜索,会得到最佳MVs,相应的Cost以及当前MB最佳的划分方式。REF在IME的基础上作进一步的分像素优化。包含两部分Fractionalmotionestimation(FME)和Bidirectionalmotionestimation(BME)。SIC也包含两部分,Skipcheck(SKC)和Intrapredictionestimation(IPE)。分别作Skip模式检查和帧内预测。图4展示了一个简单的DevicesideVME调用流程。
图4.一个简单的DevicesideVME调用流程
在使用上,RealMediaHD提供了灵活的控制。我们会去检测当前GPUdevice是否支持DevicesideVME扩展以及OpenCL的版本,如果支持的话,就会在Deviceextensions字符串中找到”cl_intel_device_side_avc_motion_estimation”。然后按照VME来加速。否则,则按照纯CPU流程去加速。由于DevicesideVME是基于H.实现,而RealMediaHD采用的是全新的RV11编解码器,RV11是继承于RMVB时代的RV10,是我们Codec团队研发的新一代高效编解码器,与H.有很大的不同,RV11编码单元尺寸支持8x8到64x64,而H.只支持16x16MB。导致16x16以上的块无法直接使用VME的结果,所以我们采取间接使用VME信息来帮助RV11快速决定编码模式。RV11GPU编码框架如图5所示。在每一帧送进Encode之前,先进行GPU端的VME,执行完成后将必要数据(包含Intramodes,MVs,Shapepartitionsetc.)Mapping到CPU端内存,然后为后续CompressFrame提供帮助。
图5.RV11GPU编码框架
RV11会根据编码块大小决定VME信息用到何种程度。16x16块以下,会根据Shape信息跳过不必要的Split,这就节省了大部分比较耗时的RDO过程。同时,高精度MVs信息直接省去了ME过程,多帧参考可以快速决定最佳参考帧,由于H.Intramode只有9种,所以VME获得的Intra信息可以很好的指导RV11,至少有一个大致预测方向,杜绝了不必要的IntraRDO。由于整个IPE过程是基于原始帧执行的,所以在高码率情况下,可以直接替代。当编码块大于16x16时,依然可以使用VME,第一种:对视频图像进行下采样,这样原来的64x64就对应下采样后的16x16块,再执行一遍VME,之后根据第二遍VME信息指导32x32和64x64这两层编码。第二种,不进行下采样,仍然使用原分辨率的VME信息,做一些快速算法,例如MVs合成,块的划分方式提前决定等等。
与此同时,为了使得ME结果更为准确,在考虑SAD的同时也需考虑MV比特数,这就导致GPU在执行时每个MB都有dependency,为了最大化并行度,我们采用了类似于45°wavefront的方式,如图6所示。
图6.45°wavefrontprocessing
图7.QCIFworkgroup分配
IntelOpenCLruntime使用的是rasterdispatch方式分配workgroup,假设我们处理一个QCIF图像,如图7所示,workgroup处理的每个MB顺序就是(0,0),(1,0),(10,0),(0,1),(10,1),(0,8),(10,8),这样就不是我们想要的wavefront方式,所以我们重新映射了OpenCLworkgroup执行顺序,使得并行度最大化。
05根据您优化RealMediaHD编码器的经验,您有什么样的建议分享给大家?
说一下我在做RealMediaHDGPU版本时总结的一些经验。
1、CPU和GPU各有所长,视频编解码中涉及到多种类型的操作,因此需要将CPU和GPU结合使用,GPU执行操作最好使用异步方式,然后利用OCLevent来同步数据,才能达到最佳的效果。
2、因为GPU与CPU的交换速度很慢,因此要尽量减少二者之间的数据交换,将数据尽可能地留在GPU中进行计算而不是反复读写。尽量一次性多读写数据,避免多次小数据量读写,尽量将数据整合到一个数据结构中,比如kernel需要8个int型数据,使用一个cl_int8参数比8个int参数好。
3、OpenCL内存分配方式很重要,对于IntelGPU,尽量分配“Zerocopy”型内存,因为Zerocopy内存可以最小化内存占用同时使I/O性能最大化。如何分配:
1)使用CL_MEM_ALLOC_HOST_PTR,让runtime来分配Zerocopy内存。
2)如果使用CPU端已经分配好的数据内存,尽量用CL_MEM_USE_HOST_PTR,同时要求分配大小是64bytes(cachelinesize)整数倍,对齐到Pagesize的边界(bytes)
4、尽量使用Map方式进行数据读写,如clEnqueueMapBuffer()。
5、避免让GPU执行过多的分支语句。如if,switch,for,do等等。
一气看完顿时能量满格有木有!为我们的攻城狮大大点赞!预告~我们下期将为大家带来以“RMHD在实时直播上如何通过码率控制实现优质视频体验”为主题的学习内容。好好学习,多多银川治白癜风最好的医院江西白癜风医院
转载请注明地址:http://www.kinghoo-ind.com/btjs/10702.html