在up squared上让ffmpeg支持硬件编解码
最新更新
应该安装完vaapi-driver后,编译ffmpeg时带上–enable-vaapi就可以支持intel的硬件编解码。一开始以为硬件编解码必须用MediaSDK,所以走了点弯路。直接按照最后两节节操作即可,如果有问题可以参考剩余的部分。
需求背景
采用一块up square board 做视频识别,开发过程中发现利用FFMPEG调用x264进行视频编解码的时候帧率很低。先进行解码,中间注释掉处理过程,再进行编码,这个帧率大概只有15fps到17fps,调用ffmpeg的接口将帧率设置到30也不行,推测是因为x264是利用软件的方法进行编解码,在这种嵌入式的板子上效率略低,于是开始研究硬件编解码。开发过程中采用的up square板子用的cpu型号是N3940, Apollo Lake 架构, datasheet上表示支持硬件编解码。 Intel开源了一套支持硬件编解码的SDK, 全称为Intel-Media-SDK, github地址:https://github.com/Intel-Media-SDK/MediaSDK 通过此SDK可以使用硬件编解码,也支持开发者往其中添加其他的编解码器。 同时了解到FFMPEG从2016年10月以后支持硬件编解码,他通过调用VAAPI 来使用Intel的硬件编解码。于是先开始着手部署VAAPI和MediaSDK进行性能测试,然后编译出支持VAAPI的FFMPEG。如果硬件编解码可行且速度能达到需求,就在项目中应用VAAPI支持的FFMPEG。
开发环境
硬件:up squared board,CPU N3940。 OS: Ubuntu 16.04
安装步骤
当前最新版本的MediaSDK依赖LibVA库和Intel Media Driver for VAAPI,后者又依赖libVA和gmmlib。
LibVA地址:https://github.com/intel/libva。
Intel Media Driver for VAAPI地址:https://github.com/intel/media-driver。
gmmlib地址:https://github.com/intel/gmmlib。
将上述描述的四个库git clone下来并且进行编译安装,按照每个库的readme文档中的指导进行操作就可以。以下只是进行稍微记录下。
libva安装步骤
(1)在编译libva之前,要执行以下命令安装一些依赖库和自动构建工具(否则./autogen.sh会出错):1
sudo apt install autoconf libtool libdrm-dev xorg xorg-dev openbox libx11-dev libgl1-mesa-glx libgl1-mesa-dev
(2)接着用以下命令完成编译安装1
2
3
4
5
6git clone https://github.com/intel/libva
cd libva
./autogen.sh
./configure
make -j4
sudo make install
gmmlib安装步骤
1 | git clone https://github.com/intel/gmmlib |
media-driver安装步骤
1 | git clone https://github.com/intel/media-driver |
MediaSDK安装步骤
(1) 首先注意Media SDK需要cmake版本至少3.6,如果没有,就通过以下方法将cmake版本更改为最新版本,用以下方法可以不用卸载旧版cmake。如果系统中有ROS的话apt-get autoremove cmake反而会把ROS的包都给干掉,已经踩过雷了。1
2
3
4wget https://cmake.org/files/v3.15/cmake-3.15.2-Linux-x86_64.tar.gz
tar -zxvf cmake-3.15.2-Linux-x86_64.tar.gz
sudo mv cmake-3.15.2-Linux-x86_64 /opt/cmake-3.15.2
sudo ln -sf /opt/cmake-3.15.2/bin/* /usr/bin/
以上步骤中主要部分是ln -sf 构建软链接,这样我们敲cmake指令就能调用到新装的cmake,安装完毕后检查下1
2
3
4nephilim@ubuntu:~/mediasdk$ cmake --version
cmake version 3.15.2
CMake suite maintained and supported by Kitware (kitware.com/cmake).
版本信息正确,就可以开始下一步。
(2)1
2
3
4
5
6
7git clone https://github.com/Intel-Media-SDK/MediaSDK
cd MediaSDK
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j4
sudo make install
MediaSDK例程测试
再刚刚新建的MediaSDK/build目录下有__bin/release目录,MediaSDK例程都在底下,运行之前先sudo ldconfig一下,否则可能会提示找不到某个mfx的so库。 准备一个yuv视频文件。1
./sample_encode h264 -i bridge-far_qcif.yuv -o test.h264 -w 1920 -h 1080
提示错误1
2
3
4
5
6[ERROR], sts=MFX_ERR_MEMORY_ALLOC(-4), CreateAllocator, CreateHWDevice failed at /home/nephilim/mediasdk/MediaSDK/samples/sample_encode/src/pipeline_encode.cpp:1094
[ERROR], sts=MFX_ERR_MEMORY_ALLOC(-4), Init, CreateAllocator failed at /home/nephilim/mediasdk/MediaSDK/samples/sample_encode/src/pipeline_encode.cpp:1625
[ERROR], sts=MFX_ERR_MEMORY_ALLOC(-4), main, pPipeline->Init failed at /home/nephilim/mediasdk/MediaSDK/samples/sample_encode/src/sample_encode.cpp:1581
Frame number: 0
针对上述提示,目前能想到的原因应该是在虚拟机环境下,mediasdk无法访问到硬件的编解码设备。查找资料得知作为SoC组成部分的GPU是不能虚拟化的,无法通过Xen、Ctrix、KVM或VMware利用GPU计算资源。为了验证这个想法对不对,使用了一条指令进行检查:1
sudo lspci -nn -s 0:02.0
在虚拟机内什么东西都没出现,但在up squared上出现了1
00:02.0 VGA compatible controller [0300]: Intel Corporation Sky Lake Integrated Graphics [8086:5a85] (rev 0b)
这表明确实虚拟机不支持对集显进行虚拟化。先不对虚拟机的问题进行深入研究,直接up squared上开干,一开始报错。1
2
3
4...
libva info: Trying to open /usr/local/lib/dri/i965_drv_video.so
libva info: va_openDriver() returns -1
...
于是检查/usr/local/lib目录下并没有这个so库,find 搜索发现/usr/lib/x86_64-linux-gnu/dri目录下有这个文件,利用ln -sf构建软连接解决了这个问题。继续执行,又报错该so库没有函数vaDriverInit_1_0,用nm -D xxx.so指令查看函数列表,发现一个vaDriverInit_0_39。搜索无果,只发现了一句话:va的驱动可能没有被正确编译。顺着这个思路找,发现了vaapi driver这个库:https://github.com/intel/intel-vaapi-driver,经过编译安装后再运行sample不再提示错误。同时,也可以编译安装libva-utils:https://github.com/intel/libva-utils。安装完后命令行运行vainfo可以看到提示信息。
安装vaapi driver和libva-utils
1 | git clone https://github.com/intel/intel-vaapi-driver |
1 | git clone https://github.com/intel/libva-utils |
编译带VAAPI的FFmpeg
先下载ffmpeg编译需要的几种依赖库(如果还有缺什么就按提示的库名去找):1
sudo apt-get install libx264-dev nasm yasm libx264-dev
下载ffmpeg源码,通过以下参数进行编译(本项目应用场景下用以下参数足够),注意其中使能vaapi的那个参数一定要带:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo apt-get install libx264-dev
./configure \
--prefix=/usr/local \
--enable-shared \
--enable-static \
--enable-libx264 \
--enable-decoder=h264 \
--enable-encoder=libx264 \
--enable-gpl \
--enable-pthreads \
--disable-nonfree \
--disable-stripping \
--enable-vaapi \
--enable-hwaccel=h264_vaapi
make -j4
sudo make install
安装完成后,可以通过ffmpeg -encoders查看编译出来的可用的编码器,如果编译正确是可以看到h264_vaapi的。试了各种指令,最后试出可以通过以下指令测试编码USB视频流是否正确1
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 -an -vf 'format=nv12,hwupload' -c:v h264_vaapi out.h264
生成的视频文件用vlc可以进行播放。所以下一步就在c++中进行调用,调整参数看下是否对帧率有影响。