GTC 大会火热进行中!别错过 NVIDIA CEO 黄仁勋的最新发布,以及 AI 和加速计算的必听会议。
图形/仿真

NVIDIA FFmpeg 转码指南

所有从 Kepler 一代开始的 NVIDIA GPUs 都支持完全加速的硬件视频编码,而从费米一代开始的所有 GPUs 都支持完全加速的硬件视频解码。截至 2019 年 7 月,Kepler、Maxwell、Pascal、Volta 和 Turing 一代 GPUs 支持硬件编码,Fermi、Kepler、Maxwell、Pascal、Volta 和 Turing 一代 GPUs 支持硬件解码。

高质量视频应用的处理需求对广播和电信网络提出了限制。消费者行为已经发生了变化,这在 OTT 视频订阅和实时流媒体迅速普及的趋势中表现得很明显。现在所有的社交媒体应用程序都在各自的平台上加入了这一功能。随着消费者从观看点播视频转向观看直播视频,直播将推动手机和 Wi-Fi 的整体视频数据流量增长。

分发给观众的视频内容通常被转换成几个自适应比特率( ABR )配置文件以进行传输。生产中的内容可能以大量编解码器格式之一到达,这些格式需要转换为另一种格式以供分发或存档。

这使得视频转码成为高效视频管道中的一个关键部分——无论是 1 : N 还是 M : N 配置文件。理想的转码解决方案需要在成本(美元/流)和能效(瓦特/流)方面具有成本效益,同时为数据中心提供具有最大吞吐量的高质量内容。视频提供商希望降低向更多屏幕提供更多高质量内容的成本。

在各个方面生成的大量视频内容需要对视频编码、解码和转码进行健壮的硬件加速。让我们看看 NVIDIA GPUs 是如何整合专用视频处理硬件的,以及如何利用它。

NVIDIA 编解码硬件

NVIDIA GPUs 船上配备了片上硬件编码器和解码器单元,通常称为 NVENC 和 NVDEC 。与 CUDA 核心分开, NVENC / NVDEC 运行编码或解码工作负载,而不会减慢同时运行的图形或 CUDA 工作负载的执行。

NVENC 和 NVDEC 支持许多重要的编解码编解码器。 NVIDIA 。最新的支持矩阵可以在 GPU 上找到。

GPU encode and decode capabilities image
图 1 : GPU 硬件功能

基于 FFmpeg 的硬件加速转码

在对视频数据进行转码时,通常使用 FFmpeg 库 。硬件加速极大地提高了工作流的性能。图 2 显示了 FFmpeg 转换过程的不同元素。

Transcoding pipeline with ffmpeg flow diagram
图片 2 :使用 NVIDIA 硬件加速的 FFmpeg 流水线转码

FFmpeg 通过 h264_cuvidhevc_cuvidh264_nvenchevc_nvenc 模块支持硬件加速解码和编码。从源代码构建时激活对硬件加速的支持需要一些额外的步骤:

  • 克隆 FFmpeg git 存储库 https://git.ffmpeg.org/ffmpeg.git
  • 从 NVIDIA 网站 下载并安装兼容的驱动程序
  • 下载并安装 CUDA 工具箱
  • 克隆 nv-codec-headers 存储库 并仅使用此存储库作为头进行安装: make install
  • 使用以下命令配置 FFmpeg (使用正确的 CUDA 库路径):
./configure --enable-cuda --enable-cuvid --enable-nvenc --enable-nonfree --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64
  • 使用多个进程进行构建,以提高构建速度并抑制过度输出: make -j -s

使用 FFmpeg 进行软件 1 : 1 转码非常简单:

ffmpeg -i input.mp4 -c:a copy -c:v h264 -b:v 5M output.mp4

但这将是缓慢的,因为它只使用基于 CPU 的软件编码器和解码器。使用硬件编码器 NVENC 和解码器 NVDEC 需要添加更多参数来告诉 ffmpeg 使用哪个编码器和解码器。最大化转码速度还意味着确保解码后的图像保存在 GPU 存储器中,以便编码器能够有效地访问它。

ffmpeg -vsync 0 -hwaccel cuvid -c:v h264_cuvid -i input.mp4 -c:a copy -c:v h264_nvenc -b:v 5M output.mp4

如果没有 -hwaccel-cuvid 选项,解码后的原始帧将通过 PCIe 总线复制回系统内存,如图 3 所示。稍后,相同的图像将通过 PCIe 复制回 GPU 内存,以便在 GPU 上进行编码。这两个额外的传输由于传输时间而造成延迟,并将增加 PCIe 带宽占用。

Memory flow without hwaccel diagram
图&& 3 :没有 hAccel 的内存流(& M )

添加 -hwaccel-cuvid 选项意味着原始解码帧将不会被复制,转码将更快、使用更少的系统资源,如图 4 所示。

Memory flow with hwaccel diagram
hwaccel 的内存流

给定 PCIe 带宽限制,复制未压缩的图像数据会使 PCIe 总线迅速饱和。防止系统和 GPU 内存之间不必要的复制,使用 -hwaccel-cuvid 的吞吐量比不使用 -hwccel-cuvid 的未优化调用高出 2 倍。

处理筛选器

代码转换通常不仅涉及到更改输入流的格式或比特率,还包括调整其大小。有两个选项可用于调整 GPU 上的大小:使用 npp_scale 过滤器或 nvcuvid resize 选项。当从一个输入到一个具有不同分辨率( 1 : 1 转码)的输出流转码时,可以使用 nvcuvid resize 选项。请参见下一行的示例。

ffmpeg -vsync 0 –hwaccel cuvid -c:v h264_cuvid –resize 1280x720 -i input.mp4 -c:a copy -c:v h264_nvenc -b:v 5M output.mp4

