window10_ffmpeg-with-nvidia-gpu编译

本文主要介绍 如何在window10的环境下 编译ffmpeg 的 硬件编解码器,NVENC 跟 NVDEC。

首先电脑需要装 一块 NVIDIA 的显卡,我的是 GeForce RTX 2060 。

NVENC 跟 NVDEC 编解码器所支持的GPU显卡可以通过下面地址查看:

Video Encode and Decode GPU Support Matrix [NEW] | NVIDIA Developer

window10_ffmpeg-with-nvidia-gpu编译_第1张图片

编译出 NVENC 跟 NVDEC 编解码器 需要先安装 CUDA toolkits ,参考官网教程安装,CUDA 安装教程 。

开始操作:

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

window10_ffmpeg-with-nvidia-gpu编译_第2张图片

从上图可以看到,本地显卡 GeForce RTX 2060 的驱动版本号是 456.71,再点击此链接,查看 显卡驱动 456.71 版本对应的 CUDA Toolkit 版本

window10_ffmpeg-with-nvidia-gpu编译_第3张图片

由于Toolkit Driver (显卡驱动) 是向后兼容的,所以我们选择 CUDA toolkits 10.1 进行安装。 CUDA toolkits 10.1 支持的 显卡驱动 最低版本是 418.96。我们的显卡驱动 版本号是 456.71,所以用 CUDA toolkits 10.1 是没问题的。

CUDA Toolkits 历史版本下载:CUDA Toolkit Archive | NVIDIA Developer

这里需要讲解一下 Toolkit Driver (显卡驱动) 跟 CUDA toolkits (CUDA工具套件)的关系。因为要编译硬件编解码器 NVENC 跟 NVDEC,所以需要安装 CUDA toolkits 进行编译。 CUDA toolkits 只是编译程序的时候需要,一旦编译出来 exe运行问题,CUDA toolkits 就没用了,也就是说客户的目标机器只需要安装 Toolkit Driver (显卡驱动) 就能用 ffmpeg.exe 里面的硬件编解码 NVENC 跟 NVDEC,客户的目标机器不需要 安装CUDA toolkits 。官网的教程有提及,如下:

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,计算机统一设备架构。

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

window10_ffmpeg-with-nvidia-gpu编译_第4张图片

window10_ffmpeg-with-nvidia-gpu编译_第5张图片

这个CUDA toolkits 经常安装失败,本人装了2个小时,官网英文教程也看了。最后是重启 window 10 再安装就好了。

window10_ffmpeg-with-nvidia-gpu编译_第6张图片

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

window10_ffmpeg-with-nvidia-gpu编译_第7张图片


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

CUDA toolkits 里面只有lib后缀的库,所以 ffmpeg 只能用 MSYS2 + MSVC 的方式编译。

NVIDIA 官方 FFmpeg 编译教程 : ffmpeg-with-nvidia-gpu

因为需要用到 MSVC ,所以需要安装 vs2019 ,请自行安装。vs2017 应该也是可以的,本文是基于 vs2019的。MSYS2 在之前的文章已经装过了。

本文虽然也是用的MSYS2,但是跟《window10_ffmpeg调试环境搭建-自己编译》不同,不能直接在 window10 CMD 里面直接 输入 .\msys2_shell.cmd -mingw64

因为需要用到 vs2019 里面的 cl.exe 来编译 ffmpeg 的代码,需要用 vs2019 里面的 link.exe 来链接库。还需要用到 vs2019 里面的 某些lib 库,例如 LIBCMT.lib。

所以MSYS2 需要继承 vs2019 的环境变量,怎么继承呢?

MSYS2 环境继承vs2019 的环境变量 操作教程:

1,修改 C:\msys64\msys2_shell.cmd 中的 rem set MSYS2_PATH_TYPE=inherit,去掉rem,取消这⼀句的注释。使MSYS2的环境变量继承当前CMD的窗口的环境变量。

2,重命名 C:/msys64/usr/bin/link.exe 为 C:/msys64/usr/bin/link.bak , 避免和MSVC 的link.exe抵触。这个是网上文章的做法,这个其实在新版的ffmpeg 里面是不需要的,在 configure里面编译的时候,调用的是 ./compat/window/mslink ,如下:

window10_ffmpeg-with-nvidia-gpu编译_第8张图片

 ./compat/window/mslink 代码
#!/bin/sh
​
LINK_EXE_PATH=$(dirname "$(command -v cl)")/link
if [ -x "$LINK_EXE_PATH" ]; then
    "$LINK_EXE_PATH" $@
