视频抽帧处理实践随笔

1,753 阅读8分钟

背景

要说最近几年最火的是什么,应该就是短视频了,随着手机这种视频采集设备、视频的编解码技术、移动网络通信的飞速发展,极大方便了视频创作,每个人都能成为一个视频自媒体,随之诞生的就是针对视频内容的内容理解需求。而视频内容处理的对象实际上就是每个视频帧,所以对视频进行抽帧就成了视频理解的基础,那每天上百万上千万的数据量下的实际生产中应该如何处理视频抽帧呢?最近两年一直在做内容理解方面的工作,也研究了一下这个问题,总结一下。

视频基础

简单介绍一下关于视频的一些基础知识,方便理解,视频涉及知识点很多,每个点都可以展开深入研究,我们的介绍较为简单,仅为理解视频抽帧的一些概念。

视频流

我们通过摄像头等视频采集设备采集出来的这组连续的图片,也就是视频“源文件”,我们称之为原始流,也叫"YUV"流,Y”表示明亮度,“U”和“V”则是色度、浓度。想要了解具体YUV的的工作原理,可以自行google一下。YUV流占用空间很大的,要保存成真正的文件,就需要对其进行编码压缩,而编码压缩这个过程肯定就是有损的。现在常见的编码格式有

  • H.263
  • H.264
  • H.265
  • MPEG-1
  • MPEG-2
  • MPEG 不同的编码格式的应用场景不同,因为其编解码效率、网络的适应性等各不相同。比如H.265相较于H.264,前者只需要后者一半的带宽,就可以传输相同质量的视频,在网络的适应性方面H.265也有显著提升,更适用于弱网等复杂网络条件下。 编码、压缩对视频处理是必不可少的,从YUV流到H.265流的过程称为编码,反之称为解码。

视频封闭格式

简单来说,视频原始流经过编码,拿到编码后的视频流,然后将它和编码后的音频流、字幕等数据,尽可能紧凑的放到一个容器里,这就是视频封闭,我们常见的avi,mp4就是视频封闭格式。封闭好的文件就是我们常见的这些视频文件啦。

视频帧

视频中单位时间上一张静止的画面,也就是组成视频的图片中的某一张,帧分为几种

  • I帧,Intra Picture,内编码帧,俗称关键帧。拥有完整的图像信息。I帧不需要依赖前后帧信息,可独立进行解码。
  • P帧,predictive-frame,前向预测编码帧。P帧需要依赖前面的I帧或者P帧才能进行编解码,因为他存储的是当前帧画面与前一帧的差别,专业的说法是压缩了时间冗余信息,或者说提取了运动特性。
  • B帧,bi-directional interpolatedprediction frame,双向预测内插编码帧。B帧存储的是本帧与前后帧的差别,因此带有B帧的视频在解码时的逻辑会更复杂些,CPU开销会更大。
  • IDR帧,Instantaneous Decoding Refresh,即时解码刷新。IDR帧是一种特殊的I帧,它是为了服务于编解码而提出的概念,IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列开始编码。

码率

码率是指视频文件在单位时间内使用的数据流量,它决定了视频的质量和大小,单位是 kb/s 或者 Mb/s。 一般来说画面越清晰、越流畅是最好的。但在实际应用中,还需要硬件的处理能力、带宽条件进行选择。

FFmpeg

上面介绍了一些视频的基本概念,那视频抽帧业界一般是怎么做的呢,基本上都是用FFmpeg来做的。FFmepg是一组音视频编解码开发套件,他是许多音频和视频格式的标准编码、解码实现,国内外大量的视频网站和视频处理软件都是以他为基础来实现的,他包含了很多组件和库文件,一般是使用命令行工具来进行调用。正常情况FFmpeg直接根据环境下载安装配置就可以了,我们这里不再赘述,除了视频截帧之外,ffmpeg还有很多强大的功能,可以自行探索一下。

截帧命令示例:

