目标
视频的硬件解码近来发展非常快速,尤其是在低功耗的设备上。本教程会讲述一些硬件加速的背景知识并解释一下GStreamer是怎么做的。
悄悄告诉你,如果设置正确地话,我们什么也不用做,GStreamer自动做完这一切的。
介绍
视频解码是非常消耗CPU的一个任务,尤其是1080P这种高分辨率的高清节目。幸运的是,现在的显卡都带了可编程的GPU,如果我们用GPU用来做视频解码,那么CPU就可以解放出来做其他的任务了。低功耗的CPU是无法做解码这样的工作的,这时硬件的配合就是必须的了。
目前来说(2012.07),每个GPU的制造商都提供了访问它们的硬件的方法(API),不幸的是各家并不相同,并没有一个强制的标准。
VAAPI(Video Acceleration API):2007年Intel设计的,目的是在Unix操作系统的XWindow系统下运行,现在开源了。现在不仅仅局限于Intel的GPU了,其他制造商也可以使用了。GStreamer通过gstreamer-vaapi和fluvadec这个插件来使用。
VDPAU(Video Decode and Presentation API for Unix):2008年NVidia设计的,最早也是运行在Unix的XWindow系统下,现在同样开源了。虽然同样已经是开源库了,但除了NVidia自己外还没有其他制造商使用。GStreamer通过vdpau和fluvadec这个插件来使用。
DXVA(DirectX Video Acceleration):微软为了Windows系统和XBox360定制的。GStreamer通过fluvadec这个插件来使用。
XVBA(X-Video Bitstream Acceleration):AMD设计,在linux操作系统的XWindow系统下下X Video的扩展。目前在AMD的ATI显卡中有支持。GStreamer通过fluvadec这个插件来使用。
VDA(Video Decode Acceleration):应用于Mac OSX10.6.3之后,仅仅加速H.264的解码,GStreamer通过fluvadec这个插件来使用。
OpenMAX(Open Media Acceleration):由非盈利性联合Khronos Group设计的,是一组跨平台的C语言编程接口。GStreamer通过gstreamer-omx这个插件来使用。
OVD(Open Video Decode):AMD的又一个API,GStreamer目前不能使用这个接口。
DCE(Distributed Codec Engine):一个开源的软件库(libdce)和TI定制的API,提供给linux系统和ARM平台的。GStreamer通过gstreamer-ducati插件可以使用。
硬件加速视频解码插件内部的工作原理
通常这些API提供了一系列的功能,比如:视频解码,后处理,解码帧的描述,或者把帧下载到系统内存等等。相应的,不同的功能插件一般是给不同的element使用的,这样pipeline可以适应任何需求。
例如:gstreamer-vaapi这个插件提供了vaapidecode、vaapiupload、vaapidownload、vaapisink这些element,允许通过VAAPI来使用硬件加速功能,上传原始视频帧数据到GPU内存,下载GPU帧到系统内存并且描述GPU帧的内容。
这里区分传统的GStreamer帧(在系统内存中)和由硬件加速API生成的帧是很重要的。硬件加速生成的帧位于GPU的内存中,是GStreamer不能直接操作的。通常他们是下载到系统内存中,然后就可以被当成普通帧来处理了,但留在GPU中由GPU来显示效率是最高的。
GStreamer需要追踪这些“硬件缓冲区”,因为这样传统的缓冲区可以继续从一个element流向另一个element,但他们的内容尽皆是硬件缓冲区的ID或者Handler。比如:一个appsink获得了硬件缓冲区ID,硬件缓冲区什么都不会响应,因为它们只能由生成它们的插件来处理。
为了让这个更加明确,这些缓冲区都有特殊的Caps,就像video/x-vdpau-output或者video/x-fluendo-va这样。在这种方式下,GStreamer的自动插入机制不会试着把硬件缓冲区去传给传统的element——因为他们根本风马牛不相及。而且,使用了这些Caps之后,自动插入机制就可以使用硬件加速来搭建pipeline了,因为,在VAAIP解码器之后,只有VAAPI sink这一种element是可以连接上去的。
这些都说明,如果一个硬件加速的API在系统中可用而且对应的GStreamer插件也有的话,playbin2等自动连接的element可用随意的使用它们来搭建pipeline,应用不需要做什么特殊的处理。
当playbin2必须在一些element中选择时,就像是选择传统的软件解码还是硬件加速的解码,它会使用rank来决定。这个rank属性是每个element都有的,它会指明优先级,playbin2会选用最高的rank的element来搭建pipeline。
所以,playbin2是否使用硬件加速的element取决于当时所有可用的element的rank值。而且,最简单地确保硬件加速的element被选中的方法是修改rank属性的值。代码如下:
static void enable_factory (const gchar *name, gboolean enable) {
GstRegistry *registry = NULL;
GstElementFactory *factory = NULL;
registry = gst_registry_get_default ();
if (!registry) return;
factory = gst_element_factory_find (name);
if (!factory) return;
if (enable) {
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), GST_RANK_PRIMARY + 1);
}
else {
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE (factory), GST_RANK_NONE);
}
gst_registry_add_feature (registry, GST_PLUGIN_FEATURE (factory));
return;
}
传给方法的第一个参数是要修改的element的名字,比如:vaapidecode或者fluvadec。
这里主要的方法是gst_plugin_feature_set_rank(),它会设置element的rank。为了方便起见,rank分成NONE,MARGINAL,SECONDARY和PRIMARY,但任何数字都可以的。比如我们可用给某个element设置PRIMARY+1,那么它就比其他设置成PRIMARY的rank高,设置一个element的rank是NONE,会让自动连接机制屏蔽它(永远选不上)。
硬件加速视频解码和GStreamer的SDK
GStreamer的SDK在2012年七月前是没有硬件加速的视频解码的插件的。主要原因是有些还没有完全写完,还有一些问题。但请记住这个情况会在不久改变。
有些插件可用在它们公开源码的基础上自己编译出来,使用Cerbero编译系统。有些插件是供应商已经编译好了。
下面会简单介绍一下当前这些插件的情况。
vdpad在gst-plugin-bad
针对VDPAU的GStreamer element,在gst-plugin-bad里面
支持mpeg2,mpeg4和H264的编解码
gstreamer-vaapi
针对VAAPI的GStreamer element,项目的网址请猛戳
这里
。
支持mpeg2,mpeg4,H264,VC1和WMV3的编解码
可用直接和Clutter配合使用,这样帧就可以一直在GPU里面
和playbin2兼容
gst-omx
针对OpenMax的GStreamer element,项目网址请猛戳
这里
。
在不同的硬件下支持不同的编解码
fluvadec
针对VAAPI,VDPAU,DXVA2,XVBA和VDA的GStreamer element.
根据不同的API,支持不同的编解码
MPEG2 | MPEG4 | H.264 | VC1 | |
---|---|---|---|---|
VAAPI |
✓ |
✓ |
✓ |
✓ |
VDPAU |
✓ |
✓ |
✓ |
✓ |
XVBA |
✓ |
✓ |
||
DXVA2 |
✓ |
|||
VDA |
✓ |
可用直接和Clutter配合使用,这样帧就可以一直在GPU里面
和playbin2兼容