else
    link.exe $@
fi
exit $?

上面是 mslink 的代码,可以看到,他的逻辑就是优先 使用 跟 cl.exe 同目录下的 link.exe。cl.exe 只有在vs2019 那里才有,C:/msys64/usr/bin 目录下没有 cl.exe,所以会优选使用 vs2019 里面的link.exe,所以不重命名 C:/msys64/usr/bin/link.exe 也没关系。

3,上面的 C:\msys64\msys2_shell.cmd 文件已经修改好了,现在要找到 x64 Native Tools Command Prompt for VS 2019 这个命令工具。

window10_ffmpeg-with-nvidia-gpu编译_第9张图片

点击 x64 Native Tools Command Prompt for VS 2019 打开命令行,一定要这样打开命令行,这样命令行才能有 vs2019 的环境变量,然后才能让 msys2 来继承,我之前说的 MSYS2_PATH_TYPE=inherit 继承的环境变量 是当前窗口的环境变量就是这个意思。

window10_ffmpeg-with-nvidia-gpu编译_第10张图片

千万不要用下面这种 win+R 的方式打开命令行,这样子打开命令行是没有 vs2019 的环境变量的。

window10_ffmpeg-with-nvidia-gpu编译_第11张图片

window10_ffmpeg-with-nvidia-gpu编译_第12张图片

4,演示完错误的打开CMD的方式,我们继续操作,在 x64 Native Tools Command Prompt for VS 2019 命令窗口输入 cd c:\msys64\ 先回到 msys64目录,然后再输入

.\msys2_shell.cmd -mingw64,启动 msys2 命令行窗口,如图:

图:

#回到 MSYS2 的安装目录
cd c:\msys64\
#启动 msys2 命令行
.\msys2_shell.cmd -mingw64

window10_ffmpeg-with-nvidia-gpu编译_第13张图片

5,在 msys2 命令行窗口 输入 echo $LIB ,可以看到 msys2 命令行窗口 已经继承了 vs2019 的 lib 环境变量。

window10_ffmpeg-with-nvidia-gpu编译_第14张图片

6,再输入一下 which cl.exe ,确认一下 cl.exe 是在vs2019的目录下,同时看下cl.exe的目录是否有link.exe。

window10_ffmpeg-with-nvidia-gpu编译_第15张图片


MSYS2 + MSVC 环境已经准备好了,MSYS2 命令行已经继承了 vs2019 的环境变量,下面开始做一些 编译 ffmpeg 前的准备工作。

编译 ffmpeg NVENC NVDEC 教程:

1,下载 FFmpeg-n4.4.1.zip ,百度网盘,提取码:rpo3 ,下载好之后解压到 C:\msys64\home\loken\ffmpeg ,这个目录是我们之前文章经常用的目录。

window10_ffmpeg-with-nvidia-gpu编译_第16张图片

2,安装所需软件,pacman -S diffutils make pkg-config yasm

window10_ffmpeg-with-nvidia-gpu编译_第17张图片

这里我需要讲解一下 pkg-config 这个软件的作用,pkg-config 这个命令行在linux安装软件经常使用,他到底是做什么用的呢?

参考阅读:Linux的pkg-config命令,在本文中 pkg-config 命令的作用是提取 ffnvcodec.pc 的变量。

3,下载 nv-codec-headers,nv-codec-headers 是 与 Nvidias 编解码器 API 接口(interface)所需的头文件的 FFmpeg 版本。

这里跟 官方教程 ffmpeg-with-nvidia-gpu 不太一样,不能直接执行 git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git 因为拉下来的 nv-codec-headers 需要的显卡驱动至少要 471.41 以上,我们本地显卡驱动是 456.71,如果直接用官网的命令会编译失败。

nv-codec-headers 的Readme 如下,可以看到 所需显卡驱动版本:

FFmpeg version of headers required to interface with Nvidias codec APIs.

Corresponds to Video Codec SDK version 11.0.10.

Minimum required driver versions:
Linux: 470.57.02 or newer
Windows: 471.41 or newer

所以 nv-codec-headers 需要手动下载,nv-codec-headers下载地址,我们选 Version 9.1.23.3 下载,因为显卡驱动是向后兼容的, 9.1.23.3 的版本可用。

4,下载完 nv-codec-headers 之后,解压到 C:\msys64\home\loken\ffmpeg 目录,如下:

