FFmpeg引入NVIDIA硬件编解码扩展

简介: FFmpeg引入NVIDIA硬件编解码扩展

本文主要介绍 如何在 window10 的环境下编译 ffmpeg 的 NVIDIA GPU硬件编解码器 h264_nvenc 跟 h264_cuvid。

并不是所有的 NVIDIA 显卡都支持 h.264 跟 h.265 编解码的,有些显卡只负责渲染,不支持编解码,例如 GeForce 830M > 945M。

可以通过 Video Encode and Decode GPU Support Matrix 查看各种 NVIDIA 显卡对编解码的支持情况,有些显卡只支持 h.264 ,不支持 h.265。

从上图可以看出,NVIDIA 显卡分为 4 类。

  1. Consumer,面向 PC 市场的 GeForce 产品线。
  2. Professional,面向工作站市场的 Quadro 产品线。
  3. Server(Data Center),针对高性能计算(HPC)的 Tesla 产品线。
  4. DGX,以 Volta (伏特)作为微架构的产品线,这条产品线比较新。


FFmpeg 源码编译的时候,引入 NVIDIA 的硬件编解码器,其实跟引入 SDL,x264 是类似的,都是链接的时候需要一些 lib 导入库,运行的时候需要一些 dll。

只是 NVIDIA 的编译安装相对麻烦一些,要特别注意各个部分的版本号是否匹配兼容

先查看自己本地 NVIDIA 的驱动版本。点击菜单栏的 "帮助""系统信息"

从上图可以看到,本地显卡 GeForce RTX 2060 的驱动版本号是 456.71,然后再通过 CUDA Toolkit and Corresponding Driver Versions 查看 驱动 456.71 对应的 CUDA Toolkit 的版本。如下:

虽然上图中,CUDA 11.0.1 等等 跟 CUDA 10.1 需要的驱动版本号都是兼容 456.71 的。但是不要选 11.0.1 的版本,因为 FFmpeg 那边可能没更新这么快的。你如果选了 11.0.1,对于初学者可能有点问题,因为 CUDA Toolkit 安装的时候会改变一些 环境变量,一旦装多个版本的 CUDA Toolkit,新手可能不知道如何配置这些环境变量避免混乱。

所以,需要看你本地的驱动版本号,选一个比较旧的,能支持你的驱动的 CUDA Toolkit 来安装即可。

本文选择的是 CUDA Toolkit 10.1 update2 ,因为这个版本貌似是个正式版,应该比较稳定。

CUDA Toolkit 历史版本下载:https://developer.nvidia.com/cuda-toolkit-archive


这里需要讲解一下 Driver (显卡驱动)跟 CUDA Toolkit (CUDA工具套件)的关系。

显卡驱动是你安装电脑的时候装的。而 CUDA Toolkit 这个安装包,实际上就是把一堆 头文件,lib导入库,dll动态库安装到你电脑,这些东西都是 FFmpeg 编译链接 或者运行的时候需要的。

FFmpeg 进行硬件编解码的时候 是通过 CUDA Toolkit 给的 dll 跟 显卡驱动 通信的。如下图:

上图是这样的, CUDA Toolkit 给的东西,那些头文件,lib导入库,只有在编译 ffmpeg.exe 的时候才需要,一旦编译出来 ffmpeg.exe ,那些 xx.h 跟 xx.lib 都没用了。然后我们只需要把 这4个dll 跟 ffmpeg.exe 一起发布给客户使用即可,客户机不需要安装 CUDA Toolkit。

官网的教程有提及,如下:

Running a CUDA application requires the system with at least one CUDA capable GPU and a driver that is compatible with the CUDA Toolkit.

CUDA 的全称是 Compute Unified Device Architecture,计算机统一设备架构,但后来 NVIDIA 取消了个全称。CUDA 就是 CUDA,不需要解释。


下面开始安装 CUDA Toolkit 10.1,安装界面如下,选择自定义安装

为了更快地安装,我们只需要选择 Development 跟 Runtime ,这两个是 编译环境运行时,也就是会把一些 头文件, lib 导入库 跟 dll 库 安装到我们电脑。

那些 Nsight 是 NVIDIA 的性能分析工具,咱们初学用不到,选太多东西安装,会经常导致安装失败,如下:

这个 CUDA Toolkit 有可能经常安装失败,可以参考 官网英文教程

CUDA Toolkit 安装完毕,在 WinCMD 命令行输入 nvcc -V,查看安装是否成功。

我们可以看一下 CUDA Toolkit 安装包装了哪些东西到电脑上,如下图:

从上图可以看出,CUDA Toolkit 就是安装了一些 头文件,lib导入库,DLL动态库。

因此,我们现在需要 把这些 头文件,lib导入库 放到 msys2 的目录,同时做一些相关配置,让 FFmpeg 的编译脚本能找到他们。

