使用GPU加速H.264编码分析

July 14th, 2011 2 comments

继前面的“GPGPU”和“CUDA和OpenCL”的简介后,接下来分析一个具体的使用案例:是否可以用GPU搭建一个高性能的H.264编解码服务器?

设想一个简单的需求:

  1. 把其他编码的视频转换为指定码率的H.264;
  2. 在转换过程中做一些简单的处理(例如增删水印、字幕的处理、声音的处理等);
  3. 需要封装成指定的一种container格式,比如mp4或mkv。

 

ffmpeg完成此项工作的大概过程是:

  1. 识别文件格式,打开视频文件容器,得到video_stream;
  2. 使用libavcodec把video_stream解码成原始的frame数据;
  3. 在frame的基础上做“需求2”的处理;
  4. 编码成H.264格式;
  5. 存放到指定格式的容器中(mp4或者mkv)。

“过程1”应该是一个轻量操作,且对于现有视频格式速度应该很快(播放器看片的时候不可能先等上几秒分析一把格式再开始播放吧?)。

“过程2”需要把原有的视频编码解码并转为ffmpeg内部使用的格式,速度会比上第一步慢不少,但是应该也是可以接受的。当然在码率比较高的情况下也会非常缓慢(在Pentium4时代的机器上看1080p的高清视频很卡)。

“过程3”是需要对每一帧进行处理,那么这步是可高度并行化的应该可以放到GPU进行。

“过程4”一定是最慢的一个环节:H.264需要将图像分割成很多个宏块, 然后利用视频帧图像的帧内和帧间的相关性, 采用帧内预测或帧间预测的编码模式, 对各个宏块进行压缩。然后形成帧,组成为码流。整个过程复杂,但宏块儿的处理是可以高度并行化的操作,应该可以放到GPU进行。

“过程5”和“过程1”类似。

所以如果想用GPU加速以上的过程,那么把“过程4”和“过程2”的密集计算从CPU上转到GPU上,应该是可能的发力点。

如果要设计这个系统,软件自底层到上层有几点需要考虑:

  1. 如果显卡可以指定,应该是Nvidia。在Linux下有完善的开发运行环境,且同时支持CUDA和OpenCL;
  2. 如果选定Nvidia显卡,那么根据前文的分析,使用CUDA是更好的GPU计算架构。并且应该使用最新的CUDA 4.0版本,因为在多GPU上能更方便的开发,并且GPU直接访问内存方面也做出了改进(CUDA 4.0的新特性详细见这里)。
  3. 在决定了以上基础设施后,为了提高单机的处理能力程序应该用何种架构来编写?单进程多线程还是多进程单线程?

关键在于在程序里如何更好的调用CUDA:

  1. 单进程多线程方式
    • 每个线程进行一个视频的转换,每个线程在其线程内部直接使用CUDA;
    • 有单独的CUDA线程,其他线程当需要时通知此线程进行运算;
  2. 多进程单线程
    • 每个进程进行一个视频的转换,在其进程内部各自独立的使用CUDA;
    • 有单独的GPU进程,其他进程当需要进行GPU运算的时IPC通知此进程进行;

在我看来,2-1的方式是最简单直接的,可以直接基于ffmpeg来实现,只需单把可并行化的部分从CPU移到GPU。但是CUDA 4.0是否支持这样做?这样做效率是否最高?

硬件配置上也有以下的问题:

  1. 是否需要在一个Server上配置多块儿GPU?虽说CUDA 4.0已经声称对此有很好的支持,但是其是否能利用好?另外受限于硬件瓶颈的一些限制(CPU计算能力、内存速度、总线速度),配置几块儿GPU比较合适?
  2. 如果使用ffmpeg,那么在一台拥有16核的服务器上,理论可以同时启动16个ffmpeg进程(单线程运行)。加入GPU运算后单个视频处理速度的提高是一定的,但是否还有这么大的并行能力?以及单位时间段内的处理能力是否提升?
  3. 加入GPU后硬件成本的增加是否值得?与单独使用CPU的相比单位成本是否更低?选用哪款Nvidia显卡的性价比最高?
  4. 如何看GPU的load average和top?

最后这件事情最难的一点在于:需要对CUDA、ffmpeg、H.264、硬件都有相当深入的了解才能做好这样的一个系统