视频编解码分为硬件加速以及非硬件加速。硬件加速是指通过显卡,FPGA等硬件进行视频编解码,由于硬件有专门优化,所以性能高,能耗低,非硬件加速编解码是指通过CPU进行视频编解码,性能就没那么高(虽然有相关CPU指令优化),由于视频编解码计算量很大,所以能耗也很高。在PC平台上主流的硬件加速编解码有Intel集成显卡,Nvidia显卡。Nvidia平台的编解码用的比较多,网上资料也多,接口也很简单,但是相对成本会高些。Intel集显平台视频编解码成本就低很多了,只要是最近几年带集显的CPU基本都支持硬件加速编解码,但是开发复杂度相对高些,网上资料也少,主要是用的人少吧。自己做过Intel集显平台在Linux以及Windows下的编解码开发,也踩过很多坑,故特地写此文章,介绍下Intel集显平台的视频编解码开发,希望更多的人能加入Intel平台视频编解码,降低成本开销。
Quick Sync Video
Intel Quick Sync Video(QSV)是Intel GPU上跟视频处理有关的一系列硬件特性的称呼。如下是Intel官网某款CPU带的显卡规格:
可以看到该显卡支持Intel Quick Sync Video。点击Quick Sync Video旁的Info提示:
英特尔® Quick Sync Video 技术可以快速转换便携式多媒体播放器的视频,还能提供在线共享、视频编辑及视频制作功能。
所以看到CPU带的集成显卡支持Quick Sync Video就表示支持硬件加速的视频编解码。
硬件支持
看下Intel不同代处理器对视频编码格式的支持情况。
Platform Name
Graphics
Adds support for...
Ironlake
gen5
MPEG-2, H.264 decode.
Sandy Bridge
gen6
VC-1 decode; H.264 encode.
Ivy Bridge
gen7
JPEG decode; MPEG-2 encode.
Bay Trail
gen7
-
Haswell
gen7.5
-
Broadwell
gen8
VP8 decode.
Braswell
gen8
H.265 decode; JPEG, VP8 encode.
Skylake
gen9
H.265 encode.
Apollo Lake
gen9
VP9, H.265 Main10 decode.
Kaby Lake
gen9.5
VP9 profile 2 decode; VP9, H.265 Main10 encode.
Coffee Lake
gen9.5
-
Gemini Lake
gen9.5
-
Cannonlake
gen10
-
可以看到从第五代开始就支持硬件加速视频编解码了,越往后支持的视频编码格式以及特性也逐渐增多。
API支持
在不同平台上可通过不同API使用Intel GPU的硬件加速能力。目前主要由两套API:VAAPI以及libmfx。
VAAPI (视频加速API,Video Acceleration API)包含一套开源的库(LibVA) 以及API规范, 用于硬件加速下的视频编解码以及处理,只有Linux上的驱动提供支持。
libmfx。Intel Media SDK中的API规范,支持视频编解码以及媒体处理。支持Windows以及Linux。
除了Intel自己的API,在Windows系统上还有其他API可使用Intel GPU的硬件加速能力,这些API属于Windows标准,由Intel显卡驱动实现。
DXVA2 / D3D11VA。标准Windows API,支持通过Intel显卡驱动进行视频编解码,FFmpeg有对应实现。
Media Foundation。标准Windows API,支持通过Intel显卡驱动进行视频编解码,FFmpeg不支持该API。
Intel媒体栈
基于Intel显卡技术,Intel媒体栈提供了一系列多媒体解决方案。例如:Intel Media driver(也称作iHD driver),Intel Media SDK, LibVA等。
下图为Intel媒体栈的各个组件示意图:
后面说下跟我们视频编解码关系比较大的。
VAAPI驱动
VAAPI驱动属于用户态驱动,用于支持LibVA,底层是i965/1915驱动。Intel提供了两种开源的VAAPI驱动:intel-vaapi-driver以及intel-media-driver,intel-media-driver较intel-vaapi-driver新,维护更积极,所以目前更推荐使用intel-media-driver。
开发库以及SDK
LibVA:VAAPI的开源库实现
LibVA-utils:VAAPI相关的一系列工具以及示例
Intel Media SDK:提供一套用于视频编解码以及处理(VPP)的API:libmfx,支持Linux/Windows,具体介绍可查看:Intel Media SDK
开发环境搭建
前面简单介绍了VAAPI以及Intel Media SDK,下面说下开发环境搭建。
Windows系统
只有Intel Media SDK支持。确保安装了集成显卡驱动,然后需要到Intel官网下载Intel Media SDK安装包。具体搭建请参考:
Intel Media SDK环境搭建:https://blog.csdn.net/y601500359/article/details/87169715
Linux系统
包含Ubuntu以及CentOS。需要安装驱动以及相应的库。
FFmpeg VAAPI/QSV开发环境搭建
对于VAAPI以及Intel Media SDK,如果使用原生API开发的话比较麻烦,好在FFmpeg提供了对应的插件。我们可以通过FFmpeg间接使用这两套API。在FFmpeg中VAAPI还是叫做VAAPI,但是Intel Media SDK却叫做QSV(一脸懵逼)。
FFmpeg-vaapi插件:基于VAAPI接口
FFmpeg-qsv插件:基于Intel Media SDK
FFmpeg VAAPI/QSV开发环境搭建我就不做搬运工了,大家可参考官网教程。
Linux FFmpeg VAAPI/QSV Installation Environment:https://01.org/linuxmedia/quickstart/ffmpeg-vaapi-qsv-installation-environment
不使用FFmpeg的开发环境搭建
有些人可能不想使用FFmpeg,对于Intel Media SDK还好,但是VAAPI就不行了,接口设计很底层,且复杂,所以对于想使用VAAPI的话,还是老老实实使用FFmpeg吧,时间就是金钱。
对于Intel Media SDK,除了可以编解码,还有可以进行视频的其他操作。2017年开始,Linux上才有开源的Intel Media SDK实现,之前Linux上的对应方案叫做Intel® Media Server Studio,现在已经不可用了。
Linux上的Intel Media SDK底层基于Libva。编译Intel Media SDK也是要安装VAAPI驱动等Intel媒体栈软件。
所以开发环境搭建还是参考上一小节的内容,只是可以选择不编译安装FFmpeg。
注意事项
安装的LibVA-utils包含一个vainfo工具,前面的开发环境搭建后,可以通过vainfo检查VAAPI的安装设置。
[root@localhost apps]# vainfo
libva info: VA-API version 1.6.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'iHD'
libva info: Trying to open /usr/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_5
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.6 (libva 2.5.0)
vainfo: Driver version: Intel iHD driver - 1.0.0
vainfo: Supported profile and entrypoints
VAProfileNone :VAEntrypointVideoProc
VAProfileNone :VAEntrypointStats
VAProfileMPEG2Simple :VAEntrypointVLD
VAProfileMPEG2Simple :VAEntrypointEncSlice
VAProfileMPEG2Main :VAEntrypointVLD
VAProfileMPEG2Main :VAEntrypointEncSlice
VAProfileH264Main :VAEntrypointVLD
VAProfileH264Main :VAEntrypointEncSlice
VAProfileH264Main :VAEntrypointFEI
VAProfileH264Main :VAEntrypointEncSliceLP
VAProfileH264High :VAEntrypointVLD
VAProfileH264High :VAEntrypointEncSlice
VAProfileH264High :VAEntrypointFEI
VAProfileH264High :VAEntrypointEncSliceLP
VAProfileVC1Simple :VAEntrypointVLD
VAProfileVC1Main :VAEntrypointVLD
VAProfileVC1Advanced :VAEntrypointVLD
VAProfileJPEGBaseline :VAEntrypointVLD
VAProfileJPEGBaseline :VAEntrypointEncPicture
VAProfileH264ConstrainedBaseline:VAEntrypointVLD
VAProfileH264ConstrainedBaseline:VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline:VAEntrypointFEI
VAProfileH264ConstrainedBaseline:VAEntrypointEncSliceLP
VAProfileVP8Version0_3 :VAEntrypointVLD
VAProfileVP8Version0_3 :VAEntrypointEncSlice
VAProfileHEVCMain :VAEntrypointVLD
VAProfileHEVCMain :VAEntrypointEncSlice
VAProfileHEVCMain :VAEntrypointFEI
VAProfileHEVCMain10 :VAEntrypointVLD
VAProfileHEVCMain10 :VAEntrypointEncSlice
VAProfileVP9Profile0 :VAEntrypointVLD
VAProfileVP9Profile2 :VAEntrypointVLD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[root@localhostapps]# vainfo
libvainfo:VA-APIversion1.6.0
libvainfo:va_getDriverName()returns0
libvainfo:Userrequesteddriver'iHD'
libvainfo:Tryingtoopen/usr/lib/dri/iHD_drv_video.so
libvainfo:Foundinitfunction__vaDriverInit_1_5
libvainfo:va_openDriver()returns0
vainfo:VA-APIversion:1.6(libva2.5.0)
vainfo:Driverversion:InteliHDdriver-1.0.0
vainfo:Supportedprofileandentrypoints
VAProfileNone:VAEntrypointVideoProc
VAProfileNone:VAEntrypointStats
VAProfileMPEG2Simple:VAEntrypointVLD
VAProfileMPEG2Simple:VAEntrypointEncSlice
VAProfileMPEG2Main:VAEntrypointVLD
VAProfileMPEG2Main:VAEntrypointEncSlice
VAProfileH264Main:VAEntrypointVLD
VAProfileH264Main:VAEntrypointEncSlice
VAProfileH264Main:VAEntrypointFEI
VAProfileH264Main:VAEntrypointEncSliceLP
VAProfileH264High:VAEntrypointVLD
VAProfileH264High:VAEntrypointEncSlice
VAProfileH264High:VAEntrypointFEI
VAProfileH264High:VAEntrypointEncSliceLP
VAProfileVC1Simple:VAEntrypointVLD
VAProfileVC1Main:VAEntrypointVLD
VAProfileVC1Advanced:VAEntrypointVLD
VAProfileJPEGBaseline:VAEntrypointVLD
VAProfileJPEGBaseline:VAEntrypointEncPicture
VAProfileH264ConstrainedBaseline:VAEntrypointVLD
VAProfileH264ConstrainedBaseline:VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline:VAEntrypointFEI
VAProfileH264ConstrainedBaseline:VAEntrypointEncSliceLP
VAProfileVP8Version0_3:VAEntrypointVLD
VAProfileVP8Version0_3:VAEntrypointEncSlice
VAProfileHEVCMain:VAEntrypointVLD
VAProfileHEVCMain:VAEntrypointEncSlice
VAProfileHEVCMain:VAEntrypointFEI
VAProfileHEVCMain10:VAEntrypointVLD
VAProfileHEVCMain10:VAEntrypointEncSlice
VAProfileVP9Profile0:VAEntrypointVLD
VAProfileVP9Profile2:VAEntrypointVLD
正常的输出类似上面,我们用到的是Intel iHD driver(即Intel Media driver),这个在设置:
#export LIBVA_DRIVER_NAME=iHD时指定,设置iHD驱动在一些情况下能获得更高的编解码性能。VAEntrypointVLD 指的是显卡能够解码这个格式,VAEntrypointEncSlice 指的是显卡可以编码这个格式。
如果运行vainfo出现如下错误:
libva info: va_openDriver() returns -1
vaInitialize failed with error code -1 (unknown libva error),exit
1
2
libvainfo:va_openDriver()returns-1
vaInitializefailedwitherrorcode-1(unknownlibvaerror),exit
说明驱动没设置正确,确保驱动都正常编译到指定目录,且驱动名称及路径:
#export LIBVA_DRIVER_NAME=iHD
#export LIBVA_DRIVERS_PATH=$ROOT_INSTALL_DIR/lib/dri
1
2
#export LIBVA_DRIVER_NAME=iHD
#export LIBVA_DRIVERS_PATH=$ROOT_INSTALL_DIR/lib/dri
设置正确。
示例代码
Intel Media SDK:https://github.com/Intel-Media-SDK/MediaSDK/tree/master/samples
ffmpeg-VAAPI:FFmpeg源码目录doc\examples下的vaapi_encode.cpp与vaapi_transcode.c
1)示例代码中,avcodec_find_encoder_by_name输入参数得是FFmpeg注册的vaapi编码器名称,例如
h264的vaapi编码器是:h264_vaapi,可通过ffmpeg -codecs | grep vaapi命令查询;
2)av_hwdevice_ctx_create输入的设备名是/dev/dri/renderD128这样的形式,可通过ls /dev/dri查询,这里的示例/dev/dri/renderD128表示Intel集显设备;
3)VAAPI编码时,输入的YUV格式必须是NV12,其他格式YUV得转为NV12格式。vaapi_encode.c有个AVFrame(sw_frame),用于存放我们输入的YUV数据,该AVFrame的data[0]用于存放Y数据,data[1]存放UV数据,由于输入格式是NV12,所以data[1]中UV数据的内存布局为:UVUVUVUV···UVUV。
FFmpeg-QSV:FFmpeg源码目录doc\examples下的qsvdec.c
参考
[1] Linux FFmpeg VAAPI/QSV Installation Environment.https://01.org/zh/linuxmedia/quickstart/ffmpeg-vaapi-qsv-installation-environment?langredirect=1.
[2] Intel media for linux.https://01.org/zh/intel-media-for-linux?langredirect=1.
[3]Linux media.https://01.org/zh/linuxmedia?langredirect=1.