视频和视频帧:FFMPEG+Intel QSV硬解的环境安装篇
导语:接触这个起初是因为项目需求,要求利用Intel的集成GPU(核显)做视频解码工作。所以本篇将重点介绍如何编译FFMPEG的QSV插件,包括Intel的libva、media-driver和msdk的源码编译办法,以及如何编译FFMPEG源码以集成QSV解码器。
写在前面
FFMPEG是处理视频、音频和图像等多媒体文件的“瑞士军刀”。笔者初步用下来确实也觉得很强大:其一是开源社区活跃,所以网上相关资料较多,尤其出现问题的时候有较多的热心网友帮忙解答;其二是FFMPEG较为成熟,FFMPEG自身天然支持CPU处理(俗称“软xx”,比如解码工作,称为软解),同时还支持各种GPU卡的硬件处理(同样举解码工作为例,称为硬解),已经查阅到的资料就包括ARM的A卡,NVDIA的N卡,以及intel的集成显卡。这个说的就比较粗了,比如N卡,就有在服务器上的独立显卡对应的CUDA库、ARM板上的multi-media库等等。
本文将重点介绍在Linux环境下集成FFMPEG的QSV插件。
QSV(Quick Sync Video)是Intel的集成加速器名字,目前市面上中低端的Intel CPU都支持,一般服务器CPU都不支持。这里提供更为权威的方法来检测自己的CPU是否支持,这步很重要,因为如果CPU不支持,后面的都白搭:
- 检查自己的CPU型号
Linux下使用cat /proc/cpuinfo
即可。笔者的CPU是Intel(R) Celeron(R) CPU J3455 @ 1.50GHz
。 - 官网上查询
官网的链接暂时找不到了,自行Google。(捂脸,回头找到了更新下)
关于编译安装的办法,官网提供了一份非常详细的文档,但是实际按照文档一步步走下来的时候,会踩到很多坑;网上找到许多网友热情分享的经验,也是良莠不齐,一度迫使我们重装系统。因此,本文以官网文档为基础,权当笔记记录。(官网上还提供了一份脚本,不建议直接使用!)
在此之前,请准备好GCC/G++ 4.9及以上版本和CMAKE 3.6及以上版本。
以及,以下所有库的编译安装路径,笔者都选择了/opt,实际真正执行的时候请自行选择。msdk的默认安装路径是/opt/intel/mediasdk,下文有详述。
附上一幅Intel官方的各个lib之间的关系图,便于在安装前对整个QSV框架有初步认知:
0. 环境准备
在正式安装va-api和media-driver之前,需要做下面几件事:
- apt安装:
$ sudo apt-get install -y git # 使用git需要
$ sudo apt-get install -y make # make编译源码很多地方需要
$ sudo apt-get install -y dh-autoreconf # autogen编译源码时需要
$ sudo apt-get install pkg-config # 编译libva时需要
$ apt-get install -y libncurses5-dev libpthread-stubs0-dev libpciaccess-dev libxvmc-dev xutils-dev libsdl2-dev libxcb-shm0-dev
2. gcc和cmake安装:
确保gcc/g++版本大于等于4.9,cmake版本大于等于3.6。
gcc/g++安装办法:
安装
$ sudo apt-get -y install gcc-4.9 gcc-4.9-multilib g++-4.9 g++-4.9-multilib
# 设置多版本
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 49
$ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 50 # 如果有的话
$ sudo update-alternatives --config gcc
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 49
$ sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 50 # 如果有的话
$ sudo update-alternatives --config g++
# 检查
$ gcc -v
$ g++ -v
cmake安装办法:
# 卸载现有的cmake
$ sudo apt remove --purge --auto-remove cmake
# 下载cmake版本
$ version=3.13
$ build=3
$ mkdir ~/temp
$ cd ~/temp
$ wget https://cmake.org/files/v$version/cmake-$version.$build.tar.gz
$ tar -xzvf cmake-$version.$build.tar.gz
$ cd cmake-$version.$build/
# 安装
$ ./bootstrap
$ make -j4
$ sudo make install
# 检查
$ cmake --version
备注:执行cmake --version
时可能会提示-bash: /usr/bin/cmake: No such file or directory
解决方案:执行sudo find / -name cmake
查找cmake被安装到哪里了(一般来说安装在/usr/local/bin/下面了),把cmake拷贝一份放在/usr/bin/下即可。
3. 检查内核版本,va-api要求Kernel 4.14.16及以上。
$ uname -ar
如果不满足要求,则按照官网的做法,更新kernel。(这步笔者没有执行过,因为笔者的版本OK)
$ sudo add-apt-repository ppa:teejee2008/ppa
$ sudo apt-get update
$ sudo apt-get -y install ukuu
$ ukuu-gtk
或者:
$ cd $WORKING_DIR
$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
$ cd linux-stable/
$ git checkout -b my_v4.14.16 v4.14.16
$ cp /boot/config-`uname -r` .config
$ make olddefconfig
$ make -j8
$ sudo make modules_install
$ sudo make install
坑:
编译linux-stable期间可能会出现 "bc: command not found " 问题, 解决方案:sudo apt-get -y install bc
Pre. 如何选择git的branch/tag?
通过官方Intel-Media-SDK的release文档(链接: [Intel-Media-SDK/MediaSDK](Intel-Media-SDK/MediaSDK))来知道分别是用libva和media-driver的哪个tag编译的。
坑点:
1. 尽量选择不带pre
的tag的组合;
2. 在没有这块之前,笔者随意用最新的分支进行编译,经常遇到编不通的时候!!!
I. VA-API编译安装
源码编译:
$ git clone https://github.com/intel/libva.git
$ git clone https://github.com/intel/libva-utils.git
$ cd $WORKING_DIR/libva
$ git checkout <libva commit id>
$ ./autogen.sh --prefix=/opt/intel/libva --libdir=/opt/intel/libva/lib
$ make -j4
$ sudo make install
$ export PKG_CONFIG_PATH=/opt/intel/libva/lib/pkgconfig
$ cd $WORKING_DIR/libva-utils
$ git checkout <libva-utils commit id>
$ ./autogen.sh --prefix=/opt/intel/libva-utils --libdir=/opt/intel/libva-utils/lib
$ make -j4
$ sudo make install
执行完sudo make isntall
后,libva和libva-utils都安装在/opt/intel下,内容如下:
编译安装时可能会遇到的“坑“:
1. 如果在运行./autogen.sh xxx
时报错:
./configure: line 17290: syntax error near unexpected token `DRM,'
./configure: line 17290: `PKG_CHECK_MODULES(DRM, libdrm >= $LIBDRM_VERSION)'
解决办法:安装pkg-config
:
$ sudo apt-get install pkg-config
2. 运行libva-utils的./autogen.sh xxx
时报错:
no package 'libva-drm' found
解决办法:设置PKG_CONFIG_PATH为/opt/intel/libva/lib/pkgconfig
$ export PKG_CONFIG_PATH=/opt/intel/libva/lib/pkgconfig
因为libva-utils依赖libva,而安装libva的时候修改了默认install路径,因此需要显性声明出来。(其实media-driver安装过程中也以来libva,也需要设置这个路径)
II. Media-Driver编译安装
源码编译:
$ git clone https://github.com/intel/media-driver.git
$ git clone https://github.com/intel/gmmlib.git
$ cd $WORKING_DIR/gmmlib
$ git checkout <gmmlib commit id>
$ cd $WORKING_DIR/media-driver
$ git checkout <media-driver commit id>
$ cd $WORKING_DIR
$ mkdir -p build
$ cd $WORKING_DIR/build
$ cmake ../media-driver \
-DMEDIA_VERSION="2.0.0" \
-DBUILD_ALONG_WITH_CMRTLIB=1 \
-DBS_DIR_GMMLIB=`pwd`/../gmmlib/Source/GmmLib/ \
-DBS_DIR_COMMON=`pwd`/../gmmlib/Source/Common/ \
-DBS_DIR_INC=`pwd`/../gmmlib/Source/inc/ \
-DBS_DIR_MEDIA=`pwd`/../media-driver \
-DCMAKE_INSTALL_PREFIX=/opt/intel/media-driver \
-DCMAKE_INSTALL_LIBDIR=/opt/intel/media-driver/lib \
-DINSTALL_DRIVERS_SYSCONF=OFF \
-DLIBVA_DRIVERS_PATH=/opt/intel/media-driver/lib/dri
$ make -j8
$ sudo make install
安装结束后,内容如下:
编译安装时可能会遇到的“坑“:
- 安装中可能会遇到如下报错:
fatal error: ../../../Utility/CpuSwizzleBlt/CpuSwizzleBlt.c: No such file or directory
解决办法:检查igdgmm文件夹(检查手段:$ find / -name igdgmm, 一般来说在/usr/include/igdgmm),把这个文件删除即可。
2. 请使用libva-utils编译出来的vainfo!
测试media-driver
是否成功安装
$ export LIBVA_DRIVER_NAME=iHD
$ export LIBVA_DRIVERS_PATH=/opt/intel/media-driver/lib/dri
$ cd /opt/intel/libva-utils/bin
$ ./vainfo
成功安装后将显示如下内容:
error: can't connect to X server!
libva info: VA-API version 1.5.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'iHD'
libva info: Trying to open /opt/intel/media-driver/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.5 (libva 2.5.0)
vainfo: Driver version: Intel iHD driver - 2.0.0
vainfo: Supported profile and entrypoints
VAProfileNone : VAEntrypointVideoProc
VAProfileNone : VAEntrypointStats
VAProfileMPEG2Simple : VAEntrypointVLD
VAProfileMPEG2Main : VAEntrypointVLD
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
VAProfileHEVCMain : VAEntrypointVLD
VAProfileHEVCMain : VAEntrypointEncSlice
VAProfileHEVCMain : VAEntrypointFEI
VAProfileHEVCMain10 : VAEntrypointVLD
VAProfileVP9Profile0 : VAEntrypointVLD
III. Intel Media SDK(MSDK)源码编译
源码编译:
$ cd $WORKING_DIR
$ git clone Intel-Media-SDK/MediaSDK
$ cd MediaSDK
$ mkdir build && cd build
$ cmake ..
$ make
$ make install
安装后,库文件都在/opt/intel/mediasdk/
(默认路径)目录下:
编译安装时可能会遇到的“坑“:
- 首先,不要按照官网的说法执行
perl tools/builder/build_mfx.pl --cmake=intel64.make.release
,最新的代码中tools目录下面早就没有builder目录了。建议按照git的readme文档操作。 - cmake要求在3.6版本及以上。
3. 执行cmake ..
时可能会报错:No package 'libva' found
。
解决方案:设置PKG_CONFIG_PATH为/opt/intel/libva/lib/pkgconfig
,原理同libva-utils时遇到的错误。
4. make的时候可能会遇到“autoreconf: not found” 问题,解决办法:执行$ sudo apt-get install autoconf automake libtool
即可。
5. 环境变量(一定要做!!!): 编译结束后,lib库在/opt/intel/mediasdk/lib/目录下,所以需要在动态连接库增加该路径:
$ export LD_LIBRARY_PATH=/opt/intel/mediasdk/lib:$LD_LIBRARY_PATH
测试MSDK是否成功安装的办法
msdk编译结束,进入/opt/intel/mediasdk/share/mfx/samples
目录,运行sample_xxx
可执行程序。如果运行OK的话,说明编译成功了。否则,就需要仔细检查哪一步操作不对。
# 测试解码能力
$ ./sample_decode h264 -i sample_outdoor_car_1080p_10fps.h264 [-o /tmp/output.yuv] -vaapi
libva info: VA-API version 1.5.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'iHD'
libva info: Trying to open /opt/intel/media-driver/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_5
libva info: va_openDriver() returns 0
Decoding Sample Version 8.4.27.
Input video AVC
Output format NV12
Input:
Resolution 1920x1088
Crop X,Y,W,H 0,0,1920,1080
Output:
Resolution 1920x1080
Frame rate 10.00
Memory type vaapi
MediaSDK impl hw
MediaSDK version 1.28
Decoding started
Frame number: 600, fps: 522.731, fread_fps: 0.000, fwrite_fps: 0.000
Decoding finished
# 测试编码能力
$ ./sample_encode h264 -i /tmp/output.yuv [-o /tmp/output.h264] -w 1920 -h 1080 -vaapi
libva info: VA-API version 1.5.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'iHD'
libva info: Trying to open /opt/intel/media-driver/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_5
libva info: va_openDriver() returns 0
Encoding Sample Version 8.4.27.
Input file format YUV420
Output video AVC
Source picture:
Resolution 1920x1088
Crop X,Y,W,H 0,0,1920,1080
Destination picture:
Resolution 1920x1088
Crop X,Y,W,H 0,0,1920,1080
Frame rate 30.00
Bit rate(Kbps) 3757
Gop size 0
Ref dist 4
Ref number 0
Idr Interval 0
Target usage balanced
Memory type vaapi
Media SDK impl hw
Media SDK version 1.30
Processing started
Processing finished
备注:开启-o
选项(保存文件到磁盘)后,发现解码速度只有10fps不到了,因此建议测试时不加这个参数。
IV. FFMPEG源码编译(集成QSV)
通过apt-get安装的ffmpeg本身不支持QSV
选项,因此必须自己去重新编译。
apt安装:
apt-get install autoconf automake bzip2 nasm yasm
FFMPEG源码编译:
# 到官网下载需要的ffmpeg源码
# 官网链接:https://www.ffmpeg.org/download.html
# 或者github链接:https://github.com/FFmpeg/FFmpeg
$ ./configure --enable-shared \
--disable-x86asm \
--disable-lzma \
--enable-pic \
--extra-cflags=-fPIC \
--extra-cxxflags=-fPIC \
--enable-libmfx \
--enable-nonfree \
--enable-encoder=h264_qsv \
--enable-decoder=h264_qsv \
--prefix=/opt/ffmpeg \
--libdir=/opt/ffmpeg/lib \
$ make -j8
$ sudo make install
编译安装完毕后:
编译安装时可能会遇到的“坑“:
- 编译时运行
./configure xxx
可能提示错误"ERROR: libmfx not found"
解决方案:确认/opt/intel/mediasdk/lib/pkgconfig/目录下是否有libmfx.pc文件,没有就创建这个文件,文件内容请自行google。接着需要指定环境变量如下:
$ export MFX_HOME=/opt/intel/mediasdk/lib/pkgconfig
$ export PKG_CONFIG_PATH=/opt/intel/mediasdk/lib/pkgconfig
测试FFMPEG集成QSV编译安装是否成功
- 查看ffmpeg是否具有qsv插件
$ cd /opt/ffmpeg/bin
$ ./ffmpeg -codecs | grep qsv
ffmpeg version 4.2.git Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 4.9.3 (Ubuntu 4.9.3-13ubuntu2)
configuration: --enable-shared --disable-x86asm --disable-lzma --enable-pic --extra-cflags=-fPIC --extra-cxxflags=-fPIC --enable-libmfx --enable-nonfree --enable-encoder=h264_qsv --enable-decoder=h264_qsv --prefix=/opt/ffmpeg --libdir=/opt/ffmpeg/lib
libavutil 56. 36.101 / 56. 36.101
libavcodec 58. 65.100 / 58. 65.100
libavformat 58. 35.101 / 58. 35.101
libavdevice 58. 9.101 / 58. 9.101
libavfilter 7. 69.101 / 7. 69.101
libswscale 5. 6.100 / 5. 6.100
libswresample 3. 6.100 / 3. 6.100
DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_qsv ) (encoders: h264_qsv h264_v4l2m2m )
DEV.L. hevc H.265 / HEVC (High Efficiency Video Coding) (decoders: hevc hevc_qsv ) (encoders: hevc_qsv )
DEVIL. mjpeg Motion JPEG (decoders: mjpeg mjpeg_qsv ) (encoders: mjpeg mjpeg_qsv )
DEV.L. mpeg2video MPEG-2 video (decoders: mpeg2video mpegvideo mpeg2_v4l2m2m mpeg2_qsv ) (encoders: mpeg2video mpeg2_qsv )
D.V.L. vc1 SMPTE VC-1 (decoders: vc1 vc1_qsv vc1_v4l2m2m )
DEV.L. vp8 On2 VP8 (decoders: vp8 vp8_v4l2m2m vp8_qsv ) (encoders: vp8_v4l2m2m )
DEV.L. vp9 Google VP9 (decoders: vp9 vp9_qsv ) (encoders: vp9_qsv )
- 运行ffmpeg命令行检查是否真正可以工作
# 测试解码速度
$ cd /opt/ffmpeg/bin
$ ./ffmpeg -hwaccel qsv -i ${input_video_file} -f null -
ffmpeg version 4.2.git Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 4.9.3 (Ubuntu 4.9.3-13ubuntu2)
configuration: --enable-shared --disable-x86asm --disable-lzma --enable-pic --extra-cflags=-fPIC --extra-cxxflags=-fPIC --enable-libmfx --enable-nonfree --enable-encoder=h264_qsv --enable-decoder=h264_qsv --prefix=/opt/ffmpeg --libdir=/opt/ffmpeg/lib
libavutil 56. 36.101 / 56. 36.101
libavcodec 58. 65.100 / 58. 65.100
libavformat 58. 35.101 / 58. 35.101
libavdevice 58. 9.101 / 58. 9.101
libavfilter 7. 69.101 / 7. 69.101
libswscale 5. 6.100 / 5. 6.100
libswresample 3. 6.100 / 3. 6.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/root/video/video.MP4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf56.40.101
description : Tencent APD MTS
Duration: 00:01:00.17, start: 0.000000, bitrate: 2239 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080, 2105 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
Metadata:
handler_name : SoundHandler
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> wrapped_avframe (native))
Stream #0:1 -> #0:1 (aac (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, null, to 'pipe:':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
description : Tencent APD MTS
encoder : Lavf58.35.101
Stream #0:0(und): Video: wrapped_avframe, yuv420p, 1920x1080, q=2-31, 200 kb/s, 30 fps, 30 tbn, 30 tbc (default)
Metadata:
handler_name : VideoHandler
encoder : Lavc58.65.100 wrapped_avframe
Stream #0:1(und): Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s (default)
Metadata:
handler_name : SoundHandler
encoder : Lavc58.65.100 pcm_s16le
frame= 1805 fps=105 q=-0.0 Lsize=N/A time=00:01:00.20 bitrate=N/A speed=3.49x
video:945kB audio:10360kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
总结
网上关于ffmpeg+qsv的资料不多不少,许多文章语焉不详或者中间步骤遗漏,因此踩过不少坑。此外,intel官网上也有不少指导安装的文档,笔者发现,写的最好的还是官方文档An Operation Guide to Build and Debug Open Source Media SDK Software Stack(文章显然有点旧了)。