/usr/local/include 新建一个目录 nv_sdk_10.1 用来放头文件。

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\include 下面所有的头文件复制到 nv_sdk_10.1 目录,如下:

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64 里面所有的 lib 导入库全部 复制到 /usr/local/lib/x64

这里我就不建 pc 文件来定位这些 头文件跟 lib了,本文后面会介绍一种新的方式,用 --extra-cflags--extra-ldflags 来搞。


本文 编译的 ffmpeg.exe 是64位,因为 64位才能最大发挥 CUDA Toolkit 的作用。NVIDIA官网教程有讲如何编译 32位,但是我看了下,32位会少很多库,应该会少很多功能,所以本文不讲解32位的编译。

FFmpeg 用 NVIDIA GPU 硬件编解码也是支持 MinGW 的编译方式的,但是 MinGW 的方式我还没实践过,所以不讲解,官网说是支持的。如下:

FFmpeg with NVIDIA GPU acceleration is supported on all Windows platforms, with compilation through Microsoft Visual Studio 2013 SP2 and above, and MinGW. Depending upon the Visual Studio Version and CUDA SDK version used, the paths specified may have to be changed accordingly.

所以本文用 msys2 + msvc 来编译 FFmpeg,不熟悉这种编译方式的请看《用msys2与msvc编译FFmpeg》



在开始编译之前,还需要用到 nv-codec-headers 项目的头文件,这里跟 官方教程 ffmpeg-with-nvidia-gpu 不太一样,不能直接执行下面命令:

git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git

上面命令拉下来的 nv-codec-headers 是master 分支的,需要的显卡驱动至少要 471.41 以上,我们本地显卡驱动是 456.71,因此如果直接用官网的命令会编译失败。

nv-codec-headersREADME 可以看到 所需显卡驱动版本:

这里提供一个下载 nv-codec-headers 历史版本的地址,历史版本下载。请选择符合自己显卡驱动的版本。本文选择的是 9.1.23.3 版本。

因此,编译 NVIDIA 硬件编解码最重要的地方就是版本匹配,3个组件的版本需要匹配兼容。不匹配 ffmpeg 的 configure 脚本会通不过。

  1. 显卡驱动 版本,本文是 456.71
  2. CUDA Toolkit 版本,本文是 10.1
  3. nv-codec-headers 版本,本文是 9.1.23.3

nv-codec-headers 项目里面有个 makefile 文件,官网教程提示要执行 make install但本文不建议使用 make install 来安装 nv-codec-headers,我们手动安装。

先把 nv-codec-headers 里面 include 目录的 ffnvcodec 文件夹复制到 /usr/local/include/,如下:

然后手动创建一个 ffnvcodec.pc 文件,内容如下:

prefix=/usr/local/include/
includedir=${prefix}
Name: ffnvcodec
Description: FFmpeg version of Nvidia Codec SDK headers
Version: 9.1.23.3
Cflags: -I${includedir}

为什么我要手动搞一个 ffnvcodec.pc,是因为用 make install 生成的 ffnvcodec.pc 里面 Cflags 的运算结果是 -IC:/msys64/usr/include, 用 cl.exe 编译的时候,是不能引入 C:/msys64/usr/include 里面的 mingw 的头文件,会跟 MSVC 的头文件同名混乱,导致报错。

如果直接 make install ,在 configure 的时候,在 ffbuild/config.log 中会报 C2054 等等错误,如图:

这个C2054 错误非常隐蔽,这个错误不会导致 configure 失败,所以看configure的输出是成功的,只是执行 ffmpeg.exe -hwaccels 显示硬件加速的时候,没有cuda这个选项输出。因此也无法使用硬件编解码。

现在需要把 ffnvcodec.pc 放到 \usr\local\lib\pkgconfig 目录,如下:

还需要执行以下命令,把 /usr/local/lib/pkgconfig/ 加入搜索路径:

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/:$PKG_CONFIG_PATH

本文不需要安装 Video_Codec_SDK,那应该是旧版本 CUDA Toolkit 的做法。

我们可以下载一个来看看,Video_Codec_SDK 里面主要是一些 lib 库跟 .h头文件,如下图。

我用 Everything 软件 搜索 nvcuvid.lib 这个库,这应该是一个导入库,不是静态库。

我电脑是装了 4个版本的 CUDA toolkits,8.0,9.0,9.2,10.1,可以看到 10.1 版本的 CUDA toolkits 并没有出现在 everything 的搜索里面。

也就是说 CUDA toolkits 从 10.1 版本开始就去掉了 nvcuvid.lib 这个库,之前的硬件解码器好像是叫 cuvid,现在好像改了个名字,叫nvdec。

所以本文编译 ffmpeg NVENC NVDEV,不需要下载安装 Video_Codec_SDK,那是旧版的方式。咱们用的 CUDA Toolkits 版本是 10.1,是新版的。