window10_ffmpeg-with-nvidia-gpu编译_第18张图片

5,安装 nv-codec-headers-n9.1.23.3。到这一步,也不能像 官方教程 ffmpeg-with-nvidia-gpu 那样直接进入 nv-codec-headers-n9.1.23.3,然后执行make install。我们需要手动改下 nv-codec-headers-n9.1.23.3 里面的 ffnvcodec.pc 文件,改动最后一行,改动如下:

Cflags: -I${includedir}
改为
Cflags: -IC:/msys64/home/loken/ffmpeg/nv-codec-headers-n9.1.23.3/include

为什么要这样改,是因为 configure 里面用 cl.exe 编译的时候,不能引入 C:/msys64/usr/include 里面的头文件,会跟 MSVC 的头文件同名混乱,导致报错。

Cflags: -I${includedir} 的运算结果就是 Cflags: -IC:/msys64/usr/include 。

如果不改,configure的时候,在ffbuild/config.log 中会报 C2054 等等错误,如图:

window10_ffmpeg-with-nvidia-gpu编译_第19张图片

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

所以学会看 ffbuild 目录下的 config.log 日志非常重要。

6,改好 ffnvcodec.pc 之后,我们进入 nv-codec-headers-n9.1.23.3 目录,执行 make install PREFIX=/usr

window10_ffmpeg-with-nvidia-gpu编译_第20张图片

从上图可以看到,make install PREFIX=/usr 命令最主要的就是把 ffnvcodec.pc 拷贝到 /usr/lib/pkgconfig 目录,/usr/include/ffnvcodec 里面的头文件我们configure编译的时候用不到,上面已经把 ffnvcodec.pc 里面的 Cflags 参数改了。所以你可以不用 make install,手动把 ffnvcodec.pc 拷贝到 /usr/lib/pkgconfig 目录,效果是一样的。可以进入 nv-codec-headers-n9.1.23.3 目录看看,实际上只有几个 .h 头文件跟 .pc 文件。

扩展知识:

网上有些文章是旧版的编译规则,旧版的需要下载 Video_Codec_SDK,我们可以下载一个来看看,Video_Codec_SDK 里面主要是一些 lib 库跟 .h头文件,如下图。

window10_ffmpeg-with-nvidia-gpu编译_第21张图片

我用 Everything 软件 搜索 nvcuvid.lib 这个库,

window10_ffmpeg-with-nvidia-gpu编译_第22张图片

我电脑是装了 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,是新版的。

编译 ffmpeg NVENC NVDEV 特别重要的一个地方就是版本号是否匹配。

  • 显卡驱动版本号
  • CUDA toolkits 版本号。
  • nv-codec-headers 版本号

上面这个 3个东西的版本号必须匹配才能编译成功。

7,安装好 nv-codec-headers 之后,继续操作,回到 /home/loken/ffmpeg 目录,创建 nv_sdk_10.1 文件夹。

cd /home/loken/ffmpeg/
mkdir nv_sdk_10.1

window10_ffmpeg-with-nvidia-gpu编译_第23张图片

window10_ffmpeg-with-nvidia-gpu编译_第24张图片

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

9,复制 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\lib\x64 下面所有的库文件到 nv_sdk_10.1 目录

window10_ffmpeg-with-nvidia-gpu编译_第25张图片


操作到这里,nv-codec-headers 已经安装好了,CUDA toolkits 的lib跟头文件也已经拷贝到 C:\msys64\home\loken\ffmpeg\nv_sdk_10.1 目录,下面正式开始编译 FFmpeg NVENC NVDEC。

FFmpeg NVENC NVDEC 编译:

1,进入 FFmpeg-n4.4.1 源码目录

cd /home/loken/ffmpeg/FFmpeg-n4.4.1

2,添加 /usr/lib/pkgconfig 路径到 $PKG_CONFIG_PATH

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

这样做是因为 我们的 ffnvcodec.pc 是安装到 /usr/lib/pkgconfig 下的。/usr/lib/pkgconfig 目录默认不在 $PKG_CONFIG_PATH 环境变量里面,如果不加进去,会导致 configure的时候找不到 ffnvcodec,然后跳过编译 cuda 硬件加速,虽然能configure成功,最后也能编译成功,但是 ffmpeg.exe -hwaccels 的时候没有 cuda这个选项输出,也就没法使用硬件编解码,从 ffbuild/config.log 可以看到错误,如下:

window10_ffmpeg-with-nvidia-gpu编译_第26张图片

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

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

