【FFMPEG】关于硬解码和软解码
⼀、⼀些命令
1、显⽰所有可⽤的硬件加速器
[root@tranCodeing ~]# ffmpeg -hwaccels
ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-39)
configuration: --prefix=/home/local/ffmpeg_sources/ffmpeg_build --pkg-config-flags=--static --extra-cflags='-I /home/local/ffmpeg_sources/ffmpeg_build/include -I/usr/local/cuda/include' --extra-ldflags='-L /home/local/ffmpeg_sources/ffmpeg_build  libavutil      56. 22.100 / 56. 22.100
libavcodec    58. 35.100 / 58. 35.100
libavformat    58. 20.100 / 58. 20.100
libavdevice    58.  5.100 / 58.  5.100
libavfilter    7. 40.101 /  7. 40.101
libswscale      5.  3.100 /  5.  3.100
libswresample  3.  3.100 /  3.  3.100
libpostproc    55.  3.100 / 55.  3.100
Hardware acceleration methods:
cuda
cuvid
2、watch -n 10 nvidia-smi
api接口和sdk接口的区别Every 10.0s: nvidia-smi                                                                                                                                              Tue Feb 25 00:11:20 2020
Tue Feb 25 00:11:20 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.44      Driver Version: 440.44      CUDA Version: 10.2    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|        Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|  0  GeForce RTX 2080    On  | 00000000:01:00.0 Off |                  N/A |
|  0%  45C    P0    40W / 225W |      0MiB /  7979MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes:                                                      GPU Memory |
|  GPU      PID  Type  Process name                            Usage      |
|=============================================================================|
|  No running processes found                                                |
+-----------------------------------------------------------------------------+
3、lspci -vnn | grep VGA -A 12
[root@tranCodeing ~]# lspci -vnn | grep VGA -A 12
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU104 [GeForce RTX 2080 Rev. A] [10de:1e87] (rev a1) (prog-if 00 [VGA controller])
Subsystem: eVga. Corp. Device [3842:2183]
Flags: bus master, fast devsel, latency 0, IRQ 153
Memory at a3000000 (32-bit, non-prefetchable) [size=16M]
Memory at 90000000 (64-bit, prefetchable) [size=256M]
Memory at a0000000 (64-bit, prefetchable) [size=32M]
I/O ports at 4000 [size=128]
[virtual] Expansion ROM at a4000000 [disabled] [size=512K]
Capabilities: [60] Power Management version 3
Capabilities: [68] MSI: Enable+ Count=1/1 Maskable- 64bit+
Capabilities: [78] Express Legacy Endpoint, MSI 00
Capabilities: [100] Virtual Channel
Capabilities: [250] Latency Tolerance Reporting
4、lshw -C display
[root@tranCodeing ~]# lshw -C display
*-display
description: VGA compatible controller
product: TU104 [GeForce RTX 2080 Rev. A]
vendor: NVIDIA Corporation
physical id: 0
bus info: pci@0000:01:00.0
version: a1
width: 64 bits
clock: 33MHz
capabilities: pm msi pciexpress vga_controller bus_master cap_list rom
configuration: driver=nvidia latency=0
resources: irq:153 memory:a3000000-a3ffffff memory:90000000-9fffffff memory:a0000000-a1ffffff ioport:4000(size=128) memory:a4000000-a407ffff
5、nvidia-smi 
[root@tranCodeing ~]# nvidia-smi
Tue Feb 25 00:13:32 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.44      Driver Version: 440.44      CUDA Version: 10.2    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|        Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|  0  GeForce RTX 2080    On  | 00000000:01:00.0 Off |                  N/A |
|  0%  45C    P0    40W / 225W |      0MiB /  7979MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes:                                                      GPU Memory |
|  GPU      PID  Type  Process name                            Usage      |
|=============================================================================|
|  No running processes found                                                |
+-----------------------------------------------------------------------------+
⼆、常识简介
1、软编码和硬编码如何区分
软编码:使⽤CPU进⾏编码
硬编码:使⽤⾮CPU进⾏编码,如显卡GPU、专⽤的DSP、FPGA、ASIC芯⽚等
2、软编码和硬编码⽐较
软编码:实现直接、简单,参数调整⽅便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常⽐硬编码要好⼀点。
硬编码:性能⾼,低码率下通常质量低于软编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。
3、⽬前的主流GPU加速平台
INTEL、AMD、NVIDIA
4、⽬前主流的GPU平台开发框架
CUDA:NVIDIA的封闭编程框架,通过框架可以调⽤GPU计算资源
AMD APP:AMD为⾃⼰的GPU提出的⼀套通⽤并⾏编程框架,标准开放,通过在CPU、GPU同时⽀持OpenCL框架,进⾏计算⼒融合。
OpenCL:开放计算语⾔,为异构平台编写程序的该框架,异构平台可包含CPU、GPU以及其他计算处理器,⽬标是使相同的运算能⽀持不同平台硬件加速。
Inel QuickSync:集成于Intel显卡中的专⽤视频编解码模块。
5、N卡和A卡
A卡指的的ATI,⼀个显卡⼚商
N指的是NVIDIA,另⼀个显卡⼚商。
N卡的产品有GeForce Ti系列,GeForce FX系列等,A卡作品有镭X系列。N卡和A卡在技术上的不同之处在于,N卡注重3D性能和速度,A卡注重2D平⾯画质。
A卡和N卡的区别如下:
1、概念不同。A卡早期是采⽤ATI显卡芯⽚的显卡,⽬前ATI已经被AMD收购,A卡称之为AMD显卡,A卡作品有镭、X系列。N卡是采⽤NVIDIA显卡芯⽚的显卡,N卡作品有GeForce(GTX)系列,GeForce FX(GT)系列等等。
2、优劣势不同。N卡的优势为GPU中每个流处理器都具有完整的ALU功能,在发出⼀条操作指令时每个流处理器都能充分⼯作。显卡频率可以达到近乎100%的状态。劣势为功耗较⼤。A卡的优势为浮点运算能⼒强⼤。劣势为软件优化度不够。
6、流程区别
硬解软编: read(ffmpeg) -》 decoder(NVIDIA) -》 |  Queue -》 encoder(ffmpeg)
软解软编:  read(ffmpeg) -》 decoder(ffmpeg) -》encoder(ffmpeg)
解码与编码之间维护⼀个队列,队列长度定为20(因为解码速度快于编码速度,数据被覆盖,丢帧)
7、并⾏计算
GPU 是⽤来处理图形任务的图形处理器,其中⼀个⾮常⼤的优势在于它的并⾏处理能⼒。⾯对单指令流多数据流(SIMD),并且数据处理的运算量远⼤于数据调度和传输的需要时,GPU 的并⾏处理效率要⾼于传统的 CPU 的处理。
为了充分的利⽤ GPU 的并⾏处理能⼒,⼤部分的显卡⼚商都推出了⾃⼰的 GPU 开发 SDK,⽐如:
NVIDIA —— CUDA
Intel —— Intel® Media SDK
AMD —— AMD APP SDK(前⾝是 ATI Stream)
8、OpenCL
OpenCL(Open Computing Language,开放计算语⾔),是⼀个为异构平台编写程序的框架,此异构平台可由CPU,GPU或其他类型的处理器组成。这种语⾔主要是为了异构平台的并⾏运⾏设计的。
从本质上来说,它和 CDUA 等等 SDK 上是不同的,它是⼀种语⾔,相当于是 JAVA 语⾔这个级别,⽽后者是⼀个开发包,相当于 JDK 这个级别。
OpenCL ⽬前的语⾔规范已经到了 2.1(Preview),⽀持最好的 AMD 的 SDK,最新版本已经⽀持了 OpenCL 2.0,其他两个只⽀持 OpenCL 1.2。
OpenCL 提供了⼀个统⼀的 API,这个 API 在上述的⼚商的 SDK 中都有实现。所以安装 CUDA 会包含 OpenCL 组件,它是英伟达对于 OpenCL 语⾔的⼀种实现。
9、OpenCL API VS SDK
OpenCL API 最⼤的优势在于它的跨平台,可以在不同的架构上运⾏,所以理论上它⽐ SDK 更有竞争⼒。但是它最⼤的问题在于它的 API Level ⽐较基础,直接使⽤它进⾏视频的编解码处理难度⽐较⼤。此外 OpenCL API 的实现是依赖于底层的 GPU 架构的,不同的⼚商提供了不同的实现,使⽤之前需要安装不同⼚商提供的实现,从这个⾓度考虑OpenCL 的跨平台并没有想象中那么完美。
SDK 的问题在于不同的⼚商的 SDK 是不兼容的。但是它提供了⽐ OpenCL API 更加丰富的功能,⽐如
NVIDIA 直接提供了视频编解码相关的接⼝,使⽤起来会⽐ OpenCL API 更加的轻松。
三、NVIDIA硬件编解码⽅案
硬件编解码可以使⽤如下⼏种⽅案:
1、基于 OpenCL 的 API ⾃⼰写⼀个编解码器
这的难度⾮常⼤,⾸先你需要对于 OpenCL API ⾮常的熟悉,其次你需要对于编解码的知识了解的⾮常透彻。这两个问题的任何⼀个都有⾮常⼤的难度,以⽬前已有的技术来说成功的概念不是特别⼤。MainConcept 公司做了这件事情,它提供了基于 OpenCL 的 H264/AVC 编码器,但是这个编码器是商⽤的(此外它还提供了基于 CUDA 的编码器和基于 Intel QSV 的编解器,以及包装过前⾯⼏者的编码器)。
所以从技术可⾏性上来说这个是可⾏的,只是⽬前来说个⼈还不具备这个实⼒。
2、使⽤ SDK 中的编解码接⼝
英伟达关于视频的编解码提供了两个相关的 SDK
NVENC
NVCUVID
前者负责硬件编码,⼆后者负责硬件解码。
NVENC是⼀个单独的 SDK,集成在最新的显卡驱动上⾯,安装最新的驱动之后可以到相关的库⽂件。在 Ubuntu 14.04 中,可以在/usr/lib/nvidia-352/⽬录下⾯到相关的库⽂件。
NVCUVID是CUDA的组件,包含在最新的CUDA Toolkit中。不过在显卡的类库中可以到libnvcuvid.so这个库⽂件。在之前版本的显卡驱动中其他还包含⼀个称之为NVCUVENC的硬件编码器和NVCUVID相对应,不过⽬前这个组件已经被NVENC替代了。
3、使⽤编码器对于 OpenCL 和 SDK 的封装
这种⽅式是个⼈认为最理想的⽅式,FFMPEG ⽬前存在⼀个编码器nvenc是对于英伟达的NVENC的封装,通过使⽤它可以和 FFMPEG ⽆缝的整合起来。此外它也包含对于Intel QSV的封装。AMD 的相关接⼝⽬前没有到相关的资料。
不过 FFMPEG 只存在NVENC的接⼝,不存在NVCUVID的封装。如果需要实现相关的解码器可能需要⾃⼰实现 FFMPEG 接⼝。
libx264有对于 OpenCL 的封装,不过我在 windows 中尝试这个功能的时候并没有成功。
另外还存在⼀个开源的格式转换器HandBrake,它包含对于Intel QuickSync的封装,以及使⽤OpenCL进⾏图象的拉伸处理和使⽤x264的opencl封装。这个项⽬缺点在于⽂档不是很丰富,研究起来有⼀定的难度。
4、NVIDIA硬件解码器分析
5、解码器的代码分析
SDK 中的 sample ⽂件夹下的 NvTranscoder 中包含了编码器和解码器的⽤法,编码器的内容不在这⾥分析,因为 FFMPEG 中已经包含了相关的代码,不需要其他的处理。
解码器在 SDK 中有⼀份封装,主要是 NvTranscoder 下的 VideoDecoder 类。⽬前这个类的具体⽤法还不是特别的清楚。分析将会从 main 函数开始。
6、私有驱动
nvenc本⾝是依赖于nvidia底层的私有驱动的,所以想要使⽤编码器⾸先需要安装nvidia的私有驱动。
[root@tranCodeing ~]# lsmod | grep nvidia
nvidia_uvm            930831  0
nvidia_drm            43690  0
nvidia_modeset      1109452  1 nvidia_drm
nvidia              20364967  2 nvidia_modeset,nvidia_uvm
drm_kms_helper        186531  1 nvidia_drm
drm                  456166  3 drm_kms_helper,nvidia_drm
ipmi_msghandler        56728  2 ipmi_devintf,nvidia
7、 FFMPEG
要想在 FFMPEG 中使⽤nvenc编码器,你需要在编译选项中加⼊enable-nvenc选项(⽼版本,新版本是⾃动检测,显⽰提供disable-nvenc的选项)。
这个选项依赖于nvEncodeAPI.h头⽂件,这个头⽂件并没有包含在私有驱动中,你需要到中下载 SDK,解压后在Samples/common/inc⽬录下有这个头⽂件,把它拷贝到可以链接到
的⽬录中去。
之后编译就可以顺利的通过,得到包含nvenc编码器的库。
8、使⽤ nvenc
NVENC
NVENC is an API developed by NVIDIA which enables the use of NVIDIA GPU cards to perform H.264 and HEVC(就是H.265) encoding. FFmpeg supports NVENC through
the h264_nvenc and hevc_nvenc encoders. In order to enable it in FFmpeg you need:
A supported GPU
Supported drivers
ffmpeg configured without --disable-nvenc
Visit  to download the SDK and to read more about the supported GPUs and supported drivers.
Usage example:
ffmpeg -i input -c:v h264_nvenc -profile high444p -pixel_format yuv444p -preset default output.mp4
You can see available presets, other options, and encoder info with ffmpeg -h encoder=h264_nvenc or ffmpeg -h encoder=hevc_nvenc.
Note: If you get the No NVENC capable devices found error make sure you're encoding to a supported pixel format. See encoder info as shown above.
CUDA/CUVID/NvDecode
CUVID, which is also called nvdec by Nvidia now, can be used for decoding on Windows and Linux. In combination with nvenc it offers full hardware transcoding.
CUVID offers decoders for H264, HEVC, MJPEG, mpeg1/2/4, vp8/9, vc1. Codec support varies by hardware. The full set of codecs being available only on Pascal hardware,
which adds VP9 and 10 bit support.
While decoding 10 bit video is supported, it is not possible to do full hardware transcoding currently (See the partial hardware example below).
Sample decode using CUVID, the cuvid decoder copies the frames to system memory in this case:
ffmpeg -c:v h264_cuvid -i input output.mkv
Full hardware transcode with CUVID and NVENC:
ffmpeg -hwaccel cuvid -c:v h264_cuvid -i input -c:v h264_nvenc -preset slow output.mkv
Partial hardware transcode, with frames passed through system memory (This is necessary for transcoding 10bit content):
ffmpeg -c:v h264_cuvid -i input -c:v h264_nvenc -preset slow output.mkv
If ffmpeg was compiled with support for libnpp, it can be used to insert a GPU based scaler into the chain:
ffmpeg -hwaccel_device 0 -hwaccel cuvid -c:v h264_cuvid -i input -vf scale_npp=-1:720 -c:v h264_nvenc -preset slow output.mkv
The -hwaccel_device option can be used to specify the GPU to be used by the cuvid hwaccel in ffmpeg.
HEVC 是 H264 的后继版本,⼜称 H265 , ⾼效视频编码(High Efficiency Video Coding)
ffmpeg -encoders | grep nv
[root@tranCodeing ~]# ffmpeg -encoders | grep nv
ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-39)
configuration: --prefix=/home/local/ffmpeg_sources/ffmpeg_build --pkg-config-flags=--static --extra-cflags='-I /home/local/ffmpeg_sources/ffmpeg_build/include -I/usr/local/cuda/include' --extra-ldflags='-L /home/local/ffmpeg_sources/ffmpeg_build  libavutil      56. 22.100 / 56. 22.100
libavcodec    58. 35.100 / 58. 35.100
libavformat    58. 20.100 / 58. 20.100
libavdevice    58.  5.100 / 58.  5.100
libavfilter    7. 40.101 /  7. 40.101
libswscale      5.  3.100 /  5.  3.100
libswresample  3.  3.100 /  3.  3.100
libpostproc    55.  3.100 / 55.  3.100
< h264_nvenc          NVIDIA NVENC H.264 encoder (codec h264)
< nvenc                NVIDIA NVENC H.264 encoder (codec h264)
< nvenc_h264          NVIDIA NVENC H.264 encoder (codec h264)
< nvenc_hevc          NVIDIA NVENC hevc encoder (codec hevc)
< hevc_nvenc          NVIDIA NVENC hevc encoder (codec hevc)
h264_nvenc  == nvenc  == nvenc_h264  nvenc_hevc  == hevc_nvenc
参考⽂章: