简介 Media SDK 是一个软件开发库,包含解码、视频处理和编码三大模块。利用 Intel 平台的硬件加速能力, Media SDK 为低端用户提供了优秀的高清视频质量,极大的降低了播放高清视频的硬件门槛。此外,强大的视频 APIs 也减轻了程序开发者的工作负担,使他们能够集中精力去处理程序的逻辑模块,而不必关心于 Media SDK 内部的复杂编解码逻辑及其如何提高效率。 本篇文章将着重讲述如何利用 Media SDK 提高程序的效率,面对的读者主要是视音频程序开发人员。 本文以下内容为: - 初始化设置之优化 - 内存选择之优化 - 多线程之优化 - 异步方式之优化 初始化设置之优化 在讨论优化之前,首先要了解一下 Media SDK 是如何初始化编解码器的。 1. 创建和初始化一个编解码 Session。Media SDK 提供了 mfxStatus MFXInit(mfxIMPL impl,mfxVersion *ver, mfxSession *session)函数来完成这个创建和初始化工作。 2. 使 用 已 创 建 的 Session 来 创 建 它 的 解 码 器 。 Media SDK 提 供 了 mfxStatus MFXVideoDECODE_Init(mfxSession session, mfxVideoParam *par)来完成解码器的创建和初始化工作。 3. 使 用 已 创 建 的 Session 来 创 建 它 的 编 码 器 。 Media SDK 提 供 了 mfxStatus MFXVideoENCODE_Init(mfxSession session, mfxVideoParam *par)来完成编码器的创建和初始化工作。 在创建和初始化编解码 Session 时,我们需要制定编解码的实现方式:硬件方式还是软件方式。最简单的方法是强制使用硬件方式。这会带来一个问题,在非 Intel 显卡支持的平台,应用程序将无法正常工作。当然,如果强制使用软件方式,虽然应用程序能够工作于其他平台,但是在 Intel 显卡平台,硬件加速特性将荡然无存!虽然应用程序可以外加代码检测平台硬件来决定如何选择,但是程序的复杂度和效率将受到影响。Media SDK 内部提供了自动选择功能,它会根据当前运行系统来选择何种方式。这样就能够兼顾不同平台及其性能。 在 MFXInit 函数中,枚举类型 mfxIMPL 定义 AUTO 功能: [crayon-69c6d8247c1ca623831347/] 相应的简单实用方式如下: [crayon-69c6d8247c1d5404231276/] 通过 MFX_IMPL_AUTO 的设置,问题迎刃而解。 那么如何获知当前的编解码实用方法呢?Media SDK 已经考虑到了这种需求,它提供了mfxStatus MFXQueryIMPL(mfxSession session, mfxIMPL *impl)来查询当前采用的方法。 此外,在优化编码器初始化时,程序必须注意 mfxInfoMFX 结构中 TargetUsage 变量的选择,它的定义如下: [crayon-69c6d8247c1d9723058164/] TargetUsage 值的选择决定了编码的性能和图像质量,它的值从 0~7,值越高效率越好,但图像质量会有所下降。最佳值应该和用户选择需求挂钩,原则上是略比最小用户需求高 1 级。 本节小结: 1. 初始化 Session 时,要使用 MFX_IMPL_AUTO。它有利于跨越硬件平台,并提高编解码效率。 2. TargetUsage 的选择应该和用户需求相结合。为了提高性能,选择略高于用户最小需求的值为佳。 内存选择之优化 Media SDK 使用内存缓冲来输入/输出视频数据,内存缓冲的不同种类将会直接影响编解码的效率。内存缓冲可以是一块在系统内存中的连续块(通过 malloc 或者 new 来分配),也可以是显卡内存的连续块(通过 Microsoft Direct3D9 Surface 函数来分配)。那么内存缓冲的 种类由谁来决定呢?本节就是以此为基础,讨论在不同情况下程序如何选择内存缓冲种类的问题。 在讨论内存缓冲对编解码影响之前,先讨论下面三种情况下的内存数据传送问题。 - 系统内存间数据如何传送? 对于程序员而言,这个是最为简单的日常编程事项。一般的使用方式是 memcpy,在一些数据较大情况下(超过 L3 的 cache 尺寸时候,用 movntqa 等指令)。不管何种方式,都是CPU-BASED 的代码,在 SIMD 下效率很高。 - 显存间数据是如何传送的? 它类似于系统内存之间的数据传送,并且显存的带宽和速率都很高,传送速度更快。 - 显存和系统内存间数据是如何传送的? 通过 DMA 方式传送内存数据,速度依赖于 DMA 的带宽和速率(普通 DMA 的传送速率在33.3MB/s,而 Ultra DMA 最高也不过 100MB/s)。相比与上述两种情况,它的传送速度明显慢。 从上面的三种情况可以看出,程序一定要尽量避免出现系统内存和显存之间的数据传送,那么 Media SDK 在什么配置下会出现此类尴尬状态呢? 初始化设置之优化小节中,程序通过 MFX_IMPL_AUTO 参数根据当前平台来自动选择硬件或软件编解码,并能通过 mfxStatus MFXQueryIMPL(mfxSession session, mfxIMPL *impl)函数来获取当前平台的编解码方式,在此将获取的编码方式分别讨论。 a)使用硬件编解码方式 硬件编解码方式主要是通过显卡的硬件加速达到高效编解码的作用,也就是说它的核心是显卡。如果我们使用系统内存为其提供缓存,会出现什么情况呢?显然,在数据输出/输出时,程序必将会有显存和系统内存之间的数据传送作用,效能将受到严重影响。在此情况下,程序的最好选择就是显存,否则必将受到性能惩罚! b)使用软件编解码方式 很显然,软件编解码的核心是 CPU。如果我们使用显存作为其缓冲,那么必将导致显存和系统内存之间的数据交互,也就会导致速度低下的程序出现,故此,系统内存是它的不二选择! 本节小结: Media SDK 中内存类型的选择分两步走: 1. 使用 MFXQueryIMPL 函数来查询当前的编解码方式。 2. 根据编解码方式(MFX_IMPL_SOFTWARE 为软件;MFX_IMPL_HARDWARE 为硬件)来决定内存选用类型。为了便于日后方便查询,笔者建立了一个小表格,如表 1 所示,以供参考。 此外,笔者对 Media SDK 的两种不同内存类型在解码器下做了一个简单的比较。在软件解码方式下,显存选取要比内存选取慢了近 1 倍,这个是相当可观的数字!切忌,正确选取内存是高效程序的基本点! 多线程之优化 初始化设置之优化小节和内存选择之优化小节中,已经对 Media SDK 的两个重要配置部分进行了分析和总结。本节,我们将着重讨论如何使用多线程技术提高视频 Converter 的效能(一种视频的常用应用)。 在运用 Media SDK 进行格式转换时,一般要涉及三大模块,他们是 Decoder,VPP 和 Encoder,数据输入输出如图 1 所示。 从图 1 可以看出,每经过一个模块,都要对数据进行同步操作。在此期间,其他两个模块是处于空闲状态,是一个典型的串行处理过程。对于英特尔的多核技术,它的多核利用率是最低的,相应的效率也较差。 那么如何对现有流程进行多线程化呢? 本节提供了一种最简单的方法,即对每个模块线程化。请参考图 2 所示。 图 2 将 Decoder,VPP 和 Encoder 三个模块分别线程化,在彼此之间以队列(queue)为数据交换。 简单的工作模式如下: - 若队列为空,后级模块等待数据。 -…