视频和视频帧:FFMPEG+Intel QSV硬解的环境安装篇

视频和视频帧: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不支持,后面的都白搭:

  1. 检查自己的CPU型号
    Linux下使用cat /proc/cpuinfo即可。笔者的CPU是Intel(R) Celeron(R) CPU J3455 @ 1.50GHz
  2. 官网上查询
    官网的链接暂时找不到了,自行Google。(捂脸,回头找到了更新下)


关于编译安装的办法,官网提供了一份非常详细的文档,但是实际按照文档一步步走下来的时候,会踩到很多坑;网上找到许多网友热情分享的经验,也是良莠不齐,一度迫使我们重装系统。因此,本文以官网文档为基础,权当笔记记录。(官网上还提供了一份脚本,不建议直接使用!)

在此之前,请准备好GCC/G++ 4.9及以上版本和CMAKE 3.6及以上版本。

以及,以下所有库的编译安装路径,笔者都选择了/opt,实际真正执行的时候请自行选择。msdk的默认安装路径是/opt/intel/mediasdk,下文有详述。

附上一幅Intel官方的各个lib之间的关系图,便于在安装前对整个QSV框架有初步认知:



0. 环境准备

在正式安装va-api和media-driver之前,需要做下面几件事:

  1. 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编译的。

msdk release note

坑点:

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下,内容如下:

libva安装后目录
libva-utils安装后目录

编译安装时可能会遇到的“坑“

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

安装结束后,内容如下:

media-driver安装后目录

编译安装时可能会遇到的“坑“

  1. 安装中可能会遇到如下报错:
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/(默认路径)目录下:

mediasdk安装后目录

编译安装时可能会遇到的“坑“

  1. 首先,不要按照官网的说法执行perl tools/builder/build_mfx.pl --cmake=intel64.make.release,最新的代码中tools目录下面早就没有builder目录了。建议按照git的readme文档操作。
  2. 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

编译安装完毕后:

ffmpeg安装后目录

编译安装时可能会遇到的“坑“

  1. 编译时运行./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(文章显然有点旧了)。

编辑于 2020-02-18 13:01