到这里, CUDA Toolkit 10.1,nv-codec-headers 9.1.23.3 都已经安装完毕,下面就可以开始用 msys2 + msvc 来编译 FFmpeg 了。

./configure \
--prefix=/home/loken/ffmpeg/build64/ffmepg-4.4-nv-10.1 \
--enable-gpl \
--enable-nonfree \
--enable-cuda-nvcc \
--enable-libnpp \
--enable-shared \
--toolchain=msvc \
--extra-cflags="-I/usr/local/include/nv_sdk_10.1" \
--extra-ldflags="-LIBPATH:/usr/local/lib/x64"

扩展知识:msvc 的 link.exe 链接器接受的搜索路径参数是 -LIBPATH,gcc 链接器接受的参数是 -L ,不要混淆。

从 configure 的输出日志,可以看到以下内容,就代表 cuda 成功了。


FFmpeg-n4.4.1 版本源码在 编译 CUDA 硬件编解码 还会报一个错误,错误提示如下:

"libavfilter/vf_scale_cuda_bicubic.ptx.c(1925): fatal error C1091: compiler limit: string exceeds 65535 bytes in length"

这是一个 FFmpeg-n4.4.1 的一个 bug,可以用 此 patch 来修复。修复之后要重新 configure


编译完成之后,执行 ./ffmpeg.exe -hwaccels 显示 ffmpeg 的硬件加速方法,如下图所示,可以看到 cuda 的选项。

至此,ffmpeg.exe 已经编译完毕。下面找一个高清电影,来测试ffmpeg 的NVENC 硬件编码。

./ffmpeg.exe -hwaccel cuvid -i juren.mp4 -vcodec h264_nvenc -acodec copy juren_h264_nvenc.mp4

从上图可以看到, cpu的负载很小,而 GPU 直接 99% 满功率了。ffmpeg.exe 硬件编码测试通过。

现在这个 ffmpeg.exe 其实依赖4个dll,nppc64_10.dllnppicc64_10.dllnppidei64_10.dllnppig64_10.dll。如下:

所以如果要发布程序,需要把这 4个 dll 跟 ffmpeg.exe 一起发布,如下:


常见错误:

1, LINK : fatal error LNK1104: cannot open file 'LIBCMTD.lib'。

这个错误是因为没用 x64 Native Tools Command Prompt for VS 2019.exe 开启CMD,msys2 没继承vs2019的环境变量,所以找不到 vs2019 目录的 LIBCMTD.lib。

2,libavfilter/vf_scale_cuda_bicubic.ptx.c(1925): fatal error C1091: compiler limit: string exceeds 65535 bytes in length

这是一个 FFmpeg-n4.4.1 的一个 bug,可以用 此 patch 来修复。


相关阅读:

1,《NVIDIA官方FFmpeg编译教程》

2,《cuda-installation-guide-microsoft-windows》

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
6月前
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
648 4
|
6月前
|
存储 编解码 vr&ar
用C++实现视频编码器:FFmpeg与SDL技术结合,轻松编写高效编解码器
用C++实现视频编码器:FFmpeg与SDL技术结合,轻松编写高效编解码器
772 0
|
编解码 Linux 计算机视觉
ffmpeg硬编解码 Inter QSV
ffmpeg硬编解码 Inter QSV
700 0
|
4月前
|
存储 编解码 容器
FFmpeg avformat_open_input() 函数返回错误protocol not found解决方法(实测有效!附简单FFMPEG的编解码流程)
我个人出现这个错误的时候是在打开文件时报的错误,开始以为我需要加上资源文件,那样QT确实能检测到文件的存在,但是在Debug中他是检测不到这个文件的。
478 1
|
5月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
268 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
6月前
|
存储 编解码 缓存
【ffmpeg 移动视频流位置】深入理解FFmpeg:精细探讨seek操作和编解码上下文
【ffmpeg 移动视频流位置】深入理解FFmpeg:精细探讨seek操作和编解码上下文
332 0
|
6月前
|
编解码 Shell
在jetson中实现ffmpeg调用硬件编解码加速处理
在jetson中实现ffmpeg调用硬件编解码加速处理
1423 0
|
编解码 并行计算 计算机视觉
ffmpeg硬件编解码Nvidia GPU
ffmpeg硬件编解码Nvidia GPU
674 0
|
编解码 Linux 编译器
FFmpeg引入x264扩展
FFmpeg引入x264扩展
224 0
|
缓存 编译器 Linux
FFmpeg引入SDL扩展
FFmpeg 引入 SDL 扩展实际上非常简单,原理就是 编译 FFmpeg 的时候加上 SDL 的导入库就行。跟其他的 C/C++ 项目引入外部动态库是一样的。
213 0