GStreamer——教程——播放教程8:Hardware-accelerated video decoding

播放教程8:视频解码硬件加速

目标

随着低功耗设备变得越来越普遍,硬件加速视频解码已经迅速变为一种必需特性。这篇教程(实际上更像一篇讲义)阐述了硬件加速的一些背景以及GStreamer如何从中收益。

如果正确设置,你不需要做任何特殊工作来激活硬件加速;GStreamer将自动启用它。

介绍

视频解码是非常消耗CPU的一个任务,尤其是1080P这种高分辨率的高清节目。幸运的是,现在的显卡都带了可编程的GPU,如果我们用GPU用来做视频解码,那么CPU就可以解放出来做其他的任务了。低功耗的CPU是无法做解码这样的工作的,这时硬件的配合就是必须的了。

目前来说(2016年6月),每个GPU的制造商都提供了访问它们的硬件的方法(API),不幸的是各家并不相同,并没有一个强制的标准。

截至2016年6月,至少存在8种不同的视频解码加速API:

  • VAAPI(视频加速API):最初由英特尔在2007年设计,针对基于Unix的操作系统上的X窗口系统,现在已开源。它现在还通过dmabuf支持Wayland。目前,它不仅限于英特尔GPU,因为其他制造商也可以自由使用此API,例如Imagination Technologies或S3 Graphics。通过gstreamer-vaapi包可以访问GStreamer。
  • OVD(开放视频解码):AMD图形卡中的另一个API,旨在为软件开发人员提供一个平台无关的方法,以利用AMD Radeon显卡内的通用视频解码(UVD)硬件。目前GStreamer无法使用。
  • DCE(分布式编解码器引擎):德州仪器开发的开源软件库(“libdce”)和API规范,针对Linux系统和ARM平台。通过gstreamer-ducati插件可以访问GStreamer。
  • Android MediaCodec:这是Android的API,用于访问设备上的硬件解码器和编码器(如果有)。可以通过gst-plugins-bad中的androidmedia插件访问。这包括编码和解码。
  • Apple VideoTool Box框架:苹果的API用于访问硬件,可通过包含编码(通过vtenc元素)和解码(通过vtdec元素)的applemedia插件访问。
  • Video4Linux:最近的Linux内核具有一个内核API,以标准方式公开硬件编解码器,现在由gst-plugins-good中的v4l2插件支持。根据平台,这可以支持解码和编码。

硬件加速视频解码插件的内部工作原理

这些API通常提供许多功能,例如视频解码,预处理或解码帧的显示。同样的,这些插件(厂商维护的硬件相关的插件)通常也为这些功能提供了不同的GStreamer element,因此pipeline的构建不会受到这些因素影响。

例如,gstreamer-vaapi系列插件提供了vaapidecodevaapipostprocvaapisink元素,这几个元素能够通过VAAPI分别完成硬件加速解码,将裸的视频帧传递给GPU内存,将GPU帧传递给系统内存以及显示GPU帧。

区分传统的GStreamer帧(驻留在系统内存中)和硬件加速API生成的帧是很重要的。后者驻留在GPU内存中,并且GStreamer无法访问这部分内存。GPU帧通常可以映射到系统内存中,这时候可以将其视为传统的GStreamer帧,但将它们留在GPU中并从那里显示出来要高效得多。

GStreamer需要跟踪这些“硬件缓冲区”的位置,以确保传统的缓冲区仍然从一个element传递到另一个element。这些硬件缓冲区使用起来就像常规的缓冲区,但是映射它们的内容要慢得多,因为它必须从硬件加速元素使用的特殊内存中检索出来。

以上意味着,假如当前系统中支持特定的硬件加速API,并且相应的GStreamer插件也可用,类似于playbin这种拥有auto-plugging机制的elements可以使用硬件加速来构建pipeline;应用程序几乎不需要做任何特殊的事情来启用它。

playbin必须在不同的但都可用的elements中进行选择时,例如传统的软件解码其(如vp8dec)和硬件加速解码器(vaapidecode),它通过这两个解码器element在GStreamer中注册的rank决定到底使用哪一个。rank是每个元素的一个属性,表示其优先级;playbin将选择符合构建完整pipeline需求且拥有最高优先级的element。

因此playbin是否使用硬件加速取决于所有可处理当前media type的elements的rank。于是最简单的使能或禁用硬件加速功能的方法就是改变与其相关的elements的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的name属性值,例如vaapidecodefluvadec

核心方法是gst_plugin_feature_set_rank,它将把请求的element factory的rank修改为期望值。为了方便起见,rank被分为NONE,MARGINAL,SECONDARY和PRIMARY四个等级,但任意数值均可。当启用一个元素时,我们将其rank设置为PRIMARY+1,因此它的rank高于其他通常具有PRIMARY rank的元素。将一个元素的rank设置为NONE将使auto-plugging机制永远不会选择它。

GStreamer开发人员通常将硬件解码器的排名低于 软件有缺陷时的软件。这应该作为一个警告。

结论

这篇教程展示了GStreamer内部如何管理硬件加速视频解码。特别地,

  • 如果有合适的API和相应的GStreamer插件可用,应用程序不需要做任何特殊的事情来启用硬件加速。

  • 硬件加速可以通过使用gst_plugin_feature_set_rank()改变解码元素的rank来影响auto-plugging元素对其的选择。

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值