继前面的“GPGPU”和“CUDA和OpenCL”的简介后,接下来分析一个具体的使用案例:是否可以用GPU搭建一个高性能的H.264编解码服务器?
设想一个简单的需求:
- 把其他编码的视频转换为指定码率的H.264;
- 在转换过程中做一些简单的处理(例如增删水印、字幕的处理、声音的处理等);
- 需要封装成指定的一种container格式,比如mp4或mkv。
ffmpeg完成此项工作的大概过程是:
- 识别文件格式,打开视频文件容器,得到video_stream;
- 使用libavcodec把video_stream解码成原始的frame数据;
- 在frame的基础上做“需求2”的处理;
- 编码成H.264格式;
- 存放到指定格式的容器中(mp4或者mkv)。
“过程1”应该是一个轻量操作,且对于现有视频格式速度应该很快(播放器看片的时候不可能先等上几秒分析一把格式再开始播放吧?)。
“过程2”需要把原有的视频编码解码并转为ffmpeg内部使用的格式,速度会比上第一步慢不少,但是应该也是可以接受的。当然在码率比较高的情况下也会非常缓慢(在Pentium4时代的机器上看1080p的高清视频很卡)。
“过程3”是需要对每一帧进行处理,那么这步是可高度并行化的应该可以放到GPU进行。
“过程4”一定是最慢的一个环节:H.264需要将图像分割成很多个宏块, 然后利用视频帧图像的帧内和帧间的相关性, 采用帧内预测或帧间预测的编码模式, 对各个宏块进行压缩。然后形成帧,组成为码流。整个过程复杂,但宏块儿的处理是可以高度并行化的操作,应该可以放到GPU进行。
“过程5”和“过程1”类似。
所以如果想用GPU加速以上的过程,那么把“过程4”和“过程2”的密集计算从CPU上转到GPU上,应该是可能的发力点。
如果要设计这个系统,软件自底层到上层有几点需要考虑:
- 如果显卡可以指定,应该是Nvidia。在Linux下有完善的开发运行环境,且同时支持CUDA和OpenCL;
- 如果选定Nvidia显卡,那么根据前文的分析,使用CUDA是更好的GPU计算架构。并且应该使用最新的CUDA 4.0版本,因为在多GPU上能更方便的开发,并且GPU直接访问内存方面也做出了改进(CUDA 4.0的新特性详细见这里)。
- 在决定了以上基础设施后,为了提高单机的处理能力程序应该用何种架构来编写?单进程多线程还是多进程单线程?
关键在于在程序里如何更好的调用CUDA:
- 单进程多线程方式
- 每个线程进行一个视频的转换,每个线程在其线程内部直接使用CUDA;
- 有单独的CUDA线程,其他线程当需要时通知此线程进行运算;
- 多进程单线程
- 每个进程进行一个视频的转换,在其进程内部各自独立的使用CUDA;
- 有单独的GPU进程,其他进程当需要进行GPU运算的时IPC通知此进程进行;
在我看来,2-1的方式是最简单直接的,可以直接基于ffmpeg来实现,只需单把可并行化的部分从CPU移到GPU。但是CUDA 4.0是否支持这样做?这样做效率是否最高?
硬件配置上也有以下的问题:
- 是否需要在一个Server上配置多块儿GPU?虽说CUDA 4.0已经声称对此有很好的支持,但是其是否能利用好?另外受限于硬件瓶颈的一些限制(CPU计算能力、内存速度、总线速度),配置几块儿GPU比较合适?
- 如果使用ffmpeg,那么在一台拥有16核的服务器上,理论可以同时启动16个ffmpeg进程(单线程运行)。加入GPU运算后单个视频处理速度的提高是一定的,但是否还有这么大的并行能力?以及单位时间段内的处理能力是否提升?
- 加入GPU后硬件成本的增加是否值得?与单独使用CPU的相比单位成本是否更低?选用哪款Nvidia显卡的性价比最高?
- 如何看GPU的load average和top?
最后这件事情最难的一点在于:需要对CUDA、ffmpeg、H.264、硬件都有相当深入的了解才能做好这样的一个系统。
http://www.qingran.net/2011/07/%E4%BD%BF%E7%94%A8gpu%E5%8A%A0%E9%80%9Fh-264%E7%BC%96%E7%A0%81%E5%88%86%E6%9E%90/