如果需要多个输出分辨率( 1 : N 转码),则 scale_npp 滤波器可以调整 GPU 上解码帧的大小。通过这种方式,我们可以生成具有多个不同分辨率的多个输出流,但对所有流只使用一个调整大小的步骤。关于 1 : 2 转码的示例,请参见下一行。

ffmpeg -vsync 0 –hwaccel cuvid -c:v h264_cuvid -i input.mp4 \ -c:a copy –vf scale_npp=1280:720 -c:v h264_nvenc -b:v 5M output_720.mp4 \ -c:a copy -vf scale_npp=640:320 -c:v h264_nvenc -b:v 3M output_360.mp4

使用 -vf "scale_npp=1280:720" 将设置 scale_npp 作为解码图像的过滤器

插值算法可以作为附加参数为 scale_npp 定义。默认情况下使用三次插值,但其他算法 MIG ht 会根据比例因子和图像提供更好的结果。建议在缩小尺度时使用超级采样算法以获得最佳质量。示例如下:

ffmpeg -vsync 0 –hwaccel cuvid -c:v h264_cuvid -i input.mp4 -c:a copy –vf scale_npp=1280:720:interp_algo=super -c:v h264_nvenc -b:v 5M output_720.mp4

混合 CPU 和 GPU 处理

有时 MIG 需要混合使用 CPU 和 hwupload_cuda 处理。例如,您可能需要在 CPU 上解码,因为 -hwaccel cuvid 解码器不支持该格式,或者 GPU 上没有滤波器。在这种情况下,不能使用 GPU 标志。相反,您需要使用 GPU 过滤器将数据从系统上传到 GPU 内存。在下面的示例中,由于未设置 -hwaccel cuvid ,因此在 GPU 上解码 H . 264 流并将其下载到系统内存中。淡入滤波器应用于系统存储器中,并使用 hwupload_cuda 滤波器将处理后的图像上传到 GPU 存储器。最后,使用 scale_npp 缩放图像并在 GPU 上编码。

ffmpeg -vsync 0 -c:v h264_cuvid -i input.264 -vf "fade,hwupload_cuda,scale_npp=1280:720" -c:v h264_nvenc output.264

多 -GPU

当在一个系统中使用多个 GPUs 时,编码和解码工作必须显式地分配给 GPU 。 GPUs 由其索引号标识;默认情况下,所有工作都在索引为 0 的 GPU 上执行。使用以下命令获取系统中所有 NVIDIA GPUs 及其相应的 ID 号的列表:

ffmpeg -vsync 0 -i input.mp4 -c:v h264_nvenc -gpu list -f null –

一旦知道了索引,就可以使用 -hwaccel_device 索引标志来设置解码和编码的活动 GPU 。在下面的例子中,工作将在索引为 1 的 GPU 上执行。

ffmpeg -vsync 0 -hwaccel cuvid -hwaccel_device 1 -c:v h264_cuvid -i input.mp4 -c:a copy -c:v h264_nvenc -b:v 5M output.mp4

优化

为了获得最佳的吞吐量,所有的编码器和解码器单元都应该被尽可能地利用。 nvidia-smi 可用于生成有关 NVENC 、 NVDEC 和一般 GPU 利用率的实时信息。

nvidia-smi dmon nvidia-smi -q -d UTILIZATION

根据这些结果可以采取多种措施。如果编码器利用率低, MIG 可以引入另一个转码管道,该管道使用 CPU 解码和 NVENC 编码来为硬件编码器生成额外的工作负载。

使用 CPU 筛选器时, PCIe 带宽 MIG ht 成为瓶颈。如果可能,筛选器应在 GPU 上运行。 FFmpeg 中有几个 CUDA 过滤器,可以用作模板来实现您自己的高性能 CUDA 过滤器。

通过使用 GPU SDK 的 NVIDIA 可视化分析器分析 ffmpeg 应用程序,您可以始终跟踪主机和设备之间的 GPU 利用率和内存传输。只需启动“ Run application to generateCPU andGPU timeline ”,然后选择带有相关 CLI 选项的 ffmpeg 应用程序。图 5 说明了应用程序

ffmpeg in nvprof image
图 5 :

绿松石块显示 CUDA 内核完成的颜色空间转换,而黄色块显示主机和设备之间的内存传输。使用 visualprofiler ,用户可以轻松地跟踪在 GPU 上执行的操作,例如 CUDA 加速的过滤器和数据传输,以确保不会执行过多的内存拷贝。

通过使用 --disable-stripping CLI 选项编译 ffmpeg 来收集 CPU – 端性能统计信息,以启用性能分析。

这可以防止编译器剥离函数名,以便像 Gprof 或 visualstudioprofiler 这样的商品探查器可以收集性能统计信息。 CPU 在硬件加速开启的情况下,负载水平应较低,并且大部分时间应花费在视频代码 SDK API 调用中,这些调用标记为“外部代码因为函数名从驱动程序库中被删除。图 6 显示了一个示例屏幕截图。

ffmpeg profiling in Visual Studio image
图 6 : visualstudio 的 ffmpeg 性能评测

 

进一步阅读

有关如何使用 FFmpeg 的更多示例以及可用的高级质量设置,请查看“ 使用 FFmpeg 和 NVIDIA GPU 硬件加速 “向导。

结论

FFmpeg 是一个强大而灵活的开源视频处理库,具有硬件加速的解码和编码后端。它允许快速的视频处理和完整的 NVIDIA GPU 硬件支持,只需几分钟。 Gprof 、 visualprofiler 和 microsoftvisualstudio 等商品开发工具可以用于精细的性能分析和调优。看看 ffmpeg 源 试试吧!

 

Tags