window10_ffmpeg-with-nvidia-gpu编译_第27张图片

这是一个bug,bug地址,ffmpeg 已经修复了,出了一个 patch ,patch 地址 。请按照patch补丁的方法修改以下文件。

  • FFmpeg-n4.4.1\compat\cuda\ptx2c.sh
  • FFmpeg-n4.4.1\configure

或者用以下命令应用这个 patch。

 git am 0001-Patch-for-ticket-9019-CUDA-Compile-Broken-Using-MSVC.patch

4,上面的操作都执行之后,可以正式开始编译 ffmpeg 了,命令如下:

./configure \
--prefix=/home/loken/ffmpeg/build64/ffmepg-4.4-nv-10.1 \
--enable-gpl \
--enable-nonfree \
--disable-shared \
--enable-cuda-nvcc \
--enable-libnpp \
--toolchain=msvc \
--extra-cflags="-I/home/loken/ffmpeg/nv_sdk_10.1" \
--extra-ldflags="-LIBPATH:/home/loken/ffmpeg/nv_sdk_10.1"
​
make -j8
make install

上面这个configure 命令有个重要知识点需要提及一下,用了 --toolchain=msvc 之后,使用的是 vs2019 目录的 cl.exe 来编译C代码,不是 MSYS2 环境的 gcc.exe了。所以 --extra-ldflags 指定库搜索路径的方式 是 -LIBPATH ,不是 -L。 -L 是 gcc.exe 用的命令参数。-LIBPATH 才是 cl.exe用的命令参数。

5,编译完成之后,build64/ffmpeg-4.4-nv-10.1 目录如下:

window10_ffmpeg-with-nvidia-gpu编译_第28张图片

window10_ffmpeg-with-nvidia-gpu编译_第29张图片

可以看到,msys2 + msvc 编译出来的 ffmpeg.exe 非常精简,不像之前 msys2 + MinGW 编译出来的 ffmpeg.exe 运行需要拷贝一堆dll库过来。

6,执行 ./ffmpeg.exe -hwaccels 显示ffmpeg的硬件加速方法,如下图所示,可以看到 cuda 的选。

cd /home/loken/ffmpeg/build64/ffmepg-4.4-nv-10.1/bin
./ffmpeg.exe -hwaccels

window10_ffmpeg-with-nvidia-gpu编译_第30张图片


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

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

window10_ffmpeg-with-nvidia-gpu编译_第31张图片

window10_ffmpeg-with-nvidia-gpu编译_第32张图片

从上图可以看到, cpu的负载很小,而GPU 直接 99% 满功率了。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"

这是一个bug,bug地址,ffmpeg 已经修复了,出了一个 patch ,patch 地址。

重要知识点:

1, 如何查看自身电脑的 GPU 型号是否支持 NVENC NVDEC 硬件编解码?

NVIDIA 官网有 Video Encode and Decode GPU Support Matrix [NEW] | NVIDIA Developer

2,如何查看自身电脑的GPU驱动对应的 CUDA toolkits 版本?

Release Notes :: CUDA Toolkit Documentation

3,如何查看自身电脑的GPU驱动对应的 nv-codec-headers 版本?

下载 nv-codec-headers,直接打开 里面的Readme ,能看到最低驱动版本支持。

4,configure 用了 --toolchain=msvc 之后,使用的是 vs2019 目录的 cl.exe 来编译C代码,不是 MSYS2 环境的 gcc.exe了。所以 --extra-ldflags 指定库搜索路径的方式 是 -LIBPATH ,不是 -L。 -L 是 gcc.exe 用的命令参数。-LIBPATH 才是 cl.exe用的命令参数。

扩展知识:

1,CUDA 全称 Compute Unified Device Architecture,翻译为 "计算机统一设备架构"。

2,CUDA 编程范例,GitHub - NVIDIA/cuda-samples: Samples for CUDA Developers which demonstrates features in CUDA Toolkit

3,客户的目标机器只需要安装 Toolkit Driver (显卡驱动) 就能用 ffmpeg.exe 里面的硬件编解码 NVENC 跟 NVDEC,客户的目标机器不需要 安装CUDA toolkits 。

window10_ffmpeg-with-nvidia-gpu编译_第33张图片

参考资料:

1,ffmpeg 硬件加速介绍

2,CompilationGuide – FFmpeg


©版权所属:弦外之音。

由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。

你可能感兴趣的:(FFmpeg源码分析,docker,linux,容器)