18

VPF:适用于 Python 的开源视频处理框架,加速视频任务、提高 GPU 利用率

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MjM5ODU3OTIyOA%3D%3D&%3Bmid=2650680765&%3Bidx=2&%3Bsn=0d0b3459dfe578525ec94639ed83249d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
2UvQzmJ.gif

点击上方“蓝字”关注“AI开发者”

2QjM3uJ.jpg!web

近日,NVIDIA 开源了适用于 Python 的视频处理框架「VideoProcessingFramework(VPF)」。该框架为开发人员提供了一个简单但功能强大的 Python 工具,可用于硬件加速的视频编码、解码和处理类等任务。

同时,由于 Python 绑定下的 C ++代码,它使开发者可以在数十行代码中实现较高的 GPU 利用率。解码后的视频帧以 NumPy 数组或 CUDA 设备指针的形式公开,以简化交互过程及其扩展功能。

目前,VPF 并未对 NVIDIA Video Codec SDK 附加任何限制,开发者可充分利用 NVIDIA 专业级 GPU 的功能。

fyeuEby.jpg!web

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

VPF 是基于 CMake 的开源跨平台框架,它依赖于 FFmpeg 库来进行(de)muxing 和 pybind11 项目从而构建 Python 绑定。它包含了一组开源的 C ++库和 Python 绑定,可与其封闭源代码 Codec SDK 进行交互。

该框架的主要功能是简化从 Python 开发 GPU 加速视频编码/解码的过程,可为视频处理任务(例如解码,编码,代码转换以及 GPU 加速的色彩空间和像素格式转换)提供完整的硬件加速。

myYzeuN.jpg!web

尽管 Python 不是性能最高的语言,但它易于使用;在 NVIDIA 发布此视频处理框架之后,它相当于在现有 Video Codec SDK C ++ 堆栈周围的 Python wrapper,将用于在 Kepler 及更高版本上基于 GPU 的视频编码/解码。这使得 VPF 在利用基于 GPU 的高性能视频加速的同时,也获得了易于阅读/编写的代码。

nEnMnqy.png!web

NVIDIA Video Codec SDK 使用效果示意图

同时值得注意的是,VPF 还利用 NVIDIA Video Codec SDK(一套全面的 API,包括用于 Windows 和 Linux 上硬件加速视频编码和解码的高性能工具,示例和文档)来提高灵活性和性能,并为开发人员提供 Python 固有的易用性。目前,该代码在 GitHub 上已开源。

Github 地址:

https://github.com/NVIDIA/VideoProcessingFramework 

    代码示例及结果

在官网博客宣布 VPF 时,开发者也提供了一个简短的 Python 代码示例,该示例使用 PyNvCodec 模块显示 Python 中的视频转码:

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 单元饱和,如下所示:

J7JvEvr.png!web

Big Buck Bunny 序列包含 14315 帧,可以在 32 秒内进行转码,而无需使用任何先进的技术(例如生产者-消费者模式),解码器和编码器将在单独的线程中启动共享解码器队列,从而可以在约 447fps 的速度下进行转码。由于所有转码均在 GPU 上完成,因此没有明显的 CPU 负载。

quYBvim.png!web

    VPF 使用类说明

VPF 中包含了多个类,其核心部分是 PyNvDecoder 和 PyNvEncoder 类,它们是与 NVIDIA Video Codec SDK 的 Python 绑定。

PyNvDecoder 和 PyNvEncoder 类支持 NV12 像素格式,所有转换均通过 GPU 加速,并在 VRAM 内存中完成,以提高性能。其中——

PyNvDecoder 类有五个主要方法:

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

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

  • Width  返回解码的帧宽度;

  • Height  返回解码的帧高度;

  • PixelFormat  返回解码的帧像素格式。

用户使用 DecodeSingleSurface 和 DecodeSingleFrame 时,不会破坏解码器的内部状态。解码器类支持 H.264 和 H.265 编解码器。

PyNvEncoder 类有六个方法:

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

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

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

  • Width  返回编码的帧宽度;

  • Height  返回编码的帧高度;

  • PixelFormat  返回编码的帧像素格式。

如果用户使用 EncodeSingleSurface 和 EncodeSingleFrame,则不会破坏编码器的内部状态。此外,PyNvEncoder 可以获取任意分辨率的输入帧,并在实际编码之前即时在 GPU 上调整其大小。

编码器类支持 H.264 和 H.265 编解码器,并且具有较低的延迟,因此在编码会话结束时,应调用 Flush 刷新编码器帧队列。

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 运行的主要数据类型有两种:

  • 用于 CPU 端数据的 NumPy 数组;

  • 用户透明 Surface 类,表示 GPU 端数据;

由于 GPU 端内存对象分配很复杂,并且会严重影响性能,因此所有归还 Surface,并在下次调用时重用先前返回的 VPF 类方法。

与此不同的是,VPF 类方法每次被调用时都会返回新的 NumPy 数组实例。移动构造函数可避免内存复制的运行成本。

    其它开源视频处理框架

一、RxFFmpeg

RxFFmpeg 是基于 ( FFmpeg 4.0 + X264 + mp3lame + fdk-aac ) 编译的适用于 Android 平台的音视频编辑、视频剪辑的快速处理框架。

包含:视频拼接,转码,压缩,裁剪,片头片尾,分离音视频,变速,添加静态贴纸和 gif 动态贴纸,添加字幕,添加滤镜,添加背景音乐,加速减速视频,倒放音视频,音频裁剪,变声,混音,图片合成视频,视频解码图片等主流特色功能。

RxFFmpeg 开源地址:

https://github.com/microshow/RxFFmpeg   

qaYNJvr.jpg!web

二、VidGear

VidGear 是一个围绕 OpenCV 视频 I/O 模块的轻量级 python 包装器,它使用多线程 Gears(又名 API)构建,每个都有独特的开拓性功能。

这些 API 提供了易于使用,高度可扩展的多线程包装器,这些包装器围绕着许多底层的最新 python 库,例如 OpenCV,FFmpeg,picamera,pafy,pyzmq 和 python-mss ➶,可以在各种设备和平台上实现高速视频帧读取功能 。它也是 imutils 库视频模块的重新实现,修复了所有主要错误,并附带了直接网络流支持。

VidGear 开源地址:

https://pypi.org/project/vidgear/   

BVNbUfe.png!web

VPF 博客地址:

https://devblogs.nvidia.com/vpf-hardware-accelerated-video-processing-framework-in-python/ 

/ 更多阅读 /

jiEbEjv.jpg!web

nQZJjub.gif点击  阅读原文 ,查看:yolov2 实战:从网络摄像头、视频文件和 youtube 中检测目标


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK