https://trac.ffmpeg.org/wiki/HWAccelIntro
http://www.cnblogs.com/my_life/articles/6728784.html
ffmpeg -hwaccels 顯示所有可用的硬件加速器
watch -n 10 nvidia-smi
lspci -vnn | grep VGA -A 12
lshw -C display
下載安裝完cuda,就會有nvidia-smi這些命令了
http://blog.csdn.net/u010264950/article/details/40888517
一、軟編碼和硬編碼如何區分
軟編碼:使用CPU進行編碼
硬編碼:使用非CPU進行編碼,如顯卡GPU、專用的DSP、FPGA、ASIC芯片等
二、軟編碼和硬編碼比較
軟編碼:實現直接、簡單,參數調整方便,升級易,但CPU負載重,性能較硬編碼低,低碼率下質量通常比硬編碼要好一點。
硬編碼:性能高,低碼率下通常質量低於軟編碼器,但部分產品在GPU硬件平台移植了優秀的軟編碼算法(如X264)的,質量基本等同於軟編碼。
三、目前的主流GPU加速平台
Intel、AMD、NVIDIA
四、目前主流的GPU平台開發框架
CUDA:NVIDIA的封閉編程框架,通過框架可以調用GPU計算資源
AMD APP:AMD為自己的GPU提出的一套通用並行編程框架,標准開放,通過在CPU、GPU同時支持OpenCL框架,進行計算力融合。
OpenCL:開放計算語言,為異構平台編寫程序的該框架,異構平台可包含CPU、GPU以及其他計算處理器,目標是使相同的運算能支持不同平台硬件加速。
Inel QuickSync:集成於Intel顯卡中的專用視頻編解碼模塊。
http://blog.csdn.net/u010264950/article/details/40888517
硬解軟編: read(ffmpeg) ---> decoder(NVIDIA) ---> | Queue(20) | ---> encoder(ffmpeg)
軟解軟編: read(ffmpeg) ---> decoder(ffmpeg) ---> encoder(ffmpeg)
解碼與編碼之間維護一個隊列,隊列長度定為20(因為解碼速度快於編碼速度,數據被覆蓋,丟幀)。
https://developer.nvidia.com/ffmpeg
http://www.echojb.com/hardware/2017/01/12/300109.html
https://bbs.archlinux.org/viewtopic.php?id=215555 這篇文章不錯,可能的錯誤原因是沒指定–pix_fmt
驗證成功
ffmpeg -loglevel debug -y -f decklink -video_input sdi -i 'DeckLink 4K Extreme 12G@22' -c:v h264_nvenc -pix_fmt yuv420p -preset default -gpu 1 -acodec aac -f flv rtmp://10.110.26.84:1935/rtmplive/decklink
注意老版本的選項可能是-pixel_format
https://developer.nvidia.com/ffmpeg
http://blog.guorongfei.com/2015/10/07/nvenc_ffmpeg_usage/
http://blog.guorongfei.com/tags/GPU/
硬件加速
硬件加速的學術名稱是 GPGPU(General-purpose computing on graphics processing units),中文名稱是通用圖形處理器。最基本的思想是使用 GPU 的運算能力完成原本需要 CPU 來進行的運算。
並行計算
GPU 是用來處理圖形任務的圖形處理器,其中一個非常大的優勢在於它的並行處理能力。面對單指令流多數據流(SIMD),並且數據處理的運算量遠大於數據調度和傳輸的需要時,GPU 的並行處理效率要高於傳統的 CPU 的處理。
為了充分的利用 GPU 的並行處理能力,大部分的顯卡廠商都推出了自己的 GPU 開發 SDK,比如:
- NVIDIA —— CUDA
- Intel —— Intel® Media SDK
- AMD —— AMD APP SDK(前身是 ATI Stream)
當然這些廠商都是各自為陣,推出的 SDK 都是只能用於自己的顯卡的 SDK,所以代碼想要在不同的平台上能夠統一是比較困難的。
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 語言的一種實現。
OpenCL API VS SDK
OpenCL API 最大的優勢在於它的跨平台,可以在不同的架構上運行,所以理論上它比 SDK 更有競爭力。但是它最大的問題在於它的 API Level 比較基礎,直接使用它進行視頻的編解碼處理難度比較大。
此外 OpenCL API 的實現是依賴於底層的 GPU 架構的,不同的廠商提供了不同的實現,使用之前需要安裝不同廠商提供的實現,從這個角度考慮 OpenCL 的跨平台並沒有想象中那么完美。
SDK 的問題在於不同的廠商的 SDK 是不兼容的。但是它提供了比 OpenCL API 更加豐富的功能,比如 NVIDIA 直接提供了視頻編解碼相關的接口,使用起來會比 OpenCL API 更加的輕松。
英偉達硬件編解碼方案
實現英偉達的 GPU 硬件編解碼可以使用如下幾種方案:
基於 OpenCL 的 API 自己寫一個編解碼器
這的難度非常大,首先你需要對於 OpenCL API 非常的熟悉,其次你需要對於編解碼的知識了解的非常透徹。這兩個問題的任何一個都有非常大的難度,以目前已有的技術來說成功的概念不是特別大。
MainConcept 公司做了這件事情,它提供了基於 OpenCL 的 H264/AVC 編碼器,但是這個編碼器是商用的(此外它還提供了基於 CUDA 的編碼器和基於 Intel QSV 的編解器,以及包裝過前面幾者的編碼器)。
所以從技術可行性上來說這個是可行的,只是目前來說個人還不具備這個實力。
使用 SDK 中的編解碼接口
英偉達關於視頻的編解碼提供了兩個相關的 SDK
- NVENC
- NVCUVID
前者負責硬件編碼,二后者負責硬件解碼。
NVENC 是一個單獨的 SDK,集成在最新的顯卡驅動上面,安裝最新的驅動之后可以找到相關的庫文件。在 Ubuntu 14.04 中,可以在 /usr/lib/nvidia-352/ 目錄下面找到相關的庫文件。
NVCUVID 是 CUDA 的組件,包含在最新的 CUDA Toolkit 中。不過在顯卡的類庫中可以找到 libnvcuvid.so 這個庫文件。在之前版本的顯卡驅動中其他還包含一個稱之為 NVCUVENC 的硬件編碼器和 NVCUVID 相對應,不過目前這個組件已經被 NVENC 替代了。
使用編碼器對於 OpenCL 和 SDK 的封裝
這種方式是個人認為最理想的方式,FFMPEG 目前存在一個編碼器 nvenc 是對於英偉達的 NVENC 的封裝,通過使用它可以和 FFMPEG 無縫的整合起來。此外它也包含對於 Intel QSV 的封裝。AMD 的相關接口目前沒有找到相關的資料。
不過 FFMPEG 只存在 NVENC 的接口,不存在 NVCUVID 的封裝。如果需要實現相關的解碼器可能需要自己實現 FFMPEG 接口。
libx264 有對於 OpenCL 的封裝,不過我在 windows 中嘗試這個功能的時候並沒有成功。
另外還存在一個開源的格式轉換器 HandBrake,它包含對於 Intel QuickSync 的封裝,以及使用 OpenCL 進行圖象的拉伸處理和使用 x264 的 opencl 封裝。這個項目缺點在於文檔不是很豐富,研究起來有一定的難度。
====
英偉達硬件解碼器分析
這篇文章主要分析 NVCUVID 提供的解碼器,里面提到的所有的源文件都可以在英偉達的 nvenc_sdk 中找到。
解碼器的代碼分析
SDK 中的 sample 文件夾下的 NvTranscoder 中包含了編碼器和解碼器的用法,編碼器的內容不在這里分析,因為 FFMPEG 中已經包含了相關的代碼,不需要其他的處理。
解碼器在 SDK 中有一份封裝,主要是 NvTranscoder 下的 VideoDecoder 類。目前這個類的具體用法還不是特別的清楚。分析將會從 main 函數開始。
。。。。。
====
英偉達硬件加速解碼器在 FFMPEG 中的使用
這篇文檔介紹如何在 ffmpeg 中使用 nvenc 硬件編碼器。
私有驅動
nvenc 本身是依賴於 nvidia 底層的私有驅動的,所以想要使用編碼器首先需要安裝 nvidia 的私有驅動。在 NVIDIA VIDEO CODEC SDK 的介紹中說明,最新版本的 nvenc sdk 5.0 在 linux 需要 346.22 以上的驅動,在 windwos 下則需要 347.07 以上的驅動
The latest NVENC SDK version available is 5.0, which requires NVIDIA GPU driver 347.09 or above for Windows and 346.22 or above for Linux.
目前 Ubuntu 15.04 上的驅動滿足這個要求,Windows 平台可以直接到官網上下載最新的驅動安裝。(個人不建議去官網下載最新的 Linux 驅動,因為我試了很多次都沒有安裝成功,最終會導致無法進入系統)。
在 Ubuntu 15.04 下使用下面的命令安裝最新的驅動。
sudo apt-get install nvidia-346 \
nvidia-346-vum \
nvidia-modprobe \
nvidia-opencl-icd-346 \
nvidia-prime \
nvidia-settings
注意 nvidia-modprobe 必須要安裝,因為私有驅動使用的內核模塊,需要安裝這個包在系統啟動的時候加載這些內核模塊。安裝完成之后可能無法進入系統,這個應該是 nvidia 中的一個 BUG,你可以重啟之后選擇 grub 中的 ubuntu 高級 選項 中低版本的內核進入系統之后重啟再選擇高版本的內核進入系統。這一點非常的詭異,目前沒有找到原因。
啟動系統之后使用 lsmod | grep nvidia 應該會得到類似下面的結果:
nvidia_uvm 69632 0
nvidia 8380416 36 nvidia_uvm
drm 348160 7 i915,drm_kms_helper,nvidia
直接通過 sudo modprobe nvidia_uvm 好像也無法成功的加載需要的模塊。
另外安裝驅動安裝完成之后會在 /dev 下面創建幾個和 nvidia 相關的設備,通過 ls /dev/nvidia* 應該會得到類型以下的結果:
/dev/nvidia0 /dev/nvidiactl /dev/nvidia-uvm
編譯 FFMPEG
要想在 FFMPEG 中使用 nvenc 編碼器,你需要在編譯選項中加入 enable-nvenc 選項(老版本,新版本是自動檢測,顯示提供disable-nvenc的選項)。
這個選項依賴於 nvEncodeAPI.h 頭文件,這個頭文件並沒有包含在私有驅動中,你需要到 NVIDIA VIDEO CODEC SDK 中下載 SDK,解壓后在 Samples/common/inc目錄下有這個頭文件,把它拷貝到可以鏈接到的目錄中去。
之后編譯就可以順利的通過,得到包含 nvenc 編碼器的庫。
使用 nvenc
FFMPEG 中直接使用 av_find_encoder_by_name("nvenc") 就可以找到這個這個編碼器並使用它。nvenc.c 的 pix_fmts_nvenc變量定義來看,這個編碼器應該是支持 YUV420P, YUV444P 和 NV12 三種格式的,但是測試的過程中發現 YUV420P 沒辦法使用,所以應該吧 AVCodecContext 的 pix_fmt 設置成 NV12。
==================
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
輸出:
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
