所有从 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 上找到。
基于 FFmpeg 的硬件加速转码
在对视频数据进行转码时,通常使用 FFmpeg 库 。硬件加速极大地提高了工作流的性能。图 2 显示了 FFmpeg 转换过程的不同元素。
FFmpeg 通过 h264_cuvid
、 hevc_cuvid
和 h264_nvenc
、 hevc_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 带宽占用。
添加 -hwaccel-cuvid 选项意味着原始解码帧将不会被复制,转码将更快、使用更少的系统资源,如图 4 所示。
给定 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 说明了应用程序
绿松石块显示 CUDA 内核完成的颜色空间转换,而黄色块显示主机和设备之间的内存传输。使用 visualprofiler ,用户可以轻松地跟踪在 GPU 上执行的操作,例如 CUDA 加速的过滤器和数据传输,以确保不会执行过多的内存拷贝。
通过使用 --disable-stripping
CLI 选项编译 ffmpeg 来收集 CPU – 端性能统计信息,以启用性能分析。
这可以防止编译器剥离函数名,以便像 Gprof 或 visualstudioprofiler 这样的商品探查器可以收集性能统计信息。 CPU 在硬件加速开启的情况下,负载水平应较低,并且大部分时间应花费在视频代码 SDK API 调用中,这些调用标记为“外部代码因为函数名从驱动程序库中被删除。图 6 显示了一个示例屏幕截图。
进一步阅读
有关如何使用 FFmpeg 的更多示例以及可用的高级质量设置,请查看“ 使用 FFmpeg 和 NVIDIA GPU 硬件加速 “向导。
结论
FFmpeg 是一个强大而灵活的开源视频处理库,具有硬件加速的解码和编码后端。它允许快速的视频处理和完整的 NVIDIA GPU 硬件支持,只需几分钟。 Gprof 、 visualprofiler 和 microsoftvisualstudio 等商品开发工具可以用于精细的性能分析和调优。看看 ffmpeg 源 试试吧!