天天看點

【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/lib -L/usr/local/cuda/lib64' --extra-libs=-lpthread --extra-libs=-lm --bindir=/root/bin --enable-gpl --enable-libfdk_aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree --enable-libfreetype --enable-cuda --enable-cuvid --enable-nvenc --enable-libnpp
  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

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.com. 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硬體解碼器分析

可以參考:https://www.cnblogs.com/lifan3a/articles/7463357.html

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

 頭檔案,這個頭檔案并沒有包含在私有驅動中,你需要到 NVIDIA VIDEO CODEC SDK 中下載下傳 SDK,解壓後在 

Samples/common/inc

目錄下有這個頭檔案,把它拷貝到可以連結到的目錄中去。

之後編譯就可以順利的通過,得到包含 

nvenc

 編碼器的庫。

8、使用 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 ​NVIDIA Video Codec SDK 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/lib -L/usr/local/cuda/lib64' --extra-libs=-lpthread --extra-libs=-lm --bindir=/root/bin --enable-gpl --enable-libfdk_aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree --enable-libfreetype --enable-cuda --enable-cuvid --enable-nvenc --enable-libnpp
  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
 V..... h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc                NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc_h264           NVIDIA NVENC H.264 encoder (codec h264)
 V..... nvenc_hevc           NVIDIA NVENC hevc encoder (codec hevc)
 V..... hevc_nvenc           NVIDIA NVENC hevc encoder (codec hevc)      

h264_nvenc  == nvenc  == nvenc_h264   nvenc_hevc  == hevc_nvenc 

參考文章:

https://trac.ffmpeg.org/wiki/HWAccelIntro

https://developer.nvidia.com/ffmpeg

  • 作者:踏雪無痕
  • 出處:http://www.cnblogs.com/chenpingzhao/
  • 本文版權歸作者和部落格園共有,如需轉載,請聯系  pingzhao1990#163.com