引言
本篇是翻译自VPF原作者在论坛上发布的关于VPF的方法以及原理介绍,基本上涵盖了整个python硬解码的过程,能对视频的编解码也能有一个很全面的认识,关于VPF的安装总结的全过程如下链接:
VideoProcessingFramework框架编译启动全过程
VideoProcessingFramework介绍
从Kepler一代的NVIDIA GPU开始支持加速的硬件视频编码,而Fermi一代以来的所有GPU都通过NVIDIA Video Codec SDK支持硬件视频加速解码。
在表现出出色的性能和灵活性的同时,它需要C / C ++的知识。另一个选择是使用第三方库和应用程序,例如FFmpeg或GStreamer,它们再次需要内置C / C ++专业知识并为每个用户自定义。
但是,硬件加速视频功能可能对更广泛的受众有用,并且VPF(视频处理框架)的目的是在使用Python处理视频时利用NVIDIA GPU的简单而强大的工具。VPF利用NVIDIA Video Codec SDK来提高灵活性和性能,并为开发人员提供Python固有的易用性。
VPF是一组C ++库和Python绑定,可为视频处理任务(例如解码,编码,代码转换以及GPU加速的色彩空间和像素格式转换)提供完整的硬件加速。VPF是基于Apache 2许可发布的基于CMake的开源跨平台软件。它依靠FFmpeg库进行 [de] muxing和pybind11项目来构建Python绑定。
VPF将C ++视频处理类导出到PyNvCodec
这个Python模块中。为了说明易用性,让我们从一个快速的代码片段开始,该代码片段显示了如何在GPU上进行完全硬件加速的视频转码,而无需在主机和设备之间复制原始帧:
import PyNvCodec as nvc
gpuID = 0
encFile = "big_buck_bunny_1080p_h264.mov"
xcodeFile = open("big_buck_bunny_1080p.h264", "wb")
nvDec = nvc.PyNvDecoder(encFile, gpuID)
nvEnc = nvc.PyNvEncoder({'preset': 'hq', 'codec': 'h264', 's': '1920x1080'}, gpuID)
while True:
rawSurface = nvDec.DecodeSingleSurface()
# Decoder will return zero surface if input file is over;
if not (rawSurface.GetCudaDevicePtr()):
break
encFrame = nvEnc.EncodeSingleSurface(rawSurface)
if(encFrame.size):
frameByteArray = bytearray(encFrame)
xcodeFile.write(frameByteArray)
# Encoder is asynchronous, so we need to flush it
encFrames = nvEnc.Flush()
for encFrame in encFrames:
encByteArray = bytearray(encFrame)
xcodeFile.write(encByteArray)
尽管设计简单,但VPF仍具有良好的性能。上面显示的代码转换示例足以使RTX 5000 GPU上的Nvenc单元饱和,如下所示:
Big Buck Bunny序列包含14,315帧,可以在32秒内进行转码,而无需使用任何先进的技术(例如生产者-消费者模式),解码器和编码器将在单独的线程中启动共享解码器队列,从而可以在约447fps的速度下进行转码。由于所有转码都在GPU上完成,因此没有明显的CPU负载。
VPF的核心部分是PyNvDecoder
和PyNvEncoder
类,它们是与NVIDIA Video Codec SDK的Python绑定。VPF操作的主要数据类型有两种:
- 用于CPU端数据的NumPy数组
- 用户透明
Surface
类,表示GPU端数据
由于GPU端内存对象的分配很复杂并且会严重影响性能,因此所有归还Surface
,拥有它们并可以Surface
在下次调用时重用先前返回的VPF类方法。与此不同的是,VPF类方法每次被调用时都会返回新的NumPy数组实例。移动构造函数用于避免内存复制开销。
PyNvDecoder
和PyNvEncoder
类支持为简单起见仅NV12像素格式。一组颜色空间和像素格式转换类支持其他像素格式。所有转换都是GPU加速的,并在VRAM内存中完成,以提高性能。
PyNvDecoder
该类有五个主要方法:
| 从输入视频解码单个帧,返回带有解码像素的Surface。下次用户调用此方法时,先前返回的Surface可能会被重用。如果未解码帧,则解码后的Surface的 |
| 从输入视频解码单帧,返回带有解码像素的NumPy数组。下次用户调用此方法时,将返回另一个NumPy数组实例。如果未解码帧,它将返回空的NumPy数组。此操作将设备复制到主机内存。 |
| 返回解码的帧宽度。 |
| 返回解码的帧高度。 |
| 返回解码的帧像素格式。 |
用户可以混音DecodeSingleSurface
和DecodeSingleFrame
通话,不会破坏解码器的内部状态。解码器类支持H.264和H.265编解码器。
PyNvEncoder
该类有六个方法:
| 以原始像素获取NV12 Surface,对其进行编码,然后将基本视频比特流作为NumPy数组返回。编码器是异步的,因此此方法可能会在前几次调用时返回空数组(取决于编码器设置),这不是错误。 |
| 接收带有原始像素的NumPy数组,对其进行编码,然后将基本视频比特流作为NumPy数组返回。编码器是异步的,因此此方法可能在前几次调用时返回空数组(取决于编码器设置),这不是错误。 |
| 冲洗编码器。除非编码器队列中的所有原始帧都已编码,否则它不会返回,并返回带有基本流字节的NumPy数组的列表。 |
| 返回编码的帧宽度。 |
| 返回编码的帧高度。 |
| 返回编码的帧像素格式。 |
如果用户混音EncodeSingleSurface
和EncodeSingleFrame
通话,则不会破坏编码器的内部状态。此外,PyNvEncoder
可以获取任意分辨率的输入帧,并在实际编码之前即时在GPU上调整其大小。编码器类支持H.264和H.265编解码器,并且具有较低的延迟,因此在编码会话结束时,应调用Flush
一种将刷新编码器帧队列的方法。
以下是受支持的编码器参数的列表:
参数 | 类型 | 含义 |
| 串 | 编码配置文件。 对于H264可能的值: hevc的可能值: |
| 整数 | 前瞻的大小。 |
| 整数+单位 | VBV初始延迟(以位为单位),可以以1,K,M为单位。 |
| 整数+单位 | 平均比特率,可以以1,K,M为单位。 |
| 整数 | 帧率。 |
| 串 | 编码预设。 可能的值: |
| 整数 | constqp速率控制模式的QP值。 |
| 整数 | 最小QP值。 |
| 整数 | 最大QP值。 |
| 整数 | VBR模式的目标恒定质量水平 可能的值: |
| 整数 | 初始QP值。 |
| (无值)启用临时AQ。 | |
| 整数+单位 | VBV缓冲区大小(以位为单位),可以1,K,M为单位。 |
| 整数 | 连续B帧的数量。 |
| 串 | 速率控制模式。 可能的值: |
| 整数 | 启用空间AQ并设置其强度 可能的值: |
| 整数+单位 | 最大比特率,可以以1,K,M为单位。 |
| 整数 | GOP(图片组)的长度。 |
| 串 | 视频编解码器。可能的值: |
HardwareSurface
类是一个包装器CUdeviceptr
:
| 将CUdeviceptr句柄返回到CUDA内存对象。 |
对于主机和设备之间的内存传输,有两个名为PyFrameUploader
和的类PySurfaceDownloader
。
PyFrameUploader
用于将NumPy数组上传到GPU。它只有一种方法:
| 将一个numpy数组上载到GPU,将句柄返回到上载的Surface。下次用户调用此方法时,先前返回的Surface可能会被重用。 |
PySurfaceDownloader
用于从GPU下载Surface。它也只有一种方法:
| 将GPU端Surface下载到CPU端numpy数组中。下次用户调用此方法时,将返回另一个numpy数组实例。 |
最后,有一PySurfaceConverter
类用于GPU加速的色彩空间和像素格式转换。以下是受支持的转化列表:
- YUV420至NV12
- NV12到YUV420
- NV12转RGB
PySurfaceConverter
有一种方法:
| 在GPU上执行转换,将句柄以输出格式返回给Surface。下次用户调用此方法时,先前返回的Surface可能会被重用。 |
总结
VPF为开发人员提供了一个简单但功能强大的Python工具,用于完全硬件加速的视频编码,解码和处理类。多亏了Python绑定下的C ++代码,它使您可以在数十行代码中实现较高的GPU利用率。解码后的视频帧以NumPy数组或CUDA设备指针的形式公开,以简化交互并扩展功能。VPF并未对NVIDIA Video Codec SDK施加任何限制,并允许您充分利用NVIDIA专业级GPU的潜力。
原文链接:
https://developer.nvidia.com/blog/vpf-hardware-accelerated-video-processing-framework-in-python/