ffmpeg -y -i input.mp4 -vf fps=0.2 ./pic/out%d.png

经过测试可知,ffmpeg截帧是需要消耗一些时间的,尤其是处理高码率视频的时候,对系统计算资源占用率也很高,那我们想一想,如何加速这个流程呢,要加速这个流程,我们肯定要先知道ffmpeg的处理流程是什么样的

FFmpeg处理流程

1.jpg FFmpeg的处理流程简单来说就6步

  1. 输入媒体文件
  2. 对文件demux
  3. 对流进行相应的decode
  4. 使用输出的编码进行encode
  5. 进行Mux操作
  6. 输出媒体文件

Demux:视频中会有音频,视频,它们在文件有各自的编码压缩方式,但为了传输过程方便,将压缩过的音频和视频捆绑在一起进行传输。首先就需要将媒体文件中的各个音频,视频,字幕流等分开。

Decode:媒体数据为了降低存储量,针对里面的音频,视频,字幕等都会采取特定方式的编码压缩。 这一步便对各自的流采用其对应的解码算法进行处理。得到原始流。 即这一步是以帧为单位实现压缩数据到原始数据转换。

Encode:这一步再按照目标的编码方式对流进行编码。即这一步是以帧为单位实现原始数据到压缩数据转换。

Mux:Demux的逆操作,把不同的流按照某种容器的规则放入容器。

FFmpeng加速方案设计

知道了FFmpeng的处理流程,我们对加速方案也就有了几个方向:

  1. 从输入加速,加快视频文件的读取,经测试,这个过程耗时很短,且视频这种流式读取,优化空间不大。
  2. 从输出加速,加快图片编码速度,考虑使用GPU加速,测试不同的编码库、输出格式的影响。
  3. 从decode加速,视频解码应该是整个流程中最耗时的部分,默认是使用CPU软解,使用GPU硬解利用GPU强大的批处理计算能力应该会有提升。

FFmpeg使用GPU加速

从 Kepler 一代开始的所有 NVIDIA® GPU 都支持完全加速的硬件视频编码和解码。NVENC和NVDEC的硬件能力通过 API暴露在 NVIDIA Video Codec SDK 中,用户可以通过这些 API 访问 NVENC 和 NVDEC 的硬件加速能力。NVENC 和 NVDEC 可以有效地与 FFmpeg 一起使用,以显着加快视频解码、编码和端到端转码的速度。

编译安装FFmpeg

要想使用GPU加速的话需要编译安装FFmpeg,这个不同环境方式方法也不太一样,具体可以参考网上的一些教程和Nvidia的文档ffmpeg-with-nvidia-gpu,当你使用ffmpeg -hwaccels命令查看到有对应的硬件加速选项的时候,就代表可以使用GPU加速了。

编译安装ffmpeg过程较为复杂,需要预先编译安装多个依赖库,生产环境应用一般采用docker容器方式进行使用。

GPU加速性能测试

我们分别对不同数量、不同分辨率的视频在CPU、单GPU和多GPU的环境下进行测试,CPU为6130,GPU为T4,具体数据不太方便贴,测试结论:

  1. 对于单条视频处理,在分辨率低于2k的时候,CPU的处理市场小于GPU的处理时长,分辨率为2k、4k或者更高的时候CPU处理时长大于GPU处理时长。
  2. 对于多条视频批处理,CPU在处理超过核心数的任务量时时长即开始稳定线性增长,GPU在处理超过1000个左右并发任务时才会开始线性增长,GPU在批处理多任务情况下有明显优势。
  3. 处理效率换算,满载情况下1张GPU的处理能力≈16张CPU处理能力。

以上只是针对视频抽帧这一个环节的相关优化,现在视频内容理解主流的处理方式一般是GPU全流程加速,处理过程中图片并不持久化或者部分持久化,直接提交给模型就行特征提取和预测,Naidia社群中也有提及相关客户的一些内容理解加速方案,感兴趣的可以看一下。