硬解,使用非CPU进行编码,如显卡GPU、专用的DSP、FPGA、ASIC芯片等。目前的主流GPU加速平台:INTEL、AMD、NVIDIA。
一、软编码和硬编码比较
软编码:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点。
硬编码:性能高,低码率下通常质量低于软编码器,但部分产品在GPU硬件平台移植了优秀的软编码算法(如X264)的,质量基本等同于软编码。
二、目前主流的GPU平台开发框架
CUVID:NVIDIA的封闭编程框架,通过框架可以调用GPU计算资源,N卡专用。
AMD APP:AMD为自己的GPU提出的一套通用并行编程框架,标准开放,通过在CPU、GPU同时支持OpenCL框架,进行计算力融合。
OpenCL:开放计算语言,为异构平台编写程序的该框架,异构平台可包含CPU、GPU以及其他计算处理器,目标是使相同的运算能支持不同平台硬件加速。
Inel QuickSync:集成于Intel显卡中的专用视频编解码模块,核显专用。
CUDA只能够在NVIDIA的GPU硬件上运行。但是,OpenCL的目标是面向任何一种并行处理器,OpenCL是第一种真正的开放自由版权编程标准,适用于异构系统上的通用计算。而异构平台可由CPU、GPU、DSP、FPGA或其他类型的处理器搭建。
DXVA:DXVA是DirectX Video Acceleration的简称,中文译为视频硬件加速。DXVA是微软公司专门定制的视频加速规范,它共有两个版本,分别是DXVA 1.0和DXVA 2.0,几乎所有的显卡都具备硬件加速能力。
三、流程区别
硬解软编: read(ffmpeg) -》 decoder(NVIDIA) -》 | Queue -》 encoder(ffmpeg)
软解软编: read(ffmpeg) -》 decoder(ffmpeg) -》encoder(ffmpeg)
解码与编码之间维护一个队列,队列长度定为20(因为解码速度快于编码速度,数据被覆盖,丢帧)
四、NVIDIA CUVID,Intel QuickSync和DXVA2,其中DXVA2又分为DXVA2 (copy-back)和DXVA2 (native),那么这几种解码方式有什么区别?
NVIDIA CUVID是NVIDIA专用硬体解码介面,可以开启硬体去交错处理。
Intel QuickSync:Intel內显专用硬体解码介面,CPU使用率比其余硬解模式稍高5~10%左右,可以开启硬体去交错处理。
DXVA2 (copy-back):为微软开发的硬体加速介面,AMD,NVIDIA,Intel显示卡均可使用,会將解码完成的资讯回传给记忆体,由于多个回传动作,故效能会比native略差,不过优势为可以在解码器与渲染器中间添加滤镜。
DXVA2 (native):为微软开发的硬体加速介面,同样AMD,NVIDIA,Intel显示卡均可使用,会將解码完成的资讯將不会传给记忆体,直接渲染,故效能比copy-back佳,缺点为限制较多。
所以解码方式推荐:DXVA2 (native) > DXVA2 (copy-back) > NVIDIA CUVID 或 Intel QuickSync。
五、NVIDIA硬件编解码方案
1、使用 SDK 中的编解码接口
英伟达关于视频的编解码提供了两个相关的 SDK
NVENC --负责硬件编码
NVCUVID --负责硬件解码
NVENC是一个单独的 SDK,集成在最新的显卡驱动上面,安装最新的驱动之后可以找到相关的库文件。在 Ubuntu 14.04 中,可以在/usr/lib/nvidia-352/目录下面找到相关的库文件。
NVCUVID是CUDA的组件,包含在最新的CUDA Toolkit中。不过在显卡的类库中可以找到libnvcuvid.so这个库文件。在之前版本的显卡驱动中其他还包含一个称之为NVCUVENC的硬件编码器和NVCUVID相对应,不过目前这个组件已经被NVENC替代了。
2、使用编码器对于 OpenCL 和 SDK 的封装
这种方式是个人认为最理想的方式,FFMPEG 目前存在一个编码器nvenc是对于英伟达的NVENC的封装,通过使用它可以和 FFMPEG 无缝的整合起来。此外它也包含对于Intel QSV的封装。AMD 的相关接口目前没有找到相关的资料。
不过 FFMPEG 只存在NVENC的接口,不存在NVCUVID的封装。如果需要实现相关的解码器可能需要自己实现 FFMPEG 接口。
libx264有对于 OpenCL 的封装,不过我在 windows 中尝试这个功能的时候并没有成功。
另外还存在一个开源的格式转换器HandBrake,它包含对于Intel QuickSync的封装,以及使用OpenCL进行图象的拉伸处理和使用x264的opencl封装。这个项目缺点在于文档不是很丰富,研究起来有一定的难度。
要想在 FFMPEG 中使用nvenc编码器,你需要在编译选项中加入enable-nvenc选项(老版本,新版本是自动检测,显示提供disable-nvenc的选项)。
这个选项依赖于nvEncodeAPI.h头文件,这个头文件并没有包含在私有驱动中,你需要到NVIDIA VIDEO CODEC SDK中下载 SDK,解压后在Samples/common/inc目录下有这个头文件,把它拷贝到可以链接到的目录中去。之后编译就可以顺利的通过,得到包含nvenc编码器的库。
六、ffmpeg硬解码绘制视频,cpu依然占用高。
cpu占用高主要是因为av_hwframe_transfer_data(sw_frame, frame, 0)占用了cpu,不要用这个函数,应该用d3d+dxva2 或者cuda+opengl硬渲染。
OpenCL主要用于通用的并行计算,它基于预定义的数据结构和代码,可以让GPU处理各种通用的计算任务,例如视频处理、金融建模、科学计算和影像处理等,充分利用现代GPU的并行可扩展性。OpenCL可以在多个硬件平台上运行,包括CPU、GPU和FPGA,并且与OpenGL、Direct3D和其他API无关,因此可以与不同的图形API进行交互。
而OpenGL专注于计算机图形处理和渲染,它提供了一个强大的渲染管道,具有着广泛的支持和广泛的用途。在游戏和虚拟现实应用程序中,OpenGL被用作实时图形渲染的标准API。但是,OpenGL无法执行通用的计算任务,这要求我们使用其他API,例如OpenCL或CUDA。
七、常用命令
1、如何用ffmpeg命令列举支持的硬件解码器:
ffmpeg -hwaccels
2、ffmpeg硬解命令:
ffmpeg -i d:\input.mp4 -vcodec libx264 d:\output.mp4
ffmpeg 转码过程中输出的 frame ,fps,q,size, bitrate ,speed 的意义。
frame表示视频当前第几帧;fps表示一秒编码了多少个视频帧;q表示编码质量;size表示写入文件的数据大小;bitrate表示比特率(单位是 kbits/s 1000位/秒);time表示当前处理文件位置时长;speed表示编码速度(多少秒视频帧/多少秒ffmpeg处理时间)。
根据speed可以计算出ffmpeg耗时,一个视频文件ffmpeg处理完成时间为:视频时长秒/speed。
ffmpeg version 4.4-full_build-www.gyan.dev Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10.2.0 (Rev6, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-libsnappy --enable-zlib --enable-librist --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-libbluray --enable-libcaca --enable-sdl2 --enable-libdav1d --enable-libzvbi --enable-librav1e --enable-libsvtav1 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-frei0r --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libglslang --enable-vulkan --enable-opencl --enable-libcdio --enable-libgme --enable-libmodplug --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libshine --enable-libtheora --enable-libtwolame --enable-libvo-amrwbenc --enable-libilbc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-ladspa --enable-libbs2b --enable-libflite --enable-libmysofa --enable-librubberband --enable-libsoxr --enable-chromaprint
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
Input #0, mpeg, from 'd:\input.mp4':
Duration: 03:37:39.62, start: 37915.032111, bitrate: 354 kb/s
Stream #0:0[0x1e0]: Video: hevc (Main), yuvj420p(pc, bt709), 960x576, 50 fps, 25 tbr, 90k tbn, 50 tbc
Stream #0:1[0x1c0]: Audio: pcm_mulaw, 8000 Hz, mono, s16, 64 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (hevc (hevc_cuvid) -> h264 (h264_nvenc))
Press [q] to stop, [?] for help
Output #0, mp4, to 'd:\ch01_202203302130002-hw3.mp4':
Metadata:
encoder : Lavf58.76.100
Stream #0:0: Video: h264 (Main) (avc1 / 0x31637661), nv12(pc, bt709, progressive), 960x576 [SAR 1:1 DAR 5:3], q=2-31, 4000 kb/s, 25 fps, 12800 tbn
Metadata:
encoder : Lavc58.134.100 h264_nvenc
Side data:
cpb: bitrate max/min/avg: 0/0/4000000 buffer size: 8000000 vbv_delay: N/A
frame=200781 fps=728 q=9.0 size= 3945472kB time=02:13:51.12 bitrate=4024.5kbits/s dup=0 drop=5 speed=29.1x
3、显示英伟达显卡nvidia-smi命令
3.1显示GPU当前的状态:
nvidia-smi
参数详解:
**GPU:**本机中的GPU编号(有多块显卡的时候,从0开始编号)
**Fan:**风扇转速(0%-100%),N/A表示没有风扇,这个速度是计算机期望的风扇转速,实际情况下如果风扇堵转,可能打不到显示的转速。
**Name:**GPU类型,图上GPU的类型是:GeForce MX250/RTX 2080Ti
**Temp:**GPU的温度(GPU温度过高会导致GPU的频率下降)
**Perf:**GPU的性能状态,从P0(最大性能)到P12(最小性能)
**Persistence-M:**持续模式的状态,持续模式虽然耗能大,但是在新的GPU应用启动时花费的时间更少。
**Pwr:Usager/Cap:**能耗表示,Usage:用了多少,Cap总共多少
**Bus-Id:**GPU总线相关显示,domain:bus:device.function
**Disp.A:**Display Active ,表示GPU的显示是否初始化
**Memory-Usage:**显存使用率
**Volatile GPU-Util:**GPU使用率
**Uncorr. ECC:**关于ECC的东西,是否开启错误检查和纠正技术,0/disabled,1/enabled
**Compute M:**计算模式,0/DEFAULT,1/EXCLUSIVE_PROCESS,2/PROHIBITED
**Processes:**显示每个进程占用的显存使用率、进程号、占用的哪个GPU
**type:**进程类型。C 表示计算进程,G 表示图形进程,C+G 表示都有。
3.2隔几秒刷新一下显存状态:
nvidia-smi -l 秒数
3.3将监控结果写入文件,并且指定写入文件的监控字段:
nvidia-smi -l 1 --format=csv --filename=report.csv --query-gpu=timestamp,name,index,utilization.gpu,memory.total,memory.used,power.draw
参考资料:
https://tool.4xseo.com/a/169.html
https://www.cnblogs.com/huty/p/8517141.html
https://blog.csdn.net/qq_40594137/article/details/124959608
https://deepinout.com/opencl/opencl-tutorials/22_difference_between_opencl_and_opengl.html