VPF:Python中的硬件加速视频处理框架

引言

本篇是翻译自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的核心部分是PyNvDecoderPyNvEncoder类,它们是与NVIDIA Video Codec SDK的Python绑定。VPF操作的主要数据类型有两种:

  • 用于CPU端数据的NumPy数组
  • 用户透明Surface类,表示GPU端数据

由于GPU端内存对象的分配很复杂并且会严重影响性能,因此所有归还Surface,拥有它们并可以Surface在下次调用时重用先前返回的VPF类方法。与此不同的是,VPF类方法每次被调用时都会返回新的NumPy数组实例。移动构造函数用于避免内存复制开销。

PyNvDecoderPyNvEncoder类支持为简单起见仅NV12像素格式。一组颜色空间和像素格式转换类支持其他像素格式。所有转换都是GPU加速的,并在VRAM内存中完成,以提高性能。

PyNvDecoder 该类有五个主要方法:

DecodeSingleSurface

从输入视频解码单个帧,返回带有解码像素的Surface。下次用户调用此方法时,先前返回的Surface可能会被重用。如果未解码帧,则解码后的Surface的GetCudaDevicePtr方法将返回零。

DecodeSingleFrame

从输入视频解码单帧,返回带有解码像素的NumPy数组。下次用户调用此方法时,将返回另一个NumPy数组实例。如果未解码帧,它将返回空的NumPy数组。此操作将设备复制到主机内存。

Width

返回解码的帧宽度。

Height

返回解码的帧高度。

PixelFormat

返回解码的帧像素格式。

用户可以混音DecodeSingleSurfaceDecodeSingleFrame通话,不会破坏解码器的内部状态。解码器类支持H.264和H.265编解码器。

PyNvEncoder该类有六个方法:

EncodeSingleSurface

以原始像素获取NV12 Surface,对其进行编码,然后将基本视频比特流作为NumPy数组返回。编码器是异步的,因此此方法可能会在前几次调用时返回空数组(取决于编码器设置),这不是错误。

EncodeSingleFrame

接收带有原始像素的NumPy数组,对其进行编码,然后将基本视频比特流作为NumPy数组返回。编码器是异步的,因此此方法可能在前几次调用时返回空数组(取决于编码器设置),这不是错误。

Flush

冲洗编码器。除非编码器队列中的所有原始帧都已编码,否则它不会返回,并返回带有基本流字节的NumPy数组的列表。

Width

返回编码的帧宽度。

Height

返回编码的帧高度。

PixelFormat

返回编码的帧像素格式。

如果用户混音EncodeSingleSurfaceEncodeSingleFrame通话,则不会破坏编码器的内部状态。此外,PyNvEncoder可以获取任意分辨率的输入帧,并在实际编码之前即时在GPU上调整其大小。编码器类支持H.264和H.265编解码器,并且具有较低的延迟,因此在编码会话结束时,应调用Flush一种将刷新编码器帧队列的方法。


以下是受支持的编码器参数的列表:

参数

类型

含义

profile

编码配置文件。

对于H264可能的值:baselinemainhigh<,code>.

hevc的可能值:main

lookahead

整数

前瞻的大小。

vbvinit

整数+单位

VBV初始延迟(以位为单位),可以以1,K,M为单位。

bitrate

整数+单位

平均比特率,可以以1,K,M为单位。

fps

整数

帧率。

preset

编码预设。 

可能的值:defaulthphqbdllll_hpll_hqlosslesslossless_hp

constqp

整数

constqp速率控制模式的QP值。

qmin

整数

最小QP值。

qmax

整数

最大QP值。

cq

整数

VBR模式的目标恒定质量水平

可能的值:[0,51]0=auto

initqp

整数

初始QP值。

temporalaq

 

(无值)启用临时AQ。

vbvbufsize

整数+单位

VBV缓冲区大小(以位为单位),可以1,K,M为单位。

bf

整数

连续B帧的数量。

rc

速率控制模式。

可能的值:constqpvbrcbrcbr_lowdelay_hqcbr_hqvbr_hq

aq

整数

启用空间AQ并设置其强度

可能的值:[0,15]0=auto

maxbitrate

整数+单位

最大比特率,可以以1,K,M为单位。

gop

整数

GOP(图片组)的长度。

codec

视频编解码器。可能的值:h264hevc

HardwareSurface类是一个包装器CUdeviceptr

GetCudaDevicePtr

将CUdeviceptr句柄返回到CUDA内存对象。

对于主机和设备之间的内存传输,有两个名为PyFrameUploader和的类PySurfaceDownloader

PyFrameUploader用于将NumPy数组上传到GPU。它只有一种方法:

UploadSingleFrame

将一个numpy数组上载到GPU,将句柄返回到上载的Surface。下次用户调用此方法时,先前返回的Surface可能会被重用。

PySurfaceDownloader用于从GPU下载Surface。它也只有一种方法:

DownloadSingleSurface

将GPU端Surface下载到CPU端numpy数组中。下次用户调用此方法时,将返回另一个numpy数组实例。

最后,有一PySurfaceConverter类用于GPU加速的色彩空间和像素格式转换。以下是受支持的转化列表:

  • YUV420至NV12
  • NV12到YUV420
  • NV12转RGB

PySurfaceConverter 有一种方法:

Execute

在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/

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值